Spaces:
Running
Running
| import { useState, useRef } from 'preact/hooks'; | |
| async function waitForConfig() { | |
| return new Promise((resolve) => { | |
| const check = () => { | |
| if (window.ChatbotConfig) resolve(window.ChatbotConfig); | |
| else setTimeout(check, 50); | |
| }; | |
| check(); | |
| }); | |
| } | |
| export function useChat() { | |
| const [messages, setMessages] = useState([]); | |
| const [isTyping, setIsTyping] = useState(false); | |
| const sessionId = useRef(null); | |
| const config = useRef(null); | |
| async function getConfig() { | |
| if (!config.current) { | |
| config.current = await waitForConfig(); | |
| } | |
| return config.current; | |
| } | |
| async function initialize() { | |
| await getConfig(); | |
| setMessages([{ | |
| id: Date.now(), | |
| sender: 'bot', | |
| text: 'Hello! How can I help you today? \u60A8\u597D\uFF01\u4ECA\u5929\u6211\u80FD\u4E3A\u60A8\u505A\u4E9B\u4EC0\u4E48\uFF1F', | |
| }]); | |
| } | |
| async function sendMessage(text) { | |
| if (isTyping || !text.trim()) return; | |
| const cfg = await getConfig(); | |
| setMessages(prev => [...prev, { id: Date.now(), sender: 'user', text }]); | |
| setIsTyping(true); | |
| try { | |
| const body = { message: text }; | |
| if (sessionId.current) body.session_id = sessionId.current; | |
| const controller = new AbortController(); | |
| const timeout = setTimeout(() => controller.abort(), cfg.REQUEST_TIMEOUT_MS); | |
| const thinkingStart = Date.now(); | |
| const res = await fetch(`${cfg.API_URL}/chat`, { | |
| method: 'POST', | |
| headers: { 'X-API-Key': cfg.API_KEY, 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(body), | |
| signal: controller.signal, | |
| }); | |
| clearTimeout(timeout); | |
| if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`); | |
| const data = await res.json(); | |
| const thinkingDuration = data.thinking | |
| ? ((Date.now() - thinkingStart) / 1000).toFixed(1) | |
| : null; | |
| sessionId.current = data.session_id; | |
| let debugInfo = null; | |
| if (cfg.SHOW_DEBUG_INFO) { | |
| debugInfo = { | |
| intent: data.intent, | |
| confidence: data.confidence?.toFixed(2), | |
| entities: data.entities, | |
| language: data.debug_info?.language, | |
| environment: data.debug_info?.environment, | |
| }; | |
| } | |
| setMessages(prev => [...prev, { | |
| id: Date.now(), | |
| sender: 'bot', | |
| text: data.response, | |
| thinking: data.thinking || null, | |
| thinkingDuration, | |
| debugInfo, | |
| }]); | |
| } catch (err) { | |
| const cfg = config.current; | |
| const errMsg = cfg?.DEBUG | |
| ? `Error: ${err.message}` | |
| : 'Sorry, I encountered an error. Please try again.'; | |
| setMessages(prev => [...prev, { id: Date.now(), sender: 'bot', text: errMsg }]); | |
| } finally { | |
| setIsTyping(false); | |
| } | |
| } | |
| return { messages, isTyping, initialize, sendMessage }; | |
| } | |