feat(core): display embedding progress (#10871)

Close [BS-2791](https://linear.app/affine-design/issue/BS-2791).
This commit is contained in:
akumatus
2025-03-14 11:58:29 +00:00
parent 99fdfe821a
commit a648edafc0
2 changed files with 18 additions and 14 deletions

View File

@@ -61,6 +61,8 @@ export type ChatContextValue = {
images: File[]; images: File[];
// chips of workspace doc or user uploaded file // chips of workspace doc or user uploaded file
chips: ChatChip[]; chips: ChatChip[];
// the progress of the embedding
embeddingProgress: [number, number];
abortController: AbortController | null; abortController: AbortController | null;
}; };

View File

@@ -47,6 +47,7 @@ const DEFAULT_CHAT_CONTEXT_VALUE: ChatContextValue = {
status: 'idle', status: 'idle',
error: null, error: null,
markdown: '', markdown: '',
embeddingProgress: [0, 0],
}; };
export class ChatPanel extends SignalWatcher( export class ChatPanel extends SignalWatcher(
@@ -192,12 +193,8 @@ export class ChatPanel extends SignalWatcher(
(a, b) => (a, b) =>
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
); );
let allDone = true;
const chips: ChatChip[] = await Promise.all( const chips: ChatChip[] = await Promise.all(
list.map(async item => { list.map(async item => {
if (item.status === 'processing') {
allDone = false;
}
if (isDocContext(item)) { if (isDocContext(item)) {
return { return {
docId: item.id, docId: item.id,
@@ -228,10 +225,10 @@ export class ChatPanel extends SignalWatcher(
...this.chatContextValue, ...this.chatContextValue,
chips, chips,
}; };
};
if (!allDone) { private readonly _initEmbeddingProgress = async () => {
await this._pollContextDocsAndFiles(); await this._pollContextDocsAndFiles();
}
}; };
private readonly _getSessionId = async () => { private readonly _getSessionId = async () => {
@@ -357,6 +354,7 @@ export class ChatPanel extends SignalWatcher(
); );
} }
await this._initChips(); await this._initChips();
await this._initEmbeddingProgress();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@@ -367,8 +365,8 @@ export class ChatPanel extends SignalWatcher(
return; return;
} }
if (this._pollAbortController) { if (this._pollAbortController) {
// already polling, return // already polling, reset timer
return; this._abortPoll();
} }
this._pollAbortController = new AbortController(); this._pollAbortController = new AbortController();
await AIProvider.context.pollContextDocsAndFiles( await AIProvider.context.pollContextDocsAndFiles(
@@ -389,17 +387,18 @@ export class ChatPanel extends SignalWatcher(
} }
const { docs = [], files = [] } = result; const { docs = [], files = [] } = result;
const hashMap = new Map<string, CopilotContextDoc | CopilotContextFile>(); const hashMap = new Map<string, CopilotContextDoc | CopilotContextFile>();
let allDone = true; const totalCount = docs.length + files.length;
let processingCount = 0;
docs.forEach(doc => { docs.forEach(doc => {
hashMap.set(doc.id, doc); hashMap.set(doc.id, doc);
if (doc.status === 'processing') { if (doc.status === 'processing') {
allDone = false; processingCount++;
} }
}); });
files.forEach(file => { files.forEach(file => {
hashMap.set(file.id, file); hashMap.set(file.id, file);
if (file.status === 'processing') { if (file.status === 'processing') {
allDone = false; processingCount++;
} }
}); });
const nextChips = this.chatContextValue.chips.map(chip => { const nextChips = this.chatContextValue.chips.map(chip => {
@@ -415,8 +414,9 @@ export class ChatPanel extends SignalWatcher(
}); });
this.updateContext({ this.updateContext({
chips: nextChips, chips: nextChips,
embeddingProgress: [totalCount - processingCount, totalCount],
}); });
if (allDone) { if (processingCount === 0) {
this._abortPoll(); this._abortPoll();
} }
}; };
@@ -544,10 +544,12 @@ export class ChatPanel extends SignalWatcher(
const style = styleMap({ const style = styleMap({
padding: width > 540 ? '8px 24px 0 24px' : '8px 12px 0 12px', padding: width > 540 ? '8px 24px 0 24px' : '8px 12px 0 12px',
}); });
const [done, total] = this.chatContextValue.embeddingProgress;
const isEmbedding = total > 0 && done < total;
return html`<div class="chat-panel-container" style=${style}> return html`<div class="chat-panel-container" style=${style}>
<div class="chat-panel-title"> <div class="chat-panel-title">
<div>AFFiNE AI</div> <div>${isEmbedding ? `Embedding ${done}/${total}` : 'AFFiNE AI'}</div>
<div <div
@click=${() => { @click=${() => {
AIProvider.toggleGeneralAIOnboarding?.(true); AIProvider.toggleGeneralAIOnboarding?.(true);