From c7260677a1298d04fae038e3e90a3390701b1c46 Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Mon, 9 Feb 2026 08:38:31 +0800 Subject: [PATCH] Debug drawer get config from page --- web/pages/Assistants.tsx | 98 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/web/pages/Assistants.tsx b/web/pages/Assistants.tsx index cb68a94..ef3d0f2 100644 --- a/web/pages/Assistants.tsx +++ b/web/pages/Assistants.tsx @@ -14,6 +14,11 @@ interface ToolItem { isCustom?: boolean; } +const isSiliconflowVendor = (vendor?: string) => { + const normalized = String(vendor || '').trim().toLowerCase(); + return normalized === 'siliconflow' || normalized === '硅基流动'; +}; + export const AssistantsPage: React.FC = () => { const [assistants, setAssistants] = useState([]); const [voices, setVoices] = useState([]); @@ -933,7 +938,10 @@ export const AssistantsPage: React.FC = () => { setDebugOpen(false)} - assistant={selectedAssistant} + assistant={selectedAssistant} + voices={voices} + llmModels={llmModels} + asrModels={asrModels} /> )} @@ -1020,7 +1028,14 @@ const BotIcon = ({className}: {className?: string}) => ( ); // --- Debug Drawer Component --- -export const DebugDrawer: React.FC<{ isOpen: boolean; onClose: () => void; assistant: Assistant }> = ({ isOpen, onClose, assistant }) => { +export const DebugDrawer: React.FC<{ + isOpen: boolean; + onClose: () => void; + assistant: Assistant; + voices: Voice[]; + llmModels: LLMModel[]; + asrModels: ASRModel[]; +}> = ({ isOpen, onClose, assistant, voices, llmModels, asrModels }) => { const [mode, setMode] = useState<'text' | 'voice' | 'video'>('text'); const [messages, setMessages] = useState<{role: 'user' | 'model', text: string}[]>([]); const [inputText, setInputText] = useState(''); @@ -1175,6 +1190,77 @@ export const DebugDrawer: React.FC<{ isOpen: boolean; onClose: () => void; assis }; const fetchRuntimeMetadata = async (): Promise> => { + const warnings: string[] = []; + const services: Record = {}; + + if (assistant.llmModelId) { + const llm = llmModels.find((item) => item.id === assistant.llmModelId); + if (llm) { + services.llm = { + provider: 'openai', + model: llm.modelName || llm.name, + apiKey: llm.apiKey, + baseUrl: llm.baseUrl, + }; + } else { + warnings.push(`LLM model not found in loaded list: ${assistant.llmModelId}`); + } + } + + if (assistant.asrModelId) { + const asr = asrModels.find((item) => item.id === assistant.asrModelId); + if (asr) { + const asrProvider = isSiliconflowVendor(asr.vendor) ? 'siliconflow' : 'buffered'; + services.asr = { + provider: asrProvider, + model: asr.modelName || asr.name, + apiKey: asrProvider === 'siliconflow' ? asr.apiKey : null, + }; + } else { + warnings.push(`ASR model not found in loaded list: ${assistant.asrModelId}`); + } + } + + if (assistant.voice) { + const voice = voices.find((item) => item.id === assistant.voice); + if (voice) { + const ttsProvider = isSiliconflowVendor(voice.vendor) ? 'siliconflow' : 'edge'; + services.tts = { + provider: ttsProvider, + model: voice.model, + apiKey: ttsProvider === 'siliconflow' ? voice.apiKey : null, + voice: voice.voiceKey || voice.id, + speed: assistant.speed || voice.speed || 1.0, + }; + } else { + services.tts = { + voice: assistant.voice, + speed: assistant.speed || 1.0, + }; + warnings.push(`Voice resource not found in loaded list: ${assistant.voice}`); + } + } + + const localResolved = { + assistantId: assistant.id, + sources: { + llmModelId: assistant.llmModelId || '', + asrModelId: assistant.asrModelId || '', + voiceId: assistant.voice || '', + }, + warnings, + sessionStartMetadata: { + systemPrompt: assistant.prompt || '', + greeting: assistant.opener || '', + services, + }, + }; + + setResolvedConfigView(JSON.stringify(localResolved, null, 2)); + return localResolved.sessionStartMetadata; + }; + + const fetchRuntimeMetadataFromDb = async (): Promise> => { try { const resolved = await fetchAssistantRuntimeConfig(assistant.id); setResolvedConfigView( @@ -1189,7 +1275,7 @@ export const DebugDrawer: React.FC<{ isOpen: boolean; onClose: () => void; assis 2, ), ); - return resolved.sessionStartMetadata || {}; + return resolved.sessionStartMetadata || { systemPrompt: assistant.prompt || '', greeting: assistant.opener || '', services: {} }; } catch (error) { console.error('Failed to load runtime config, using fallback.', error); const fallback = { @@ -1239,7 +1325,11 @@ export const DebugDrawer: React.FC<{ isOpen: boolean; onClose: () => void; assis return; } - const metadata = await fetchRuntimeMetadata(); + let metadata = await fetchRuntimeMetadata(); + if (!metadata || typeof metadata !== 'object') { + // Safety fallback, should not happen with local resolution. + metadata = await fetchRuntimeMetadataFromDb(); + } setWsStatus('connecting'); setWsError('');