Integrate React Query for data management and enhance Debug Preferences
- Added React Query for managing API calls related to assistants and voices. - Introduced `useAssistantsQuery` and `useVoicesQuery` hooks for fetching data. - Implemented mutations for creating, updating, and deleting voices using React Query. - Integrated a global `QueryClient` for managing query states and configurations. - Refactored components to utilize the new query hooks, improving data handling and performance. - Added a Zustand store for managing debug preferences, including WebSocket URL and audio settings.
This commit is contained in:
@@ -5,6 +5,7 @@ import { Plus, Search, Play, Square, Copy, Trash2, Mic, MessageSquare, Save, Vid
|
||||
import { Button, Input, Badge, Drawer, Dialog, Switch } from '../components/UI';
|
||||
import { ASRModel, Assistant, AssistantOpenerToolCall, KnowledgeBase, LLMModel, TabValue, Tool, Voice } from '../types';
|
||||
import { createAssistant, deleteAssistant, fetchASRModels, fetchAssistantOpenerAudioPcmBuffer, fetchAssistants, fetchKnowledgeBases, fetchLLMModels, fetchTools, fetchVoices, generateAssistantOpenerAudio, previewVoice, updateAssistant as updateAssistantApi } from '../services/backendApi';
|
||||
import { useDebugPrefsStore } from '../stores/debugPrefsStore';
|
||||
|
||||
const isOpenAICompatibleVendor = (vendor?: string) => {
|
||||
const normalized = String(vendor || '').trim().toLowerCase();
|
||||
@@ -2365,12 +2366,17 @@ export const DebugDrawer: React.FC<{
|
||||
const [dynamicVariables, setDynamicVariables] = useState<DynamicVariableEntry[]>([]);
|
||||
const [dynamicVariablesError, setDynamicVariablesError] = useState('');
|
||||
const dynamicVariableSeqRef = useRef(0);
|
||||
const [wsUrl, setWsUrl] = useState<string>(() => {
|
||||
const fromStorage = localStorage.getItem('debug_ws_url');
|
||||
if (fromStorage) return fromStorage;
|
||||
const defaultHost = window.location.hostname || 'localhost';
|
||||
return `ws://${defaultHost}:8000/ws`;
|
||||
});
|
||||
const wsUrl = useDebugPrefsStore((state) => state.wsUrl);
|
||||
const setWsUrl = useDebugPrefsStore((state) => state.setWsUrl);
|
||||
const aecEnabled = useDebugPrefsStore((state) => state.aecEnabled);
|
||||
const setAecEnabled = useDebugPrefsStore((state) => state.setAecEnabled);
|
||||
const nsEnabled = useDebugPrefsStore((state) => state.nsEnabled);
|
||||
const setNsEnabled = useDebugPrefsStore((state) => state.setNsEnabled);
|
||||
const agcEnabled = useDebugPrefsStore((state) => state.agcEnabled);
|
||||
const setAgcEnabled = useDebugPrefsStore((state) => state.setAgcEnabled);
|
||||
const clientToolEnabledMap = useDebugPrefsStore((state) => state.clientToolEnabledMap);
|
||||
const setClientToolEnabled = useDebugPrefsStore((state) => state.setClientToolEnabled);
|
||||
const hydrateClientToolDefaults = useDebugPrefsStore((state) => state.hydrateClientToolDefaults);
|
||||
const nextDynamicVariableId = () => {
|
||||
dynamicVariableSeqRef.current += 1;
|
||||
return `var_${dynamicVariableSeqRef.current}`;
|
||||
@@ -2432,16 +2438,6 @@ export const DebugDrawer: React.FC<{
|
||||
const [selectedCamera, setSelectedCamera] = useState<string>('');
|
||||
const [selectedMic, setSelectedMic] = useState<string>('');
|
||||
const [isSwapped, setIsSwapped] = useState(false);
|
||||
const [aecEnabled, setAecEnabled] = useState<boolean>(() => localStorage.getItem('debug_audio_aec') !== '0');
|
||||
const [nsEnabled, setNsEnabled] = useState<boolean>(() => localStorage.getItem('debug_audio_ns') !== '0');
|
||||
const [agcEnabled, setAgcEnabled] = useState<boolean>(() => localStorage.getItem('debug_audio_agc') !== '0');
|
||||
const [clientToolEnabledMap, setClientToolEnabledMap] = useState<Record<string, boolean>>(() => {
|
||||
const result: Record<string, boolean> = {};
|
||||
for (const tool of DEBUG_CLIENT_TOOLS) {
|
||||
result[tool.id] = localStorage.getItem(`debug_client_tool_enabled_${tool.id}`) !== '0';
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
const micAudioCtxRef = useRef<AudioContext | null>(null);
|
||||
const micSourceRef = useRef<MediaStreamAudioSourceNode | null>(null);
|
||||
@@ -2557,8 +2553,8 @@ export const DebugDrawer: React.FC<{
|
||||
}, [isOpen, assistant, mode]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('debug_ws_url', wsUrl);
|
||||
}, [wsUrl]);
|
||||
hydrateClientToolDefaults(DEBUG_CLIENT_TOOLS.map((tool) => tool.id));
|
||||
}, [hydrateClientToolDefaults]);
|
||||
|
||||
useEffect(() => {
|
||||
wsStatusRef.current = wsStatus;
|
||||
@@ -2578,24 +2574,6 @@ export const DebugDrawer: React.FC<{
|
||||
setDynamicVariablesError('');
|
||||
}, [assistant.id, isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('debug_audio_aec', aecEnabled ? '1' : '0');
|
||||
}, [aecEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('debug_audio_ns', nsEnabled ? '1' : '0');
|
||||
}, [nsEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('debug_audio_agc', agcEnabled ? '1' : '0');
|
||||
}, [agcEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
for (const tool of DEBUG_CLIENT_TOOLS) {
|
||||
localStorage.setItem(`debug_client_tool_enabled_${tool.id}`, isClientToolEnabled(tool.id) ? '1' : '0');
|
||||
}
|
||||
}, [clientToolEnabledMap]);
|
||||
|
||||
useEffect(() => {
|
||||
clientToolEnabledMapRef.current = clientToolEnabledMap;
|
||||
}, [clientToolEnabledMap]);
|
||||
@@ -4223,7 +4201,7 @@ export const DebugDrawer: React.FC<{
|
||||
</div>
|
||||
<Switch
|
||||
checked={enabled}
|
||||
onCheckedChange={(next) => setClientToolEnabledMap((prev) => ({ ...prev, [tool.id]: next }))}
|
||||
onCheckedChange={(next) => setClientToolEnabled(tool.id, next)}
|
||||
title={enabled ? '点击关闭' : '点击开启'}
|
||||
aria-label={`${tool.name} ${enabled ? '开启' : '关闭'}`}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user