From 9e3a3d43db92c3f4f2bed89b94d402cbc5283a12 Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 9 Dec 2024 19:25:38 +0800 Subject: [PATCH] Feat: Provide iframe for external calls --- .../api-service/chat-api-key-modal/index.tsx | 2 +- .../chat-overview-modal/api-content.tsx | 17 ++++----- .../api-service/embed-modal/index.less | 4 +++ .../api-service/embed-modal/index.tsx | 30 ++++++++++++++-- web/src/components/api-service/hooks.ts | 29 +++++++-------- web/src/hooks/logic-hooks.ts | 2 ++ web/src/hooks/user-setting-hooks.tsx | 24 +++++++++++-- web/src/interfaces/database/chat.ts | 2 +- web/src/locales/ja.ts | 33 ++++++++--------- web/src/pages/chat/index.tsx | 35 ++++++++++--------- web/src/pages/chat/share/large.tsx | 3 +- web/src/pages/chat/shared-hooks.ts | 4 +-- web/src/pages/flow/header/index.tsx | 23 +++++++----- web/src/pages/flow/hooks.tsx | 14 ++++++++ 14 files changed, 142 insertions(+), 80 deletions(-) diff --git a/web/src/components/api-service/chat-api-key-modal/index.tsx b/web/src/components/api-service/chat-api-key-modal/index.tsx index e586d37273d..2497f0fa26e 100644 --- a/web/src/components/api-service/chat-api-key-modal/index.tsx +++ b/web/src/components/api-service/chat-api-key-modal/index.tsx @@ -63,7 +63,7 @@ const ChatApiKeyModal = ({ diff --git a/web/src/components/api-service/chat-overview-modal/api-content.tsx b/web/src/components/api-service/chat-overview-modal/api-content.tsx index 033e28e8f98..cd00e69fe86 100644 --- a/web/src/components/api-service/chat-overview-modal/api-content.tsx +++ b/web/src/components/api-service/chat-overview-modal/api-content.tsx @@ -3,8 +3,7 @@ import apiDoc from '@parent/docs/references/http_api_reference.md'; import MarkdownPreview from '@uiw/react-markdown-preview'; import { Button, Card, Flex, Space } from 'antd'; import ChatApiKeyModal from '../chat-api-key-modal'; -import EmbedModal from '../embed-modal'; -import { usePreviewChat, useShowEmbedModal } from '../hooks'; +import { usePreviewChat } from '../hooks'; import BackendServiceApi from './backend-service-api'; const ApiContent = ({ @@ -22,10 +21,10 @@ const ApiContent = ({ hideModal: hideApiKeyModal, showModal: showApiKeyModal, } = useSetModalState(); - const { embedVisible, hideEmbedModal, showEmbedModal, embedToken } = - useShowEmbedModal(idKey, id); + // const { embedVisible, hideEmbedModal, showEmbedModal, embedToken } = + // useShowEmbedModal(idKey); - const { handlePreview } = usePreviewChat(idKey, id); + const { handlePreview } = usePreviewChat(idKey); return (
@@ -36,7 +35,9 @@ const ApiContent = ({ - + {/* */} @@ -50,13 +51,13 @@ const ApiContent = ({ idKey={idKey} > )} - {embedVisible && ( + {/* {embedVisible && ( - )} + )} */}
); }; diff --git a/web/src/components/api-service/embed-modal/index.less b/web/src/components/api-service/embed-modal/index.less index 5e807d8526e..a986de6dc72 100644 --- a/web/src/components/api-service/embed-modal/index.less +++ b/web/src/components/api-service/embed-modal/index.less @@ -6,3 +6,7 @@ padding: 10px; background-color: #e8e8ea; } + +.id { + .linkText(); +} diff --git a/web/src/components/api-service/embed-modal/index.tsx b/web/src/components/api-service/embed-modal/index.tsx index 908470c240e..1caee0a644d 100644 --- a/web/src/components/api-service/embed-modal/index.tsx +++ b/web/src/components/api-service/embed-modal/index.tsx @@ -3,16 +3,25 @@ import HightLightMarkdown from '@/components/highlight-markdown'; import { SharedFrom } from '@/constants/chat'; import { useTranslate } from '@/hooks/common-hooks'; import { IModalProps } from '@/interfaces/common'; -import { Card, Modal, Tabs, TabsProps } from 'antd'; +import { Card, Modal, Tabs, TabsProps, Typography } from 'antd'; + import styles from './index.less'; +const { Paragraph, Link } = Typography; + const EmbedModal = ({ visible, hideModal, token = '', form, beta = '', -}: IModalProps & { token: string; form: SharedFrom; beta: string }) => { + isAgent, +}: IModalProps & { + token: string; + form: SharedFrom; + beta: string; + isAgent: boolean; +}) => { const { t } = useTranslate('chat'); const text = ` @@ -66,6 +75,23 @@ const EmbedModal = ({ onCancel={hideModal} > +
+ {t(isAgent ? 'flow' : 'chat', { keyPrefix: 'header' })} + ID +
+ + {token} + + + {t('howUseId')} + ); }; diff --git a/web/src/components/api-service/hooks.ts b/web/src/components/api-service/hooks.ts index 7ca92619611..e041229d31d 100644 --- a/web/src/components/api-service/hooks.ts +++ b/web/src/components/api-service/hooks.ts @@ -6,6 +6,7 @@ import { } from '@/hooks/common-hooks'; import { useCreateSystemToken, + useFetchManualSystemTokenList, useFetchSystemTokenList, useRemoveSystemToken, } from '@/hooks/user-setting-hooks'; @@ -17,9 +18,7 @@ import { useCallback } from 'react'; export const useOperateApiKey = (idKey: string, dialogId?: string) => { const { removeToken } = useRemoveSystemToken(); const { createToken, loading: creatingLoading } = useCreateSystemToken(); - const { data: tokenList, loading: listLoading } = useFetchSystemTokenList({ - [idKey]: dialogId, - }); + const { data: tokenList, loading: listLoading } = useFetchSystemTokenList(); const showDeleteConfirm = useShowDeleteConfirm(); @@ -77,12 +76,11 @@ const getUrlWithToken = (token: string, from: string = 'chat') => { return `${protocol}//${host}/chat/share?shared_id=${token}&from=${from}`; }; -const useFetchTokenListBeforeOtherStep = (idKey: string, dialogId?: string) => { +const useFetchTokenListBeforeOtherStep = () => { const { showTokenEmptyError } = useShowTokenEmptyError(); - const { data: tokenList, refetch } = useFetchSystemTokenList({ - [idKey]: dialogId, - }); + const { data: tokenList, fetchSystemTokenList } = + useFetchManualSystemTokenList(); let token = '', beta = ''; @@ -96,15 +94,15 @@ const useFetchTokenListBeforeOtherStep = (idKey: string, dialogId?: string) => { Array.isArray(tokenList) && tokenList.length > 0 ? tokenList[0].token : ''; const handleOperate = useCallback(async () => { - const ret = await refetch(); - const list = ret.data; + const ret = await fetchSystemTokenList(); + const list = ret; if (Array.isArray(list) && list.length > 0) { return list[0]?.token; } else { showTokenEmptyError(); return false; } - }, [showTokenEmptyError, refetch]); + }, [fetchSystemTokenList, showTokenEmptyError]); return { token, @@ -113,17 +111,14 @@ const useFetchTokenListBeforeOtherStep = (idKey: string, dialogId?: string) => { }; }; -export const useShowEmbedModal = (idKey: string, dialogId?: string) => { +export const useShowEmbedModal = () => { const { visible: embedVisible, hideModal: hideEmbedModal, showModal: showEmbedModal, } = useSetModalState(); - const { handleOperate, token, beta } = useFetchTokenListBeforeOtherStep( - idKey, - dialogId, - ); + const { handleOperate, token, beta } = useFetchTokenListBeforeOtherStep(); const handleShowEmbedModal = useCallback(async () => { const succeed = await handleOperate(); @@ -141,8 +136,8 @@ export const useShowEmbedModal = (idKey: string, dialogId?: string) => { }; }; -export const usePreviewChat = (idKey: string, dialogId?: string) => { - const { handleOperate } = useFetchTokenListBeforeOtherStep(idKey, dialogId); +export const usePreviewChat = (idKey: string) => { + const { handleOperate } = useFetchTokenListBeforeOtherStep(); const open = useCallback( (t: string) => { diff --git a/web/src/hooks/logic-hooks.ts b/web/src/hooks/logic-hooks.ts index 42089749294..5c8afebb1ed 100644 --- a/web/src/hooks/logic-hooks.ts +++ b/web/src/hooks/logic-hooks.ts @@ -12,6 +12,7 @@ import { PaginationProps, message } from 'antd'; import { FormInstance } from 'antd/lib'; import axios from 'axios'; import { EventSourceParserStream } from 'eventsource-parser/stream'; +import { omit } from 'lodash'; import { ChangeEventHandler, useCallback, @@ -336,6 +337,7 @@ export const useSelectDerivedMessages = () => { }), prompt: answer.prompt, audio_binary: answer.audio_binary, + ...omit(answer, 'reference'), }, ]; }); diff --git a/web/src/hooks/user-setting-hooks.tsx b/web/src/hooks/user-setting-hooks.tsx index 6b14f3536f6..2f19cb9c805 100644 --- a/web/src/hooks/user-setting-hooks.tsx +++ b/web/src/hooks/user-setting-hooks.tsx @@ -169,17 +169,34 @@ export const useFetchSystemStatus = () => { }; }; -export const useFetchSystemTokenList = (params: Record) => { +export const useFetchManualSystemTokenList = () => { + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['fetchManualSystemTokenList'], + mutationFn: async () => { + const { data } = await userService.listToken(); + + return data?.data ?? []; + }, + }); + + return { data, loading, fetchSystemTokenList: mutateAsync }; +}; + +export const useFetchSystemTokenList = () => { const { data, isFetching: loading, refetch, } = useQuery({ - queryKey: ['fetchSystemTokenList', params], + queryKey: ['fetchSystemTokenList'], initialData: [], gcTime: 0, queryFn: async () => { - const { data } = await userService.listToken(params); + const { data } = await userService.listToken(); return data?.data ?? []; }, @@ -213,6 +230,7 @@ export const useRemoveSystemToken = () => { export const useCreateSystemToken = () => { const queryClient = useQueryClient(); + const { data, isPending: loading, diff --git a/web/src/interfaces/database/chat.ts b/web/src/interfaces/database/chat.ts index ea89eb42712..6bc9577ef9c 100644 --- a/web/src/interfaces/database/chat.ts +++ b/web/src/interfaces/database/chat.ts @@ -35,7 +35,7 @@ export interface IDialog { description: string; icon: string; id: string; - dialog_id?: string; + dialog_id: string; kb_ids: string[]; kb_names: string[]; language: string; diff --git a/web/src/locales/ja.ts b/web/src/locales/ja.ts index 9f55d1d8c24..0a0f63e6552 100644 --- a/web/src/locales/ja.ts +++ b/web/src/locales/ja.ts @@ -33,6 +33,7 @@ export default { pleaseSelect: '選択してください', pleaseInput: '入力してください', submit: '送信', + japanese: '日本語', }, login: { login: 'ログイン', @@ -85,8 +86,7 @@ export default { name: '名前', namePlaceholder: '名前を入力してください', doc: 'ドキュメント', - datasetDescription: - '😉 パースが成功すると、質問と回答が可能になります。', + datasetDescription: '😉 パースが成功すると、質問と回答が可能になります。', addFile: 'ファイルを追加', searchFiles: 'ファイルを検索', localFiles: 'ローカルファイル', @@ -157,8 +157,7 @@ export default { topK: 'トップK', topKTip: `Kチャンクがリランキングモデルに供給されます。`, delimiter: `区切り文字`, - delimiterTip: - '複数文字の区切り文字をサポートしています。', + delimiterTip: '複数文字の区切り文字をサポートしています。', html4excel: 'ExcelをHTMLに変換', html4excelTip: `有効にすると、スプレッドシートはHTMLテーブルとして解析されます。それ以外の場合、キーと値のペアとして解析されます。`, autoKeywords: '自動キーワード', @@ -182,7 +181,7 @@ export default { embeddingModelTip: 'チャンクを埋め込みに変換するモデルです。一度チャンクが作成されると変更できません。', permissionsTip: - "「チーム」に設定すると、全てのチームメンバーがナレッジベースを管理できます。", + '「チーム」に設定すると、全てのチームメンバーがナレッジベースを管理できます。', chunkTokenNumberTip: 'チャンクのトークンしきい値を設定します。このしきい値を下回る段落は、次の段落と結合され、しきい値を超えた時点でチャンクが作成されます。', chunkMethod: 'チャンク方法', @@ -201,8 +200,7 @@ export default { methodExamplesDescription: '以下のスクリーンショットは明確な説明のために提供されています。', dialogueExamplesTitle: '会話の例', - methodEmpty: - 'ナレッジベースカテゴリの視覚的説明がここに表示されます', + methodEmpty: 'ナレッジベースカテゴリの視覚的説明がここに表示されます', book: `

対応ファイル形式はDOCX, PDF, TXTです。

PDF形式の書籍では、解析時間を短縮するため、ページ範囲を設定してください。

`, laws: `

対応ファイル形式はDOCX, PDF, TXTです。

@@ -305,7 +303,7 @@ export default { entityTypes: 'エンティティタイプ', pageRank: 'ページランク', pageRankTip: `これは関連性スコアを高めるために使用されます。すべての取得されたチャンクの関連性スコアにこの数値が加算されます。 -特定のナレッジベースを最初に検索したい場合は、他のものよりも高いページランクスコアを設定してください。` +特定のナレッジベースを最初に検索したい場合は、他のものよりも高いページランクスコアを設定してください。`, }, chunk: { chunk: 'チャンク', @@ -360,8 +358,7 @@ export default { {knowledge} 上記がナレッジベースです。`, systemMessage: '入力してください!', - systemTip: - 'LLMが質問に答える際に従う指示を設定します。', + systemTip: 'LLMが質問に答える際に従う指示を設定します。', topN: 'トップN', topNTip: `類似度スコアがしきい値を超えるチャンクのうち、上位N件のみがLLMに供給されます。`, variable: '変数', @@ -406,7 +403,8 @@ export default { quote: '引用を表示', quoteTip: '元のテキストの出典を表示しますか?', selfRag: 'Self-RAG', - selfRagTip: '詳細は次を参照してください:https://huggingface.co/papers/2310.11511', + selfRagTip: + '詳細は次を参照してください:https://huggingface.co/papers/2310.11511', overview: 'チャットID', pv: 'メッセージ数', uv: 'アクティブユーザー数', @@ -486,7 +484,7 @@ export default { newPassword: '新しいパスワード', newPasswordMessage: 'パスワードを入力してください!', newPasswordDescription: - '新しいパスワードは8文字以上でなければなりません。', + '新しいパスワードは8文字以上でなければなりません。', confirmPassword: '新しいパスワードの確認', confirmPasswordMessage: 'パスワードを確認してください!', confirmPasswordNonMatchMessage: @@ -568,7 +566,7 @@ export default { SparkModelNameMessage: 'Sparkモデルを選択してください', addSparkAPIPassword: 'Spark APIパスワード', SparkAPIPasswordMessage: 'APIパスワードを入力してください', - addSparkAPPID: 'Spark APPID', + addSparkAPPID: 'Spark APPID', SparkAPPIDMessage: 'APPIDを入力してください', addSparkAPISecret: 'Spark APIシークレット', SparkAPISecretMessage: 'APIシークレットを入力してください', @@ -579,8 +577,7 @@ export default { yiyanAKMessage: 'APIキーを入力してください', addyiyanSK: 'yiyanシークレットキー', yiyanSKMessage: 'シークレットキーを入力してください', - FishAudioModelNameMessage: - '音声合成モデルに名前を付けてください', + FishAudioModelNameMessage: '音声合成モデルに名前を付けてください', addFishAudioAK: 'Fish Audio APIキー', addFishAudioAKMessage: 'APIキーを入力してください', addFishAudioRefID: 'FishAudio参照ID', @@ -700,7 +697,7 @@ export default { relevantDescription: `LLMを使用して、上流の出力がユーザーの最新のクエリに関連しているかどうかを評価するコンポーネント。各判定結果に対して次のコンポーネントを指定してください。`, rewriteQuestionDescription: `ナレッジベースから関連情報を取得できなかった場合にユーザーのクエリを修正するコンポーネント。定義されたループの上限に達するまでこのプロセスを繰り返します。上流が「Relevant」、下流が「Retrieval」であることを確認してください。`, messageDescription: - "静的メッセージを送信するコンポーネント。複数のメッセージが提供されている場合は、その中からランダムに1つを選択して送信します。下流がインターフェースコンポーネント「Answer」であることを確認してください。", + '静的メッセージを送信するコンポーネント。複数のメッセージが提供されている場合は、その中からランダムに1つを選択して送信します。下流がインターフェースコンポーネント「Answer」であることを確認してください。', keywordDescription: `ユーザーの入力からトップNの検索結果を取得するコンポーネント。使用前にTopNの値が適切に設定されていることを確認してください。`, switchDescription: `前のコンポーネントの出力に基づいて条件を評価し、それに応じて実行の流れを指示するコンポーネント。ケースを定義し、各ケースのアクションまたは条件が満たされない場合のデフォルトアクションを指定することで、複雑な分岐ロジックを可能にします。`, wikipediaDescription: `wikipedia.orgから検索を行うコンポーネントで、TopNを使用して検索結果の数を指定します。既存のナレッジベースを補完します。`, @@ -800,7 +797,7 @@ export default { news: 'ニュースと情報', law: '法律と規制', contract: '契約', - }, + }, baiduSourceLangOptions: { auto: '自動検出', zh: '中国語', @@ -1089,4 +1086,4 @@ export default { chat: 'チャット', }, }, -}; \ No newline at end of file +}; diff --git a/web/src/pages/chat/index.tsx b/web/src/pages/chat/index.tsx index b461f004661..d9a8784ca31 100644 --- a/web/src/pages/chat/index.tsx +++ b/web/src/pages/chat/index.tsx @@ -29,17 +29,19 @@ import { useSelectDerivedConversationList, } from './hooks'; +import EmbedModal from '@/components/api-service/embed-modal'; +import { useShowEmbedModal } from '@/components/api-service/hooks'; import SvgIcon from '@/components/svg-icon'; +import { SharedFrom } from '@/constants/chat'; import { useClickConversationCard, useClickDialogCard, useFetchNextDialogList, useGetChatSearchParams, } from '@/hooks/chat-hooks'; -import { useSetModalState, useTranslate } from '@/hooks/common-hooks'; +import { useTranslate } from '@/hooks/common-hooks'; import { useSetSelectedRecord } from '@/hooks/logic-hooks'; import { IDialog } from '@/interfaces/database/chat'; -import ChatIdModal from './chat-id-modal'; import styles from './index.less'; const { Text } = Typography; @@ -80,13 +82,10 @@ const Chat = () => { showDialogEditModal, } = useEditDialog(); const { t } = useTranslate('chat'); - const { - visible: overviewVisible, - hideModal: hideOverviewModal, - showModal: showOverviewModal, - } = useSetModalState(); const { currentRecord, setRecord } = useSetSelectedRecord(); const [controller, setController] = useState(new AbortController()); + const { showEmbedModal, hideEmbedModal, embedVisible, beta } = + useShowEmbedModal(); const handleAppCardEnter = (id: string) => () => { handleItemEnter(id); @@ -118,7 +117,7 @@ const Chat = () => { info?.domEvent?.preventDefault(); info?.domEvent?.stopPropagation(); setRecord(dialog); - showOverviewModal(); + showEmbedModal(); }; const handleRemoveConversation = @@ -191,7 +190,7 @@ const Chat = () => { label: ( - {t('overview')} + {t('publish', { keyPrefix: 'flow' })} ), }, @@ -368,14 +367,16 @@ const Chat = () => { initialName={initialConversationName} loading={conversationRenameLoading} > - {overviewVisible && ( - + + {embedVisible && ( + )} ); diff --git a/web/src/pages/chat/share/large.tsx b/web/src/pages/chat/share/large.tsx index 159156cef70..b4ccea51f24 100644 --- a/web/src/pages/chat/share/large.tsx +++ b/web/src/pages/chat/share/large.tsx @@ -9,13 +9,12 @@ import { useSendSharedMessage, } from '../shared-hooks'; import { buildMessageItemReference } from '../utils'; + import styles from './index.less'; const ChatContainer = () => { const { from, sharedId: conversationId } = useGetSharedChatSearchParams(); - // const { data } = useFetchNextSharedConversation(conversationId); - const { handlePressEnter, handleInputChange, diff --git a/web/src/pages/chat/shared-hooks.ts b/web/src/pages/chat/shared-hooks.ts index eb885504d71..763187b09df 100644 --- a/web/src/pages/chat/shared-hooks.ts +++ b/web/src/pages/chat/shared-hooks.ts @@ -72,8 +72,8 @@ export const useSendSharedMessage = () => { async (message: Message, id?: string) => { const res = await send({ conversation_id: id ?? conversationId, - quote: false, - question: message, + quote: true, + question: message.content, session_id: get(derivedMessages, '0.session_id'), }); diff --git a/web/src/pages/flow/header/index.tsx b/web/src/pages/flow/header/index.tsx index 77cee287cac..5b5d47574be 100644 --- a/web/src/pages/flow/header/index.tsx +++ b/web/src/pages/flow/header/index.tsx @@ -1,15 +1,15 @@ import EmbedModal from '@/components/api-service/embed-modal'; import { useShowEmbedModal } from '@/components/api-service/hooks'; import { SharedFrom } from '@/constants/chat'; -import { useSetModalState, useTranslate } from '@/hooks/common-hooks'; +import { useTranslate } from '@/hooks/common-hooks'; import { useFetchFlow } from '@/hooks/flow-hooks'; import { ArrowLeftOutlined } from '@ant-design/icons'; import { Button, Flex, Space } from 'antd'; import { useCallback } from 'react'; import { Link, useParams } from 'umi'; -import FlowIdModal from '../flow-id-modal'; import { useGetBeginNodeDataQuery, + useGetBeginNodeDataQueryIsEmpty, useSaveGraph, useSaveGraphBeforeOpeningDebugDrawer, useWatchAgentChange, @@ -27,12 +27,16 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => { const { handleRun } = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer); const { data } = useFetchFlow(); const { t } = useTranslate('flow'); - const { visible, hideModal, showModal } = useSetModalState(); const { id } = useParams(); const time = useWatchAgentChange(chatDrawerVisible); const getBeginNodeDataQuery = useGetBeginNodeDataQuery(); const { showEmbedModal, hideEmbedModal, embedVisible, beta } = - useShowEmbedModal('canvasId', id); + useShowEmbedModal(); + const isBeginNodeDataQueryEmpty = useGetBeginNodeDataQueryIsEmpty(); + + const handleShowEmbedModal = useCallback(() => { + showEmbedModal(); + }, [showEmbedModal]); const handleRunAgent = useCallback(() => { const query: BeginQuery[] = getBeginNodeDataQuery(); @@ -69,12 +73,13 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => { - - {embedVisible && ( @@ -84,9 +89,9 @@ const FlowHeader = ({ showChatDrawer, chatDrawerVisible }: IProps) => { token={id!} form={SharedFrom.Agent} beta={beta} + isAgent > )} - {visible && } ); }; diff --git a/web/src/pages/flow/hooks.tsx b/web/src/pages/flow/hooks.tsx index a8f7df5c2f1..21a238483fb 100644 --- a/web/src/pages/flow/hooks.tsx +++ b/web/src/pages/flow/hooks.tsx @@ -474,6 +474,20 @@ export const useGetBeginNodeDataQuery = () => { return getBeginNodeDataQuery; }; +export const useGetBeginNodeDataQueryIsEmpty = () => { + const [isBeginNodeDataQueryEmpty, setIsBeginNodeDataQueryEmpty] = + useState(false); + const getBeginNodeDataQuery = useGetBeginNodeDataQuery(); + const nodes = useGraphStore((state) => state.nodes); + + useEffect(() => { + const query: BeginQuery[] = getBeginNodeDataQuery(); + setIsBeginNodeDataQueryEmpty(query.length === 0); + }, [getBeginNodeDataQuery, nodes]); + + return isBeginNodeDataQueryEmpty; +}; + export const useSaveGraphBeforeOpeningDebugDrawer = (show: () => void) => { const { saveGraph, loading } = useSaveGraph(); const { resetFlow } = useResetFlow();