From c24f72beb1ea7c9b653123d9301411f5d847cfd2 Mon Sep 17 00:00:00 2001 From: tegnike Date: Wed, 21 Aug 2024 10:58:53 +0200 Subject: [PATCH 1/5] =?UTF-8?q?WebSocket=E3=83=A2=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=E4=B8=8D=E8=A6=81=E3=81=AA=E3=83=97=E3=83=AD=E3=83=91?= =?UTF-8?q?=E3=83=86=E3=82=A3=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/useWebSocket.tsx | 8 ++------ src/features/chat/handlers.ts | 2 -- src/features/stores/home.ts | 2 -- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/components/useWebSocket.tsx b/src/components/useWebSocket.tsx index 379e75d2..132e34d0 100644 --- a/src/components/useWebSocket.tsx +++ b/src/components/useWebSocket.tsx @@ -16,7 +16,6 @@ interface Params { const useWebSocket = ({ handleSendChat }: Params) => { const webSocketMode = settingsStore((s) => s.webSocketMode) - const voicePlaying = homeStore((s) => s.voicePlaying) const [tmpMessages, setTmpMessages] = useState([]) @@ -74,14 +73,11 @@ const useWebSocket = ({ handleSendChat }: Params) => { // WebSocketモード用の処理 useEffect(() => { - if (tmpMessages.length > 0 && !voicePlaying) { + if (tmpMessages.length > 0) { const message = tmpMessages[0] - if (message.role == 'assistant') { - homeStore.setState({ voicePlaying: true }) - } setTmpMessages((tmpMessages) => tmpMessages.slice(1)) handleSendChat(message.text, message.role) } - }, [tmpMessages, voicePlaying, handleSendChat]) + }, [tmpMessages, handleSendChat]) } export default useWebSocket diff --git a/src/features/chat/handlers.ts b/src/features/chat/handlers.ts index cfe06afc..f37501fa 100644 --- a/src/features/chat/handlers.ts +++ b/src/features/chat/handlers.ts @@ -427,13 +427,11 @@ export const handleSendChatFn = codeLog: updateLog, assistantMessage: newMessage, chatProcessing: false, - voicePlaying: false, }) }) } catch (e) { homeStore.setState({ chatProcessing: false, - voicePlaying: false, }) } } else if (role == 'code' || role == 'output' || role == 'executing') { diff --git a/src/features/stores/home.ts b/src/features/stores/home.ts index 937e1cf0..5c9c4556 100644 --- a/src/features/stores/home.ts +++ b/src/features/stores/home.ts @@ -24,7 +24,6 @@ export interface TransientState { triggerShutter: boolean webcamStatus: boolean ws: WebSocket | null - voicePlaying: boolean // WebSocketモード用の設定 } export type HomeState = PersistedState & TransientState @@ -60,7 +59,6 @@ const homeStore = create()( triggerShutter: false, webcamStatus: false, ws: null, - voicePlaying: false, }), { name: 'aitube-kit-home', From e878367b1e5855fb850e55d6a8de97f77e324ff0 Mon Sep 17 00:00:00 2001 From: tegnike Date: Wed, 21 Aug 2024 11:27:32 +0200 Subject: [PATCH 2/5] =?UTF-8?q?WebSocket=E3=81=AE=E5=87=A6=E7=90=86?= =?UTF-8?q?=E3=82=92handleSendChat=E3=81=8B=E3=82=89=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/form.tsx | 8 +- src/components/useWebSocket.tsx | 12 +- src/components/useYoutube.tsx | 2 +- src/features/chat/handlers.ts | 153 ++++++++++++++---------- src/features/youtube/youtubeComments.ts | 2 +- 5 files changed, 106 insertions(+), 71 deletions(-) diff --git a/src/components/form.tsx b/src/components/form.tsx index cb019a83..066642f7 100644 --- a/src/components/form.tsx +++ b/src/components/form.tsx @@ -5,7 +5,10 @@ import settingsStore from '@/features/stores/settings' import homeStore from '@/features/stores/home' import menuStore from '@/features/stores/menu' import slideStore from '@/features/stores/slide' -import { handleSendChatFn } from '../features/chat/handlers' +import { + handleSendChatFn, + handleReceiveTextFromWsFn, +} from '../features/chat/handlers' import { MessageInputContainer } from './messageInputContainer' import useWebSocket from './useWebSocket' import useYoutube from './useYoutube' @@ -26,9 +29,10 @@ export const Form = () => { NotConnectedToExternalAssistant: t('NotConnectedToExternalAssistant'), APIKeyNotEntered: t('APIKeyNotEntered'), }) + const handleReceiveTextFromWs = handleReceiveTextFromWsFn() useYoutube({ handleSendChat }) - useWebSocket({ handleSendChat }) + useWebSocket({ handleReceiveTextFromWs }) useEffect(() => { // テキストと画像がそろったら、チャットを送信 diff --git a/src/components/useWebSocket.tsx b/src/components/useWebSocket.tsx index 132e34d0..ec271d9f 100644 --- a/src/components/useWebSocket.tsx +++ b/src/components/useWebSocket.tsx @@ -11,10 +11,10 @@ interface TmpMessage { } interface Params { - handleSendChat: (text: string, role?: string) => Promise + handleReceiveTextFromWs: (text: string, role?: string) => Promise } -const useWebSocket = ({ handleSendChat }: Params) => { +const useWebSocket = ({ handleReceiveTextFromWs }: Params) => { const webSocketMode = settingsStore((s) => s.webSocketMode) const [tmpMessages, setTmpMessages] = useState([]) @@ -29,7 +29,9 @@ const useWebSocket = ({ handleSendChat }: Params) => { const handleMessage = (event: MessageEvent) => { console.log('Received message:', event.data) const jsonData = JSON.parse(event.data) - setTmpMessages((prevMessages) => [...prevMessages, jsonData]) + if (jsonData.text != '') { + setTmpMessages((prevMessages) => [...prevMessages, jsonData]) + } } const handleError = (event: Event) => { console.error('WebSocket error:', event) @@ -76,8 +78,8 @@ const useWebSocket = ({ handleSendChat }: Params) => { if (tmpMessages.length > 0) { const message = tmpMessages[0] setTmpMessages((tmpMessages) => tmpMessages.slice(1)) - handleSendChat(message.text, message.role) + handleReceiveTextFromWs(message.text, message.role) } - }, [tmpMessages, handleSendChat]) + }, [tmpMessages, handleReceiveTextFromWs]) } export default useWebSocket diff --git a/src/components/useYoutube.tsx b/src/components/useYoutube.tsx index 98402296..0265f6d5 100644 --- a/src/components/useYoutube.tsx +++ b/src/components/useYoutube.tsx @@ -9,7 +9,7 @@ import { processAIResponse } from '../features/chat/handlers' const INTERVAL_MILL_SECONDS_RETRIEVING_COMMENTS = 5000 // 5秒 interface Params { - handleSendChat: (text: string, role?: string) => Promise + handleSendChat: (text: string) => Promise } const useYoutube = async ({ handleSendChat }: Params) => { diff --git a/src/features/chat/handlers.ts b/src/features/chat/handlers.ts index f37501fa..be2e6130 100644 --- a/src/features/chat/handlers.ts +++ b/src/features/chat/handlers.ts @@ -386,13 +386,14 @@ export const processAIResponse = async ( /** * アシスタントとの会話を行う * 画面のチャット欄から入力されたときに実行される処理 + * Youtubeでチャット取得した場合もこの関数を使用する */ export const handleSendChatFn = (errors: { NotConnectedToExternalAssistant: string APIKeyNotEntered: string }) => - async (text: string, role?: string) => { + async (text: string) => { const newMessage = text if (newMessage === null) return @@ -406,68 +407,25 @@ export const handleSendChatFn = console.log('websocket mode: true') homeStore.setState({ chatProcessing: true }) - if (role !== undefined && role !== 'user') { - // WebSocketからの返答を処理 - - if (role == 'assistant') { - let aiText = `${'[neutral]'} ${newMessage}` - try { - const aiTalks = textsToScreenplay([aiText], ss.koeiroParam) - - // 文ごとに音声を生成 & 再生、返答を表示 - speakCharacter(aiTalks[0], async () => { - // アシスタントの返答をログに追加 - const updateLog: Message[] = [ - ...hs.codeLog, - { role: 'assistant', content: newMessage }, - ] - - homeStore.setState({ - chatLog: updateLog, - codeLog: updateLog, - assistantMessage: newMessage, - chatProcessing: false, - }) - }) - } catch (e) { - homeStore.setState({ - chatProcessing: false, - }) - } - } else if (role == 'code' || role == 'output' || role == 'executing') { - // コードコメントの処理 - // ループ完了後にAI応答をコードログに追加 - const updateLog: Message[] = [ - ...hs.codeLog, - { role: role, content: newMessage }, - ] - homeStore.setState({ codeLog: updateLog, chatProcessing: false }) - } else { - // その他のコメントの処理(現想���では使用されないはず) - console.log('error role:', role) - } + // WebSocketで送信する処理 + if (hs.ws?.readyState === WebSocket.OPEN) { + // ユーザーの発言を追加して表示 + const updateLog: Message[] = [ + ...hs.codeLog, + { role: 'user', content: newMessage }, + ] + homeStore.setState({ + chatLog: updateLog, + codeLog: updateLog, + }) + + // WebSocket送信 + hs.ws.send(JSON.stringify({ content: newMessage, type: 'chat' })) } else { - // WebSocketで送信する処理 - - if (hs.ws?.readyState === WebSocket.OPEN) { - // ユーザーの発言を追加して表示 - const updateLog: Message[] = [ - ...hs.codeLog, - { role: 'user', content: newMessage }, - ] - homeStore.setState({ - chatLog: updateLog, - codeLog: updateLog, - }) - - // WebSocket送信 - hs.ws.send(JSON.stringify({ content: newMessage, type: 'chat' })) - } else { - homeStore.setState({ - assistantMessage: errors['NotConnectedToExternalAssistant'], - chatProcessing: false, - }) - } + homeStore.setState({ + assistantMessage: errors['NotConnectedToExternalAssistant'], + chatProcessing: false, + }) } } else { // ChatVRM original mode @@ -597,3 +555,74 @@ export const handleSendChatFn = homeStore.setState({ chatProcessing: false }) } } + +/** + * WebSocketからのテキストを受信したときの処理 + */ +export const handleReceiveTextFromWsFn = + () => async (text: string, role?: string) => { + const newMessage = text + + if (newMessage === null) return + + const ss = settingsStore.getState() + const hs = homeStore.getState() + + if (!ss.webSocketMode) { + console.log('websocket mode: false') + return + } + + // 未メンテなので不具合がある可能性あり + console.log('websocket mode: true') + homeStore.setState({ chatProcessing: true }) + + if (role !== undefined && role !== 'user') { + // WebSocketからの返答を処理 + + if (role == 'assistant') { + let aiText = `${'[neutral]'} ${newMessage}` + try { + const aiTalks = textsToScreenplay([aiText], ss.koeiroParam) + + // 文ごとに音声を生成 & 再生、返答を表示 + speakCharacter( + aiTalks[0], + () => { + // アシスタントの返答をログに追加 + const updateLog: Message[] = [ + ...hs.codeLog, + { role: 'assistant', content: newMessage }, + ] + hs.assistantMessage + // hs.incrementChatProcessingCount() + homeStore.setState({ + chatLog: updateLog, + codeLog: updateLog, + assistantMessage: newMessage, + chatProcessing: false, + }) + }, + () => { + // hs.decrementChatProcessingCount() + } + ) + } catch (e) { + homeStore.setState({ + chatProcessing: false, + }) + } + } else if (role == 'code' || role == 'output' || role == 'executing') { + // コードコメントの処理 + // ループ完了後にAI応答をコードログに追加 + const updateLog: Message[] = [ + ...hs.codeLog, + { role: role, content: newMessage }, + ] + homeStore.setState({ codeLog: updateLog, chatProcessing: false }) + } else { + // その他のコメントの処理(現在の想定では使用されないはず) + console.log('error role:', role) + } + } + } diff --git a/src/features/youtube/youtubeComments.ts b/src/features/youtube/youtubeComments.ts index 92ab8b2e..8e0f3a7e 100644 --- a/src/features/youtube/youtubeComments.ts +++ b/src/features/youtube/youtubeComments.ts @@ -103,7 +103,7 @@ export const fetchAndProcessComments = async ( setYoutubeContinuationCount: (count: number) => void, youtubeSleepMode: boolean, setYoutubeSleepMode: (mode: boolean) => void, - handleSendChat: (text: string, role?: string) => void, + handleSendChat: (text: string) => void, preProcessAIResponse: (messages: Message[]) => void ): Promise => { try { From ae2309e5d69998e5a6481c0b5a842f1c2c72ca78 Mon Sep 17 00:00:00 2001 From: tegnike Date: Wed, 21 Aug 2024 14:39:59 +0200 Subject: [PATCH 3/5] =?UTF-8?q?WebSocket=E3=83=A2=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AEUI=E8=A1=A8=E7=A4=BA=E4=BF=AE=E6=AD=A3=EF=BC=88CodeLog?= =?UTF-8?q?=E3=82=92=E5=89=8A=E9=99=A4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/en/translation.json | 1 - locales/ja/translation.json | 1 - locales/ko/translation.json | 1 - locales/zh/translation.json | 1 - src/components/chatLog.tsx | 71 +++++++++++---- src/components/codeLog.tsx | 154 -------------------------------- src/components/menu.tsx | 7 +- src/components/settings/log.tsx | 13 +-- src/components/useWebSocket.tsx | 63 ++++++++++--- src/features/chat/handlers.ts | 44 ++++----- src/features/stores/home.ts | 5 +- src/utils/migrateStore.ts | 2 +- 12 files changed, 128 insertions(+), 235 deletions(-) delete mode 100644 src/components/codeLog.tsx diff --git a/locales/en/translation.json b/locales/en/translation.json index 415154fe..dd8168de 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -63,7 +63,6 @@ "ConversationHistoryReset": "Reset Conversation History", "NotConnectedToExternalAssistant": "Not connected to an external assistant.", "APIKeyNotEntered": "API key is not entered.", - "CodeLog": "Code Log", "ChatLog": "Conversation Log", "EnterYourQuestion": "Enter your question here", "AnswerGenerating": "Answer Generating", diff --git a/locales/ja/translation.json b/locales/ja/translation.json index baf9f3d7..89ec58c0 100644 --- a/locales/ja/translation.json +++ b/locales/ja/translation.json @@ -64,7 +64,6 @@ "ConversationHistoryReset": "会話履歴リセット", "NotConnectedToExternalAssistant": "外部アシスタントと接続されていません。", "APIKeyNotEntered": "APIキーが入力されていません。", - "CodeLog": "コードログ", "ChatLog": "会話ログ", "EnterYourQuestion": "聞きたいことをいれてね", "AnswerGenerating": "回答生成中", diff --git a/locales/ko/translation.json b/locales/ko/translation.json index c6f848dc..dc8fe6de 100644 --- a/locales/ko/translation.json +++ b/locales/ko/translation.json @@ -63,7 +63,6 @@ "ConversationHistoryReset": "대화 기록 재설정", "NotConnectedToExternalAssistant": "외부 어시스턴트와 연결되지 않았습니다.", "APIKeyNotEntered": "API 키가 입력되지 않았습니다.", - "CodeLog": "코드 로그", "ChatLog": "대화 로그", "EnterYourQuestion": "질문을 입력하세요", "AnswerGenerating": "답변 생성중", diff --git a/locales/zh/translation.json b/locales/zh/translation.json index 37e60476..6e261942 100644 --- a/locales/zh/translation.json +++ b/locales/zh/translation.json @@ -63,7 +63,6 @@ "ConversationHistoryReset": "重設聊天記錄", "NotConnectedToExternalAssistant": "未連接外部助理。", "APIKeyNotEntered": "尚未輸入 API 金鑰。", - "CodeLog": "程式碼日誌", "ChatLog": "聊天記錄", "EnterYourQuestion": "在此輸入您的問題", "AnswerGenerating": "正在生成回答", diff --git a/src/components/chatLog.tsx b/src/components/chatLog.tsx index e51b540a..4acf0a27 100644 --- a/src/components/chatLog.tsx +++ b/src/components/chatLog.tsx @@ -28,6 +28,9 @@ export const ChatLog = () => {
{messages.map((msg, i) => { + const prevRole = i > 0 ? messages[i - 1].role : '' + const nextRole = i < messages.length - 1 ? messages[i + 1].role : '' + return (
{typeof msg.content === 'string' ? ( @@ -35,6 +38,8 @@ export const ChatLog = () => { role={msg.role} message={msg.content} characterName={characterName} + prevRole={prevRole} + nextRole={nextRole} /> ) : ( <> @@ -42,6 +47,8 @@ export const ChatLog = () => { role={msg.role} message={msg.content[0].text} characterName={characterName} + prevRole={prevRole} + nextRole={nextRole} /> { const roleColor = - role !== 'user' ? 'bg-secondary text-white ' : 'bg-base text-primary' + role !== 'user' ? 'bg-secondary text-white' : 'bg-base text-primary' const roleText = role !== 'user' ? 'text-secondary' : 'text-primary' const offsetX = role === 'user' ? 'pl-40' : 'pr-40' - return ( -
- {role === 'code' ? ( -
-          {message}
-        
- ) : ( - <> -
- {role !== 'user' ? characterName || 'CHARACTER' : 'YOU'} -
-
-
- {message} + const sameAsPrevRole = role === prevRole + const sameAsNextRole = role === nextRole + + if (role === 'code') { + const messageLines = message.split('\n\n') + return ( +
+
+ {messageLines.map((line, index) => ( +
+ {line}
-
- + ))} +
+
+ ) + } + + return ( +
+ {!sameAsPrevRole && ( +
+ {role !== 'user' ? characterName || 'CHARACTER' : 'YOU'} +
)} +
+
{message}
+
) } diff --git a/src/components/codeLog.tsx b/src/components/codeLog.tsx deleted file mode 100644 index 2e916b54..00000000 --- a/src/components/codeLog.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import { useEffect, useRef } from 'react' - -import homeStore from '@/features/stores/home' - -export const CodeLog = () => { - const chatScrollRef = useRef(null) - const messages = homeStore((s) => s.codeLog) - - useEffect(() => { - chatScrollRef.current?.scrollIntoView({ - behavior: 'auto', - block: 'center', - }) - }, []) - - useEffect(() => { - chatScrollRef.current?.scrollIntoView({ - behavior: 'smooth', - block: 'center', - }) - }, [messages]) - - return ( - // 画面サイズによって変える -
-
-
-
- {messages.map((msg, i) => { - const prevRole = i > 0 ? messages[i - 1].role : '' - const nextRole = - i < messages.length - 1 ? messages[i + 1].role : '' - - const content = - typeof msg.content === 'string' - ? msg.content - : msg.content[0].text - - return ( -
- -
- ) - })} -
-
-
-
- ) -} - -const Chat = ({ - role, - message, - prevRole, - nextRole, -}: { - role: string - message: string - prevRole: string - nextRole: string -}) => { - const bgColor = - role === 'code' || role === 'output' || role === 'executing' - ? 'bg-black' - : 'bg-white' - let textColor: string - switch (role) { - case 'code': - case 'output': - case 'executing': - textColor = 'text-white' - break - case 'assistant': - textColor = 'text-secondary' - break - default: - textColor = 'text-primary' - } - const same_as_prev_role = role === prevRole - const same_as_next_role = role === nextRole - - if (role === 'code') { - // 改行文字でメッセージを分割 - const messageLines = message.split('\n\n') - return ( -
-
- {messageLines.map((line, index) => ( -
- {line} -
- ))} -
-
- ) - } else if (role === 'output' || role === 'executing') { - // 改行文字でメッセージを分割 - const messageLines = message.split('\n') - return ( -
-
- {messageLines.map((line, index) => ( -
- {line} -
- ))} -
-
- ) - } else { - // 改行文字でメッセージを分割 - const messageLines = message.split('\n') - return ( -
-
- {messageLines - .filter((line) => line.trim() !== '') - .map((line, index) => ( -
- {line} -
- ))} -
-
- ) - } -} diff --git a/src/components/menu.tsx b/src/components/menu.tsx index f43f1635..07049026 100644 --- a/src/components/menu.tsx +++ b/src/components/menu.tsx @@ -7,7 +7,6 @@ import settingsStore from '@/features/stores/settings' import slideStore from '@/features/stores/slide' import { AssistantText } from './assistantText' import { ChatLog } from './chatLog' -import { CodeLog } from './codeLog' import { IconButton } from './iconButton' import Settings from './settings' import { Webcam } from './webcam' @@ -118,14 +117,14 @@ export const Menu = () => { {showChatLog ? ( setShowChatLog(false)} /> ) : ( setShowChatLog(true)} @@ -208,7 +207,7 @@ export const Menu = () => {
{slideMode && slideVisible && }
- {webSocketMode ? showChatLog && : showChatLog && } + {webSocketMode ? showChatLog && : showChatLog && } {showSettings && setShowSettings(false)} />} {!showChatLog && assistantMessage && !slideVisible && ( diff --git a/src/components/settings/log.tsx b/src/components/settings/log.tsx index 77baad25..97a481da 100644 --- a/src/components/settings/log.tsx +++ b/src/components/settings/log.tsx @@ -24,7 +24,7 @@ const Log = () => {
{ - homeStore.setState({ chatLog: [], codeLog: [] }) + homeStore.setState({ chatLog: [] }) settingsStore.setState({ difyConversationId: '' }) }} > @@ -51,7 +51,6 @@ const Log = () => { value={value.content} onChange={(e) => { handleChangeChatLog(index, e.target.value) - handleChangeCodeLog(index, e.target.value) }} > ) : ( @@ -81,13 +80,3 @@ const handleChangeChatLog = (targetIndex: number, text: string) => { homeStore.setState({ chatLog: newChatLog }) } - -const handleChangeCodeLog = (targetIndex: number, text: string) => { - const hs = homeStore.getState() - - const newCodeLog = hs.codeLog.map((m, i) => { - return i === targetIndex ? { role: m.role, content: text } : m - }) - - homeStore.setState({ chatLog: newCodeLog }) -} diff --git a/src/components/useWebSocket.tsx b/src/components/useWebSocket.tsx index ec271d9f..13949d73 100644 --- a/src/components/useWebSocket.tsx +++ b/src/components/useWebSocket.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { useEffect, useState, useCallback } from 'react' import homeStore from '@/features/stores/home' import settingsStore from '@/features/stores/settings' @@ -8,6 +8,7 @@ interface TmpMessage { text: string role: string emotion: string + state: string } interface Params { @@ -16,9 +17,57 @@ interface Params { const useWebSocket = ({ handleReceiveTextFromWs }: Params) => { const webSocketMode = settingsStore((s) => s.webSocketMode) - const [tmpMessages, setTmpMessages] = useState([]) + const [currentMessage, setCurrentMessage] = useState<{ + role: string + text: string + }>({ role: '', text: '' }) + + const processMessage = useCallback( + async (message: TmpMessage) => { + if (message.state === 'start') { + setCurrentMessage({ role: '', text: '' }) + } else if (message.state === 'end') { + if (currentMessage.role && currentMessage.text) { + await handleReceiveTextFromWs( + currentMessage.text, + currentMessage.role + ) + setCurrentMessage({ role: '', text: '' }) + } + } else { + if (currentMessage.role === message.role) { + setCurrentMessage((prev) => ({ + ...prev, + text: + prev.text + + (message.role === 'assistant' + ? message.text + : '\n' + message.text), + })) + } else { + if (currentMessage.role && currentMessage.text) { + await handleReceiveTextFromWs( + currentMessage.text, + currentMessage.role + ) + } + setCurrentMessage({ role: message.role, text: message.text }) + } + } + }, + [currentMessage.role, currentMessage.text, handleReceiveTextFromWs] + ) + useEffect(() => { + if (tmpMessages.length > 0) { + const message = tmpMessages[0] + setTmpMessages((prev) => prev.slice(1)) + processMessage(message) + } + }, [tmpMessages, processMessage]) + + // WebSocket接続の設定(既存のコード) useEffect(() => { const ss = settingsStore.getState() if (!ss.webSocketMode) return @@ -73,13 +122,7 @@ const useWebSocket = ({ handleReceiveTextFromWs }: Params) => { } }, [webSocketMode]) - // WebSocketモード用の処理 - useEffect(() => { - if (tmpMessages.length > 0) { - const message = tmpMessages[0] - setTmpMessages((tmpMessages) => tmpMessages.slice(1)) - handleReceiveTextFromWs(message.text, message.role) - } - }, [tmpMessages, handleReceiveTextFromWs]) + return null } + export default useWebSocket diff --git a/src/features/chat/handlers.ts b/src/features/chat/handlers.ts index be2e6130..3df295bc 100644 --- a/src/features/chat/handlers.ts +++ b/src/features/chat/handlers.ts @@ -411,12 +411,11 @@ export const handleSendChatFn = if (hs.ws?.readyState === WebSocket.OPEN) { // ユーザーの発言を追加して表示 const updateLog: Message[] = [ - ...hs.codeLog, + ...hs.chatLog, { role: 'user', content: newMessage }, ] homeStore.setState({ chatLog: updateLog, - codeLog: updateLog, }) // WebSocket送信 @@ -561,9 +560,7 @@ export const handleSendChatFn = */ export const handleReceiveTextFromWsFn = () => async (text: string, role?: string) => { - const newMessage = text - - if (newMessage === null) return + if (text === null || role === undefined) return const ss = settingsStore.getState() const hs = homeStore.getState() @@ -573,15 +570,12 @@ export const handleReceiveTextFromWsFn = return } - // 未メンテなので不具合がある可能性あり console.log('websocket mode: true') homeStore.setState({ chatProcessing: true }) - if (role !== undefined && role !== 'user') { - // WebSocketからの返答を処理 - - if (role == 'assistant') { - let aiText = `${'[neutral]'} ${newMessage}` + if (role !== 'user') { + if (role === 'assistant') { + let aiText = `${'[neutral]'} ${text}` try { const aiTalks = textsToScreenplay([aiText], ss.koeiroParam) @@ -591,16 +585,13 @@ export const handleReceiveTextFromWsFn = () => { // アシスタントの返答をログに追加 const updateLog: Message[] = [ - ...hs.codeLog, - { role: 'assistant', content: newMessage }, + ...hs.chatLog, + { role: 'assistant', content: text }, ] - hs.assistantMessage // hs.incrementChatProcessingCount() homeStore.setState({ chatLog: updateLog, - codeLog: updateLog, - assistantMessage: newMessage, - chatProcessing: false, + assistantMessage: text, }) }, () => { @@ -608,21 +599,20 @@ export const handleReceiveTextFromWsFn = } ) } catch (e) { - homeStore.setState({ - chatProcessing: false, - }) + console.error('Error in speakCharacter:', e) } - } else if (role == 'code' || role == 'output' || role == 'executing') { - // コードコメントの処理 - // ループ完了後にAI応答をコードログに追加 + } else if (role === 'code' || role === 'output' || role === 'executing') { const updateLog: Message[] = [ - ...hs.codeLog, - { role: role, content: newMessage }, + ...hs.chatLog, + { role: role, content: text }, ] - homeStore.setState({ codeLog: updateLog, chatProcessing: false }) + homeStore.setState({ + chatLog: updateLog, + }) } else { - // その他のコメントの処理(現在の想定では使用されないはず) console.log('error role:', role) } } + + homeStore.setState({ chatProcessing: false }) } diff --git a/src/features/stores/home.ts b/src/features/stores/home.ts index 5c9c4556..be7cfa37 100644 --- a/src/features/stores/home.ts +++ b/src/features/stores/home.ts @@ -7,7 +7,6 @@ import { Viewer } from '../vrmViewer/viewer' export interface PersistedState { userOnboarded: boolean chatLog: Message[] - codeLog: Message[] dontShowIntroduction: boolean } @@ -34,7 +33,6 @@ const homeStore = create()( // persisted states userOnboarded: false, chatLog: [], - codeLog: [], dontShowIntroduction: false, // transient states @@ -62,9 +60,8 @@ const homeStore = create()( }), { name: 'aitube-kit-home', - partialize: ({ chatLog, codeLog, dontShowIntroduction }) => ({ + partialize: ({ chatLog, dontShowIntroduction }) => ({ chatLog, - codeLog, dontShowIntroduction, }), } diff --git a/src/utils/migrateStore.ts b/src/utils/migrateStore.ts index b6288268..56b14c0b 100644 --- a/src/utils/migrateStore.ts +++ b/src/utils/migrateStore.ts @@ -7,7 +7,7 @@ const migrateStore = () => { if (!rawStore) return type Store = Omit & - Pick & { + Pick & { selectLanguage: string } From 8185e902f68bc60480c6aa85ddffffc3eb36c9fc Mon Sep 17 00:00:00 2001 From: tegnike Date: Wed, 21 Aug 2024 17:50:07 +0200 Subject: [PATCH 4/5] =?UTF-8?q?websocket.tsx=20=E3=83=AA=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=AF=E3=82=BF=E3=83=AA=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/settings/websocket.tsx | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/components/settings/websocket.tsx b/src/components/settings/websocket.tsx index b5969a81..d6cf258f 100644 --- a/src/components/settings/websocket.tsx +++ b/src/components/settings/websocket.tsx @@ -25,25 +25,14 @@ const WebSocket = () => { {t('ExternalConnectionMode')}
- {webSocketMode ? ( - { - settingsStore.setState({ webSocketMode: false }) - webSocketMode && handleChangeYoutubeMode(false) - }} - > - {t('StatusOn')} - - ) : ( - { - settingsStore.setState({ webSocketMode: true }) - webSocketMode && handleChangeYoutubeMode(false) - }} - > - {t('StatusOff')} - - )} + { + settingsStore.setState({ webSocketMode: !webSocketMode }) + webSocketMode && handleChangeYoutubeMode(false) + }} + > + {webSocketMode ? t('StatusOn') : t('StatusOff')} +
) From 8e059970be35101bfdc338a89747e773bcee215c Mon Sep 17 00:00:00 2001 From: tegnike Date: Wed, 21 Aug 2024 18:11:56 +0200 Subject: [PATCH 5/5] =?UTF-8?q?websocket=E3=83=A2=E3=83=BC=E3=83=89?= =?UTF-8?q?=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=E6=99=82=E3=81=AE=E3=83=AD?= =?UTF-8?q?=E3=82=B8=E3=83=83=E3=82=AF=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/settings/websocket.tsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/components/settings/websocket.tsx b/src/components/settings/websocket.tsx index d6cf258f..1c000435 100644 --- a/src/components/settings/websocket.tsx +++ b/src/components/settings/websocket.tsx @@ -1,24 +1,11 @@ import { useTranslation } from 'react-i18next' - -import homeStore from '@/features/stores/home' -import menuStore from '@/features/stores/menu' import settingsStore from '@/features/stores/settings' import { TextButton } from '../textButton' const WebSocket = () => { const { t } = useTranslation() - const webSocketMode = settingsStore((s) => s.webSocketMode) - const handleChangeYoutubeMode = (youtubeMode: boolean) => { - settingsStore.setState({ youtubeMode }) - - if (youtubeMode) { - homeStore.setState({ modalImage: '' }) - menuStore.setState({ showWebcam: false }) - } - } - return (
@@ -28,7 +15,6 @@ const WebSocket = () => { { settingsStore.setState({ webSocketMode: !webSocketMode }) - webSocketMode && handleChangeYoutubeMode(false) }} > {webSocketMode ? t('StatusOn') : t('StatusOff')}