123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- <template>
- <div class="levitatedSphere" v-show="show">
- <div class="ls_hello" v-if="showIndex == 0">
- <el-image
- style="width: 100%; height: 100%"
- v-show="aiStatus == 1"
- :src="require('../../../assets/icon/course/aiTalk.svg')"
- fit="fill"
- ></el-image>
- <el-image
- style="width: 100%; height: 100%"
- v-show="aiStatus == 2"
- :src="require('../../../assets/icon/course/aiVanish.svg')"
- fit="fill"
- ></el-image>
- <el-image
- style="width: 100%; height: 100%"
- v-show="aiStatus == 0"
- :src="require('../../../assets/icon/course/aiWait.svg')"
- fit="fill"
- ></el-image>
- </div>
- <div
- class="ls_text"
- :style="{
- width: userText || aiText || showTextIndex == 2 ? '300px' : '0px'
- }"
- >
- <div class="ls_t_ai" v-if="[0, 2].includes(showTextIndex)">
- <span
- v-if="[0].includes(showTextIndex)"
- v-html="htmlContent(aiText)"
- ></span>
- <span v-if="[2].includes(showTextIndex)">正在组织语言...</span>
- </div>
- <div class="ls_t_user" v-if="[1].includes(showTextIndex)">
- {{ userText }}
- </div>
- </div>
- <!-- 录音转文字 -->
- <iframe
- allow="camera *; microphone *;display-capture;midi;encrypted-media;"
- src="https://beta.cloud.cocorobo.cn/browser/public/index.html"
- ref="iiframe"
- v-show="false"
- ></iframe>
- <!-- 文字转语音-->
- <iframe
- allow="camera *; microphone *;display-capture;midi;encrypted-media;"
- src="https://beta.cloud.cocorobo.cn/browser/public/index1.html"
- ref="iiframe2"
- v-show="false"
- ></iframe>
- </div>
- </template>
- <script>
- import { v4 as uuidv4 } from "uuid";
- import MarkdownIt from "markdown-it";
- export default {
- data() {
- return {
- show: false,
- showIndex: 0, //0 :在说话 1 : 接收 2:待命
- aiStatus: 0,
- aiText: "您好,我是小可,有什么可以帮助您的?",
- userText: "",
- showTextIndex: 0, //0:ai,1:用户, 2:组织语言 3: 无
- timer: null,
- isOpen: false,
- userId: this.$route.query.userid,
- chatLoading: false,
- talkLoading: false,
- source: null,
- talkTextList: []
- };
- },
- computed: {
- htmlContent() {
- const md = new MarkdownIt();
- return _md => {
- return md.render(_md);
- };
- }
- },
- methods: {
- recordStart(_text) {
- // try {
- // this.$parent.changeRecordType(1);
- // return this.$message.success("已开启语音助手,请说“可可同学”来唤醒")
- if (this.isOpen)
- return this.$message.info("已开启语音助手,无需重复开启");
- let iiframe = this.$refs["iiframe"];
- iiframe.contentWindow.window.document.getElementById(
- "languageOptions"
- ).selectedIndex = 2; //普通话
- iiframe.contentWindow.testdoContinuousPronunciationAssessment();
- this.$message.success("已开启语音助手,请说“可可同学”来唤醒");
- this.$parent.changeRecordType(1);
- this.isOpen = true;
- iiframe.contentWindow.onRecognizedResult = e => {
- let _msg = e.privText;
- // let _msg = _text;
- console.log("👇");
- console.log(_msg);
- if (!_msg) return console.log("输出为空");
- if (_msg.indexOf("可可同学") != -1 && !this.show) {
- this.aiText = "您好,我是小可,有什么可以帮助您的?";
- this.aiStatus = 0;
- this.showIndex = 0;
- this.show = true;
- console.log("已唤醒");
- return;
- } else if (this.show == true) {
- if (this.showTextIndex == 2 || this.chatLoading || this.talkLoading) {
- return console.log("组织语言中");
- } else {
- this.showTextIndex = 1;
- this.aiText = "";
- this.userText += _msg;
- this.aiStatus = 1;
- if (this.timer) {
- clearTimeout(this.timer);
- this.timer = null;
- }
- this.timer = setTimeout(() => {
- if (this.userText.indexOf("关闭语音助手") != -1) {
- // return setTimeout(()=>{
- (this.show = false), (this.showTextIndex = 3);
- this.aiStatus = 2;
- this.aiText = "";
- this.userText = "";
- this.stopRecord();
- return;
- // },1000)
- }
- this.showTextIndex = 2;
- this.aiText = "";
- if (/计时(.+)分钟/.test(this.userText)) {
- // setTimeout(() => {
- let _number = this.userText.match(/计时(.+)分钟/)[1];
- let _time = 0;
- if (!/^\d+$/.test(_number)) {
- _time = this.chineseToNumber(_number) * 60;
- } else {
- _time = parseInt(_numberList[1]) * 60;
- }
- this.$emit("startTime", _time);
- this.aiStatus = 0;
- this.showTextIndex = 0;
- this.aiText =
- "好的,我已为您计时" +
- this.userText.match(/计时(.+)分钟/)[1] +
- "分钟。";
- this.userText = "";
- this.timer = setTimeout(() => {
- this.showTextIndex = 3;
- this.aiStatus = 2;
- this.aiText = "";
- this.userText = "";
- }, 3000);
- // }, 2000);
- } else {
- this.chatLoading = true;
- const _uuid = uuidv4();
- let params = {
- assistant_id: "f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b",
- userId: this.userId,
- message: this.userText,
- session_name: _uuid + "-qgt",
- uid: _uuid,
- file_ids: []
- };
- this.ajax
- // .post("https://claude3.cocorobo.cn/chat", params)
- // .post("https://gpt4.cocorobo.cn/chat", params)
- .post(
- "https://gpt4.cocorobo.cn/ai_agent_park_chat_new",
- params
- )
- .then(res => {
- if (res.data.FunctionResponse.result == "发送成功") {
- this.userText = "";
- } else {
- // this.$message.warning(res.data.FunctionResponse.result);
- console.log(res.data.FunctionResponse.result);
- this.chatLoading = false;
- this.aiStatus = 0;
- this.showTextIndex = 0;
- this.aiText = "对不起,我无法理解您的问题,请重新提问";
- this.timer = setTimeout(() => {
- this.showTextIndex = 3;
- this.aiStatus = 2;
- this.aiText = "";
- this.userText = "";
- }, 3000);
- }
- })
- .catch(e => {
- console.log(e);
- this.chatLoading = false;
- this.aiStatus = 0;
- this.showTextIndex = 0;
- this.aiText = "对不起,我无法理解您的问题,请重新提问";
- this.timer = setTimeout(() => {
- this.showTextIndex = 3;
- this.aiStatus = 2;
- this.aiText = "";
- this.userText = "";
- }, 3000);
- });
- // 通过流获取ai对话数据
- this.getAtAuContent(_uuid);
- }
- }, 5000);
- }
- } else {
- console.log("不响应");
- }
- };
- // } catch (error) {
- // console.log("ai录音报错👇");
- // console.log(error);
- // setTimeout(() => {
- // this.recordStart();
- // }, 1000);
- // }
- },
- stopRecord() {
- // this.$parent.changeRecordType(0);
- // this.$message.success("已关闭语音助手")
- // return
- let iiframe = this.$refs["iiframe"];
- iiframe.contentWindow.window.document
- .getElementById("scenarioStopButton")
- .click();
- // 录音借宿
- iiframe.contentWindow.onSessionStopped = (s, e) => {
- this.isOpen = false;
- this.show = false;
- this.showTextIndex = 3;
- this.$parent.changeRecordType(0);
- this.$message.success("已关闭语音助手");
- if (this.talkLoading) {
- this.$refs.iiframe2.contentWindow.closesynthesizer();
- }
- this.userText = "";
- this.aiText = "";
- };
- },
- chineseToNumber(chinese) {
- const chineseNumbers = {
- 零: 0,
- 一: 1,
- 二: 2,
- 三: 3,
- 四: 4,
- 五: 5,
- 六: 6,
- 七: 7,
- 八: 8,
- 九: 9,
- 十: 10,
- 百: 100,
- 千: 1000,
- 万: 10000,
- 亿: 100000000
- };
- let result = 0;
- let tempNum = 0; // 用于累积处理
- let sectionNum = 0; // 每个段的值
- for (let i = 0; i < chinese.length; i++) {
- const char = chinese[i];
- const num = chineseNumbers[char];
- if (num === undefined) {
- throw new Error(`Unexpected character: ${char}`);
- }
- if (
- num === 10 ||
- num === 100 ||
- num === 1000 ||
- num === 10000 ||
- num === 100000000
- ) {
- if (tempNum === 0) tempNum = 1; // 如果前面没有数,默认是1
- tempNum *= num;
- if (num === 10000 || num === 100000000) {
- sectionNum += tempNum;
- result += sectionNum;
- tempNum = 0;
- sectionNum = 0;
- }
- } else {
- tempNum += num;
- }
- }
- result += sectionNum + tempNum;
- return result;
- },
- removeMarkdown(text) {
- return text
- .replace(/[#*_~`>+\-]/g, "") // 移除 #、*、_、~、`、>、+、- 符号
- .replace(/!\[.*?\]\(.*?\)/g, "") // 移除图片
- .replace(/\[.*?\]\(.*?\)/g, "") // 移除链接
- .replace(/```[\s\S]*?```/g, "") // 移除代码块(不使用 s 标志)
- .replace(/`[^`]*`/g, "") // 移除行内代码
- .replace(/\d+\./g, "") // 移除有序列表
- .replace(/^\s*[-*+]\s+/gm, "") // 移除无序列表
- .replace(/\s+/g, " ") // 将多个空白字符替换为一个空格
- .trim(); // 去除字符串两端的空白字符
- },
- getAtAuContent(_uid) {
- this.source = new EventSource(
- `https://gpt4.cocorobo.cn/question/${_uid}`
- );
- //http://gpt4.cocorobo.cn:8011/question/ https://gpt4.cocorobo.cn/question/
- let _allText = "";
- let _mdText = "";
- let _talkText = "";
- // let _talkIndex = 0;
- // const md = new MarkdownIt();
- this.source.onmessage = _e => {
- let _eData = JSON.parse(_e.data);
- if (_eData.content.replace("'", "").replace("'", "") == "[DONE]") {
- let _result = [];
- if ("result" in _eData) {
- _result = _eData.result;
- for (let i = 0; i < _result.length; i++) {
- _mdText = _mdText.replace(_result[i].text, _result[i].fileName);
- }
- }
- _mdText = _mdText.replace("_", "");
- this.aiText = _mdText;
- if (_talkText != "") {
- let _resultText = this.removeMarkdown(_talkText);
- this.talkTextList.push(_resultText);
- _talkText = "";
- if (!this.talkLoading) this.talkText();
- }
- this.chatLoading = false;
- this.source.close();
- } else {
- // _talkIndex+=1;
- let _text = _eData.content.replace("'", "").replace("'", "");
- if (_allText == "") {
- _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
- _talkText += _text.replace(/^\n+/, "");
- } else {
- _allText += _text;
- _talkText += _text;
- }
- `~`;
- _mdText = _allText + "_";
- _mdText = _mdText.replace(/\\n/g, "\n");
- _mdText = _mdText.replace(/\\/g, "");
- if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
- this.aiText = _mdText;
- this.showTextIndex = 0;
- if (/[,。:;?!)]/.test(_talkText)) {
- let _resultText = this.removeMarkdown(_talkText);
- this.talkTextList.push(_resultText);
- _talkText = "";
- if (!this.talkLoading) this.talkText();
- }
- // if(_talkIndex==10){
- // _talkIndex = 0;
- // this.talkTextList.push(_talkText)
- // _talkText = "";
- // if(!this.talkLoading)this.talkText();
- // }
- }
- };
- },
- talkText() {
- let _text = this.talkTextList.shift();
- let _talkTextIiframe2 = this.$refs.iiframe2;
- if (_text) {
- this.talkLoading = true;
- if (this.timer) {
- clearTimeout(this.timer);
- this.timer = null;
- }
- // console.log(`👉转语音:${_text}`);
- // setTimeout(()=>{
- // this.talkText();
- // },2000)
- _talkTextIiframe2.contentWindow.texttospeech(_text, this.talkText);
- } else {
- console.log("👉转语音结束👈");
- _talkTextIiframe2.contentWindow.closesynthesizer();
- this.talkLoading = false;
- // this.timer = setTimeout(() => {
- // this.showTextIndex = 3;
- // this.aiStatus = 2;
- // this.aiText = "";
- // this.userText = "";
- // this.time = null;
- // }, 5000);
- }
- }
- },
- mounted() {
- // // this.recordStart()
- // setTimeout(()=>{
- // this.recordStart("可可同学。")
- // setTimeout(()=>{
- // this.recordStart("世界上最大的火山是什么。")
- // setTimeout(()=>{
- // this.recordStart("位于哪里。他温度怎么样。")
- // },2000)
- // },2000)
- // },2000)
- }
- };
- </script>
- <style scoped>
- .levitatedSphere {
- position: fixed;
- width: auto;
- height: auto;
- top: 20px;
- right: 10px;
- z-index: 9999;
- display: flex;
- }
- .ls_hello {
- width: 80px;
- height: 80px;
- position: absolute;
- top: 0;
- right: 0;
- }
- .ls_text {
- position: absolute;
- right: 100px;
- top: 20px;
- max-width: 300px;
- display: flex;
- justify-content: flex-end;
- }
- .ls_t_ai {
- padding: 12px;
- width: auto;
- height: auto;
- border-radius: 12px 0px 12px 12px;
- background: #00000099;
- color: #fff;
- }
- .ls_t_user {
- padding: 12px;
- width: auto;
- height: auto;
- border-radius: 12px 12px 12px 12px;
- background: #00000099;
- color: #fff;
- }
- </style>
|