feat: 支持聊天多版本答案切换
- 为管理端、公共聊天和用户中心补充回答变体查询与切换能力 - 支持基于指定轮次重新生成并同步前后端多版本状态 - 保留 application.yml 与本地截图文件为未提交状态
This commit is contained in:
@@ -4,7 +4,11 @@ import type { ChatTimeTimelineItem } from '@easyflow/types';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { useEasyFlowDrawer } from '@easyflow/common-ui';
|
||||
import { ChatTimeHistoryMapper } from '@easyflow/utils';
|
||||
import {
|
||||
createChatVariantSwitchController,
|
||||
ChatTimeHistoryMapper,
|
||||
ChatTimeTimelineBuilder,
|
||||
} from '@easyflow/utils';
|
||||
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import {
|
||||
@@ -53,6 +57,15 @@ const messagePage = ref({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const variantSwitchStateVersion = ref(0);
|
||||
const variantSwitchController = createChatVariantSwitchController<any, ChatTimeTimelineItem>({
|
||||
mapRecords: (records) => ChatTimeHistoryMapper.fromHistoryRecords(records),
|
||||
onStateChange: () => {
|
||||
variantSwitchStateVersion.value += 1;
|
||||
},
|
||||
replaceRound: (items, roundId, nextItems) =>
|
||||
ChatTimeTimelineBuilder.replaceRoundMessages(items, roundId, nextItems),
|
||||
});
|
||||
|
||||
const [Drawer, drawerApi] = useEasyFlowDrawer({
|
||||
appendToMain: false,
|
||||
@@ -164,12 +177,88 @@ async function loadMessages(reset = false) {
|
||||
: loadedMessageRecordCount.value + (res.data?.records || []).length;
|
||||
messagePage.value.total = res.data?.total || 0;
|
||||
messagePage.value.pageNumber = nextPageNumber;
|
||||
prefetchVisibleVariants();
|
||||
}
|
||||
|
||||
function normalizeMessages(records: any[]) {
|
||||
return ChatTimeHistoryMapper.fromHistoryRecords([...records].reverse());
|
||||
}
|
||||
|
||||
async function handleSelectVariant(
|
||||
item: ChatTimeTimelineItem,
|
||||
direction: 'next' | 'previous',
|
||||
) {
|
||||
if (!currentSession.value?.id || !item.roundId) {
|
||||
return;
|
||||
}
|
||||
const current = Number(item.variantIndex || item.selectedVariantIndex || 1);
|
||||
const variantIndex = direction === 'previous' ? current - 1 : current + 1;
|
||||
await variantSwitchController.switchVariant({
|
||||
fetchVariants: () =>
|
||||
fetchRoundVariants(String(currentSession.value.id), String(item.roundId)),
|
||||
items: messageList.value,
|
||||
persistVariant: async () => {
|
||||
const [, res] = await tryit(api.post)(
|
||||
`/api/v1/chatHistory/sessions/${currentSession.value.id}/rounds/${item.roundId}/selectVariant`,
|
||||
{
|
||||
variantIndex,
|
||||
},
|
||||
);
|
||||
if (res?.errorCode !== 0 || !res?.data) {
|
||||
throw new Error(res?.message || '答案版本切换失败');
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
roundId: item.roundId,
|
||||
sessionId: currentSession.value.id,
|
||||
targetVariantIndex: variantIndex,
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchRoundVariants(sessionId: string, roundId: string) {
|
||||
const [, res] = await tryit(api.get)(
|
||||
`/api/v1/chatHistory/sessions/${sessionId}/rounds/${roundId}/variants`,
|
||||
);
|
||||
if (res?.errorCode !== 0) {
|
||||
throw new Error(res?.message || '答案版本加载失败');
|
||||
}
|
||||
return res.data || [];
|
||||
}
|
||||
|
||||
function prefetchVisibleVariants() {
|
||||
const sessionId = String(currentSession.value?.id || '');
|
||||
if (!sessionId) {
|
||||
return;
|
||||
}
|
||||
for (const item of messageList.value) {
|
||||
if (
|
||||
item.role === 'assistant' &&
|
||||
item.roundId &&
|
||||
Number(item.variantCount || 0) > 1
|
||||
) {
|
||||
variantSwitchController.prefetchVariants({
|
||||
fetchVariants: () => fetchRoundVariants(sessionId, String(item.roundId)),
|
||||
roundId: item.roundId,
|
||||
sessionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function currentSwitchingRoundIds() {
|
||||
variantSwitchStateVersion.value;
|
||||
const sessionId = String(currentSession.value?.id || '');
|
||||
if (!sessionId) {
|
||||
return [];
|
||||
}
|
||||
return messageList.value
|
||||
.filter(
|
||||
(item) =>
|
||||
item.roundId && variantSwitchController.isSwitching(sessionId, item.roundId),
|
||||
)
|
||||
.map((item) => String(item.roundId));
|
||||
}
|
||||
|
||||
function changePage(pageNumber: number) {
|
||||
query.value.pageNumber = pageNumber;
|
||||
fetchSessions();
|
||||
@@ -421,6 +510,8 @@ function closeDetail() {
|
||||
:messages="messageList"
|
||||
:has-more="hasMoreMessages"
|
||||
:on-load-more="() => loadMessages(false)"
|
||||
:switching-round-ids="currentSwitchingRoundIds()"
|
||||
@select-variant="handleSelectVariant($event.item, $event.direction)"
|
||||
@close="closeDetail"
|
||||
/>
|
||||
</Drawer>
|
||||
|
||||
Reference in New Issue
Block a user