From 1476d27514874e9c95002451a81878bd9bec8382 Mon Sep 17 00:00:00 2001
From: wujingjing <gersonwu@qq.com>
Date: 星期六, 14 十二月 2024 15:36:53 +0800
Subject: [PATCH] 多轮对话

---
 src/api/ai/chat.ts                                      |   11 +++
 vite.config.ts                                          |    2 
 src/components/chat/Chat.vue                            |   60 ++++++++++++++++---
 src/components/chat/chatComponents/multiChat/Select.vue |   37 ++++++++++++
 src/components/chat/chatComponents/multiChat/index.ts   |    6 ++
 src/components/chat/hooks/useScrollLoad.ts              |   25 ++++++-
 src/components/chat/model/types.ts                      |   28 +++++---
 7 files changed, 142 insertions(+), 27 deletions(-)

diff --git a/src/api/ai/chat.ts b/src/api/ai/chat.ts
index 12be70d..20bcaa5 100644
--- a/src/api/ai/chat.ts
+++ b/src/api/ai/chat.ts
@@ -502,3 +502,14 @@
 			'Content-Type': 'application/x-www-form-urlencoded',
 		},
 	});
+
+
+	export const question_stream_reply = (params) =>
+	request({
+		url: `/chat/question_stream_reply`,
+		method: 'post',
+		params: params,
+		headers: {
+			'Content-Type': 'application/x-www-form-urlencoded',
+		},
+	});
\ No newline at end of file
diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue
index 1f8ac88..75d56af 100644
--- a/src/components/chat/Chat.vue
+++ b/src/components/chat/Chat.vue
@@ -61,6 +61,7 @@
 
 												<!-- #region ====================== 杩囩▼杈撳嚭 ======================-->
 												<el-steps v-show="item.stepIsShow" class="mt-3" direction="vertical" :active="activeStep">
+													
 													<el-step
 														v-for="(subItem, index) in item.stepList"
 														:title="subItem.title"
@@ -73,10 +74,26 @@
 															<span class="ywifont ywicon-loading1 animate-spin !text-[24px]"></span>
 														</template>
 														<template #title>
-															<span class=""
-																>{{ subItem.title
-																}}<span v-if="subItem.ms" class="text-green-600">{{ `锛�${subItem.ms}锛塦 }}</span></span
+															<span class="">
+																{{ subItem.title }}
+
+																<span v-if="subItem.ms" class="text-green-600">{{ `锛�${subItem.ms}锛塦 }}</span></span
 															>
+														</template>
+
+														<template #description v-if="subItem?.subStep?.length > 0">
+															<div class="my-1 flex flex-col gap-1 text-[14px]">
+
+													
+																<component
+																	:key="`${item.historyId}-${index + 1}-${multiChatIndex + 1}`"
+																	v-for="(multiChatItem, multiChatIndex) in subItem.subStep"
+																	:order="`${index + 1}-${multiChatIndex + 1}`"
+																	:item="multiChatItem"
+																	:is="multiChatTypeMapCom[multiChatItem.type]"
+																	:disabled="!(index + 1 === item.stepList.length && isTalking && msgIndex === computedMessageList.length - 1)"
+																/>
+															</div>
 														</template>
 													</el-step>
 												</el-steps>
@@ -279,8 +296,11 @@
 					</div>
 				</div>
 			</div>
-			<div class="absolute right-28 bottom-40 " v-if="!isBottom">
-				<div class="flex items-center justify-center size-[38px]  cursor-pointer hover:text-[#0284ff] border rounded-full hover:bg-[#f6f7f9] shadow bg-white" @click="scrollToBottom">
+			<div class="absolute right-28 bottom-40" v-if="!isBottom">
+				<div
+					class="flex items-center justify-center size-[38px] cursor-pointer hover:text-[#0284ff] border rounded-full hover:bg-[#f6f7f9] shadow bg-white"
+					@click="scrollToBottom"
+				>
 					<i class="ywifont ywicon-xiangxiajiantou !text-[20px]" />
 				</div>
 			</div>
@@ -346,12 +366,15 @@
 	isSharePage,
 	roomConfig,
 } from '/@/stores/chatRoom';
+
+import { multiChatTypeMapCom } from '/@/components/chat/chatComponents/multiChat';
 import emitter from '/@/utils/mitt';
 import { ErrorCode } from '/@/utils/request';
 import { toMyFixed } from '/@/utils/util';
 const chatWidth = '75%';
 const voicePageIsShow = ref(false);
 let isTalking = ref(false);
+
 let messageContent = ref<ChatContent>({
 	type: AnswerType.Text,
 	values: '',
@@ -547,6 +570,20 @@
 					computedMessageList.value.at(-1).conclusion = chunkRes.value;
 					chunkRes.value = '鍒嗘瀽缁撴潫';
 				}
+
+				if (chunkRes.mode === 'question') {
+					const stepList = computedMessageList.value.at(-1).stepList;
+					const lastStepItem = stepList.at(-1);
+					if (!lastStepItem.subStep) {
+						lastStepItem.subStep = [];
+					}
+					lastStepItem.subStep.push({
+						type: chunkRes.value.type,
+						data: chunkRes.value,
+					});
+					scrollToBottom();
+					return;
+				}
 				const stepList = computedMessageList.value.at(-1).stepList;
 				const currentTimeStamp = new Date().getTime();
 				const ms = toMyFixed(currentTimeStamp - lastTimestamp, 2) + ' ms';
@@ -560,10 +597,13 @@
 					stepList.at(-1).ms = ms;
 				}
 				lastTimestamp = currentTimeStamp;
-
 				const stepItem = convertProcessItem(chunkRes);
+
 				stepList.push(stepItem);
-				scrollToBottom();
+
+				if (chunkRes.mode !== 'result') {
+					scrollToBottom();
+				}
 			},
 			{
 				cancelToken: currentSource.token,
@@ -581,7 +621,7 @@
 	});
 
 	questionRes = await resultP;
-	isTalking.value = false;
+	// isTalking.value = false;
 
 	const content = parseContent(res, true);
 	return content;
@@ -945,10 +985,10 @@
 	font-size: 16px !important;
 }
 :deep(.el-step__description) {
-	height: 20px;
+	min-height: 20px;
 }
 
 :deep(.el-step:last-of-type .el-step__description) {
-	display: none;
+	// display: none;
 }
 </style>
diff --git a/src/components/chat/chatComponents/multiChat/Select.vue b/src/components/chat/chatComponents/multiChat/Select.vue
new file mode 100644
index 0000000..39272bd
--- /dev/null
+++ b/src/components/chat/chatComponents/multiChat/Select.vue
@@ -0,0 +1,37 @@
+<template>
+	<div class="flex flex-col gap-1">
+		<span class="text-gray-600 font-normal">{{ `${order} ${item?.data?.title}` }}</span>
+
+		<div v-if="item?.data?.options?.length > 0" class="flex-items-center gap-5">
+			<span
+				@click="select(subItem)"
+				v-for="subItem in item?.data?.options"
+				class="flex w-fit items-center cursor-pointer border-solid border px-3 border-gray-300 hover:text-blue-400 rounded-lg"
+				:class="{ 'cursor-not-allowed': disabled,  }"
+				>{{ subItem }}</span
+			>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch } from 'vue';
+import { question_stream_reply } from '/@/api/ai/chat';
+const props = defineProps(['order', 'item', 'disabled']);
+// :class="[...(subItem === activeOption ? ['bg-blue-400', 'text-white'] : []), disabled ? 'cursor-not-allowed' : '']"
+// 'bg-blue-400': subItem === activeOption, 'text-white': subItem === activeOption.value
+const activeOption = ref();
+const select = async (option) => {
+	if (props.disabled) return;
+	const res = await question_stream_reply({
+		select: option,
+		reply_id: props.item?.data?.reply_id,
+	});
+	if (res.json_ok) {
+		activeOption.value = option;
+	}
+};
+
+
+</script>
+<style scoped lang="scss"></style>
diff --git a/src/components/chat/chatComponents/multiChat/index.ts b/src/components/chat/chatComponents/multiChat/index.ts
new file mode 100644
index 0000000..329ea11
--- /dev/null
+++ b/src/components/chat/chatComponents/multiChat/index.ts
@@ -0,0 +1,6 @@
+import { MultiChatType } from '../../model/types';
+import Select from './Select.vue';
+
+export const multiChatTypeMapCom = {
+	[MultiChatType.Select]: Select,
+};
diff --git a/src/components/chat/hooks/useScrollLoad.ts b/src/components/chat/hooks/useScrollLoad.ts
index 4a8b0ec..63be29d 100644
--- a/src/components/chat/hooks/useScrollLoad.ts
+++ b/src/components/chat/hooks/useScrollLoad.ts
@@ -1,7 +1,7 @@
 import moment from 'moment';
 import { Ref, ShallowRef, computed, nextTick, onBeforeUnmount, ref, unref } from 'vue';
 import { LOAD_CHAT_LIMIT } from '../constants';
-import { AnswerType, ChatContent, ChatMessage, RoleEnum, StepEnum, StepItem } from '../model/types';
+import { AnswerType, ChatContent, ChatMessage, MultiChatType, RoleEnum, StepEnum, StepItem } from '../model/types';
 import { GetHistoryAnswer, QueryHistoryDetail, getShareChatJsonByPost } from '/@/api/ai/chat';
 import router from '/@/router';
 import { isSharePage } from '/@/stores/chatRoom';
@@ -22,14 +22,29 @@
 	return {
 		status: StepEnum.Success,
 		title: processItem.value,
-	};
+	} as StepItem;
 };
 export const convertProcessToStep = (process: any[]) => {
-	const stepList = (process ?? []).map<StepItem>((item) => {
-		return convertProcessItem(item);
-	});
+	const stepList = (process ?? []).reduce((preVal, curVal) => {
+		if (curVal.mode === 'question') {
+			const last = preVal.at(-1);
+			if (!last.subStep) {
+				last.subStep = [];
+			}
+			const sub = {
+				data: curVal.value,
+				type: MultiChatType.Select,
+			};
+			last.subStep.push(sub);
+		} else {
+			const cur = convertProcessItem(curVal);
+			preVal.push(cur);
+		}
+		return preVal;
+	}, []);
 	return stepList;
 };
+
 /**
  * 婊氬姩鍔犺浇鏁版嵁
  * @returns
diff --git a/src/components/chat/model/types.ts b/src/components/chat/model/types.ts
index 3212f7e..90ffaa1 100644
--- a/src/components/chat/model/types.ts
+++ b/src/components/chat/model/types.ts
@@ -54,22 +54,20 @@
 	role: RoleEnum;
 	content?: ChatContent;
 	state?: null | '1' | '0';
-	sectionAId?:string,
-	createTime?:string,
-	stepList?:StepItem[],
-	stepIsShow?:boolean,
-	isStopMsg?:boolean,
+	sectionAId?: string;
+	createTime?: string;
+	stepList?: StepItem[];
+	stepIsShow?: boolean;
+	isStopMsg?: boolean;
 	/** @description 鏄惁琚�夋嫨鍒嗕韩 */
-	isChecked:boolean,
-	conclusion?:any[]
+	isChecked: boolean;
+	conclusion?: any[];
 }
 
 export const roleImageMap = {
 	[RoleEnum.user]: userPic,
 	[RoleEnum.assistant]: assistantPic,
 };
-
-
 
 export const enum StepEnum {
 	Loading,
@@ -81,10 +79,18 @@
 	[StepEnum.Success]: 'process',
 	[StepEnum.Error]: 'process',
 };
+export const enum MultiChatType {
+	Select = 'select',
+}
+type SubStep = {
+	data:any;
+	type: MultiChatType.Select;
+};
 
 export type StepItem = {
 	title: string;
 	status: StepEnum;
 	// 娑堣�楁椂闂�
-	ms?:string | number;
-};
\ No newline at end of file
+	ms?: string | number;
+	subStep?: SubStep[];
+};
diff --git a/vite.config.ts b/vite.config.ts
index c8bccb9..badea13 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -58,7 +58,7 @@
 			host: '0.0.0.0',
 			port: env.VITE_PORT as unknown as number,
 			open: JSON.parse(env.VITE_OPEN),
-			hmr: false,
+			hmr: true,
 		},
 		build: {
 			// outDir: 'dist/' + mode.mode,

--
Gitblit v1.9.3