mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-15 05:37:32 +00:00
feat(core): support ai network search (#9357)
### What Changed?
- Add `PerplexityProvider` in backend.
- Update session prompt name if user toggle network search mode in chat panel.
- Add experimental flag for AI network search feature.
- Add unit tests and e2e tests.
Search results are streamed and appear word for word:
<div class='graphite__hidden'>
<div>🎥 Video uploaded on Graphite:</div>
<a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/56f6ec7b-4b21-405f-9612-43e083f6fb84.mov">
<img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/56f6ec7b-4b21-405f-9612-43e083f6fb84.mov">
</a>
</div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/56f6ec7b-4b21-405f-9612-43e083f6fb84.mov">录屏2024-12-27 18.58.40.mov</video>
Click the little globe icon to manually turn on/off Internet search:
<div class='graphite__hidden'>
<div>🎥 Video uploaded on Graphite:</div>
<a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/778f1406-bf29-498e-a90d-7dad813392d1.mov">
<img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/778f1406-bf29-498e-a90d-7dad813392d1.mov">
</a>
</div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/778f1406-bf29-498e-a90d-7dad813392d1.mov">录屏2024-12-27 19.01.16.mov</video>
When there is an image, it will automatically switch to the openai model:
<div class='graphite__hidden'>
<div>🎥 Video uploaded on Graphite:</div>
<a href="https://app.graphite.dev/media/video/sJGviKxfE3Ap685cl5bj/56431d8e-75e1-4d84-ab4a-b6636042cc6a.mov">
<img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/sJGviKxfE3Ap685cl5bj/56431d8e-75e1-4d84-ab4a-b6636042cc6a.mov">
</a>
</div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/56431d8e-75e1-4d84-ab4a-b6636042cc6a.mov">录屏2024-12-27 19.02.13.mov</video>
This commit is contained in:
@@ -105,7 +105,13 @@ const feedbackLink: Record<NonNullable<Flag['feedbackType']>, string> = {
|
||||
github: 'https://github.com/toeverything/AFFiNE/issues',
|
||||
};
|
||||
|
||||
const ExperimentalFeaturesItem = ({ flag }: { flag: Flag }) => {
|
||||
const ExperimentalFeaturesItem = ({
|
||||
flag,
|
||||
flagKey,
|
||||
}: {
|
||||
flag: Flag;
|
||||
flagKey: string;
|
||||
}) => {
|
||||
const value = useLiveData(flag.$);
|
||||
const t = useI18n();
|
||||
const onChange = useCallback(
|
||||
@@ -128,7 +134,7 @@ const ExperimentalFeaturesItem = ({ flag }: { flag: Flag }) => {
|
||||
<div className={styles.rowContainer}>
|
||||
<div className={styles.switchRow}>
|
||||
{t[flag.displayName]()}
|
||||
<Switch checked={value} onChange={onChange} />
|
||||
<Switch data-testid={flagKey} checked={value} onChange={onChange} />
|
||||
</div>
|
||||
{!!flag.description && (
|
||||
<Tooltip content={t[flag.description]()}>
|
||||
@@ -175,6 +181,7 @@ const ExperimentalFeaturesMain = () => {
|
||||
{Object.keys(AFFINE_FLAGS).map(key => (
|
||||
<ExperimentalFeaturesItem
|
||||
key={key}
|
||||
flagKey={key}
|
||||
flag={featureFlagService.flags[key as keyof AFFINE_FLAGS]}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { ChatPanel } from '@affine/core/blocksuite/presets/ai';
|
||||
import { AINetworkSearchService } from '@affine/core/modules/ai-button/services/network-search';
|
||||
import {
|
||||
DocModeProvider,
|
||||
RefNodeSlotsProvider,
|
||||
} from '@blocksuite/affine/blocks';
|
||||
import type { AffineEditorContainer } from '@blocksuite/affine/presets';
|
||||
import { useFramework } from '@toeverything/infra';
|
||||
import { forwardRef, useEffect, useRef } from 'react';
|
||||
|
||||
import * as styles from './chat.css';
|
||||
@@ -20,6 +22,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
||||
) {
|
||||
const chatPanelRef = useRef<ChatPanel | null>(null);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const framework = useFramework();
|
||||
|
||||
useEffect(() => {
|
||||
if (onLoad && chatPanelRef.current) {
|
||||
@@ -45,6 +48,13 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
||||
chatPanelRef.current.host = editor.host;
|
||||
chatPanelRef.current.doc = editor.doc;
|
||||
containerRef.current?.append(chatPanelRef.current);
|
||||
const searchService = framework.get(AINetworkSearchService);
|
||||
const networkSearchConfig = {
|
||||
visible: searchService.visible,
|
||||
enabled: searchService.enabled,
|
||||
setEnabled: searchService.setEnabled,
|
||||
};
|
||||
chatPanelRef.current.networkSearchConfig = networkSearchConfig;
|
||||
} else {
|
||||
chatPanelRef.current.host = editor.host;
|
||||
chatPanelRef.current.doc = editor.doc;
|
||||
@@ -63,7 +73,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
||||
];
|
||||
|
||||
return () => disposable.forEach(d => d?.dispose());
|
||||
}, [editor]);
|
||||
}, [editor, framework]);
|
||||
|
||||
return <div className={styles.root} ref={containerRef} />;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user