From 5fb58c10b2bb44b3f2d3bdab4d7a6619271e2bbf Mon Sep 17 00:00:00 2001
From: wujingjing <gersonwu@qq.com>
Date: 星期三, 02 四月 2025 17:51:39 +0800
Subject: [PATCH] smallScreenClick

---
 src/components/chat/hooks/useAssistantContentOpt.ts |  147 ++++++++++++++++++++++++++++++++++++------------
 1 files changed, 109 insertions(+), 38 deletions(-)

diff --git a/src/components/chat/hooks/useAssistantContentOpt.ts b/src/components/chat/hooks/useAssistantContentOpt.ts
index d829180..e95a358 100644
--- a/src/components/chat/hooks/useAssistantContentOpt.ts
+++ b/src/components/chat/hooks/useAssistantContentOpt.ts
@@ -1,34 +1,55 @@
 import { ElMessage } from 'element-plus';
-import type { ComputedRef, Ref } from 'vue';
-import { computed, nextTick, ref } from 'vue';
-import useClipboard from 'vue-clipboard3';
-import type { ChatMessage } from '../model/types';
+import { computed, nextTick, onDeactivated, ref } from 'vue';
+// import useClipboard from 'vue-clipboard3';
+import { onClickOutside, useClipboard } from '@vueuse/core';
+import markdownToTxt from 'markdown-to-txt';
 import { AnswerState, AnswerType, RoleEnum } from '../model/types';
 import { SetHistoryAnswerState } from '/@/api/ai/chat';
-import { useClickOther } from '/@/hooks/useClickOther';
-import { onClickOutside } from '@vueuse/core';
-import {  isSharePage } from '/@/stores/chatRoom';
-
+import { isSharePage } from '/@/stores/chatRoom';
+import BrowserSpeechSynthesis from '/@/utils/speech/synthesis';
 export type AssistantContentOptOption = {
 	sendChatMessage: any;
-	displayMessageList: ComputedRef<ChatMessage[]>;
 };
+const activeSpeakItem = ref(null);
 
 export const useAssistantContentOpt = (option: AssistantContentOptOption) => {
-	const { sendChatMessage, displayMessageList } = option;
-	const { toClipboard } = useClipboard();
-	const preQuestion = ref(null);
+	const isSpeaking = ref(false);
+	const { sendChatMessage } = option;
+	const { copy } = useClipboard();
 
 	const copyClick = (item) => {
-		const type = item.content.type;
-		let text = '';
-		if (type === AnswerType.Knowledge) {
-			text = item.content.values?.map((item) => item.answer).join('\n\n') ?? '';
-		} else {
-			text = item.content.values;
-		}
+		const isText = checkIsText(item);
+		if (!isText) return;
+		const text = getPlainText(item);
 		ElMessage.success('澶嶅埗鎴愬姛');
-		toClipboard(text);
+		copy(text);
+	};
+
+	const checkIsText = (item) => {
+		const isText = item?.content?.values?.some((item) => item?.content?.type === AnswerType.Knowledge);
+		return isText;
+	};
+
+	const getPlainText = (item) => {
+		const knowledgeText = item.content.values
+			.filter((item) => {
+				const type = item?.content?.type;
+				return type === AnswerType.Knowledge;
+			})
+			.reduce((acc, cur) => {
+				const answer = cur?.content?.values
+					?.map((item) => {
+						const mdText = item.answer;
+						const linkText = item.metadata?.Title;
+						if (linkText) {
+							return `${mdText}\n\n${linkText}`;
+						}
+						return mdText;
+					})
+					.join('\n\n');
+				return acc + answer;
+			}, '');
+		return markdownToTxt(knowledgeText);
 	};
 
 	const likeClick = async (item) => {
@@ -38,7 +59,6 @@
 			answer_state: toSetState,
 		});
 		item.state = toSetState;
-		
 	};
 
 	const unLikeClick = async (item) => {
@@ -48,8 +68,6 @@
 			answer_state: toSetState,
 		});
 		item.state = toSetState;
-
-	
 	};
 	const feedbackPosition = ref({
 		x: 0,
@@ -69,10 +87,15 @@
 		feedbackIsShow.value = true;
 		nextTick(() => {
 			feedbackPosition.value = {
-				x: -feedbackPanelRef.value[index].$el.clientWidth + offsetX,
-				y: -feedbackPanelRef.value[index].$el.clientHeight + offsetY,
+				x: -feedbackPanelRef.value[index]?.$el.clientWidth + offsetX,
+				y: -feedbackPanelRef.value[index]?.$el.clientHeight + offsetY,
 			};
 		});
+	};
+
+	const isItemSpeaking = (item) => {
+		const checkSpeak = activeSpeakItem.value === item && isSpeaking.value;
+		return checkSpeak;
 	};
 
 	onClickOutside(
@@ -90,15 +113,9 @@
 	// 		feedbackContent.value = '';
 	// 	}
 	// );
-	const showAskMore = computed(() => {
-		if (!displayMessageList.value || displayMessageList.value.length === 0) return false;
-		const last = displayMessageList.value.at(-1);
-		const isShow = last?.role === RoleEnum.assistant && last?.content?.values && last.content?.askMoreList?.length > 0;
-		return isShow && !isSharePage ;
-	});
 
 	const showFixQuestion = (item) => {
-		const isShow = item?.role === RoleEnum.assistant && item?.content?.values && item.content?.origin?.err_json?.fix_question;
+		const isShow = item?.role === RoleEnum.assistant && item.content?.origin?.sample_question?.length > 0 && !isSharePage.value;
 		return isShow;
 	};
 	const askMoreClick = (item) => {
@@ -107,17 +124,69 @@
 	};
 
 	const fixQuestionClick = (item, originData) => {
-		if (!item.question) return;
-		preQuestion.value = originData?.question;
+		if (!item) return;
+		// preQuestion.value = originData?.question;
 		try {
 			sendChatMessage({
 				type: AnswerType.Text,
-				values: item.question,
+				values: item,
 			});
 		} finally {
-			preQuestion.value = null;
+			// preQuestion.value = null;
 		}
 	};
+
+	let isEnterStop = false;
+
+	const resetSpeak = () => {
+		isSpeaking.value = false;
+		isEnterStop = false;
+		const instance = BrowserSpeechSynthesis.getInstance();
+		instance.cancel();
+		activeSpeakItem.value = null;
+	};
+
+	const speechClick = (item) => {
+		if (!checkIsText(item)) return;
+		if (activeSpeakItem.value !== item) {
+			resetSpeak();
+		}
+		isSpeaking.value = !isSpeaking.value;
+		if (isSpeaking.value) {
+			startSpeechClick(item);
+		} else {
+			stopSpeechClick();
+		}
+	};
+
+	const startSpeechClick = (item) => {
+		activeSpeakItem.value = item;
+
+		const instance = BrowserSpeechSynthesis.getInstance();
+		instance.onEnd(() => {
+			resetSpeak();
+		});
+		if (isEnterStop) {
+			instance.resume();
+		} else {
+			const text = getPlainText(item);
+			if (text) {
+				instance.speak(text);
+			}
+		}
+		isEnterStop = false;
+	};
+
+	const stopSpeechClick = () => {
+		isEnterStop = true;
+		const instance = BrowserSpeechSynthesis.getInstance();
+		instance.pause();
+	};
+
+	onDeactivated(() => {
+		const instance = BrowserSpeechSynthesis.getInstance();
+		instance.cancel();
+	});
 
 	return {
 		copyClick,
@@ -132,8 +201,10 @@
 		feedbackClick,
 		askMoreClick,
 		fixQuestionClick,
-		preQuestion,
-		showAskMore,
 		showFixQuestion,
+		speechClick,
+		isSpeaking,
+		isItemSpeaking,
+		checkIsText,
 	};
 };

--
Gitblit v1.9.3