perf: 对话式运行状态归6类

This commit is contained in:
rd
2025-08-27 12:04:23 +08:00
parent 4baf054d5c
commit 6e7bf7f9e4
6 changed files with 135 additions and 57 deletions

View File

@ -34,7 +34,10 @@ export interface UseChatHandlerReturn {
senderRef: Ref<null> senderRef: Ref<null>
} }
export enum EnumTeamRunStatus { export enum EnumTeamRunStatus {
TeamRunStarted = 'TeamRunStarted', // 开始 TeamRunStarted = 'TeamRunStarted', // 对话开始
TeamRunResponseContent = 'TeamRunResponseContent', // 执行中 TeamRunResponseContent = 'TeamRunResponseContent', // 对话执行中
TeamRunCompleted = 'TeamRunCompleted', // 完成 TeamRunCompleted = 'TeamRunCompleted', // 对话完成
RunStarted = 'RunStarted', // l2开始运行
RunResponseContent = 'RunResponseContent', // l2执行中
RunCompleted = 'RunCompleted', // l2完成
} }

View File

@ -37,6 +37,7 @@ export default {
antdMessage.warning('停止生成后可发送'); antdMessage.warning('停止生成后可发送');
return; return;
} }
conversationList.value.push({ conversationList.value.push({
role: QUESTION_ROLE, role: QUESTION_ROLE,
content: message, content: message,
@ -47,6 +48,7 @@ export default {
const handleCancel = () => { const handleCancel = () => {
// 中止当前正在输出的回答 // 中止当前正在输出的回答
console.log('handleCancel', currentTaskId.value)
if (generateLoading.value) { if (generateLoading.value) {
bubbleListRef.value?.abortTypingByKey(currentTaskId.value); bubbleListRef.value?.abortTypingByKey(currentTaskId.value);
sseController.value?.abort?.(); sseController.value?.abort?.();
@ -105,9 +107,10 @@ export default {
() => props.inputInfo, () => props.inputInfo,
(newVal) => { (newVal) => {
if (newVal) { if (newVal) {
const { message } = newVal;
conversationList.value.push({ conversationList.value.push({
role: QUESTION_ROLE, role: QUESTION_ROLE,
content: newVal, content: message,
}); });
initSse(newVal); initSse(newVal);
} }

View File

@ -39,6 +39,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
const currentTaskId = ref<string | null>(null); const currentTaskId = ref<string | null>(null);
const showRightView = ref(false); const showRightView = ref(false);
const rightViewInfo = ref<any>({}); const rightViewInfo = ref<any>({});
const lastTeamRunTaskId = ref<string | null>(null); // 最近一个对话的id
// 初始化markdown // 初始化markdown
const md = markdownit({ const md = markdownit({
@ -145,7 +146,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
// style: ANSWER_STYLE, // style: ANSWER_STYLE,
// footer: ({ item }: { item: any }) => { // footer: ({ item }: { item: any }) => {
// const nonQuestionElements = conversationList.value.filter((item) => item.role !== QUESTION_ROLE); // const nonQuestionElements = conversationList.value.filter((item) => item.role !== QUESTION_ROLE);
// const isLastAnswer = nonQuestionElements[nonQuestionElements.length - 1]?.id === item.id; // const isLastRunTask = nonQuestionElements[nonQuestionElements.length - 1]?.id === item.id;
// }, // },
// }); // });
}; };
@ -161,23 +162,62 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
// antdMessage.error('连接服务器失败'); // antdMessage.error('连接服务器失败');
// }; // };
const handleTaskStart = (data: MESSAGE.Answer) => { const onRefresh = (run_id: string) => {
generateLoading.value = true;
conversationList.value = conversationList.value.filter((item) => item.run_id !== run_id);
initSse({ message: senderRef.value?.searchValue });
};
// 获取同一个对话下的最后一个run_task
const getLastRunTask = (data: MESSAGE.Answer, teamRunTaskId: string) => {
const allRunTask = conversationList.value.filter(
(item) => item.role === ANSWER_ROLE && item.team_run_id === teamRunTaskId && !item.isTeamRunTask,
);
return allRunTask[allRunTask.length - 1] ?? {};
};
const getFirstRunTask = (data: MESSAGE.Answer, teamRunTaskId: string) => {
const allRunTask = conversationList.value.filter(
(item) => item.role === ANSWER_ROLE && item.team_run_id === teamRunTaskId && !item.isTeamRunTask,
);
return allRunTask[0] ?? {};
};
const isLastRunTask = (data: MESSAGE.Answer, teamRunTaskId: string): boolean => {
const { run_id } = data;
return getLastRunTask(data, teamRunTaskId).run_id === run_id;
};
const isFirstRunTask = (data: MESSAGE.Answer, teamRunTaskId: string): boolean => {
const { run_id } = data;
return getFirstRunTask(data, teamRunTaskId).run_id === run_id;
};
const isLastTeamRunTask = (data: MESSAGE.Answer) => {
const { run_id } = data;
const lastElement = conversationList.value[conversationList.value.length - 1];
return lastElement && lastElement.run_id === run_id;
};
// 过程节点开始
const handleRunTaskStart = (data: MESSAGE.Answer) => {
const { run_id } = data; const { run_id } = data;
currentTaskId.value = run_id; currentTaskId.value = run_id;
conversationList.value.push({ conversationList.value.push({
run_id, run_id,
key: run_id,
team_run_id: lastTeamRunTaskId.value,
content: data, content: data,
output: data.output, output: data.output,
role: ANSWER_ROLE, role: ANSWER_ROLE,
messageRender: (data: MESSAGE.Answer) => { messageRender: (data: MESSAGE.Answer) => {
let outputEleClass: string = `thought-chain-output border-l-#E6E6E8 border-l-1px pl-12px relative left-6px mb-4px`; let outputEleClass: string = `thought-chain-output border-l-#E6E6E8 border-l-1px pl-12px relative left-6px mb-4px`;
!isLastAnswer(data) && (outputEleClass += ' hasLine pb-12px pt-4px'); !isLastRunTask(data, lastTeamRunTaskId.value) && (outputEleClass += ' hasLine pb-12px pt-4px');
return ( return (
<> <>
<div class="flex items-center"> {isFirstRunTask(data, lastTeamRunTaskId.value) && (
<span class="font-family-medium color-#211F24 text-14px font-400 lh-22px mr-4px"></span> <div class="flex items-center">
<IconCaretUp size={16} class="color-#211F24" /> <span class="font-family-medium color-#211F24 text-14px font-400 lh-22px mr-4px"></span>
</div> <IconCaretUp size={16} class="color-#211F24" />
</div>
)}
<div class="relative thought-chain-item"> <div class="relative thought-chain-item">
<div class="flex items-center mb-4px"> <div class="flex items-center mb-4px">
<img src={icon2} width={13} height={13} class="mr-4px" /> <img src={icon2} width={13} height={13} class="mr-4px" />
@ -190,51 +230,67 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
}, },
}); });
}; };
// 过程节点更新
const onRefresh = (run_id: string) => { const handleRunTaskUpdate = (data: MESSAGE.Answer) => {
generateLoading.value = true;
conversationList.value = conversationList.value.filter((item) => item.run_id !== run_id);
initSse({ message: senderRef.value?.searchValue });
};
const isLastAnswer = (data: MESSAGE.Answer) => {
const { run_id } = data;
const nonQuestionElements = conversationList.value.filter(
(item) => item.role === ANSWER_ROLE && item.run_id === run_id,
);
return nonQuestionElements[nonQuestionElements.length - 1]?.run_id === run_id;
};
const isLastTask = (data: MESSAGE.Answer) => {
const { run_id } = data;
const lastElement = conversationList.value[conversationList.value.length - 1];
return lastElement && lastElement.run_id === run_id;
};
// 节点更新处理
const handleTaskUpdate = (data: MESSAGE.Answer) => {
const { run_id, output } = data; const { run_id, output } = data;
const existingItemIndex = conversationList.value.findIndex((item) => item.run_id === run_id); const existingItem = conversationList.value.find((item) => item.run_id === run_id);
if (existingItem && output) {
existingItem.content.output += output;
}
};
// 过程节点结束
const handleRunTaskEnd = (data: MESSAGE.Answer) => {
const { run_id, output } = data;
if (existingItemIndex !== -1 && output) { const existingItem = conversationList.value.find((item) => item.run_id === run_id);
const existingItem = conversationList.value[existingItemIndex];
if (existingItem) {
existingItem.content.output += output; existingItem.content.output += output;
} }
}; };
const handleTaskEnd = (data: MESSAGE.Answer) => { // 任务开始
const { run_id, output, team_session_state } = data; const handleTeamRunTaskStart = (data: MESSAGE.Answer) => {
// console.log('handleRunTaskStart');
const { run_id } = data;
lastTeamRunTaskId.value = run_id;
currentTaskId.value = run_id;
conversationList.value.push({
run_id,
isTeamRunTask: true,
team_run_id: lastTeamRunTaskId.value,
key: run_id,
content: data,
output: data.output,
role: ANSWER_ROLE,
messageRender: (data: MESSAGE.Answer) => {
return <div v-html={md.render(data.output ?? '')} />;
},
});
};
// 任务更新
const handleTeamRunTaskUpdate = (data: MESSAGE.Answer) => {
const { run_id, output } = data;
const existingItem = conversationList.value.find((item) => item.run_id === run_id); const existingItem = conversationList.value.find((item) => item.run_id === run_id);
resetGenerateStatus(); if (existingItem && output) {
if (existingItem) {
existingItem.content.output += output; existingItem.content.output += output;
existingItem.footer = ({ item: any }) => { }
};
// 任务结束
const handleTeamRunTaskEnd = (data: MESSAGE.Answer) => {
const { run_id, team_session_state } = data;
const lastRunTask = getLastRunTask(data, lastTeamRunTaskId.value);
resetGenerateStatus();
console.log('handleTeamRunTaskEnd', { data }, { lastRunTask });
if (lastRunTask) {
lastRunTask.footer = () => {
return ( return (
<div class="flex items-center"> <div class="flex items-center">
<Tooltip title="复制" onClick={() => onCopy(existingItem.content.output)}> <Tooltip title="复制" onClick={() => onCopy(lastRunTask.content.output)}>
<IconCopy size={16} class="color-#737478 cursor-pointer mr-12px" /> <IconCopy size={16} class="color-#737478 cursor-pointer mr-12px" />
</Tooltip> </Tooltip>
{team_session_state && ( {team_session_state && (
@ -242,7 +298,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
<IconDownload size={16} class="color-#737478 cursor-pointer mr-12px" /> <IconDownload size={16} class="color-#737478 cursor-pointer mr-12px" />
</Tooltip> </Tooltip>
)} )}
{isLastTask(data) && ( {isLastTeamRunTask(data) && (
<Tooltip title="重新生成" onClick={() => onRefresh(run_id)}> <Tooltip title="重新生成" onClick={() => onRefresh(run_id)}>
<IconRefresh size={16} class="color-#737478 cursor-pointer" /> <IconRefresh size={16} class="color-#737478 cursor-pointer" />
</Tooltip> </Tooltip>
@ -256,19 +312,29 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
handleFileReview(data); handleFileReview(data);
} }
}; };
// 消息处理主函数 // 消息处理主函数
const handleMessage = (parsedData: { event: string; data: MESSAGE.Answer }) => { const handleMessage = (parsedData: { event: string; data: MESSAGE.Answer }) => {
const { data } = parsedData; const { data } = parsedData;
const { status } = data; const { status } = data;
switch (status) { switch (status) {
case EnumTeamRunStatus.RunStarted:
handleRunTaskStart(data);
break;
case EnumTeamRunStatus.RunResponseContent:
handleRunTaskUpdate(data);
break;
case EnumTeamRunStatus.RunCompleted:
handleRunTaskEnd(data);
break;
case EnumTeamRunStatus.TeamRunStarted: case EnumTeamRunStatus.TeamRunStarted:
handleTaskStart(data); handleTeamRunTaskStart(data);
break; break;
case EnumTeamRunStatus.TeamRunResponseContent: case EnumTeamRunStatus.TeamRunResponseContent:
handleTaskUpdate(data); handleTeamRunTaskUpdate(data);
break; break;
case EnumTeamRunStatus.TeamRunCompleted: case EnumTeamRunStatus.TeamRunCompleted:
handleTaskEnd(data); handleTeamRunTaskEnd(data);
break; break;
default: default:
break; break;

View File

@ -105,7 +105,6 @@ export default defineComponent({
// 暴露控制方法 // 暴露控制方法
const abortTypingByKey = (key: string | number) => { const abortTypingByKey = (key: string | number) => {
bubbleRefs.value[key]?.abortTyping?.(); bubbleRefs.value[key]?.abortTyping?.();
console.log('abortTypingByKey----', bubbleRefs.value[key])
}; };
// 对外暴露能力 // 对外暴露能力
expose({ expose({

View File

@ -36,9 +36,9 @@ const showInOnePage = computed(() => {
const layoutPageClass = computed(() => { const layoutPageClass = computed(() => {
let result = showInOnePage.value ? 'overflow-hidden' : ''; let result = showInOnePage.value ? 'overflow-hidden' : '';
if (isHomeRoute.value) { if (isHomeRoute.value) {
result += 'pb-8px pr-8px'; result += ' pb-8px pr-8px';
} else { } else {
result += 'pb-24px pr-24px'; result += ' pb-24px pr-24px';
} }
return result; return result;
}); });

View File

@ -1,18 +1,25 @@
declare global { declare global {
namespace MESSAGE { namespace MESSAGE {
type TASK_STATUS = 'TeamRunStarted' | 'TeamRunResponseContent' | 'TeamRunCompleted'; type TASK_STATUS =
| 'RunStarted'
| 'RunResponseContent'
| 'RunCompleted'
| 'TeamRunStarted'
| 'TeamRunResponseContent'
| 'TeamRunCompleted';
interface Answer { interface Answer {
message: string; message: string;
node: string; node: string;
output: string; output: string;
run_id: string; run_id: string;
team_run_id: string;
status: TASK_STATUS; status: TASK_STATUS;
extra_data: { extra_data: {
type: string, type: string;
data: Record<string, any> data: Record<string, any>;
}, };
team_session_state: any team_session_state: any;
} }
} }
} }