feat(playground): enhance SSE debugging and add image paste support with i18n

- Add SSEViewer component for interactive SSE message inspection
  * Display SSE data stream with collapsible panels
  * Show parsed JSON with syntax highlighting
  * Display key information badges (content, tokens, finish reason)
  * Support copy individual or all SSE messages
  * Show error messages with detailed information

- Support Ctrl+V to paste images in chat input
  * Enable image paste in CustomInputRender component
  * Auto-detect and add pasted images to image list
  * Show toast notifications for paste results

- Add complete i18n support for 6 languages
  * Chinese (zh): Complete translations
  * English (en): Complete translations
  * Japanese (ja): Add 28 new translations
  * French (fr): Add 28 new translations
  * Russian (ru): Add 28 new translations
  * Vietnamese (vi): Add 32 new translations

- Update .gitignore to exclude data directory
This commit is contained in:
ImogeneOctaviap794
2025-11-26 16:54:11 +08:00
parent d98e7b3dbf
commit c2053a7f43
20 changed files with 810 additions and 65 deletions

View File

@@ -179,6 +179,8 @@ export const useApiRequest = (
request: payload,
timestamp: new Date().toISOString(),
response: null,
sseMessages: null, // 非流式请求清除 SSE 消息
isStreaming: false,
}));
setActiveDebugTab(DEBUG_TABS.REQUEST);
@@ -291,6 +293,8 @@ export const useApiRequest = (
request: payload,
timestamp: new Date().toISOString(),
response: null,
sseMessages: [], // 新增:存储 SSE 消息数组
isStreaming: true, // 新增:标记流式状态
}));
setActiveDebugTab(DEBUG_TABS.REQUEST);
@@ -314,7 +318,12 @@ export const useApiRequest = (
isStreamComplete = true; // 标记流正常完成
source.close();
sseSourceRef.current = null;
setDebugData((prev) => ({ ...prev, response: responseData }));
setDebugData((prev) => ({
...prev,
response: responseData,
sseMessages: [...(prev.sseMessages || []), '[DONE]'], // 添加 DONE 标记
isStreaming: false,
}));
completeMessage();
return;
}
@@ -328,6 +337,12 @@ export const useApiRequest = (
hasReceivedFirstResponse = true;
}
// 新增:将 SSE 消息添加到数组
setDebugData((prev) => ({
...prev,
sseMessages: [...(prev.sseMessages || []), e.data],
}));
const delta = payload.choices?.[0]?.delta;
if (delta) {
if (delta.reasoning_content) {
@@ -347,6 +362,8 @@ export const useApiRequest = (
setDebugData((prev) => ({
...prev,
response: responseData + `\n\nError: ${errorInfo}`,
sseMessages: [...(prev.sseMessages || []), e.data], // 即使解析失败也保存原始数据
isStreaming: false,
}));
setActiveDebugTab(DEBUG_TABS.RESPONSE);

View File

@@ -18,8 +18,10 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { useState, useCallback, useRef, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import {
DEFAULT_MESSAGES,
getDefaultMessages,
DEFAULT_CONFIG,
DEBUG_TABS,
MESSAGE_STATUS,
@@ -33,9 +35,27 @@ import {
import { processIncompleteThinkTags } from '../../helpers';
export const usePlaygroundState = () => {
const { t } = useTranslation();
// 使用惰性初始化,确保只在组件首次挂载时加载配置和消息
const [savedConfig] = useState(() => loadConfig());
const [initialMessages] = useState(() => loadMessages() || DEFAULT_MESSAGES);
const [initialMessages] = useState(() => {
const loaded = loadMessages();
// 检查是否是旧的中文默认消息,如果是则清除
if (loaded && loaded.length === 2 && loaded[0].id === '2' && loaded[1].id === '3') {
const hasOldChinese =
loaded[0].content === '你好' ||
loaded[1].content === '你好,请问有什么可以帮助您的吗?' ||
loaded[1].content === '你好!很高兴见到你。有什么我可以帮助你的吗?';
if (hasOldChinese) {
// 清除旧的默认消息
localStorage.removeItem('playground_messages');
return null;
}
}
return loaded;
});
// 基础配置状态
const [inputs, setInputs] = useState(
@@ -60,8 +80,16 @@ export const usePlaygroundState = () => {
const [groups, setGroups] = useState([]);
const [status, setStatus] = useState({});
// 消息相关状态 - 使用加载的消息初始化
const [message, setMessage] = useState(initialMessages);
// 消息相关状态 - 使用加载的消息或默认消息初始化
const [message, setMessage] = useState(() => initialMessages || getDefaultMessages(t));
// 当语言改变时,如果是默认消息则更新
useEffect(() => {
// 只在没有保存的消息时才更新默认消息
if (!initialMessages) {
setMessage(getDefaultMessages(t));
}
}, [t, initialMessages]); // 当语言改变时
// 调试状态
const [debugData, setDebugData] = useState({
@@ -168,7 +196,7 @@ export const usePlaygroundState = () => {
if (resetMessages) {
setMessage([]);
setTimeout(() => {
setMessage(DEFAULT_MESSAGES);
setMessage(getDefaultMessages(t));
}, 0);
}
}, []);