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

@ -7,8 +7,9 @@
<script setup>
import { useUserStore } from '@/stores';
import { useChatStore } from '@/stores/modules/chat';
import { getUserEnterpriseInfo } from '@/utils/user';
import { initApp } from '@/utils/user';
import { useSidebarStore } from '@/stores/modules/side-bar';
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
@ -16,6 +17,7 @@ import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
const userStore = useUserStore();
const route = useRoute();
const sidebarStore = useSidebarStore();
const chatStore = useChatStore();
const redTheme = {
token: {
@ -25,11 +27,10 @@ const redTheme = {
};
const init = async () => {
const { isLogin, getUserInfo } = userStore;
const { isLogin } = userStore;
if (isLogin) {
await getUserInfo(); // 初始化用户信息
await getUserEnterpriseInfo();
await initApp();
sidebarStore.startUnreadInfoPolling();
} else {

View File

@ -28,7 +28,7 @@ export const getConversationList = (params: {}) => {
return Http.get(`/v1/conversation/message/list`, params);
};
export const baseUrl = 'http://192.168.40.41:8001';
export const baseUrl = 'https://agent.lvfunai.com';
export const getHeaders = () => {
const store = useEnterpriseStore();
return {
@ -42,7 +42,7 @@ export const getHeaders = () => {
/**
* 获取智能体信息
*/
export const getAgentInfo = async () => {
export const getAgentData = async () => {
const { data } = await axios.get(`${baseUrl}/api/agent/info`, {
headers: getHeaders(),
});

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;
}

View File

@ -1,7 +1,8 @@
import { defineStore } from 'pinia';
import { createSession, getAgentInfo } from '@/api/all/chat';
import { createSession, getAgentData } from '@/api/all/chat';
import { handleUserHome } from '@/utils/user';
import { glsWithCatch, slsWithCatch, rlsWithCatch } from '@/utils/stroage';
interface ChatState {
searchValue?: string;
@ -16,7 +17,7 @@ type agentInfo = {
export const useChatStore = defineStore('chat', {
state: (): ChatState => ({
searchValue: '',
agentInfo: {},
agentInfo: (glsWithCatch('agentInfo') && JSON.parse(glsWithCatch('agentInfo') as string)) || {},
}),
actions: {
setSearchValue(searchValue: string) {
@ -26,19 +27,17 @@ export const useChatStore = defineStore('chat', {
this.searchValue = '';
},
async getAgentInfo() {
const { code, data } = await getAgentInfo();
const { code, data } = await getAgentData();
if (code === 200) {
this.setAgentInfo(data);
}
},
setAgentInfo(agentInfo: agentInfo) {
this.agentInfo = agentInfo;
slsWithCatch('agentInfo', JSON.stringify(agentInfo));
},
clearAgentInfo() {
this.agentInfo = {};
},
clearAllAgentInfo() {
this.agentInfo = {};
this.searchValue = '';
},
async onCreateSession() {

View File

@ -8,6 +8,7 @@ declare global {
node?: string;
output?: string;
run_id?: string;
step_run_id?: string;
teamRunTaskId?: string;
isCollapse?: boolean;
status?: RUN_TASK_STATUS | TEAM_RUN_TASK_STATUS;

View File

@ -3,7 +3,7 @@ import type { EventSourceMessage } from '@microsoft/fetch-event-source';
import { useEnterpriseStore } from '@/stores/modules/enterprise';
import { glsWithCatch } from '@/utils/stroage';
const customHost = 'http://192.168.40.41:8001';
const customHost = 'https://agent.lvfunai.com';
//
// const customHost = 'http://localhost:3000';
const DEFAULT_SSE_URL = `${customHost}/api/agent/runs`;

View File

@ -7,6 +7,7 @@ import router from '@/router';
import { useUserStore } from '@/stores';
import { useEnterpriseStore } from '@/stores/modules/enterprise';
import { useSidebarStore } from '@/stores/modules/side-bar';
import { useChatStore } from '@/stores/modules/chat';
// 登录
export function goUserLogin(query?: any) {
@ -16,20 +17,28 @@ export function goUserLogin(query?: any) {
export const getUserEnterpriseInfo = async () => {
const enterpriseStore = useEnterpriseStore();
// const sidebarStore = useSidebarStore();
const userStore = useUserStore();
// const userStore = useUserStore();
await enterpriseStore.getEnterpriseInfo(); // 初始化企业信息
// sidebarStore.getUserNavbarMenuList(); // 初始化navbar菜单
// userStore.getUserAllowAccessRoutes(); // 初始化允许访问的路由
};
// 登录处理
export async function handleUserLogin() {
export async function initApp() {
const userStore = useUserStore();
const sidebarStore = useSidebarStore();
const chatStore = useChatStore();
await chatStore.getAgentInfo(); // 初始化智能体信息
await userStore.getUserInfo(); // 初始化用户信息
await getUserEnterpriseInfo(); // 初始化企业信息、navbar菜单、允许访问的路由
}
// 登录处理
export async function handleUserLogin() {
const sidebarStore = useSidebarStore();
await initApp();
sidebarStore.startUnreadInfoPolling(); // 初始化未读信息
handleUserHome();
@ -45,7 +54,9 @@ export function handleUserLogout() {
const userStore = useUserStore();
const enterpriseStore = useEnterpriseStore();
const sidebarStore = useSidebarStore();
const chatStore = useChatStore();
chatStore.clearAgentInfo(); // 清除智能体信息
userStore.clearUserInfo(); // 清除用户信息
userStore.clearToken(); // 清除token
enterpriseStore.clearUserEnterpriseInfo(); // 清除企业信息

View File

@ -19,8 +19,6 @@ export default {
});
onMounted(() => {
chatStore.getAgentInfo();
searchValue.value = chatStore.searchValue;
chatStore.clearSearchValue();
});
@ -28,7 +26,7 @@ export default {
return () => (
<div class="chat-wrap rounded-12px w-full h-full">
{conversationId.value ? (
<ConversationDetail inputInfo={{ message: searchValue.value }} />
<ConversationDetail inputInfo={{ message: searchValue.value }} conversationId={conversationId.value} />
) : (
<ConversationCreate />
)}