feat(web): 重构前端UI并支持OpenAI协议
- 添加账号管理详情页(基本信息、提示词、CapCut、参考图标签页) - 重构资产页面,按项目组分开展示图片/视频 - 聊天界面支持深度思考内容折叠展示、复制、删除消息 - 设置页面支持Agent配置(Anthropic/OpenAI协议)和工具配置 - 后端支持OpenAI兼容协议流式输出和DeepSeek思考模式 - 添加对话置顶/删除功能、数据库迁移、资产清单API - 添加账号参考图上传/删除、技能配置持久化、连接测试API
This commit is contained in:
@@ -16,57 +16,51 @@ export function useChat(conversationId: string | null) {
|
||||
const [thinking, setThinking] = useState(false);
|
||||
const [toolStatus, setToolStatus] = useState<string | null>(null);
|
||||
const [pipeline, setPipeline] = useState<PipelineState | null>(null);
|
||||
const pendingRef = useRef(false);
|
||||
const initRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
chatSocket.connect();
|
||||
|
||||
chatSocket.on('connected', () => setConnected(true));
|
||||
|
||||
chatSocket.on('history', (data) => {
|
||||
// Bind all event handlers once
|
||||
const onConnected = () => setConnected(true);
|
||||
const onHistory = (data: Record<string, unknown>) => {
|
||||
setMessages((data.messages as Message[]) || []);
|
||||
});
|
||||
|
||||
chatSocket.on('message', (data) => {
|
||||
};
|
||||
const onMessage = (data: Record<string, unknown>) => {
|
||||
setMessages((prev) => [...prev, data as unknown as Message]);
|
||||
});
|
||||
|
||||
// Streaming
|
||||
chatSocket.on('status', (data) => {
|
||||
};
|
||||
const onStatus = (data: Record<string, unknown>) => {
|
||||
if (data.status === 'thinking') setThinking(true);
|
||||
if (data.status === 'done') { setThinking(false); setToolStatus(null); }
|
||||
});
|
||||
|
||||
chatSocket.on('message_start', (data) => {
|
||||
};
|
||||
const onMessageStart = (data: Record<string, unknown>) => {
|
||||
setThinking(false);
|
||||
setMessages((prev) => [...prev, {
|
||||
id: data.id as string,
|
||||
role: 'assistant',
|
||||
role: 'assistant' as const,
|
||||
content: '',
|
||||
reasoningContent: '',
|
||||
created_at: new Date().toISOString(),
|
||||
conversation_id: '',
|
||||
} as Message]);
|
||||
});
|
||||
|
||||
chatSocket.on('text_delta', (data) => {
|
||||
}]);
|
||||
};
|
||||
const onReasoningDelta = (data: Record<string, unknown>) => {
|
||||
setMessages((prev) => prev.map((m) =>
|
||||
m.id === data.id ? { ...m, reasoningContent: (m.reasoningContent || '') + (data.text as string) } : m
|
||||
));
|
||||
};
|
||||
const onTextDelta = (data: Record<string, unknown>) => {
|
||||
setMessages((prev) => prev.map((m) =>
|
||||
m.id === data.id ? { ...m, content: m.content + (data.text as string) } : m
|
||||
));
|
||||
});
|
||||
|
||||
chatSocket.on('message_end', () => {
|
||||
};
|
||||
const onMessageEnd = () => {
|
||||
setThinking(false);
|
||||
});
|
||||
|
||||
// Tools
|
||||
chatSocket.on('tool_start', (data) => {
|
||||
};
|
||||
const onToolStart = (data: Record<string, unknown>) => {
|
||||
setToolStatus(`执行: ${data.tool}...`);
|
||||
});
|
||||
|
||||
chatSocket.on('tool_result', (data) => {
|
||||
};
|
||||
const onToolResult = (data: Record<string, unknown>) => {
|
||||
setToolStatus(null);
|
||||
setThinking(true);
|
||||
// Save tool result as a tool-type message for inline display
|
||||
setMessages((prev) => [...prev, {
|
||||
id: `tool-${Date.now()}`,
|
||||
role: 'tool' as const,
|
||||
@@ -74,34 +68,60 @@ export function useChat(conversationId: string | null) {
|
||||
created_at: new Date().toISOString(),
|
||||
conversation_id: '',
|
||||
}]);
|
||||
});
|
||||
|
||||
chatSocket.on('tool_error', (data) => {
|
||||
};
|
||||
const onToolError = (data: Record<string, unknown>) => {
|
||||
setToolStatus(`失败: ${data.tool}`);
|
||||
setTimeout(() => setToolStatus(null), 4000);
|
||||
});
|
||||
|
||||
// Pipeline progress
|
||||
chatSocket.on('pipeline_progress', (data) => {
|
||||
};
|
||||
const onPipelineProgress = (data: Record<string, unknown>) => {
|
||||
setPipeline({
|
||||
phase: data.phase as string,
|
||||
progress: data.progress as number,
|
||||
currentItem: data.currentItem as number,
|
||||
totalItems: data.totalItems as number,
|
||||
status: data.status as string,
|
||||
currentItem: data.currentItem as number | undefined,
|
||||
totalItems: data.totalItems as number | undefined,
|
||||
status: data.status as string | undefined,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return () => { chatSocket.disconnect(); };
|
||||
chatSocket.on('connected', onConnected);
|
||||
chatSocket.on('history', onHistory);
|
||||
chatSocket.on('message', onMessage);
|
||||
chatSocket.on('status', onStatus);
|
||||
chatSocket.on('message_start', onMessageStart);
|
||||
chatSocket.on('reasoning_delta', onReasoningDelta);
|
||||
chatSocket.on('text_delta', onTextDelta);
|
||||
chatSocket.on('message_end', onMessageEnd);
|
||||
chatSocket.on('tool_start', onToolStart);
|
||||
chatSocket.on('tool_result', onToolResult);
|
||||
chatSocket.on('tool_error', onToolError);
|
||||
chatSocket.on('pipeline_progress', onPipelineProgress);
|
||||
chatSocket.connect();
|
||||
|
||||
return () => {
|
||||
chatSocket.off('connected', onConnected);
|
||||
chatSocket.off('history', onHistory);
|
||||
chatSocket.off('message', onMessage);
|
||||
chatSocket.off('status', onStatus);
|
||||
chatSocket.off('message_start', onMessageStart);
|
||||
chatSocket.off('reasoning_delta', onReasoningDelta);
|
||||
chatSocket.off('text_delta', onTextDelta);
|
||||
chatSocket.off('message_end', onMessageEnd);
|
||||
chatSocket.off('tool_start', onToolStart);
|
||||
chatSocket.off('tool_result', onToolResult);
|
||||
chatSocket.off('tool_error', onToolError);
|
||||
chatSocket.off('pipeline_progress', onPipelineProgress);
|
||||
chatSocket.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Load conversation when ID changes
|
||||
useEffect(() => {
|
||||
if (conversationId && connected && !pendingRef.current) {
|
||||
pendingRef.current = true;
|
||||
if (conversationId && connected && !initRef.current) {
|
||||
initRef.current = true;
|
||||
chatSocket.send('init', { conversationId });
|
||||
}
|
||||
if (!conversationId) {
|
||||
pendingRef.current = false;
|
||||
initRef.current = false;
|
||||
setMessages([]);
|
||||
}
|
||||
}, [conversationId, connected]);
|
||||
@@ -118,5 +138,9 @@ export function useChat(conversationId: string | null) {
|
||||
chatSocket.send('create_conversation', { title, accountId });
|
||||
}, []);
|
||||
|
||||
return { messages, connected, thinking, toolStatus, pipeline, send, stop, createConversation };
|
||||
const removeMessage = useCallback((msgId: string) => {
|
||||
setMessages((prev) => prev.filter((m) => m.id !== msgId));
|
||||
}, []);
|
||||
|
||||
return { messages, connected, thinking, toolStatus, pipeline, send, stop, createConversation, removeMessage };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user