perf: 主agent对话交互调整

This commit is contained in:
rd
2025-08-28 12:03:52 +08:00
parent ce5bd35e37
commit 10fc946eca
13 changed files with 190 additions and 136 deletions

View File

@ -11,16 +11,12 @@ import { FILE_TYPE } from '@/components/xt-chat/chat-view/constants';
export default {
emits: ['close'],
props: {
showRightView: {
type: Boolean,
default: false,
},
rightViewInfo: {
type: Object,
default: {},
rightViewData: {
type: Array,
default: () => [],
},
},
setup(props, { emit, expose }) {
setup(props: { rightViewData: any[] }, { emit, expose }) {
const bubbleRef = ref(null);
const md = markdownit({
@ -30,15 +26,21 @@ export default {
typographer: true,
});
console.log(props.rightViewData)
const dataSource = computed(() => {
return props.rightViewData.find((v) => v.task_type === '任务管理') ?? {};
});
const tasks = computed(() => {
return props.rightViewInfo.payload?.tasks ?? [];
return dataSource.value.payload?.tasks ?? [];
});
const isTaskManage = computed(() => {
return props.rightViewInfo.task_type === '任务管理';
return dataSource.value.task_type === '任务管理';
});
const isMediaCenter = computed(() => {
return props.rightViewInfo.task_type === '素材中心';
const hasMediaCenter = computed(() => {
return props.rightViewData.some((v) => v.task_type === '素材中心')
});
const onDownload = () => {
@ -49,7 +51,7 @@ export default {
const {
api: { endpoint, method },
payload,
} = props.rightViewInfo;
} = dataSource.value;
Http[method.toLowerCase()]?.(endpoint, payload).then((res) => {
const { code } = res;
if (code === 200) {
@ -61,7 +63,7 @@ export default {
const {
api: { endpoint, method },
payload,
} = props.rightViewInfo;
} = dataSource.value;
Http[method.toLowerCase()]?.(endpoint, payload).then((res) => {
const { code } = res;
if (code === 200) {
@ -75,7 +77,7 @@ export default {
const renderHeader = () => {
return (
<header class="header flex justify-end items-center mb-16px px-32px">
{isMediaCenter.value && (
{hasMediaCenter.value && (
<Button
type="outline"
size="medium"
@ -87,17 +89,15 @@ export default {
</Button>
)}
{isTaskManage.value && (
<Button
type="outline"
size="medium"
class="mr-16px"
v-slots={{ icon: () => <icon-plus size="14" /> }}
onClick={onAddTaskManage}
>
任务管理
</Button>
)}
<Button
type="outline"
size="medium"
class="mr-16px"
v-slots={{ icon: () => <icon-plus size="14" /> }}
onClick={onAddTaskManage}
>
任务管理
</Button>
{/*<Button
type="outline"
size="medium"
@ -113,7 +113,7 @@ export default {
);
};
const renderTaskManage = () => {
const { file_type } = props.rightViewInfo;
const { file_type } = dataSource.value;
return tasks.value.map((item) => {
const { params, execution_time, name } = item;
if (file_type === FILE_TYPE.topic_only) {
@ -129,7 +129,7 @@ export default {
<p>{`${params.media_account}${params.platform}`}</p>
<p>{`日期:${execution_time}`}</p>
<p>{`选题:${params.topic}`}</p>
<p>{`标题${name}`}</p>
<p>{`标题${name}`}</p>
<p>{`正文:${params.content}`}</p>
</div>
);
@ -137,41 +137,41 @@ export default {
return null;
});
};
const renderMediaCenter = () => {
return tasks.value.map((item) => {
const { params, execution_time, name, content } = item;
const { file_type } = props.rightViewInfo;
if (file_type === FILE_TYPE.content_only) {
return (
<div class="mb-20px">
<p>{params?.media_account ?? '-'}</p>
<p>📅 {`${execution_time}`}</p>
<p class="mb-10">📝 {`${name}`}</p>
<p>正文</p>
<p>📝 {`${content}`}</p>
</div>
);
} else if (file_type === FILE_TYPE.topic_with_content) {
return (
<div class="mb-20px">
<p>{`${params.media_account}${params.platform}`}</p>
<p>{`日期:${execution_time}`}</p>
<p>{`选题:${params.topic}`}</p>
<p>{`标题${name}`}</p>
<p>{`正文:${params.content}`}</p>
</div>
);
}
});
};
// const renderMediaCenter = () => {
// return tasks.value.map((item) => {
// const { params, execution_time, name, content } = item;
// const { file_type } = dataSource.value;
// if (file_type === FILE_TYPE.content_only) {
// return (
// <div class="mb-20px">
// <p>{params?.media_account ?? '-'}</p>
// <p>📅 {`${execution_time}`}</p>
// <p class="mb-10">📝 {`${name}`}</p>
// <p>正文:</p>
// <p>📝 {`${content}`}</p>
// </div>
// );
// } else if (file_type === FILE_TYPE.topic_with_content) {
// return (
// <div class="mb-20px">
// <p>{`${params.media_account}${params.platform}`}</p>
// <p>{`日期:${execution_time}`}</p>
// <p>{`选题:${params.topic}`}</p>
// <p>{`标题${name}`}</p>
// <p>{`正文:${params.content}`}</p>
// </div>
// );
// }
// });
// };
const renderContainer = () => {
const renderMessage = () => {
if (isTaskManage.value) {
return renderTaskManage();
}
if (isMediaCenter.value) {
return renderMediaCenter();
}
// if (isMediaCenter.value) {
// return renderMediaCenter();
// }
return null;
};
return (

View File

@ -40,6 +40,7 @@ export default {
const handleSubmit = () => {
emit('submit', localSearchValue.value);
localSearchValue.value = ''
};
const handleCancel = () => {
emit('cancel');

View File

@ -30,7 +30,7 @@ export interface UseChatHandlerReturn {
generateLoading?: Ref<boolean>;
conversationList?: Ref<any[]>;
showRightView?: Ref<boolean>;
rightViewInfo?: Ref<any>;
rightViewData?: Ref<any>;
senderRef?: Ref<null>
}
export enum EnumTeamRunStatus {

View File

@ -17,20 +17,20 @@ export default {
type: Object as () => CHAT.TInputInfo,
default: null,
},
conversationId: {
type: String,
default: '',
},
},
setup(props, { emit, expose }) {
const chatStore = useChatStore();
const route = useRoute();
// const route = useRoute();
const rightViewRef = ref(null);
const bubbleListRef = ref<any>(null);
const sseController = ref<any>(null);
const conversationId = computed(() => {
return route.params.conversationId;
});
const handleSubmit = (message: string) => {
if (generateLoading.value) {
antdMessage.warning('停止生成后可发送');
@ -76,7 +76,7 @@ export default {
handleMessage,
body: JSON.stringify({
content: message,
session_id: conversationId.value,
session_id: props.conversationId,
agent_id: chatStore.agentInfo.agent_id,
}),
});
@ -87,10 +87,26 @@ export default {
}
};
const getConversationInfo = async () => {
const { data, code } = await getConversationList({
session_id: props.conversationId,
agent_id: chatStore.agentInfo.agent_id,
});
if (code === 200) {
conversationList.value = [
...conversationList.value,
...(data.list?.flat(1) ?? []).map((v) => ({
...v,
teamRunTaskId: v.step_run_id,
})),
];
}
};
const {
roles,
showRightView,
rightViewInfo,
rightViewData,
currentTaskId,
handleMessage,
conversationList,
@ -102,7 +118,7 @@ export default {
watch(
() => props.inputInfo,
(newVal) => {
async (newVal) => {
if (newVal) {
const { message } = newVal;
conversationList.value.push({
@ -114,18 +130,15 @@ export default {
},
{ deep: true },
);
onMounted(async () => {
if (conversationId.value) {
const { data, code } = await getConversationList({
session_id: conversationId.value,
agent_id: chatStore.agentInfo.agent_id,
});
if (code === 200) {
conversationList.value = data.list?.flat(1) ?? []
watch(
() => props.conversationId,
(newVal) => {
if (newVal) {
getConversationInfo();
}
}
});
},
{ immediate: true },
);
return () => (
<div class="chat-view-wrap w-full h-full flex">
@ -157,7 +170,7 @@ export default {
{showRightView.value && (
<RightView
ref={rightViewRef}
rightViewInfo={rightViewInfo.value}
rightViewData={rightViewData.value}
showRightView={showRightView.value}
onClose={() => (showRightView.value = false)}
/>

View File

@ -46,7 +46,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
const generateLoading = ref<boolean>(false);
const currentTaskId = ref<string | null>(null);
const showRightView = ref(false);
const rightViewInfo = ref<any>({});
const rightViewData = ref<any>({});
const lastTeamRunTaskId = ref<string | null>(null); // 最近一个对话的id
// 初始化markdown
@ -94,14 +94,30 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
variant: 'borderless',
style: ROLE_STYLE,
messageRender: (message: string) => {
return <div v-html={md.render(message)} />
return <div v-html={md.render(message)} />;
},
footer: (params) => {
const { content, item } = params as { content: string; item: MESSAGE.Answer };
const isShow = conversationList.value[conversationList.value.length - 1].run_id === item.run_id;
return (
<div class="flex items-center">
<Tooltip title="复制" onClick={() => onCopy(content)}>
<IconCopy size={16} class="color-#737478 cursor-pointer mr-12px" />
</Tooltip>
{isShow && (
<Tooltip title="重新生成" onClick={() => handleRemoteRefresh(item)}>
<IconRefresh size={16} class="color-#737478 cursor-pointer" />
</Tooltip>
)}
</div>
);
},
},
};
// 下载处理
const onDownload = () => {
console.log('onDownload', rightViewInfo.value);
console.log('onDownload', rightViewData.value);
};
const onCopy = (content: string) => {
@ -114,10 +130,25 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
generateLoading.value = false;
};
const handleRemoteRefresh = (item: MESSAGE.Answer) => {
generateLoading.value = true;
const targetIndex = conversationList.value.findIndex(
(v) => v.teamRunTaskId === item.teamRunTaskId && v.run_id === item.run_id && v.role === REMOTE_ASSISTANT_ROLE,
);
const message = conversationList.value[targetIndex - 1]?.content;
conversationList.value.splice(targetIndex, 1);
initSse({ message });
};
const onRefresh = (run_id: string) => {
generateLoading.value = true;
conversationList.value = conversationList.value.filter((item) => item.run_id !== run_id);
initSse({ message: senderRef.value?.searchValue });
const targetIndex = conversationList.value.findIndex((v) => v.teamRunTaskId === run_id);
conversationList.value = conversationList.value.filter((item) => item.teamRunTaskId !== run_id);
const message = conversationList.value[targetIndex - 1]?.content;
initSse({ message });
};
const getAllRunTask = (teamRunTaskId: string) => {
@ -128,7 +159,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
const getRunTask = (run_id: string) => {
return conversationList.value.find((item) => item.run_id === run_id && !item.isTeamRunTask);
};
// 设置当前对话所有过程任务展开收起状态
// 设置当前对话所有思考过程任务展开收起状态
const setRunTaskCollapse = (teamRunTaskId: string, isCollapse: boolean) => {
getAllRunTask(teamRunTaskId).forEach((item) => {
item.content.isCollapse = isCollapse;
@ -157,11 +188,6 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
const isFirstRunTask = (run_id: string): boolean => {
return getFirstRunTask(lastTeamRunTaskId.value).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) => {
@ -184,7 +210,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
return (
<>
{isFirstRunTask(run_id) && (
<div class="flex items-center">
<div class="flex items-center mb-8px">
<span class="font-family-medium color-#211F24 text-14px font-400 lh-22px mr-4px"></span>
{isCollapse ? (
<IconCaretUp
@ -278,36 +304,39 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
return;
}
// 含有思考过程,折叠思考过程,展示结果
if (_hasRunTask) {
setRunTaskCollapse(lastTeamRunTaskId.value, false);
if (extra_data) {
showRightView.value = true;
rightViewData.value = extra_data.data;
}
_targetTask.content.customRender = () => (
<>
<div v-html={md.render(output)} />
{extra_data && (
<div class="file-card mt-10px">
<IconFile class="w-24px h-24px mr-16px color-#6D4CFE" />
<div>
<TextOverTips
context={FILE_TYPE_MAP?.[extra_data.data?.file_type] ?? '-'}
class="font-family-medium color-#211F24 text-14px font-400 lh-22px mb-4px"
/>
<span class="color-#939499 font-family-regular text-12px font-400 lh-22px">
{exactFormatTime(dayjs().unix())}
</span>
</div>
</div>
)}
</>
);
} else {
_targetTask.content.teamRunStatus = EnumTeamRunStatus.TeamRunCompleted;
}
// 含有文档,右侧展示预览区域
if (extra_data) {
showRightView.value = true;
rightViewInfo.value = extra_data.data?.[0] ?? {};
_targetTask.content.customRender = () => (
<>
<div v-html={md.render(output)} />
<div class="file-card mt-10px">
<IconFile class="w-24px h-24px mr-16px color-#6D4CFE" />
<div>
<TextOverTips
context={FILE_TYPE_MAP?.[extra_data.data?.file_type] ?? '-'}
class="font-family-medium color-#211F24 text-14px font-400 lh-22px mb-4px"
/>
<span class="color-#939499 font-family-regular text-12px font-400 lh-22px">
{exactFormatTime(dayjs().unix())}
</span>
</div>
</div>
</>
);
}
_targetTask.footer = () => {
const isShow = conversationList.value[conversationList.value.length - 1].teamRunTaskId === run_id;
return (
<div class="flex items-center">
{!extra_data && (
@ -320,7 +349,7 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
<IconCopy size={16} class="color-#737478 cursor-pointer mr-12px" />
</Tooltip>
)}
{isLastTeamRunTask(data) && (
{isShow && (
<Tooltip title="重新生成" onClick={() => onRefresh(run_id)}>
<IconRefresh size={16} class="color-#737478 cursor-pointer" />
</Tooltip>
@ -366,6 +395,6 @@ export default function useChatHandler({ initSse }): UseChatHandlerReturn {
generateLoading,
conversationList,
showRightView,
rightViewInfo,
rightViewData,
};
}

View File

@ -4,6 +4,7 @@
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
}