/* Copyright (C) 2025 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useState, useCallback, useRef, useEffect } from 'react'; import { DEFAULT_MESSAGES, DEFAULT_CONFIG, DEBUG_TABS, MESSAGE_STATUS, } from '../../constants/playground.constants'; import { loadConfig, saveConfig, loadMessages, saveMessages, } from '../../components/playground/configStorage'; import { processIncompleteThinkTags } from '../../helpers'; export const usePlaygroundState = () => { // 使用惰性初始化,确保只在组件首次挂载时加载配置和消息 const [savedConfig] = useState(() => loadConfig()); const [initialMessages] = useState(() => loadMessages() || DEFAULT_MESSAGES); // 基础配置状态 const [inputs, setInputs] = useState( savedConfig.inputs || DEFAULT_CONFIG.inputs, ); const [parameterEnabled, setParameterEnabled] = useState( savedConfig.parameterEnabled || DEFAULT_CONFIG.parameterEnabled, ); const [showDebugPanel, setShowDebugPanel] = useState( savedConfig.showDebugPanel || DEFAULT_CONFIG.showDebugPanel, ); const [customRequestMode, setCustomRequestMode] = useState( savedConfig.customRequestMode || DEFAULT_CONFIG.customRequestMode, ); const [customRequestBody, setCustomRequestBody] = useState( savedConfig.customRequestBody || DEFAULT_CONFIG.customRequestBody, ); // UI状态 const [showSettings, setShowSettings] = useState(false); const [models, setModels] = useState([]); const [groups, setGroups] = useState([]); const [status, setStatus] = useState({}); // 消息相关状态 - 使用加载的消息初始化 const [message, setMessage] = useState(initialMessages); // 调试状态 const [debugData, setDebugData] = useState({ request: null, response: null, timestamp: null, previewRequest: null, previewTimestamp: null, }); const [activeDebugTab, setActiveDebugTab] = useState(DEBUG_TABS.PREVIEW); const [previewPayload, setPreviewPayload] = useState(null); // 编辑状态 const [editingMessageId, setEditingMessageId] = useState(null); const [editValue, setEditValue] = useState(''); // Refs const sseSourceRef = useRef(null); const chatRef = useRef(null); const saveConfigTimeoutRef = useRef(null); const saveMessagesTimeoutRef = useRef(null); // 配置更新函数 const handleInputChange = useCallback((name, value) => { setInputs((prev) => ({ ...prev, [name]: value })); }, []); const handleParameterToggle = useCallback((paramName) => { setParameterEnabled((prev) => ({ ...prev, [paramName]: !prev[paramName], })); }, []); // 消息保存函数 - 改为立即保存,可以接受参数 const saveMessagesImmediately = useCallback( (messagesToSave) => { // 如果提供了参数,使用参数;否则使用当前状态 saveMessages(messagesToSave || message); }, [message], ); // 配置保存 const debouncedSaveConfig = useCallback(() => { if (saveConfigTimeoutRef.current) { clearTimeout(saveConfigTimeoutRef.current); } saveConfigTimeoutRef.current = setTimeout(() => { const configToSave = { inputs, parameterEnabled, showDebugPanel, customRequestMode, customRequestBody, }; saveConfig(configToSave); }, 1000); }, [ inputs, parameterEnabled, showDebugPanel, customRequestMode, customRequestBody, ]); // 配置导入/重置 const handleConfigImport = useCallback((importedConfig) => { if (importedConfig.inputs) { setInputs((prev) => ({ ...prev, ...importedConfig.inputs })); } if (importedConfig.parameterEnabled) { setParameterEnabled((prev) => ({ ...prev, ...importedConfig.parameterEnabled, })); } if (typeof importedConfig.showDebugPanel === 'boolean') { setShowDebugPanel(importedConfig.showDebugPanel); } if (importedConfig.customRequestMode) { setCustomRequestMode(importedConfig.customRequestMode); } if (importedConfig.customRequestBody) { setCustomRequestBody(importedConfig.customRequestBody); } // 如果导入的配置包含消息,也恢复消息 if (importedConfig.messages && Array.isArray(importedConfig.messages)) { setMessage(importedConfig.messages); } }, []); const handleConfigReset = useCallback((options = {}) => { const { resetMessages = false } = options; setInputs(DEFAULT_CONFIG.inputs); setParameterEnabled(DEFAULT_CONFIG.parameterEnabled); setShowDebugPanel(DEFAULT_CONFIG.showDebugPanel); setCustomRequestMode(DEFAULT_CONFIG.customRequestMode); setCustomRequestBody(DEFAULT_CONFIG.customRequestBody); // 只有在明确指定时才重置消息 if (resetMessages) { setMessage([]); setTimeout(() => { setMessage(DEFAULT_MESSAGES); }, 0); } }, []); // 清理定时器 useEffect(() => { return () => { if (saveConfigTimeoutRef.current) { clearTimeout(saveConfigTimeoutRef.current); } }; }, []); // 页面首次加载时,若最后一条消息仍处于 LOADING/INCOMPLETE 状态,自动修复 useEffect(() => { if (!Array.isArray(message) || message.length === 0) return; const lastMsg = message[message.length - 1]; if ( lastMsg.status === MESSAGE_STATUS.LOADING || lastMsg.status === MESSAGE_STATUS.INCOMPLETE ) { const processed = processIncompleteThinkTags( lastMsg.content || '', lastMsg.reasoningContent || '', ); const fixedLastMsg = { ...lastMsg, status: MESSAGE_STATUS.COMPLETE, content: processed.content, reasoningContent: processed.reasoningContent || null, isThinkingComplete: true, }; const updatedMessages = [...message.slice(0, -1), fixedLastMsg]; setMessage(updatedMessages); // 保存修复后的消息列表 setTimeout(() => saveMessagesImmediately(updatedMessages), 0); } }, []); return { // 配置状态 inputs, parameterEnabled, showDebugPanel, customRequestMode, customRequestBody, // UI状态 showSettings, models, groups, status, // 消息状态 message, // 调试状态 debugData, activeDebugTab, previewPayload, // 编辑状态 editingMessageId, editValue, // Refs sseSourceRef, chatRef, saveConfigTimeoutRef, // 更新函数 setInputs, setParameterEnabled, setShowDebugPanel, setCustomRequestMode, setCustomRequestBody, setShowSettings, setModels, setGroups, setStatus, setMessage, setDebugData, setActiveDebugTab, setPreviewPayload, setEditingMessageId, setEditValue, // 处理函数 handleInputChange, handleParameterToggle, debouncedSaveConfig, saveMessagesImmediately, handleConfigImport, handleConfigReset, }; };