feat(core): support chat panel chips and suggest current doc for embedding (#9747)

Support issue [BS-2347](https://linear.app/affine-design/issue/BS-2347).

## What Changed?
- Add chat panel components
  - `chat-panel-chips`
  - `chat-panel-doc-chip`
  - `chat-panel-file-chip`
  - `chat-panel-chip`
- Add `chips` and `docs` field in `ChatContextValue`
- Add `extractMarkdownFromDoc` function to extract markdown content of a doc
- Add e2e test

Click a candidate card to add it into AI chat context:
<div class='graphite__hidden'>
          <div>🎥 Video uploaded on Graphite:</div>
            <a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/4e6b11ef-f993-4e6a-9f40-b2826af1990c.mov">
              <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/4e6b11ef-f993-4e6a-9f40-b2826af1990c.mov">
            </a>
          </div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/4e6b11ef-f993-4e6a-9f40-b2826af1990c.mov">录屏2025-01-17 01.02.04.mov</video>
This commit is contained in:
akumatus
2025-01-18 08:35:19 +00:00
parent 59611fa002
commit d048ac6c91
14 changed files with 656 additions and 35 deletions

View File

@@ -1,10 +1,13 @@
import { ChatPanel } from '@affine/core/blocksuite/presets/ai';
import { AINetworkSearchService } from '@affine/core/modules/ai-button/services/network-search';
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
import { WorkspaceService } from '@affine/core/modules/workspace';
import {
DocModeProvider,
RefNodeSlotsProvider,
} from '@blocksuite/affine/blocks';
import type { AffineEditorContainer } from '@blocksuite/affine/presets';
import { createSignalFromObservable } from '@blocksuite/affine-shared/utils';
import { useFramework } from '@toeverything/infra';
import { forwardRef, useEffect, useRef } from 'react';
@@ -49,12 +52,26 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
chatPanelRef.current.doc = editor.doc;
containerRef.current?.append(chatPanelRef.current);
const searchService = framework.get(AINetworkSearchService);
const networkSearchConfig = {
const docDisplayMetaService = framework.get(DocDisplayMetaService);
const workspaceService = framework.get(WorkspaceService);
chatPanelRef.current.networkSearchConfig = {
visible: searchService.visible,
enabled: searchService.enabled,
setEnabled: searchService.setEnabled,
};
chatPanelRef.current.networkSearchConfig = networkSearchConfig;
chatPanelRef.current.docDisplayConfig = {
getIcon: (docId: string) => {
return docDisplayMetaService.icon$(docId, { type: 'lit' }).value;
},
getTitle: (docId: string) => {
const title$ = docDisplayMetaService.title$(docId);
return createSignalFromObservable(title$, '');
},
getDoc: (docId: string) => {
const doc = workspaceService.workspace.docCollection.getDoc(docId);
return doc;
},
};
} else {
chatPanelRef.current.host = editor.host;
chatPanelRef.current.doc = editor.doc;