feat(app): add textEngine toggle for chat mode (Coze ↔ S2S)

- localStorage-persistent textEngine state ('coze' | 's2s')
- Header button toggles between the two engines when in chat mode
- ChatPanel remounts on engine switch via key=sessionId-textEngine
- Voice mode completely unaffected
This commit is contained in:
User
2026-04-17 09:36:13 +08:00
parent af9faf26c9
commit 3e72cd54d3

View File

@@ -1,10 +1,11 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { Settings2, Zap, Mic, MessageSquare, History, Plus } from 'lucide-react';
import { Settings2, Zap, Mic, MessageSquare, History, Plus, Film } from 'lucide-react';
import VoicePanel from './components/VoicePanel';
import ChatPanel from './components/ChatPanel';
import SettingsPanel from './components/SettingsPanel';
import { getVoiceConfig } from './services/voiceApi';
import SessionHistoryPanel from './components/SessionHistoryPanel';
import VideoPanel from './components/VideoPanel';
export default function App() {
const [showSettings, setShowSettings] = useState(false);
@@ -19,14 +20,25 @@ export default function App() {
// 文字聊天消息(用于切回语音时注入上下文)
const [chatMessages, setChatMessages] = useState([]);
const [settings, setSettings] = useState({
botName: '小智',
systemRole: '你是一个友善的智能助手,名叫小智。你擅长帮用户解答各类问题。',
speakingStyle: '请使用温和、清晰的口吻。',
greetingText: '你好,我是你的智能语音助手,有什么可以帮你的吗?',
modelVersion: '1.2.1.0',
modelVersion: 'O',
speaker: 'zh_female_vv_jupiter_bigtts',
enableWebSearch: false,
});
// 文字对话引擎: 'coze' (原方舟 HTTP/SSE) | 's2s' (S2S WebSocket, event 501)
const [textEngine, setTextEngine] = useState(() => {
try {
return localStorage.getItem('bigwo_text_engine') || 'coze';
} catch (_) {
return 'coze';
}
});
const toggleTextEngine = useCallback(() => {
setTextEngine((prev) => {
const next = prev === 'coze' ? 's2s' : 'coze';
try { localStorage.setItem('bigwo_text_engine', next); } catch (_) {}
return next;
});
}, []);
useEffect(() => {
getVoiceConfig()
@@ -108,14 +120,18 @@ export default function App() {
</div>
<div>
<h1 className="text-sm font-semibold text-white leading-tight">
{mode === 'voice' ? '语音通话' : '文字对话'}
{mode === 'voice' ? '语音通话' : mode === 'chat' ? '文字对话' : 'AI 视频'}
</h1>
<p className="text-[11px] text-slate-400 leading-tight">
{mode === 'voice'
? '直连 S2S 语音 · ChatTTSText'
: handoff?.subtitles?.length > 0
? '语音转接 · 上下文已延续'
: '方舟 LLM · Function Calling'}
: mode === 'chat'
? (textEngine === 's2s'
? 'S2S 文字 · event 501 ChatTextQuery'
: (handoff?.subtitles?.length > 0
? '语音转接 · 上下文已延续'
: '方舟 LLM · Function Calling'))
: 'Seedance · AI 视频生成'}
</p>
</div>
</div>
@@ -158,7 +174,30 @@ export default function App() {
>
<MessageSquare className="w-3 h-3" /> 文字
</button>
<button
onClick={() => setMode('video')}
className={`flex items-center gap-1 px-2.5 py-1 rounded-md text-xs transition-all ${
mode === 'video'
? 'bg-violet-500/20 text-violet-300 font-medium'
: 'text-slate-500 hover:text-slate-300'
}`}
>
<Film className="w-3 h-3" /> 视频
</button>
</div>
{mode === 'chat' && (
<button
onClick={toggleTextEngine}
className={`px-2 py-1 rounded-md text-[11px] font-medium transition-colors border ${
textEngine === 's2s'
? 'bg-emerald-500/15 text-emerald-300 border-emerald-500/30'
: 'bg-slate-700/40 text-slate-300 border-slate-600/40'
}`}
title="切换文字对话引擎 (S2S 走 event 501, Coze 走 HTTP/SSE)"
>
{textEngine === 's2s' ? 'S2S' : 'Coze'}
</button>
)}
{mode === 'voice' && (
<button
onClick={() => setShowSettings(!showSettings)}
@@ -207,18 +246,23 @@ export default function App() {
</div>
</div>
</>
) : (
) : mode === 'chat' ? (
/* Chat Panel */
handoff && (
<ChatPanel
key={handoff.sessionId}
key={`${handoff.sessionId}-${textEngine}`}
sessionId={handoff.sessionId}
voiceSubtitles={handoff.subtitles}
settings={settings}
onBack={handleBackToVoice}
onMessagesChange={setChatMessages}
useS2S={textEngine === 's2s'}
playAudioReply={false}
/>
)
) : (
/* Video Panel */
<VideoPanel />
)}
</main>