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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}, []);
|
||||
|
||||
Reference in New Issue
Block a user