diff --git a/frontend-web/src/pages/StrategyRoutes.tsx b/frontend-web/src/pages/StrategyRoutes.tsx
index 4ed27e5a..f49d0805 100644
--- a/frontend-web/src/pages/StrategyRoutes.tsx
+++ b/frontend-web/src/pages/StrategyRoutes.tsx
@@ -61,47 +61,28 @@ export default function StrategyRoutes() {
/>
{/* 任务管理 */}
}>
+ } />
{/* XK任务 */}
- }
+ element={}
/>
- }
+ element={}
/>
{/* pg中任务 */}
- }
+ element={}
/>
- }
+ element={}
/>
- }
+ element={}
/>
{/* COH中任务 */}
}
/>
-
}
/>
-
{/* MNTY任务 */}
-
- }
- />
-
- }
- />
-
- }
- />
+ } />
+ } />
+ } />
{/* 资源管理 */}
{
+ const runMultiRoundStream = async (
+ url: string,
+ query: string,
+ side: 'left' | 'right' | null = null,
+ options: {
+ passSideToToolCall?: boolean;
+ guardHistoryBySide?: boolean;
+ logCompareResult?: boolean;
+ } = {},
+ ) => {
+ const {
+ passSideToToolCall = false,
+ guardHistoryBySide = false,
+ logCompareResult = false,
+ } = options;
setError(null);
setIsLoading(true);
setIsPreConnectLoading(true);
+
try {
- const response = await fetch(`${generateUrl}/generate`, {
+ const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: query }),
@@ -1109,20 +1130,14 @@ const GeneralQA: React.FC<{
};
if (!side) {
state.current.messageList.push(assistantMessage); // 数据存储
- // 接口连通后再展示多轮检索主题与过程
setMessages((prev) => [...prev, assistantMessage]);
} else if (side === 'left' || side === 'right') {
state.current.compareResult[state.current.compareIndex][side].thinkingTrace = createMultiRoundStreamTrace();
- updatePane(side, (pane) => {
- return {
- ...pane,
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- });
+ updatePane(side, (pane) => ({ ...pane, thinkingTrace: createMultiRoundStreamTrace() }));
}
const reader = response.body.getReader();
- // 保存 reader 引用,用于"停止生成"功能
+ // 保存 reader 引用,用于“停止生成”功能
if (!side) {
readerRef.current = reader;
} else {
@@ -1135,8 +1150,8 @@ const GeneralQA: React.FC<{
while (true) {
const { done, value } = await reader.read();
if (done) {
- console.log('聊天记录', state.current.compareResult);
- if (!side) {
+ console.log('聊天记录', logCompareResult ? state.current.compareResult : state.current.messageList);
+ if (!guardHistoryBySide || !side) {
chatHistoryAddSearch();
}
break;
@@ -1163,7 +1178,7 @@ const GeneralQA: React.FC<{
break;
}
case 'tool_call': {
- handleToolCall(data as ToolCallData, assistantId, side);
+ handleToolCall(data as ToolCallData, assistantId, passSideToToolCall ? side : null);
break;
}
case 'message': {
@@ -1228,464 +1243,27 @@ const GeneralQA: React.FC<{
}
};
- /**
- * 处理任务检索 请求。
- *
- * 多轮接口采用 SSE:每行 `data:` 都描述一个事件。组件根据事件类型分别更新 taskId、工具调用、
- * 最终回答和引用来源。当前用户入口暂时走本地模拟,此方法保留给接口连通后切换使用。
- */
- const handleTaskRun = async (query: string, side: 'left' | 'right' | null = null) => {
- setError(null);
- setIsLoading(true);
- setIsPreConnectLoading(true);
+ // 多轮 RAG 检索:透传 side、仅非对比模式落库、日志打印 compareResult。
+ const handleRun = (query: string, side: 'left' | 'right' | null = null) =>
+ runMultiRoundStream(`${generateUrl}/generate`, query, side, {
+ passSideToToolCall: true,
+ guardHistoryBySide: true,
+ logCompareResult: true,
+ });
- try {
- const response = await fetch(`${taskChatUrl}/generate`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ prompt: query }),
- });
+ // 任务检索:透传 side,但 done 时无条件落库。
+ const handleTaskRun = (query: string, side: 'left' | 'right' | null = null) =>
+ runMultiRoundStream(`${taskChatUrl}/generate`, query, side, {
+ passSideToToolCall: true,
+ });
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
+ // 画像检索:不透传 side,done 时无条件落库。
+ const handleHxRun = (query: string, side: 'left' | 'right' | null = null) =>
+ runMultiRoundStream(`${taskChatUrl}/generate_b2`, query, side);
- if (!response.body) {
- throw new Error('Response body is null');
- }
- setIsPreConnectLoading(false);
-
- const assistantId = `assistant-${Date.now()}`;
- const assistantMessage: Message = {
- id: assistantId,
- role: 'assistant',
- content: '',
- timestamp: new Date(),
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- if (!side) {
- state.current.messageList.push(assistantMessage); // 数据存储
- // 接口连通后再展示多轮检索主题与过程
- setMessages((prev) => [...prev, assistantMessage]);
- } else if (side === 'left' || side === 'right') {
- state.current.compareResult[state.current.compareIndex][side].thinkingTrace = createMultiRoundStreamTrace();
- updatePane(side, (pane) => {
- return {
- ...pane,
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- });
- }
-
- const reader = response.body.getReader();
- if (!side) {
- readerRef.current = reader;
- } else {
- compareReaderRef.current[side] = reader;
- }
- const decoder = new TextDecoder();
- let buffer = '';
-
- try {
- while (true) {
- const { done, value } = await reader.read();
- if (done) {
- console.log('聊天记录', state.current.messageList);
- chatHistoryAddSearch();
- break;
- }
-
- buffer += decoder.decode(value, { stream: true });
- const lines = buffer.split('\n');
- const lastLine = lines.pop();
- buffer = lastLine || '';
-
- for (const line of lines) {
- if (!line.startsWith('data: ')) continue;
-
- try {
- const parsedData = JSON.parse(line.slice(6)) as {
- event: string;
- data: any;
- };
- const { event, data } = parsedData;
-
- switch (event) {
- case 'task_created': {
- taskIdRef.current = data?.task_id || null;
- break;
- }
- case 'tool_call': {
- handleToolCall(data as ToolCallData, assistantId, side);
- break;
- }
- case 'message': {
- if (typeof data === 'string') {
- setMessages((prevMessages) => prevMessages.map((msg) => {
- if (msg.id !== assistantId || !msg.thinkingTrace) return msg;
- return {
- ...msg,
- thinkingTrace: {
- ...msg.thinkingTrace,
- finalAnswerMarkdown: `${msg.thinkingTrace.finalAnswerMarkdown}${data}`,
- },
- };
- }));
- }
- break;
- }
- case 'references': {
- const refs = Array.isArray(data?.references) ? data.references : [];
- const mappedRefs = refs.map(mapReferenceToSource);
- setSearchProcess((prev) => ({
- ...prev,
- hits: mappedRefs.length,
- }));
- setMessages((prevMessages) => prevMessages.map((msg) => (
- msg.id === assistantId
- ? { ...msg, sources: mappedRefs }
- : msg
- )));
- break;
- }
- case 'done': {
- setIsLoading(false);
- break;
- }
- default:
- console.log(`未知事件类型: ${event}`, data);
- }
- } catch (parseError) {
- console.error('JSON解析错误:', parseError);
- console.error('原始数据:', line.slice(6));
- }
- }
- }
- } finally {
- if (readerRef.current) {
- readerRef.current.releaseLock();
- readerRef.current = null;
- }
- }
- } catch (runError) {
- console.error('处理请求时发生错误:', runError);
- setIsLoading(false);
- setError(runError instanceof Error ? runError.message : '发生未知错误,请稍后重试');
- setIsPreConnectLoading(false);
- } finally {
- // 无论成功还是失败,都要重置加载状态和解锁提交
- setIsPreConnectLoading(false);
- setIsLoading(false);
- submitLockRef.current = false;
- handleStopCompareSide(side);
- }
- };
-
- /**
-* 处理画像检索 请求。
-*
-* 多轮接口采用 SSE:每行 `data:` 都描述一个事件。组件根据事件类型分别更新 taskId、工具调用、
-* 最终回答和引用来源。当前用户入口暂时走本地模拟,此方法保留给接口连通后切换使用。
-*/
- const handleHxRun = async (query: string, side: 'left' | 'right' | null = null) => {
- setError(null);
- setIsLoading(true);
- setIsPreConnectLoading(true);
-
- try {
- const response = await fetch(`${taskChatUrl}/generate_b2`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ prompt: query }),
- });
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- if (!response.body) {
- throw new Error('Response body is null');
- }
- setIsPreConnectLoading(false);
-
- const assistantId = `assistant-${Date.now()}`;
- const assistantMessage: Message = {
- id: assistantId,
- role: 'assistant',
- content: '',
- timestamp: new Date(),
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- if (!side) {
- state.current.messageList.push(assistantMessage); // 数据存储
- // 接口连通后再展示多轮检索主题与过程
- setMessages((prev) => [...prev, assistantMessage]);
- } else if (side === 'left' || side === 'right') {
- state.current.compareResult[state.current.compareIndex][side].thinkingTrace = createMultiRoundStreamTrace();
- updatePane(side, (pane) => {
- return {
- ...pane,
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- });
- }
-
- const reader = response.body.getReader();
- if (!side) {
- readerRef.current = reader;
- } else {
- compareReaderRef.current[side] = reader;
- }
- const decoder = new TextDecoder();
- let buffer = '';
-
- try {
- while (true) {
- const { done, value } = await reader.read();
- if (done) {
- console.log('聊天记录', state.current.messageList);
- chatHistoryAddSearch();
- break;
- }
-
- buffer += decoder.decode(value, { stream: true });
- const lines = buffer.split('\n');
- const lastLine = lines.pop();
- buffer = lastLine || '';
-
- for (const line of lines) {
- if (!line.startsWith('data: ')) continue;
-
- try {
- const parsedData = JSON.parse(line.slice(6)) as {
- event: string;
- data: any;
- };
- const { event, data } = parsedData;
-
- switch (event) {
- case 'task_created': {
- taskIdRef.current = data?.task_id || null;
- break;
- }
- case 'tool_call': {
- handleToolCall(data as ToolCallData, assistantId);
- break;
- }
- case 'message': {
- if (typeof data === 'string') {
- setMessages((prevMessages) => prevMessages.map((msg) => {
- if (msg.id !== assistantId || !msg.thinkingTrace) return msg;
- return {
- ...msg,
- thinkingTrace: {
- ...msg.thinkingTrace,
- finalAnswerMarkdown: `${msg.thinkingTrace.finalAnswerMarkdown}${data}`,
- },
- };
- }));
- }
- break;
- }
- case 'references': {
- const refs = Array.isArray(data?.references) ? data.references : [];
- const mappedRefs = refs.map(mapReferenceToSource);
- setSearchProcess((prev) => ({
- ...prev,
- hits: mappedRefs.length,
- }));
- setMessages((prevMessages) => prevMessages.map((msg) => (
- msg.id === assistantId
- ? { ...msg, sources: mappedRefs }
- : msg
- )));
- break;
- }
- case 'done': {
- setIsLoading(false);
- break;
- }
- default:
- console.log(`未知事件类型: ${event}`, data);
- }
- } catch (parseError) {
- console.error('JSON解析错误:', parseError);
- console.error('原始数据:', line.slice(6));
- }
- }
- }
- } finally {
- if (readerRef.current) {
- readerRef.current.releaseLock();
- readerRef.current = null;
- }
- }
- } catch (runError) {
- console.error('处理请求时发生错误:', runError);
- setIsLoading(false);
- setError(runError instanceof Error ? runError.message : '发生未知错误,请稍后重试');
- setIsPreConnectLoading(false);
- } finally {
- // 无论成功还是失败,都要重置加载状态和解锁提交
- setIsPreConnectLoading(false);
- setIsLoading(false);
- submitLockRef.current = false;
- handleStopCompareSide(side);
- }
- };
-
- /**
-* 处理画像检索 请求。
-*
-* 多轮接口采用 SSE:每行 `data:` 都描述一个事件。组件根据事件类型分别更新 taskId、工具调用、
-* 最终回答和引用来源。当前用户入口暂时走本地模拟,此方法保留给接口连通后切换使用。
-*/
- const newsReportRun = async (query: string, side: 'left' | 'right' | null = null) => {
- setError(null);
- setIsLoading(true);
- setIsPreConnectLoading(true);
-
- try {
- const response = await fetch(`${taskChatUrl}/generate_report`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ prompt: query }),
- });
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- if (!response.body) {
- throw new Error('Response body is null');
- }
- setIsPreConnectLoading(false);
-
- const assistantId = `assistant-${Date.now()}`;
- const assistantMessage: Message = {
- id: assistantId,
- role: 'assistant',
- content: '',
- timestamp: new Date(),
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- if (!side) {
- state.current.messageList.push(assistantMessage); // 数据存储
- // 接口连通后再展示多轮检索主题与过程
- setMessages((prev) => [...prev, assistantMessage]);
- } else if (side === 'left' || side === 'right') {
- state.current.compareResult[state.current.compareIndex][side].thinkingTrace = createMultiRoundStreamTrace();
- updatePane(side, (pane) => {
- return {
- ...pane,
- thinkingTrace: createMultiRoundStreamTrace(),
- };
- });
- }
-
- const reader = response.body.getReader();
- if (!side) {
- readerRef.current = reader;
- } else {
- compareReaderRef.current[side] = reader;
- }
- const decoder = new TextDecoder();
- let buffer = '';
-
- try {
- while (true) {
- const { done, value } = await reader.read();
- if (done) {
- console.log('聊天记录', state.current.messageList);
- chatHistoryAddSearch();
- break;
- }
-
- buffer += decoder.decode(value, { stream: true });
- const lines = buffer.split('\n');
- const lastLine = lines.pop();
- buffer = lastLine || '';
-
- for (const line of lines) {
- if (!line.startsWith('data: ')) continue;
-
- try {
- const parsedData = JSON.parse(line.slice(6)) as {
- event: string;
- data: any;
- };
- const { event, data } = parsedData;
-
- switch (event) {
- case 'task_created': {
- taskIdRef.current = data?.task_id || null;
- break;
- }
- case 'tool_call': {
- handleToolCall(data as ToolCallData, assistantId);
- break;
- }
- case 'message': {
- if (typeof data === 'string') {
- setMessages((prevMessages) => prevMessages.map((msg) => {
- if (msg.id !== assistantId || !msg.thinkingTrace) return msg;
- return {
- ...msg,
- thinkingTrace: {
- ...msg.thinkingTrace,
- finalAnswerMarkdown: `${msg.thinkingTrace.finalAnswerMarkdown}${data}`,
- },
- };
- }));
- }
- break;
- }
- case 'references': {
- const refs = Array.isArray(data?.references) ? data.references : [];
- const mappedRefs = refs.map(mapReferenceToSource);
- setSearchProcess((prev) => ({
- ...prev,
- hits: mappedRefs.length,
- }));
- setMessages((prevMessages) => prevMessages.map((msg) => (
- msg.id === assistantId
- ? { ...msg, sources: mappedRefs }
- : msg
- )));
- break;
- }
- case 'done': {
- setIsLoading(false);
- break;
- }
- default:
- console.log(`未知事件类型: ${event}`, data);
- }
- } catch (parseError) {
- console.error('JSON解析错误:', parseError);
- console.error('原始数据:', line.slice(6));
- }
- }
- }
- } finally {
- if (readerRef.current) {
- readerRef.current.releaseLock();
- readerRef.current = null;
- }
- }
- } catch (runError) {
- console.error('处理请求时发生错误:', runError);
- setIsLoading(false);
- setError(runError instanceof Error ? runError.message : '发生未知错误,请稍后重试');
- setIsPreConnectLoading(false);
- } finally {
- // 无论成功还是失败,都要重置加载状态和解锁提交
- setIsPreConnectLoading(false);
- setIsLoading(false);
- submitLockRef.current = false;
- handleStopCompareSide(side);
- }
- };
+ // 新闻报告生成:不透传 side,done 时无条件落库。
+ const newsReportRun = (query: string, side: 'left' | 'right' | null = null) =>
+ runMultiRoundStream(`${taskChatUrl}/generate_report`, query, side);
/**
* 单一模式下的发送入口。
diff --git a/frontend-web/src/strategy-components/components/task-components/FanganTy.tsx b/frontend-web/src/strategy-components/components/task-components/FanganTy.tsx
index b2831a51..6b42e2c2 100644
--- a/frontend-web/src/strategy-components/components/task-components/FanganTy.tsx
+++ b/frontend-web/src/strategy-components/components/task-components/FanganTy.tsx
@@ -3,15 +3,9 @@ import "./css/iframe.css";
import { useTheme } from "@/contexts/ThemeContext";
-interface FanganTyPageProps {
- title: string;
- category: string;
- subCategory: string;
-}
-
const TYURL = import.meta.env.VITE_AIPI_B2ACTOR_URL || "";
-const FanganTyPage: React.FC = () => {
+const FanganTyPage: React.FC = () => {
const { theme } = useTheme();
const isDark = theme === "dark";
const [iframeUrl, setIframeUrl] = useState("");
diff --git a/frontend-web/src/strategy-components/components/task-components/XXTy.tsx b/frontend-web/src/strategy-components/components/task-components/XXTy.tsx
index bd0c8c7e..51abae74 100644
--- a/frontend-web/src/strategy-components/components/task-components/XXTy.tsx
+++ b/frontend-web/src/strategy-components/components/task-components/XXTy.tsx
@@ -3,15 +3,9 @@ import "./css/iframe.css";
import { useTheme } from "@/contexts/ThemeContext";
-interface XXTyPageProps {
- title: string;
- category: string;
- subCategory: string;
-}
-
const TYURL = import.meta.env.VITE_AIPI_B2ACTOR_URL || "";
-const XXTyPage: React.FC = () => {
+const XXTyPage: React.FC = () => {
const { theme } = useTheme();
const isDark = theme === "dark";
const [iframeUrl, setIframeUrl] = useState("");
diff --git a/frontend-web/src/strategy-components/components/task-components/XingdongTy.tsx b/frontend-web/src/strategy-components/components/task-components/XingdongTy.tsx
index 6e635ab3..98322871 100644
--- a/frontend-web/src/strategy-components/components/task-components/XingdongTy.tsx
+++ b/frontend-web/src/strategy-components/components/task-components/XingdongTy.tsx
@@ -3,15 +3,9 @@ import "./css/iframe.css";
import { useTheme } from "@/contexts/ThemeContext";
-interface XingdongTyPageProps {
- title: string;
- category: string;
- subCategory: string;
-}
-
const TYURL = import.meta.env.VITE_AIPI_B2ACTOR_URL || "";
-const XingdongTyPage: React.FC = () => {
+const XingdongTyPage: React.FC = () => {
const { theme } = useTheme();
const isDark = theme === "dark";
const [iframeUrl, setIframeUrl] = useState("");