wujingjing
2025-04-13 ad747a1fba37c9ea63dab1351ce22bc1d5802d4e
src/components/chat/components/playBar/hook/useDigitalHuman.ts
@@ -1,22 +1,46 @@
import { nextTick, onDeactivated, onMounted, ref } from 'vue';
import { SignJWT } from 'jose';
import { nextTick, onDeactivated, onMounted, ref } from 'vue';
import axios from 'axios';
import { ElMessage } from 'element-plus';
import { markdownToTxt } from 'markdown-to-txt';
import './libs/duix.js';
import { questionStreamByPost } from '/@/api/ai/chat';
import { activeGroupType, activeRoomId } from '/@/stores/chatRoom';
import { markdownToTxt } from 'markdown-to-txt';
import type { QuestionLifecycle } from '../../../types';
export type UseDigitalHumanProps = {
   container: string;
   autoSendMessage: (question: string, lifecycleCall?: QuestionLifecycle) => void;
};
export const getKnowledgePlainText = (item) => {
   let result = '';
   const knowledgeText = item.knowledge.reduce((acc, cur) => {
      const mdText = cur.answer;
      const linkText = cur.metadata?.Title;
      if (linkText) {
         return `${mdText}\n\n${linkText}`;
      }
      return acc + mdText;
   }, '');
   // const conclusionText =
   //    item.conclusion
   //       ?.filter((item) => !!item.report)
   //       .map((item) => item.report)
   //       .join('\n\n') ?? '';
   // result += knowledgeText + conclusionText;
   result = knowledgeText;
   return markdownToTxt(result);
};
export const useDigitalHuman = (props: UseDigitalHumanProps) => {
   const { container } = props;
   const { container, autoSendMessage } = props;
   const digitalHumanWidth = '240px';
   const duixConfig = {
      appId: '1356792813207031808',
      appKey: '659b068e-900c-4fe5-bb96-3ca70fe0aae4',
      sign: '',
      conversationId: '1909088110274277378',
      conversationId: '1911336603251347458',
      /** @description 过期时间(小时) */
      expired: 12,
   };
@@ -30,6 +54,32 @@
      digitalHumanIsShow.value = false;
      resetDuixStatus();
   };
   /**
    * 检查数字人是否可用
    */
   const checkIsUseable = async () => {
      const config = {
         method: 'get',
         url: `https://duix.guiji.ai/duix-openapi-v2/v1/getconcurrentNumber?appId=${duixConfig.appId}`,
         headers: {
            priority: 'u=1, i',
            sig: duixConfig.sign,
         },
      };
      const response = await axios(config);
      const data = response.data.data;
      const total = data.totalConcurrentNumber;
      const user = data.userConcurrentNumber;
      if (total === null || total === 0) {
         return false;
      }
      if (total !== null && total === user) {
         return false;
      }
      return true;
   };
   const resetDuixStatus = () => {
      humanIsLoading.value = true;
@@ -37,25 +87,6 @@
      // isSpeaking.value = false;
      digitalHumanIsShow.value = false;
      duix?.stop();
   };
   const getPlainText = (item) => {
      let result = '';
      const knowledgeText = item.knowledge.reduce((acc, cur) => {
         const mdText = cur.answer;
         const linkText = cur.metadata?.Title;
         if (linkText) {
            return `${mdText}\n\n${linkText}`;
         }
         return acc + mdText;
      }, '');
      // const conclusionText =
      //    item.conclusion
      //       ?.filter((item) => !!item.report)
      //       .map((item) => item.report)
      //       .join('\n\n') ?? '';
      // result += knowledgeText + conclusionText;
      result = knowledgeText;
      return markdownToTxt(result);
   };
   let isWaitingSpeak = false;
@@ -67,6 +98,19 @@
      duix.speak({
         content,
      });
   };
   const startDuix = () => {
      const conversationId = duixConfig.conversationId; // duix平台会话id
      duix
         .start({ conversationId, openAsr: true, wipeGreen: true })
         .then((res) => {
            console.info('start', res);
         })
         .catch((err) => {
            console.error('start error', err);
         });
   };
   const initDuix = () => {
@@ -81,9 +125,7 @@
      duix.on('intialSucccess', () => {
         console.info('intialSucccess');
         // 此时初始化成功,可调用start
         duix.start({ conversationId, openAsr: true,wipeGreen:true }).then((res) => {
            console.info('start', res);
         });
         startDuix();
      });
      duix.on('bye', (data) => {
         console.info('bye', data);
@@ -110,6 +152,7 @@
      duix.on('speakEnd', (data) => {
         if (!isWaitingSpeak) {
            isReceiveRes.value = false;
            duix.openAsr().then((...a) => {});
         }
      });
      duix.on('speakSection', (data) => {
@@ -123,45 +166,30 @@
         if (isReceiveRes.value) {
            return;
         }
         duix.closeAsr().then((...a) => {});
         let hasResult = false;
         isReceiveRes.value = true;
         try {
            isWaitingSpeak = true;
            duix.speak({
               content: '已收到您的问题,正在思考中...请稍等',
            });
            questionStreamByPost(
               {
                  question: data,
                  history_group_id: activeRoomId.value,
                  raw_mode: false,
                  group_type: activeGroupType.value,
                  is_digital_human: true,
               },
               (chunkRes) => {
                  if (chunkRes.mode === 'result' && chunkRes.value?.answer_type === 'knowledge') {
                     const plainText = getPlainText(chunkRes.value);
                     hasResult = true;
                     speakContent(plainText);
                  } else if (!chunkRes.value?.json_ok && chunkRes.value?.err_code === 'MESSAGE') {
                     if (hasResult) return;
                     hasResult = true;
                     speakContent(chunkRes.value.json_msg);
                  }
         isWaitingSpeak = true;
         duix.speak({
            content: '已收到您的问题,正在思考中...请稍等',
         });
                  if (chunkRes.mode === 'finish') {
                     if (!hasResult) {
                        speakContent('暂时无法口头描述你所说的问题');
                     } else {
                        hasResult = false;
                     }
                     // isReceiveRes.value = false;
         let content = '';
         try {
            autoSendMessage(data, {
               receiveText: (text: string) => {
                  content += text;
               },
               finish: () => {
                  if (!content) {
                     speakContent('暂时无法口头描述你所说的问题');
                  } else {
                     speakContent(content);
                  }
               }
            );
               },
            });
         } catch (error) {
            console.error(error);
            isReceiveRes.value = false;
         }
      });
@@ -180,20 +208,23 @@
   let hasInitDuix = false;
   let duix: any;
   const openDigitalHuman = () => {
   const openDigitalHuman = async () => {
      duixConfig.sign = await createSig(duixConfig.appId, duixConfig.appKey, 60 * 60 * duixConfig.expired);
      const isUsable = await checkIsUseable();
      if (!isUsable) {
         ElMessage.warning('"资源占用中,请检查后再试~"');
         return;
      }
      digitalHumanIsShow.value = true;
      nextTick(async () => {
         duixConfig.sign = await createSig(duixConfig.appId, duixConfig.appKey, 60 * 60 * duixConfig.expired);
      nextTick(() => {
         if (!hasInitDuix) {
            hasInitDuix = true;
            duix = new DUIX();
            initDuix();
         } else {
            duix.start({ conversationId: duixConfig.conversationId, openAsr: true }).then((res) => {
               console.info('start', res);
            });
            startDuix();
         }
      });
   };
@@ -226,5 +257,6 @@
      isHumanTalking: isReceiveRes,
      closeDigitalHuman,
      humanIsLoading,
      digitalHumanWidth,
   };
};