diff --git a/packages/frontend/core/src/blocksuite/ai/actions/types.ts b/packages/frontend/core/src/blocksuite/ai/actions/types.ts index febc97e902..99a819db0d 100644 --- a/packages/frontend/core/src/blocksuite/ai/actions/types.ts +++ b/packages/frontend/core/src/blocksuite/ai/actions/types.ts @@ -13,8 +13,6 @@ import type { EditorHost } from '@blocksuite/affine/std'; import type { GfxModel } from '@blocksuite/affine/std/gfx'; import type { BlockModel } from '@blocksuite/affine/store'; -import type { DocContext, FileContext } from '../chat-panel/chat-context'; - export const translateLangs = [ 'English', 'Spanish', @@ -114,12 +112,28 @@ declare global { type AIActionTextResponse = T['stream'] extends true ? TextStream : Promise; + interface AIDocContextOption { + docId: string; + docTitle: string; + docContent: string; + tags: string; + createDate: string; + updatedDate: string; + } + + interface AIFileContextOption { + blobId: string; + fileName: string; + fileType: string; + fileContent: string; + } + interface ChatOptions extends AITextActionOptions { sessionId?: string; isRootSession?: boolean; contexts?: { - docs: DocContext[]; - files: FileContext[]; + docs: AIDocContextOption[]; + files: AIFileContextOption[]; }; } diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-config.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-config.ts index 3fa6de8455..979ecad955 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-config.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-config.ts @@ -1,12 +1,3 @@ -import type { TagMeta } from '@affine/core/components/page-list'; -import type { - SearchCollectionMenuAction, - SearchDocMenuAction, - SearchTagMenuAction, -} from '@affine/core/modules/search-menu/services'; -import type { Collection } from '@affine/env/filter'; -import type { LinkedMenuGroup } from '@blocksuite/affine/blocks/root'; -import type { DocMeta, Store } from '@blocksuite/affine/store'; import type { Signal } from '@preact/signals-core'; export interface AppSidebarConfig { @@ -25,52 +16,3 @@ export interface AINetworkSearchConfig { enabled: Signal; setEnabled: (state: boolean) => void; } - -export interface DocDisplayConfig { - getIcon: (docId: string) => any; - getTitle: (docId: string) => string; - getTitleSignal: (docId: string) => { - signal: Signal; - cleanup: () => void; - }; - getDocMeta: (docId: string) => Partial | null; - getDocPrimaryMode: (docId: string) => 'page' | 'edgeless'; - getDoc: (docId: string) => Store | null; - getReferenceDocs: (docIds: string[]) => { - signal: Signal< - Array<{ - docId: string; - title: string; - }> - >; - cleanup: () => void; - }; - getTags: () => { - signal: Signal; - cleanup: () => void; - }; - getTagTitle: (tagId: string) => string; - getTagPageIds: (tagId: string) => string[]; - getCollections: () => { - signal: Signal; - cleanup: () => void; - }; -} - -export interface SearchMenuConfig { - getDocMenuGroup: ( - query: string, - action: SearchDocMenuAction, - abortSignal: AbortSignal - ) => LinkedMenuGroup; - getTagMenuGroup: ( - query: string, - action: SearchTagMenuAction, - abortSignal: AbortSignal - ) => LinkedMenuGroup; - getCollectionMenuGroup: ( - query: string, - action: SearchCollectionMenuAction, - abortSignal: AbortSignal - ) => LinkedMenuGroup; -} diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-context.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-context.ts index 6739678517..c762d3fdfa 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-context.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-context.ts @@ -1,5 +1,3 @@ -import type { Signal } from '@preact/signals-core'; - import type { AIError } from '../provider'; export type ChatMessage = { @@ -34,22 +32,6 @@ export type ChatStatus = | 'idle' | 'transmitting'; -export interface DocContext { - docId: string; - docTitle: string; - docContent: string; - tags: string; - createDate: string; - updatedDate: string; -} - -export interface FileContext { - blobId: string; - fileName: string; - fileType: string; - fileContent: string; -} - export type ChatContextValue = { // history messages of the chat items: ChatItem[]; @@ -61,10 +43,6 @@ export type ChatContextValue = { markdown: string; // images of the selected content or user uploaded images: File[]; - // chips of workspace doc or user uploaded file - chips: ChatChip[]; - // the progress of the embedding - embeddingProgress: [number, number]; abortController: AbortController | null; }; @@ -73,39 +51,3 @@ export type ChatBlockMessage = ChatMessage & { userName?: string; avatarUrl?: string; }; - -export type ChipState = 'candidate' | 'processing' | 'finished' | 'failed'; - -export interface BaseChip { - /** - * candidate: the chip is a candidate for the chat - * processing: the chip is processing - * finished: the chip is successfully processed - * failed: the chip is failed to process - */ - state: ChipState; - tooltip?: string | null; - createdAt?: number | null; -} - -export interface DocChip extends BaseChip { - docId: string; - markdown?: Signal | null; - tokenCount?: number | null; -} - -export interface FileChip extends BaseChip { - file: File; - fileId?: string | null; - blobId?: string | null; -} - -export interface TagChip extends BaseChip { - tagId: string; -} - -export interface CollectionChip extends BaseChip { - collectionId: string; -} - -export type ChatChip = DocChip | FileChip | TagChip | CollectionChip; diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-input.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-input.ts index 72885fa6a3..86d9947e03 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-input.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-input.ts @@ -14,18 +14,17 @@ import { property, query, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { ChatAbortIcon, ChatSendIcon } from '../_common/icons'; +import type { + ChatChip, + DocDisplayConfig, + FileChip, +} from '../components/ai-chat-chips'; +import { isDocChip, isFileChip } from '../components/ai-chat-chips'; import { type AIError, AIProvider } from '../provider'; import { reportResponse } from '../utils/action-reporter'; import { readBlobAsURL } from '../utils/image'; -import type { AINetworkSearchConfig, DocDisplayConfig } from './chat-config'; -import type { - ChatContextValue, - ChatMessage, - DocContext, - FileChip, - FileContext, -} from './chat-context'; -import { isDocChip, isFileChip } from './components/utils'; +import type { AINetworkSearchConfig } from './chat-config'; +import type { ChatContextValue, ChatMessage } from './chat-context'; import { PROMPT_NAME_AFFINE_AI, PROMPT_NAME_NETWORK_SEARCH } from './const'; const MaximumImageCount = 32; @@ -201,6 +200,9 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) { @property({ attribute: false }) accessor chatContextValue!: ChatContextValue; + @property({ attribute: false }) + accessor chips: ChatChip[] = []; + @property({ attribute: false }) accessor getSessionId!: () => Promise; @@ -232,8 +234,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) { private get _isNetworkDisabled() { return ( !!this.chatContextValue.images.length || - !!this.chatContextValue.chips.filter(chip => chip.state === 'finished') - .length + !!this.chips.filter(chip => chip.state === 'finished').length ); } @@ -575,7 +576,10 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) { string, { docId: string; docContent: string } >(); - const fileContexts = new Map(); + const fileContexts = new Map< + string, + BlockSuitePresets.AIFileContextOption + >(); const { files: matchedFiles = [], docs: matchedDocs = [] } = (await AIProvider.context?.matchContext(contextId, userInput)) ?? {}; @@ -592,7 +596,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) { if (context) { context.fileContent += `\n${file.content}`; } else { - const fileChip = this.chatContextValue.chips.find( + const fileChip = this.chips.find( chip => isFileChip(chip) && chip.fileId === file.fileId ) as FileChip | undefined; if (fileChip && fileChip.blobId) { @@ -606,7 +610,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) { } }); - this.chatContextValue.chips.forEach(chip => { + this.chips.forEach(chip => { if (isDocChip(chip) && !!chip.markdown?.value) { docContexts.set(chip.docId, { docId: chip.docId, @@ -615,7 +619,9 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) { } }); - const docs: DocContext[] = Array.from(docContexts.values()).map(doc => { + const docs: BlockSuitePresets.AIDocContextOption[] = Array.from( + docContexts.values() + ).map(doc => { const docMeta = this.docDisplayConfig.getDocMeta(doc.docId); const docTitle = this.docDisplayConfig.getTitle(doc.docId); const tags = docMeta?.tags diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts index 2259df3216..69dd4a3b25 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts @@ -21,40 +21,38 @@ import { createRef, type Ref, ref } from 'lit/directives/ref.js'; import { styleMap } from 'lit/directives/style-map.js'; import { throttle } from 'lodash-es'; +import type { + ChatChip, + CollectionChip, + DocChip, + DocDisplayConfig, + FileChip, + SearchMenuConfig, + TagChip, +} from '../components/ai-chat-chips'; +import { + isCollectionChip, + isDocChip, + isTagChip, +} from '../components/ai-chat-chips'; import { AIProvider } from '../provider'; import { extractSelectedContent } from '../utils/extract'; import { getSelectedImagesAsBlobs, getSelectedTextContent, } from '../utils/selection-utils'; -import type { - AINetworkSearchConfig, - AppSidebarConfig, - DocDisplayConfig, - SearchMenuConfig, -} from './chat-config'; -import type { - ChatChip, - ChatContextValue, - ChatItem, - CollectionChip, - DocChip, - FileChip, - TagChip, -} from './chat-context'; +import type { AINetworkSearchConfig, AppSidebarConfig } from './chat-config'; +import type { ChatContextValue, ChatItem } from './chat-context'; import type { ChatPanelMessages } from './chat-panel-messages'; -import { isCollectionChip, isDocChip, isTagChip } from './components/utils'; const DEFAULT_CHAT_CONTEXT_VALUE: ChatContextValue = { quote: '', images: [], abortController: null, items: [], - chips: [], status: 'idle', error: null, markdown: '', - embeddingProgress: [0, 0], }; export class ChatPanel extends SignalWatcher( @@ -245,10 +243,7 @@ export class ChatPanel extends SignalWatcher( return aTime - bTime; }); - this.chatContextValue = { - ...this.chatContextValue, - chips, - }; + this.updateChips(chips); }; private readonly _initEmbeddingProgress = async () => { @@ -307,6 +302,12 @@ export class ChatPanel extends SignalWatcher( @state() accessor chatContextValue: ChatContextValue = DEFAULT_CHAT_CONTEXT_VALUE; + @state() + accessor chips: ChatChip[] = []; + + @state() + accessor embeddingProgress: [number, number] = [0, 0]; + private _chatSessionId: string | null | undefined = null; private _chatContextId: string | null | undefined = null; @@ -391,6 +392,16 @@ export class ChatPanel extends SignalWatcher( } }; + private readonly _resetPanel = () => { + this._abortPoll(); + this._chatSessionId = null; + this._chatContextId = null; + this.chatContextValue = DEFAULT_CHAT_CONTEXT_VALUE; + this.isLoading = true; + this.chips = []; + this.embeddingProgress = [0, 0]; + }; + private readonly _pollContextDocsAndFiles = async () => { if (!this._chatSessionId || !this._chatContextId || !AIProvider.context) { return; @@ -444,7 +455,7 @@ export class ChatPanel extends SignalWatcher( hashMap.set(file.id, file); file.status && count[file.status]++; }); - const nextChips = this.chatContextValue.chips.map(chip => { + const nextChips = this.chips.map(chip => { if (isTagChip(chip) || isCollectionChip(chip)) { return chip; } @@ -460,10 +471,8 @@ export class ChatPanel extends SignalWatcher( return chip; }); const total = count.finished + count.processing + count.failed; - this.updateContext({ - chips: nextChips, - embeddingProgress: [count.finished, total], - }); + this.embeddingProgress = [count.finished, total]; + this.updateChips(nextChips); if (count.processing === 0) { this._abortPoll(); } @@ -476,12 +485,7 @@ export class ChatPanel extends SignalWatcher( protected override updated(_changedProperties: PropertyValues) { if (_changedProperties.has('doc')) { - this._abortPoll(); - this._chatSessionId = null; - this._chatContextId = null; - this.chatContextValue = DEFAULT_CHAT_CONTEXT_VALUE; - this.isLoading = true; - + this._resetPanel(); requestAnimationFrame(async () => { await this._initPanel(); }); @@ -576,6 +580,10 @@ export class ChatPanel extends SignalWatcher( this.chatContextValue = { ...this.chatContextValue, ...context }; }; + updateChips = (chips: ChatChip[]) => { + this.chips = chips; + }; + continueInChat = async () => { const text = await getSelectedTextContent(this.host, 'plain-text'); const markdown = await getSelectedTextContent(this.host, 'markdown'); @@ -592,7 +600,7 @@ export class ChatPanel extends SignalWatcher( const style = styleMap({ padding: width > 540 ? '8px 24px 0 24px' : '8px 12px 0 12px', }); - const [done, total] = this.chatContextValue.embeddingProgress; + const [done, total] = this.embeddingProgress; const isEmbedding = total > 0 && done < total; return html`
@@ -617,14 +625,15 @@ export class ChatPanel extends SignalWatcher( > Promise; @property({ attribute: false }) - accessor updateContext!: (context: Partial) => void; + accessor updateChips!: (chips: ChatChip[]) => void; @property({ attribute: false }) accessor pollContextDocsAndFiles!: () => void; @@ -134,9 +134,7 @@ export class ChatPanelChips extends SignalWatcher( state: 'candidate', })); const moreCandidates = candidates.length > MAX_CANDIDATES; - const allChips = this.chatContextValue.chips.concat( - candidates.slice(0, MAX_CANDIDATES) - ); + const allChips = this.chips.concat(candidates.slice(0, MAX_CANDIDATES)); const isCollapsed = this.isCollapsed && allChips.length > 1; const chips = isCollapsed ? allChips.slice(0, 1) : allChips; @@ -232,8 +230,7 @@ export class ChatPanelChips extends SignalWatcher( this.isCollapsed = true; } - // TODO only update when the chips are changed - if (_changedProperties.has('chatContextValue')) { + if (_changedProperties.has('chips')) { this._updateReferenceDocs(); } } @@ -324,11 +321,9 @@ export class ChatPanelChips extends SignalWatcher( private readonly _addChip = async (chip: ChatChip) => { this.isCollapsed = false; // remove the chip if it already exists - const chips = this._omitChip(this.chatContextValue.chips, chip); - this.updateContext({ - chips: [...chips, chip], - }); - if (chips.length < this.chatContextValue.chips.length) { + const chips = this._omitChip(this.chips, chip); + this.updateChips([...chips, chip]); + if (chips.length < this.chips.length) { await this._removeFromContext(chip); } await this._addToContext(chip); @@ -339,7 +334,7 @@ export class ChatPanelChips extends SignalWatcher( chip: ChatChip, options: Partial ) => { - const index = this._findChipIndex(this.chatContextValue.chips, chip); + const index = this._findChipIndex(this.chips, chip); if (index === -1) { return; } @@ -347,21 +342,17 @@ export class ChatPanelChips extends SignalWatcher( ...chip, ...options, }; - this.updateContext({ - chips: [ - ...this.chatContextValue.chips.slice(0, index), - nextChip, - ...this.chatContextValue.chips.slice(index + 1), - ], - }); + this.updateChips([ + ...this.chips.slice(0, index), + nextChip, + ...this.chips.slice(index + 1), + ]); }; private readonly _removeChip = async (chip: ChatChip) => { - const chips = this._omitChip(this.chatContextValue.chips, chip); - this.updateContext({ - chips, - }); - if (chips.length < this.chatContextValue.chips.length) { + const chips = this._omitChip(this.chips, chip); + this.updateChips(chips); + if (chips.length < this.chips.length) { await this._removeFromContext(chip); } }; @@ -518,7 +509,7 @@ export class ChatPanelChips extends SignalWatcher( newChip: DocChip, newTokenCount: number ) => { - const estimatedTokens = this.chatContextValue.chips.reduce((acc, chip) => { + const estimatedTokens = this.chips.reduce((acc, chip) => { if (isFileChip(chip) || isTagChip(chip) || isCollectionChip(chip)) { return acc; } @@ -536,7 +527,7 @@ export class ChatPanelChips extends SignalWatcher( }; private readonly _updateReferenceDocs = () => { - const docIds = this.chatContextValue.chips + const docIds = this.chips .filter(isDocChip) .filter(chip => chip.state !== 'candidate') .map(chip => chip.docId); diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/chip.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/chip.ts similarity index 98% rename from packages/frontend/core/src/blocksuite/ai/chat-panel/components/chip.ts rename to packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/chip.ts index 5e03548403..bfed860c40 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/chip.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/chip.ts @@ -5,7 +5,7 @@ import { CloseIcon, PlusIcon } from '@blocksuite/icons/lit'; import { css, html, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; -import type { ChipState } from '../chat-context'; +import type { ChipState } from './type'; export class ChatPanelChip extends SignalWatcher( WithDisposable(ShadowlessElement) diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/collection-chip.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/collection-chip.ts similarity index 96% rename from packages/frontend/core/src/blocksuite/ai/chat-panel/components/collection-chip.ts rename to packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/collection-chip.ts index d17cd85ded..88af22a66b 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/collection-chip.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/collection-chip.ts @@ -5,7 +5,7 @@ import { CollectionsIcon } from '@blocksuite/icons/lit'; import { html } from 'lit'; import { property } from 'lit/decorators.js'; -import type { CollectionChip } from '../chat-context'; +import type { CollectionChip } from './type'; import { getChipIcon, getChipTooltip } from './utils'; export class ChatPanelCollectionChip extends SignalWatcher( diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/doc-chip.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/doc-chip.ts similarity index 97% rename from packages/frontend/core/src/blocksuite/ai/chat-panel/components/doc-chip.ts rename to packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/doc-chip.ts index 60dbecb686..32f61c6d8c 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/doc-chip.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/doc-chip.ts @@ -7,8 +7,7 @@ import { property } from 'lit/decorators.js'; import throttle from 'lodash-es/throttle'; import { extractMarkdownFromDoc } from '../../utils/extract'; -import type { DocDisplayConfig } from '../chat-config'; -import type { DocChip } from '../chat-context'; +import type { DocChip, DocDisplayConfig } from './type'; import { estimateTokenCount, getChipIcon, getChipTooltip } from './utils'; const EXTRACT_DOC_THROTTLE = 1000; diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/file-chip.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/file-chip.ts similarity index 96% rename from packages/frontend/core/src/blocksuite/ai/chat-panel/components/file-chip.ts rename to packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/file-chip.ts index a24e69cd09..2580af2178 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/file-chip.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/file-chip.ts @@ -4,7 +4,7 @@ import { ShadowlessElement } from '@blocksuite/affine/std'; import { html } from 'lit'; import { property } from 'lit/decorators.js'; -import type { FileChip } from '../chat-context'; +import type { FileChip } from './type'; import { getChipIcon, getChipTooltip } from './utils'; export class ChatPanelFileChip extends SignalWatcher( diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/index.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/index.ts new file mode 100644 index 0000000000..f7e6c3718e --- /dev/null +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/index.ts @@ -0,0 +1,2 @@ +export * from './type'; +export * from './utils'; diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/tag-chip.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/tag-chip.ts similarity index 97% rename from packages/frontend/core/src/blocksuite/ai/chat-panel/components/tag-chip.ts rename to packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/tag-chip.ts index 71b42fc5ea..6fba7507a7 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/tag-chip.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/tag-chip.ts @@ -5,7 +5,7 @@ import { ShadowlessElement } from '@blocksuite/affine/std'; import { css, html } from 'lit'; import { property } from 'lit/decorators.js'; -import type { TagChip } from '../chat-context'; +import type { TagChip } from './type'; import { getChipIcon, getChipTooltip } from './utils'; export class ChatPanelTagChip extends SignalWatcher( diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/type.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/type.ts new file mode 100644 index 0000000000..8a35b8823b --- /dev/null +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/type.ts @@ -0,0 +1,95 @@ +import type { TagMeta } from '@affine/core/components/page-list'; +import type { + SearchCollectionMenuAction, + SearchDocMenuAction, + SearchTagMenuAction, +} from '@affine/core/modules/search-menu/services'; +import type { Collection } from '@affine/env/filter'; +import type { LinkedMenuGroup } from '@blocksuite/affine/blocks/root'; +import type { DocMeta, Store } from '@blocksuite/affine/store'; +import type { Signal } from '@preact/signals-core'; + +export type ChipState = 'candidate' | 'processing' | 'finished' | 'failed'; + +export interface BaseChip { + /** + * candidate: the chip is a candidate for the chat + * processing: the chip is processing + * finished: the chip is successfully processed + * failed: the chip is failed to process + */ + state: ChipState; + tooltip?: string | null; + createdAt?: number | null; +} + +export interface DocChip extends BaseChip { + docId: string; + markdown?: Signal | null; + tokenCount?: number | null; +} + +export interface FileChip extends BaseChip { + file: File; + fileId?: string | null; + blobId?: string | null; +} + +export interface TagChip extends BaseChip { + tagId: string; +} + +export interface CollectionChip extends BaseChip { + collectionId: string; +} + +export type ChatChip = DocChip | FileChip | TagChip | CollectionChip; + +export interface DocDisplayConfig { + getIcon: (docId: string) => any; + getTitle: (docId: string) => string; + getTitleSignal: (docId: string) => { + signal: Signal; + cleanup: () => void; + }; + getDocMeta: (docId: string) => Partial | null; + getDocPrimaryMode: (docId: string) => 'page' | 'edgeless'; + getDoc: (docId: string) => Store | null; + getReferenceDocs: (docIds: string[]) => { + signal: Signal< + Array<{ + docId: string; + title: string; + }> + >; + cleanup: () => void; + }; + getTags: () => { + signal: Signal; + cleanup: () => void; + }; + getTagTitle: (tagId: string) => string; + getTagPageIds: (tagId: string) => string[]; + getCollections: () => { + signal: Signal; + cleanup: () => void; + }; +} + +export interface SearchMenuConfig { + getDocMenuGroup: ( + query: string, + action: SearchDocMenuAction, + abortSignal: AbortSignal + ) => LinkedMenuGroup; + getTagMenuGroup: ( + query: string, + action: SearchTagMenuAction, + abortSignal: AbortSignal + ) => LinkedMenuGroup; + getCollectionMenuGroup: ( + query: string, + action: SearchCollectionMenuAction, + abortSignal: AbortSignal + ) => LinkedMenuGroup; +} diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/utils.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/utils.ts similarity index 98% rename from packages/frontend/core/src/blocksuite/ai/chat-panel/components/utils.ts rename to packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/utils.ts index a88a49af4c..49d04948d8 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/components/utils.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-chips/utils.ts @@ -9,7 +9,7 @@ import type { DocChip, FileChip, TagChip, -} from '../chat-context'; +} from './type'; export function getChipTooltip( state: ChipState, diff --git a/packages/frontend/core/src/blocksuite/ai/effects.ts b/packages/frontend/core/src/blocksuite/ai/effects.ts index bae038ec45..71f2993f62 100644 --- a/packages/frontend/core/src/blocksuite/ai/effects.ts +++ b/packages/frontend/core/src/blocksuite/ai/effects.ts @@ -23,16 +23,8 @@ import { ActionMindmap } from './chat-panel/actions/mindmap'; import { ActionSlides } from './chat-panel/actions/slides'; import { ActionText } from './chat-panel/actions/text'; import { AILoading } from './chat-panel/ai-loading'; -import { ChatPanelChips } from './chat-panel/chat-panel-chips'; import { ChatPanelInput } from './chat-panel/chat-panel-input'; import { ChatPanelMessages } from './chat-panel/chat-panel-messages'; -import { ChatPanelAddPopover } from './chat-panel/components/add-popover'; -import { ChatPanelCandidatesPopover } from './chat-panel/components/candidates-popover'; -import { ChatPanelChip } from './chat-panel/components/chip'; -import { ChatPanelCollectionChip } from './chat-panel/components/collection-chip'; -import { ChatPanelDocChip } from './chat-panel/components/doc-chip'; -import { ChatPanelFileChip } from './chat-panel/components/file-chip'; -import { ChatPanelTagChip } from './chat-panel/components/tag-chip'; import { AssistantAvatar } from './chat-panel/content/assistant-avatar'; import { ChatContentImages } from './chat-panel/content/images'; import { ChatContentPureText } from './chat-panel/content/pure-text'; @@ -40,6 +32,14 @@ import { ChatContentRichText } from './chat-panel/content/rich-text'; import { ChatMessageAction } from './chat-panel/message/action'; import { ChatMessageAssistant } from './chat-panel/message/assistant'; import { ChatMessageUser } from './chat-panel/message/user'; +import { ChatPanelAddPopover } from './components/ai-chat-chips/add-popover'; +import { ChatPanelCandidatesPopover } from './components/ai-chat-chips/candidates-popover'; +import { ChatPanelChips } from './components/ai-chat-chips/chat-panel-chips'; +import { ChatPanelChip } from './components/ai-chat-chips/chip'; +import { ChatPanelCollectionChip } from './components/ai-chat-chips/collection-chip'; +import { ChatPanelDocChip } from './components/ai-chat-chips/doc-chip'; +import { ChatPanelFileChip } from './components/ai-chat-chips/file-chip'; +import { ChatPanelTagChip } from './components/ai-chat-chips/tag-chip'; import { effects as componentAiItemEffects } from './components/ai-item'; import { AIScrollableTextRenderer } from './components/ai-scrollable-text-renderer'; import { AskAIButton } from './components/ask-ai-button';