import React, { useCallback, useContext, useEffect, useState, useRef } from 'react'; import { useSearchParams } from 'react-router-dom'; import { UserContext } from '../../context/User/index.js'; import { API, getUserIdFromLocalStorage, showError, getLogo, } from '../../helpers/index.js'; import { Card, Chat, Input, Layout, Select, Slider, TextArea, Typography, Button, MarkdownRender, Tag, Tabs, TabPane, Toast, Tooltip, Modal, } from '@douyinfe/semi-ui'; import { SSE } from 'sse'; import { Settings, Sparkles, ChevronRight, ChevronUp, Brain, Zap, MessageSquare, SlidersHorizontal, Hash, Thermometer, Type, Users, Loader2, Target, Repeat, Ban, Shuffle, ToggleLeft, Code, Eye, EyeOff, FileText, Clock, Check, X, Copy, RefreshCw, Trash2, } from 'lucide-react'; import { StyleContext } from '../../context/Style/index.js'; import { useTranslation } from 'react-i18next'; import { renderGroupOption, truncateText, stringToColor } from '../../helpers/render.js'; import { IconSend } from '@douyinfe/semi-icons'; let id = 4; function getId() { return `${id++}`; } const generateAvatarDataUrl = (username) => { if (!username) { return 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/docs-icon.png'; } const firstLetter = username[0].toUpperCase(); const bgColor = stringToColor(username); const svg = ` ${firstLetter} `; return `data:image/svg+xml;base64,${btoa(svg)}`; }; const Playground = () => { const { t } = useTranslation(); const [userState, userDispatch] = useContext(UserContext); const roleInfo = { user: { name: userState?.user?.username || 'User', avatar: generateAvatarDataUrl(userState?.user?.username), }, assistant: { name: 'Assistant', avatar: getLogo(), }, system: { name: 'System', avatar: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/other/logo.png', }, }; const defaultMessage = [ { role: 'user', id: '2', createAt: 1715676751919, content: t('你好'), }, { role: 'assistant', id: '3', createAt: 1715676751919, content: t('你好,请问有什么可以帮助您的吗?'), reasoningContent: '', isReasoningExpanded: false, }, ]; const defaultModel = 'deepseek-r1'; const [inputs, setInputs] = useState({ model: defaultModel, group: '', max_tokens: 0, temperature: 0, top_p: 1, frequency_penalty: 0, presence_penalty: 0, seed: null, stream: true, }); const [parameterEnabled, setParameterEnabled] = useState({ max_tokens: true, temperature: true, top_p: false, frequency_penalty: false, presence_penalty: false, seed: false, }); const [searchParams, setSearchParams] = useSearchParams(); const [status, setStatus] = useState({}); const [systemPrompt, setSystemPrompt] = useState( 'You are a helpful assistant. You can help me by answering my questions. You can also ask me questions.', ); const [message, setMessage] = useState(defaultMessage); const [models, setModels] = useState([]); const [groups, setGroups] = useState([]); const [showSettings, setShowSettings] = useState(true); const [showDebugPanel, setShowDebugPanel] = useState(true); const [debugData, setDebugData] = useState({ request: null, response: null, timestamp: null }); const [activeDebugTab, setActiveDebugTab] = useState('request'); const [styleState, styleDispatch] = useContext(StyleContext); const sseSourceRef = useRef(null); const handleInputChange = (name, value) => { setInputs((inputs) => ({ ...inputs, [name]: value })); }; const handleParameterToggle = (paramName) => { setParameterEnabled(prev => ({ ...prev, [paramName]: !prev[paramName] })); }; useEffect(() => { if (searchParams.get('expired')) { showError(t('未登录或登录已过期,请重新登录!')); } let status = localStorage.getItem('status'); if (status) { status = JSON.parse(status); setStatus(status); } loadModels(); loadGroups(); }, [searchParams, t]); const loadModels = async () => { let res = await API.get(`/api/user/models`); const { success, message, data } = res.data; if (success) { let localModelOptions = data.map((model) => ({ label: model, value: model, })); setModels(localModelOptions); const hasDefault = localModelOptions.some(option => option.value === defaultModel); if (!hasDefault && localModelOptions.length > 0) { setInputs((inputs) => ({ ...inputs, model: localModelOptions[0].value })); } } else { showError(t(message)); } }; const loadGroups = async () => { let res = await API.get(`/api/user/self/groups`); const { success, message, data } = res.data; if (success) { let localGroupOptions = Object.entries(data).map(([group, info]) => ({ label: truncateText(info.desc, '50%'), value: group, ratio: info.ratio, fullLabel: info.desc, })); if (localGroupOptions.length === 0) { localGroupOptions = [ { label: t('用户分组'), value: '', ratio: 1, }, ]; } else { const localUser = JSON.parse(localStorage.getItem('user')); const userGroup = (userState.user && userState.user.group) || (localUser && localUser.group); if (userGroup) { const userGroupIndex = localGroupOptions.findIndex( (g) => g.value === userGroup, ); if (userGroupIndex > -1) { const userGroupOption = localGroupOptions.splice( userGroupIndex, 1, )[0]; localGroupOptions.unshift(userGroupOption); } } } setGroups(localGroupOptions); handleInputChange('group', localGroupOptions[0].value); } else { showError(t(message)); } }; const getSystemMessage = () => { if (systemPrompt !== '') { return { role: 'system', id: '1', createAt: 1715676751919, content: systemPrompt, }; } }; let handleNonStreamRequest = async (payload) => { setDebugData(prev => ({ ...prev, request: payload, timestamp: new Date().toISOString(), response: null })); setActiveDebugTab('request'); try { const response = await fetch('/pg/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'New-Api-User': getUserIdFromLocalStorage(), }, body: JSON.stringify(payload), }); if (!response.ok) { let errorBody = ''; try { errorBody = await response.text(); } catch (e) { errorBody = '无法读取错误响应体'; } const errorInfo = { error: 'HTTP错误', status: response.status, statusText: response.statusText, body: errorBody, timestamp: new Date().toISOString() }; setDebugData(prev => ({ ...prev, response: JSON.stringify(errorInfo, null, 2) })); setActiveDebugTab('response'); throw new Error(`HTTP error! status: ${response.status}, body: ${errorBody}`); } const data = await response.json(); setDebugData(prev => ({ ...prev, response: JSON.stringify(data, null, 2) })); setActiveDebugTab('response'); if (data.choices && data.choices[0]) { const choice = data.choices[0]; let content = choice.message?.content || ''; let reasoningContent = choice.message?.reasoning_content || ''; if (content.includes('')) { const thinkTagRegex = /([\s\S]*?)<\/think>/g; let thoughts = []; let replyParts = []; let lastIndex = 0; let match; thinkTagRegex.lastIndex = 0; while ((match = thinkTagRegex.exec(content)) !== null) { replyParts.push(content.substring(lastIndex, match.index)); thoughts.push(match[1]); lastIndex = match.index + match[0].length; } replyParts.push(content.substring(lastIndex)); content = replyParts.join(''); if (thoughts.length > 0) { if (reasoningContent) { reasoningContent += '\n\n---\n\n' + thoughts.join('\n\n---\n\n'); } else { reasoningContent = thoughts.join('\n\n---\n\n'); } } } content = content.replace(/<\/?think>/g, '').trim(); setMessage((prevMessage) => { const newMessages = [...prevMessage]; const lastMessage = newMessages[newMessages.length - 1]; if (lastMessage && lastMessage.status === 'loading') { newMessages[newMessages.length - 1] = { ...lastMessage, content: content, reasoningContent: reasoningContent, status: 'complete', isReasoningExpanded: false }; } return newMessages; }); } } catch (error) { console.error('Non-stream request error:', error); const errorInfo = { error: '非流式请求错误', message: error.message, timestamp: new Date().toISOString(), stack: error.stack }; if (error.message.includes('HTTP error')) { errorInfo.details = '服务器返回了错误状态码'; } else if (error.message.includes('Failed to fetch')) { errorInfo.details = '网络连接失败或服务器无响应'; } setDebugData(prev => ({ ...prev, response: JSON.stringify(errorInfo, null, 2) })); setActiveDebugTab('response'); setMessage((prevMessage) => { const newMessages = [...prevMessage]; const lastMessage = newMessages[newMessages.length - 1]; if (lastMessage && lastMessage.status === 'loading') { newMessages[newMessages.length - 1] = { ...lastMessage, content: t('请求发生错误: ') + error.message, status: 'error', isReasoningExpanded: false }; } return newMessages; }); } }; let handleSSE = (payload) => { setDebugData(prev => ({ ...prev, request: payload, timestamp: new Date().toISOString(), response: null })); setActiveDebugTab('request'); let source = new SSE('/pg/chat/completions', { headers: { 'Content-Type': 'application/json', 'New-Api-User': getUserIdFromLocalStorage(), }, method: 'POST', payload: JSON.stringify(payload), }); sseSourceRef.current = source; let responseData = ''; let hasReceivedFirstResponse = false; source.addEventListener('message', (e) => { if (e.data === '[DONE]') { source.close(); sseSourceRef.current = null; setDebugData(prev => ({ ...prev, response: responseData })); completeMessage(); return; } try { let payload = JSON.parse(e.data); responseData += e.data + '\n'; if (!hasReceivedFirstResponse) { setActiveDebugTab('response'); hasReceivedFirstResponse = true; } const delta = payload.choices?.[0]?.delta; if (delta) { if (delta.reasoning_content) { streamMessageUpdate(delta.reasoning_content, 'reasoning'); } if (delta.content) { streamMessageUpdate(delta.content, 'content'); } } } catch (error) { console.error('Failed to parse SSE message:', error); const errorInfo = `解析错误: ${error.message}`; setDebugData(prev => ({ ...prev, response: responseData + `\n\nError: ${errorInfo}` })); setActiveDebugTab('response'); streamMessageUpdate(t('解析响应数据时发生错误'), 'content'); completeMessage('error'); } }); source.addEventListener('error', (e) => { console.error('SSE Error:', e); const errorMessage = e.data || t('请求发生错误'); const errorInfo = { error: 'SSE连接错误', message: errorMessage, status: source.status, readyState: source.readyState, timestamp: new Date().toISOString() }; setDebugData(prev => ({ ...prev, response: responseData + '\n\nSSE Error:\n' + JSON.stringify(errorInfo, null, 2) })); setActiveDebugTab('response'); streamMessageUpdate(errorMessage, 'content'); completeMessage('error'); sseSourceRef.current = null; source.close(); }); source.addEventListener('readystatechange', (e) => { if (e.readyState >= 2) { if (source.status !== undefined && source.status !== 200) { const errorInfo = { error: 'HTTP状态错误', status: source.status, readyState: source.readyState, timestamp: new Date().toISOString() }; setDebugData(prev => ({ ...prev, response: responseData + '\n\nHTTP Error:\n' + JSON.stringify(errorInfo, null, 2) })); setActiveDebugTab('response'); source.close(); streamMessageUpdate(t('连接已断开'), 'content'); completeMessage('error'); } } }); try { source.stream(); } catch (error) { console.error('Failed to start SSE stream:', error); const errorInfo = { error: '启动SSE流失败', message: error.message, timestamp: new Date().toISOString() }; setDebugData(prev => ({ ...prev, response: 'Stream启动失败:\n' + JSON.stringify(errorInfo, null, 2) })); setActiveDebugTab('response'); streamMessageUpdate(t('建立连接时发生错误'), 'content'); completeMessage('error'); } }; const onMessageSend = useCallback( (content, attachment) => { console.log('attachment: ', attachment); setMessage((prevMessage) => { const newMessage = [ ...prevMessage, { role: 'user', content: content, createAt: Date.now(), id: getId(), }, ]; const getPayload = () => { let systemMessage = getSystemMessage(); let messages = newMessage.map((item) => { return { role: item.role, content: item.content, }; }); if (systemMessage) { messages.unshift(systemMessage); } const payload = { messages: messages, stream: inputs.stream, model: inputs.model, group: inputs.group, }; if (parameterEnabled.max_tokens && inputs.max_tokens > 0) { payload.max_tokens = parseInt(inputs.max_tokens); } if (parameterEnabled.temperature) { payload.temperature = inputs.temperature; } if (parameterEnabled.top_p) { payload.top_p = inputs.top_p; } if (parameterEnabled.frequency_penalty) { payload.frequency_penalty = inputs.frequency_penalty; } if (parameterEnabled.presence_penalty) { payload.presence_penalty = inputs.presence_penalty; } if (parameterEnabled.seed && inputs.seed !== null && inputs.seed !== '') { payload.seed = parseInt(inputs.seed); } return payload; }; const payload = getPayload(); if (inputs.stream) { handleSSE(payload); } else { handleNonStreamRequest(payload); } newMessage.push({ role: 'assistant', content: '', reasoningContent: '', isReasoningExpanded: true, createAt: Date.now(), id: getId(), status: 'loading', }); return newMessage; }); }, [getSystemMessage, inputs, setMessage], ); const completeMessage = useCallback((status = 'complete') => { setMessage((prevMessage) => { const lastMessage = prevMessage[prevMessage.length - 1]; if (lastMessage.status === 'complete' || lastMessage.status === 'error') { return prevMessage; } return [...prevMessage.slice(0, -1), { ...lastMessage, status: status, isReasoningExpanded: false }]; }); }, [setMessage]); const streamMessageUpdate = useCallback((textChunk, type) => { setMessage((prevMessage) => { const lastMessage = prevMessage[prevMessage.length - 1]; let newMessage = { ...lastMessage }; if (lastMessage.status === 'error') { return prevMessage; } if (lastMessage.status === 'loading' || lastMessage.status === 'incomplete') { if (type === 'reasoning') { newMessage = { ...newMessage, reasoningContent: (lastMessage.reasoningContent || '') + textChunk, status: 'incomplete', }; } else if (type === 'content') { const shouldCollapseReasoning = !lastMessage.content && lastMessage.reasoningContent && lastMessage.isReasoningExpanded; const newContent = (lastMessage.content || '') + textChunk; let shouldCollapseFromThinkTag = false; if (lastMessage.isReasoningExpanded && newContent.includes('')) { const thinkMatches = newContent.match(//g); const thinkCloseMatches = newContent.match(/<\/think>/g); if (thinkMatches && thinkCloseMatches && thinkCloseMatches.length >= thinkMatches.length) { shouldCollapseFromThinkTag = true; } } newMessage = { ...newMessage, content: newContent, status: 'incomplete', isReasoningExpanded: (shouldCollapseReasoning || shouldCollapseFromThinkTag) ? false : lastMessage.isReasoningExpanded, }; } } return [...prevMessage.slice(0, -1), newMessage]; }); }, [setMessage]); const handleMessageCopy = useCallback((message) => { if (!message.content) return; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(message.content).then(() => { Toast.success({ content: t('消息已复制到剪贴板'), duration: 2, }); }).catch(err => { console.error('Clipboard API 复制失败:', err); fallbackCopyToClipboard(message.content); }); } else { fallbackCopyToClipboard(message.content); } }, [t]); const fallbackCopyToClipboard = useCallback((text) => { try { if (!document.execCommand) { throw new Error('execCommand not supported'); } const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.top = '-9999px'; textArea.style.left = '-9999px'; textArea.style.opacity = '0'; textArea.style.pointerEvents = 'none'; textArea.style.zIndex = '-1'; textArea.setAttribute('readonly', ''); document.body.appendChild(textArea); if (textArea.select) { textArea.select(); } if (textArea.setSelectionRange) { textArea.setSelectionRange(0, text.length); } const successful = document.execCommand('copy'); document.body.removeChild(textArea); if (successful) { Toast.success({ content: t('消息已复制到剪贴板'), duration: 2, }); } else { throw new Error('execCommand copy failed'); } } catch (err) { console.error('回退复制方案也失败:', err); let errorMessage = t('复制失败,请手动选择文本复制'); if (window.location.protocol === 'http:' && window.location.hostname !== 'localhost') { errorMessage = t('复制功能需要 HTTPS 环境,请手动复制'); } else if (!navigator.clipboard && !document.execCommand) { errorMessage = t('浏览器不支持复制功能,请手动复制'); } Toast.error({ content: errorMessage, duration: 4, }); } }, [t]); const handleMessageReset = useCallback((targetMessage) => { setMessage(prevMessages => { const messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id); if (messageIndex === -1) return prevMessages; if (targetMessage.role === 'user') { const newMessages = prevMessages.slice(0, messageIndex); setTimeout(() => { onMessageSend(targetMessage.content); }, 100); return newMessages; } else if (targetMessage.role === 'assistant') { let userMessageIndex = messageIndex - 1; while (userMessageIndex >= 0 && prevMessages[userMessageIndex].role !== 'user') { userMessageIndex--; } if (userMessageIndex >= 0) { const userMessage = prevMessages[userMessageIndex]; const newMessages = prevMessages.slice(0, userMessageIndex); setTimeout(() => { onMessageSend(userMessage.content); }, 100); return newMessages; } } return prevMessages; }); }, [onMessageSend]); const handleMessageDelete = useCallback((targetMessage) => { Modal.confirm({ title: t('确认删除'), content: t('确定要删除这条消息吗?'), okText: t('确定'), cancelText: t('取消'), okButtonProps: { type: 'danger', }, onOk: () => { setMessage(prevMessages => { const messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id); if (messageIndex === -1) return prevMessages; if (targetMessage.role === 'user' && messageIndex < prevMessages.length - 1) { const nextMessage = prevMessages[messageIndex + 1]; if (nextMessage.role === 'assistant') { Toast.success({ content: t('已删除消息及其回复'), duration: 2, }); return prevMessages.filter((_, index) => index !== messageIndex && index !== messageIndex + 1); } } Toast.success({ content: t('消息已删除'), duration: 2, }); return prevMessages.filter(msg => msg.id !== targetMessage.id); }); }, }); }, [setMessage, t]); const onStopGenerator = useCallback(() => { if (sseSourceRef.current) { sseSourceRef.current.close(); sseSourceRef.current = null; setMessage((prevMessage) => { const lastMessage = prevMessage[prevMessage.length - 1]; if (lastMessage.status === 'loading' || lastMessage.status === 'incomplete') { let currentContent = lastMessage.content || ''; let currentReasoningContent = lastMessage.reasoningContent || ''; let finalDisplayableContent = currentContent; let extractedThinking = currentReasoningContent; const thinkTagRegex = /([\s\S]*?)<\/think>/g; let match; let thoughtsFromPairedTags = []; let contentParts = []; let lastIndex = 0; thinkTagRegex.lastIndex = 0; let tempContentForPairExtraction = finalDisplayableContent; while ((match = thinkTagRegex.exec(tempContentForPairExtraction)) !== null) { contentParts.push(tempContentForPairExtraction.substring(lastIndex, match.index)); thoughtsFromPairedTags.push(match[1]); lastIndex = match.index + match[0].length; } contentParts.push(tempContentForPairExtraction.substring(lastIndex)); if (thoughtsFromPairedTags.length > 0) { const pairedThoughtsStr = thoughtsFromPairedTags.join('\n\n---\n\n'); if (extractedThinking) { extractedThinking += '\n\n---\n\n' + pairedThoughtsStr; } else { extractedThinking = pairedThoughtsStr; } } finalDisplayableContent = contentParts.join(''); const lastOpenThinkIndex = finalDisplayableContent.lastIndexOf(''); if (lastOpenThinkIndex !== -1) { const fragmentAfterLastOpen = finalDisplayableContent.substring(lastOpenThinkIndex); if (!fragmentAfterLastOpen.includes('')) { const unclosedThought = fragmentAfterLastOpen.substring(''.length); if (unclosedThought.trim()) { if (extractedThinking) { extractedThinking += '\n\n---\n\n' + unclosedThought; } else { extractedThinking = unclosedThought; } } finalDisplayableContent = finalDisplayableContent.substring(0, lastOpenThinkIndex); } } finalDisplayableContent = finalDisplayableContent.replace(/<\/?think>/g, '').trim(); return [...prevMessage.slice(0, -1), { ...lastMessage, status: 'complete', reasoningContent: extractedThinking || null, content: finalDisplayableContent, isReasoningExpanded: false }]; } return prevMessage; }); } }, [setMessage]); const DebugToggle = () => { return ( ); }; const SettingsToggle = () => { if (!styleState.isMobile) return null; return ( ); } const renderInputArea = useCallback((props) => { return ; }, []); const renderChatBoxAction = useCallback((props) => { const { message } = props; const isLoading = message.status === 'loading' || message.status === 'incomplete'; return (
{!isLoading && (
); }, [handleMessageReset, handleMessageCopy, handleMessageDelete, t]); const renderCustomChatContent = useCallback( ({ message, className }) => { if (message.status === 'error') { return (
{message.content || t('请求发生错误')}
); } const toggleReasoningExpansion = (messageId) => { setMessage(prevMessages => prevMessages.map(msg => msg.id === messageId && msg.role === 'assistant' ? { ...msg, isReasoningExpanded: !msg.isReasoningExpanded } : msg ) ); }; const isThinkingStatus = message.status === 'loading' || message.status === 'incomplete'; let currentExtractedThinkingContent = null; let currentDisplayableFinalContent = message.content || ""; let thinkingSource = null; if (message.role === 'assistant') { let baseContentForDisplay = message.content || ""; let combinedThinkingContent = ""; if (message.reasoningContent) { combinedThinkingContent = message.reasoningContent; thinkingSource = 'reasoningContent'; } if (baseContentForDisplay.includes('([\s\S]*?)<\/think>/g; let match; let thoughtsFromPairedTags = []; let replyParts = []; let lastIndex = 0; thinkTagRegex.lastIndex = 0; let tempContent = baseContentForDisplay; while ((match = thinkTagRegex.exec(tempContent)) !== null) { replyParts.push(tempContent.substring(lastIndex, match.index)); thoughtsFromPairedTags.push(match[1]); lastIndex = match.index + match[0].length; } replyParts.push(tempContent.substring(lastIndex)); if (thoughtsFromPairedTags.length > 0) { const pairedThoughtsStr = thoughtsFromPairedTags.join('\n\n---\n\n'); if (combinedThinkingContent) { combinedThinkingContent += '\n\n---\n\n' + pairedThoughtsStr; } else { combinedThinkingContent = pairedThoughtsStr; } if (thinkingSource === 'reasoningContent') { thinkingSource = 'reasoningContent & tags'; } else if (!thinkingSource) { thinkingSource = ' tags'; } } baseContentForDisplay = replyParts.join(''); } if (isThinkingStatus && baseContentForDisplay.includes(''); if (lastOpenThinkIndex !== -1) { const fragmentAfterLastOpen = baseContentForDisplay.substring(lastOpenThinkIndex); if (!fragmentAfterLastOpen.includes('')) { const unclosedThought = fragmentAfterLastOpen.substring(''.length); if (unclosedThought.trim()) { if (combinedThinkingContent) { combinedThinkingContent += '\n\n---\n\n' + unclosedThought; } else { combinedThinkingContent = unclosedThought; } if (thinkingSource && (thinkingSource.includes(' tags') || thinkingSource.includes('reasoningContent'))) { thinkingSource += ' + streaming '; } else if (!thinkingSource) { thinkingSource = 'streaming '; } } baseContentForDisplay = baseContentForDisplay.substring(0, lastOpenThinkIndex); } } } currentExtractedThinkingContent = combinedThinkingContent || null; if (typeof baseContentForDisplay === 'string') { currentDisplayableFinalContent = baseContentForDisplay.replace(/<\/?think>/g, '').trim(); } else { currentDisplayableFinalContent = ""; } } const headerText = isThinkingStatus ? t('思考中...') : t('思考过程'); const finalExtractedThinkingContent = currentExtractedThinkingContent; const finalDisplayableFinalContent = currentDisplayableFinalContent; if (message.role === 'assistant' && isThinkingStatus && !finalExtractedThinkingContent && (!finalDisplayableFinalContent || finalDisplayableFinalContent.trim() === '')) { return (
{t('正在思考...')} AI 正在分析您的问题
); } return (
{message.role === 'assistant' && finalExtractedThinkingContent && (
toggleReasoningExpansion(message.id)} >
{headerText} {thinkingSource && ( 来源: {thinkingSource} )}
{isThinkingStatus && (
思考中
)} {!isThinkingStatus && (
{message.isReasoningExpanded ? : }
)}
{message.isReasoningExpanded && (
)}
)} {(finalDisplayableFinalContent && finalDisplayableFinalContent.trim() !== '') && (
)}
); }, [t, setMessage], ); return (
{(showSettings || !styleState.isMobile) && (
{t('模型设置')}
{/* 分组选择 */}
{t('分组')}
handleInputChange('model', value)} value={inputs.model} autoComplete='new-password' optionList={models} className="!rounded-lg" />
{/* Temperature */}
Temperature {inputs.temperature}
控制输出的随机性和创造性 handleInputChange('temperature', value)} className="mt-2" disabled={!parameterEnabled.temperature} />
{/* Top P */}
Top P {inputs.top_p}
核采样,控制词汇选择的多样性 handleInputChange('top_p', value)} className="mt-2" disabled={!parameterEnabled.top_p} />
{/* Frequency Penalty */}
Frequency Penalty {inputs.frequency_penalty}
频率惩罚,减少重复词汇的出现 handleInputChange('frequency_penalty', value)} className="mt-2" disabled={!parameterEnabled.frequency_penalty} />
{/* Presence Penalty */}
Presence Penalty {inputs.presence_penalty}
存在惩罚,鼓励讨论新话题 handleInputChange('presence_penalty', value)} className="mt-2" disabled={!parameterEnabled.presence_penalty} />
{/* MaxTokens */}
Max Tokens
handleInputChange('max_tokens', value)} className="!rounded-lg" disabled={!parameterEnabled.max_tokens} />
{/* Seed */}
Seed (可选,用于复现结果)
handleInputChange('seed', value === '' ? null : value)} className="!rounded-lg" disabled={!parameterEnabled.seed} />
{/* Stream Toggle */}
流式输出
{/* System Prompt */}
System Prompt