From 0bc61881c4abfd35dd6008dee582c31f66ad08dc Mon Sep 17 00:00:00 2001 From: BiggerRain <15911122312@163.COM> Date: Tue, 4 Mar 2025 15:49:04 +0800 Subject: [PATCH] chore: Coco chat window input and message (#237) --- src/components/Assistant/Chat.tsx | 52 ++++++++++--------- src/components/Assistant/ChatHeader.tsx | 20 +++++--- src/components/Assistant/Greetings.tsx | 20 ++++++++ src/components/ChatMessage/QueryIntent.tsx | 2 +- src/components/Search/InputBox.tsx | 60 +++++++++++++--------- src/locales/zh/translation.json | 2 +- src/pages/chat/index.tsx | 40 +++++++-------- src/pages/main/index.tsx | 6 +-- src/stores/chatStore.ts | 8 +-- 9 files changed, 126 insertions(+), 84 deletions(-) create mode 100644 src/components/Assistant/Greetings.tsx diff --git a/src/components/Assistant/Chat.tsx b/src/components/Assistant/Chat.tsx index a335e9b3..43f6f90b 100644 --- a/src/components/Assistant/Chat.tsx +++ b/src/components/Assistant/Chat.tsx @@ -22,7 +22,8 @@ import { Sidebar } from "@/components/Assistant/Sidebar"; import { useConnectStore } from "@/stores/connectStore"; import { useSearchStore } from "@/stores/searchStore"; import { IServer } from "@/stores/appStore"; -import FileList from "../Search/FileList"; +import FileList from "@/components/Search/FileList"; +import { Greetings } from "./Greetings"; interface ChatAIProps { isTransitioned: boolean; @@ -33,6 +34,7 @@ interface ChatAIProps { setIsSidebarOpen?: (value: boolean) => void; isSidebarOpen?: boolean; clearChatPage?: () => void; + isChatPage?: boolean; } export interface ChatAIRef { @@ -56,6 +58,7 @@ const ChatAI = memo( setIsSidebarOpen, isSidebarOpen = false, clearChatPage, + isChatPage = false, }, ref ) => { @@ -174,6 +177,7 @@ const ChatAI = memo( }); }, []); + // send、new、history const clearCurrentChat = useCallback(() => { setQuery_intent(undefined); setFetch_source(undefined); @@ -258,11 +262,12 @@ const ChatAI = memo( useEffect(() => { let unlisten_message = null; + console.log("connected:", connected); if (connected) { setErrorShow(false); unlisten_message = listen("ws-message", (event) => { dealMsg(String(event.payload)); - console.log("message:", event.payload); + // console.log("message:", event.payload); }); } @@ -415,7 +420,6 @@ const ChatAI = memo( ); const init = (value: string) => { - console.log("init", value, curChatEnd, activeChat); if (!curChatEnd) return; if (!activeChat?._id) { createNewChat(value); @@ -424,16 +428,10 @@ const ChatAI = memo( } }; - const handleSendMessage = useCallback( - async (content: string, newChat?: Chat) => { - newChat = newChat || activeChat; + const sendMessage = useCallback( + async (content: string, newChat: Chat) => { if (!newChat?._id || !content) return; - setQuestion(content); - await chatHistory(newChat); - setTimedoutShow(false); - setErrorShow(false); - clearCurrentChat(); try { // console.log("sourceDataIds", sourceDataIds); let response: any = await invoke("send_message", { @@ -464,7 +462,21 @@ const ChatAI = memo( console.error("Failed to fetch user data:", error); } }, - [activeChat, isSearchActive, isDeepThinkActive] + [JSON.stringify(activeChat?.messages), isSearchActive, isDeepThinkActive] + ); + + const handleSendMessage = useCallback( + async (content: string, newChat?: Chat) => { + newChat = newChat || activeChat; + if (!newChat?._id || !content) return; + setQuestion(content); + await chatHistory(newChat, (chat) => sendMessage(content, chat)); + + setTimedoutShow(false); + setErrorShow(false); + clearCurrentChat(); + }, + [activeChat, sendMessage] ); const chatClose = async () => { @@ -527,7 +539,7 @@ const ChatAI = memo( }; }, []); - const chatHistory = async (chat: Chat) => { + const chatHistory = async (chat: Chat, callback?: (chat: Chat) => void) => { try { let response: any = await invoke("session_chat_history", { serverId: currentService?.id, @@ -543,6 +555,7 @@ const ChatAI = memo( messages: hits, }; setActiveChat(updatedChat); + callback && callback(updatedChat) } catch (error) { console.error("Failed to fetch user data:", error); } @@ -550,6 +563,7 @@ const ChatAI = memo( const onSelectChat = async (chat: any) => { chatClose(); + clearCurrentChat(); try { let response: any = await invoke("open_session_chat", { serverId: currentService?.id, @@ -655,20 +669,12 @@ const ChatAI = memo( isSidebarOpen={isSidebarOpenChat} activeChat={activeChat} reconnect={reconnect} + isChatPage={isChatPage} /> {/* Chat messages */}
- + {activeChat?.messages?.map((message, index) => ( void; + isChatPage?: boolean; } export function ChatHeader({ @@ -47,6 +48,7 @@ export function ChatHeader({ setIsSidebarOpen, activeChat, reconnect, + isChatPage = false, }: ChatHeaderProps) { const { t } = useTranslation(); @@ -77,7 +79,7 @@ export function ChatHeader({ ); if (currentServiceExists) { - switchServer(currentService); + switchServer(currentService, true); } else { switchServer(enabledServers[enabledServers.length - 1]); } @@ -108,7 +110,7 @@ export function ChatHeader({ } }; - const switchServer = async (server: IServer) => { + const switchServer = async (server: IServer, isCurrent: boolean = false) => { if (!server) return; try { // Switch UI first, then switch server connection @@ -117,8 +119,10 @@ export function ChatHeader({ setMessages(""); // Clear previous messages onCreateNewChat(); // - await disconnect(); - reconnect && reconnect(server); + if (!(isCurrent && connected)) { + await disconnect(); + reconnect && reconnect(server); + } } catch (error) { console.error("switchServer:", error); } @@ -306,9 +310,11 @@ export function ChatHeader({ - + {isChatPage ? null : ( + + )}
); diff --git a/src/components/Assistant/Greetings.tsx b/src/components/Assistant/Greetings.tsx new file mode 100644 index 00000000..e948ccf3 --- /dev/null +++ b/src/components/Assistant/Greetings.tsx @@ -0,0 +1,20 @@ +import { useTranslation } from "react-i18next"; + +import { ChatMessage } from "@/components/ChatMessage"; + +export const Greetings = () => { + const { t } = useTranslation(); + + return ( + + ); +}; diff --git a/src/components/ChatMessage/QueryIntent.tsx b/src/components/ChatMessage/QueryIntent.tsx index edf440d6..27519dea 100644 --- a/src/components/ChatMessage/QueryIntent.tsx +++ b/src/components/ChatMessage/QueryIntent.tsx @@ -37,7 +37,7 @@ export const QueryIntent = ({ ChunkData, getSuggestion }: QueryIntentProps) => { const lastMatch = allMatches[allMatches.length - 1]; const jsonString = lastMatch.replace(/|<\/JSON>/g, ""); const data = JSON.parse(jsonString); - console.log("QueryIntent", data); + // console.log("QueryIntent", data); if (data?.suggestion && getSuggestion) { getSuggestion(data?.suggestion) } diff --git a/src/components/Search/InputBox.tsx b/src/components/Search/InputBox.tsx index bae0dded..a4ce7e73 100644 --- a/src/components/Search/InputBox.tsx +++ b/src/components/Search/InputBox.tsx @@ -21,6 +21,7 @@ import { } from "@headlessui/react"; import clsx from "clsx"; import { useReactive, useRequest } from "ahooks"; +import { isArray } from "lodash-es"; import ChatSwitch from "@/components/Common/ChatSwitch"; import AutoResizeTextarea from "./AutoResizeTextarea"; @@ -31,14 +32,13 @@ import { useSearchStore } from "@/stores/searchStore"; import { metaOrCtrlKey } from "@/utils/keyboardUtils"; import { useConnectStore } from "@/stores/connectStore"; import TypeIcon from "@/components/Common/Icons/TypeIcon"; -import { isArray } from "lodash-es"; import InputExtra from "./InputExtra"; interface ChatInputProps { onSend: (message: string) => void; disabled: boolean; disabledChange: () => void; - changeMode: (isChatMode: boolean) => void; + changeMode?: (isChatMode: boolean) => void; isChatMode: boolean; inputValue: string; changeInput: (val: string) => void; @@ -47,6 +47,7 @@ interface ChatInputProps { setIsSearchActive: () => void; isDeepThinkActive: boolean; setIsDeepThinkActive: () => void; + isChatPage?: boolean; } export default function ChatInput({ @@ -62,6 +63,7 @@ export default function ChatInput({ setIsSearchActive, isDeepThinkActive, setIsDeepThinkActive, + isChatPage = false, }: ChatInputProps) { const { t } = useTranslation(); @@ -266,7 +268,7 @@ export default function ChatInput({ if (!isChatMode) return; if (connected) return; if (countdown <= 0) { - console.log("ReconnectClick", 111111); + console.log("ReconnectClick"); ReconnectClick(); return; } @@ -310,8 +312,16 @@ export default function ChatInput({ }; return ( -
-
+
+
{!isChatMode && !sourceData ? ( @@ -326,7 +336,9 @@ export default function ChatInput({ { + changeInput(value); + }} connected={connected} handleKeyDown={(e) => { if (e.key === "Enter") { @@ -657,23 +669,25 @@ export default function ChatInput({
)} -
- {showTooltip && isCommandPressed ? ( -
- T -
- ) : null} - { - value && disabledChange(); - changeMode(value); - setSourceData(undefined); - }} - /> -
+ {isChatPage ? null : ( +
+ {showTooltip && isCommandPressed ? ( +
+ T +
+ ) : null} + { + value && disabledChange(); + changeMode && changeMode(value); + setSourceData(undefined); + }} + /> +
+ )}
); diff --git a/src/locales/zh/translation.json b/src/locales/zh/translation.json index dab3a735..2f2144e8 100644 --- a/src/locales/zh/translation.json +++ b/src/locales/zh/translation.json @@ -138,7 +138,7 @@ "fetch_source": "检索 {{count}} 份文档", "pick_source": "智能预选 {{count}} 个结果", "pick_source_start": "正在智能预选", - "deep_read": "深度阅读,", + "deep_read": "深度阅读", "think": "AI 正在思考...", "thoughtTime": "思考了数秒", "keywords": "关键词", diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 4d7675ad..c9c6363a 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -2,10 +2,10 @@ import { useState, useRef, useEffect } from "react"; import { invoke } from "@tauri-apps/api/core"; import ChatAI, { ChatAIRef } from "@/components/Assistant/Chat"; -import { ChatInput } from "@/components/Assistant/ChatInput"; import { Sidebar } from "@/components/Assistant/Sidebar"; import type { Chat } from "@/components/Assistant/types"; import { useConnectStore } from "@/stores/connectStore"; +import InputBox from "@/components/Search/InputBox"; interface ChatProps {} @@ -17,13 +17,15 @@ export default function Chat({}: ChatProps) { const [chats, setChats] = useState([]); const [activeChat, setActiveChat] = useState(); const [isSidebarOpen, setIsSidebarOpen] = useState(true); - const [isTyping, setIsTyping] = useState(false); + const isTyping = false; - const [curChatEnd, setCurChatEnd] = useState(true); + const [input, setInput] = useState(""); const [isSearchActive, setIsSearchActive] = useState(false); const [isDeepThinkActive, setIsDeepThinkActive] = useState(false); + const isChatPage = true + useEffect(() => { getChatHistory(); }, []); @@ -62,6 +64,7 @@ export default function Chat({}: ChatProps) { }; const handleSendMessage = async (content: string) => { + setInput(content); chatAIRef.current?.init(content); }; @@ -116,17 +119,7 @@ export default function Chat({}: ChatProps) { }; const cancelChat = async () => { - if (!activeChat?._id) return; - try { - let response: any = await invoke("cancel_session_chat", { - serverId: currentService?.id, - sessionId: activeChat?._id, - }); - response = JSON.parse(response || ""); - console.log("_cancel", response); - } catch (error) { - console.error("Failed to fetch user data:", error); - } + chatAIRef.current?.cancelChat(); }; const clearChat = () => { @@ -134,6 +127,10 @@ export default function Chat({}: ChatProps) { setActiveChat(undefined); }; + const reconnect = () => { + chatAIRef.current?.reconnect(); + }; + return (
@@ -169,23 +166,24 @@ export default function Chat({}: ChatProps) { setIsSidebarOpen={setIsSidebarOpen} isSidebarOpen={isSidebarOpen} clearChatPage={clearChat} + isChatPage={isChatPage} /> {/* Input area */}
- { - cancelChat(); - setCurChatEnd(true); - setIsTyping(false); - }} + disabledChange={cancelChat} + reconnect={reconnect} isSearchActive={isSearchActive} setIsSearchActive={() => setIsSearchActive((prev) => !prev)} isDeepThinkActive={isDeepThinkActive} setIsDeepThinkActive={() => setIsDeepThinkActive((prev) => !prev)} + isChatPage={isChatPage} />
diff --git a/src/pages/main/index.tsx b/src/pages/main/index.tsx index f9b1ab2d..8ffd852b 100644 --- a/src/pages/main/index.tsx +++ b/src/pages/main/index.tsx @@ -64,7 +64,7 @@ export default function DesktopApp() { setIsTransitioned(value); } - async function changeInput(value: string) { + function changeInput(value: string) { setInput(value); } @@ -114,9 +114,7 @@ export default function DesktopApp() { inputValue={input} onSend={handleSendMessage} disabled={isTyping} - disabledChange={() => { - cancelChat(); - }} + disabledChange={cancelChat} changeMode={changeMode} changeInput={changeInput} reconnect={reconnect} diff --git a/src/stores/chatStore.ts b/src/stores/chatStore.ts index 9b05a4b1..280af7c0 100644 --- a/src/stores/chatStore.ts +++ b/src/stores/chatStore.ts @@ -46,10 +46,10 @@ export const useChatStore = create()( { name: "chat-state", // storage: createJSONStorage(() => sessionStorage), - partialize: (state) => - Object.fromEntries( - Object.entries(state).filter(([key]) => key === "curChatEnd") - ), + partialize: (state) => ({ + curChatEnd: state.curChatEnd, + connected: state.connected, + }), } ) );