|
@@ -1,559 +1,2141 @@
|
|
|
<template>
|
|
|
- <div class="chat" v-loading="loading">
|
|
|
- <div class="c_chat" ref="chatRef">
|
|
|
- <div class="c_c_item" v-for="item in chatList" :key="item.uid">
|
|
|
- <div class="c_c_i_user" v-if="item.content">
|
|
|
- <div class="c_c_i_u_message">
|
|
|
- <div class="c_c_i_u_m_top">
|
|
|
- <span class="chatTime">{{ item.createtime }}</span>
|
|
|
- <span>科科</span>
|
|
|
- </div>
|
|
|
- <div class="c_c_i_u_m_bottom">
|
|
|
- <span class="coptText" @click="copyText(item.aiContent)"></span>
|
|
|
- <div
|
|
|
- class="c_c_i_u_m_content chatContent"
|
|
|
- v-html="item.content"
|
|
|
- ></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="c_c_i_u_avatar">
|
|
|
- <el-avatar
|
|
|
- style="width: 100%; height: 100%"
|
|
|
- :src="require('../../../../assets/icon/pblCourse/userAvatar.png')"
|
|
|
- fit="fit"
|
|
|
- ></el-avatar>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="c_c_i_ai">
|
|
|
- <div class="c_c_i_ai_avatar">
|
|
|
- <el-avatar
|
|
|
- style="width: 100%; height: 100%"
|
|
|
- :src="
|
|
|
- require('../../../../assets/icon/pblCourse/aiTeacherAvatar.png')
|
|
|
- "
|
|
|
- fit="fit"
|
|
|
- ></el-avatar>
|
|
|
- </div>
|
|
|
- <div class="c_c_i_ai_message">
|
|
|
- <div class="c_c_i_ai_m_top">
|
|
|
- <span>小可老师</span>
|
|
|
- <span class="chatTime">{{ item.createtime }}</span>
|
|
|
- </div>
|
|
|
- <div class="c_c_i_ai_m_bottom">
|
|
|
- <div
|
|
|
- v-loading="item.loading"
|
|
|
- class="c_c_i_ai_m_content chatContent"
|
|
|
- v-html="item.aiContent"
|
|
|
- ></div>
|
|
|
- <span class="coptText" @click="copyText(item.aiContent)"></span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <!-- <div class="c_controls">
|
|
|
- <span class="c_controls_item" @click="clearChat">清空对话</span>
|
|
|
- </div> -->
|
|
|
- <div class="c_bottom" v-loading="chatLoading">
|
|
|
- <!-- <div class="c_b_record">
|
|
|
- <span></span>
|
|
|
- </div> -->
|
|
|
- <div class="c_b_inputArea">
|
|
|
- <el-input
|
|
|
- class="c_b_input"
|
|
|
- @keyup.enter.native="send()"
|
|
|
- v-model="textValue"
|
|
|
- >
|
|
|
- </el-input>
|
|
|
- <!-- <span></span> -->
|
|
|
- </div>
|
|
|
- <div class="c_b_send" @click="send">
|
|
|
- <span></span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div class="chatArea" v-loading="loading">
|
|
|
+ <div class="m-operation">
|
|
|
+ <div>实时转录</div>
|
|
|
+ <div>{{createTime}}</div>
|
|
|
+ </div>
|
|
|
+ <div class="titBar">
|
|
|
+ <div class="titBarLeft">
|
|
|
+ <div
|
|
|
+ @click="cutBar(index)"
|
|
|
+ :class="pageStatus == index ? 'titBarBorder' : ''"
|
|
|
+ v-for="(i, index) in titBarList"
|
|
|
+ :key="index + 'a'"
|
|
|
+ >
|
|
|
+ <img :src="pageStatus == index ? i.ico : i.ico1" alt="" />{{
|
|
|
+ i.title
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="titBarRig">
|
|
|
+ <!-- <img src="@/assets/icon/classroomObservation/put.png" alt="" />
|
|
|
+ <div style="cursor: pointer">收起</div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-top">
|
|
|
+ <!-- 开始页面 -->
|
|
|
+ <startPage
|
|
|
+ v-show="showIndexPage"
|
|
|
+ @startTape="recordedStart"
|
|
|
+ @uploadTape="uploadRecording"
|
|
|
+ :uploadFileLoading="uploadFileLoading"
|
|
|
+ />
|
|
|
+ <!-- 原文速递 -->
|
|
|
+ <transcription
|
|
|
+ v-show="pageStatus == 1 && !showIndexPage"
|
|
|
+ :showGetTextLoading="showGetTextLoading"
|
|
|
+ :data="transcriptionData"
|
|
|
+ >
|
|
|
+ <!-- <el-button
|
|
|
+ style="position: absolute; bottom: 10px; right: 20px"
|
|
|
+ type="primary"
|
|
|
+ @click.stop="saveEditorBar(true)"
|
|
|
+ >保存</el-button
|
|
|
+ > -->
|
|
|
+ </transcription>
|
|
|
+ <!-- ai对话 -->
|
|
|
+ <tape
|
|
|
+ ref="tapeRef"
|
|
|
+ :aiNameList="roleList"
|
|
|
+ :chatData="chatList"
|
|
|
+ v-show="pageStatus == 0 && !showIndexPage"
|
|
|
+ :loading="chatLoading"
|
|
|
+ />
|
|
|
+ <!-- <div class="t-t-m-Item" v-show="cardStatus==1"> -->
|
|
|
+ <EditorBar
|
|
|
+ class="editorBar"
|
|
|
+ :showGetTextLoading="showGetTextLoading"
|
|
|
+ v-model="editorBarData.content"
|
|
|
+ v-if="pageStatus == 2 && !showIndexPage && editorBarData.type == '0'"
|
|
|
+ v-loading="uploadFileLoading"
|
|
|
+ @change="changeEditor"
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ style="position: absolute; bottom: 20px; right: 20px; z-index: 10002"
|
|
|
+ type="primary"
|
|
|
+ @click.stop="saveEditorBar(true)"
|
|
|
+ >保存</el-button
|
|
|
+ >
|
|
|
+ </EditorBar>
|
|
|
+ <iframe
|
|
|
+ ref="viframe"
|
|
|
+ v-if="
|
|
|
+ pageStatus == 2 &&
|
|
|
+ !showIndexPage &&
|
|
|
+ editorBarData.type == '1' &&
|
|
|
+ /\.(xlsx|doc|docx)$/i.test(editorBarData.url)
|
|
|
+ "
|
|
|
+ style="width: 100%; height: 100%; border: none"
|
|
|
+ v-loading="uploadFileLoading"
|
|
|
+ :src="
|
|
|
+ 'https://view.officeapps.live.com/op/view.aspx?src=' +
|
|
|
+ encodeURIComponent(editorBarData.url)
|
|
|
+ "
|
|
|
+ ></iframe>
|
|
|
+ <vpdf
|
|
|
+ style="width: 100%; height: 100%; border: none"
|
|
|
+ :pdfUrl="editorBarData.url"
|
|
|
+ v-if="
|
|
|
+ pageStatus == 2 &&
|
|
|
+ !showIndexPage &&
|
|
|
+ editorBarData.type == '1' &&
|
|
|
+ /\.(pdf)$/i.test(editorBarData.url)
|
|
|
+ "
|
|
|
+ />
|
|
|
+ <!-- </div> -->
|
|
|
+ </div>
|
|
|
+ <div class="ca-bottom">
|
|
|
+ <div class="ca-b-operation">
|
|
|
+ <div class="ca-b-o-header">
|
|
|
+ <div class="ca-b-o-h-left">
|
|
|
+ <!-- <div class="ca-b-o-h-l-select" @click.stop="changeAnalysis()">
|
|
|
+ <span class="ca-b-o-h-l-s-icon el-icon-collection"></span>
|
|
|
+ <div class="ca-b-o-h-s-l-text">课堂观察</div>
|
|
|
+ <span class="ca-b-o-h-s-l-icon2 el-icon-caret-top"></span>
|
|
|
+ </div> -->
|
|
|
+ <!--
|
|
|
+ <div class="ca-b-o-h-l-select" style="color: #3681fc">
|
|
|
+ <div
|
|
|
+ style="cursor: pointer"
|
|
|
+ class="ca-b-o-h-s-l-text"
|
|
|
+ @click.stop="languageShow = !languageShow"
|
|
|
+ >
|
|
|
+ {{ languageList.find((i) => i.label == languageRadio).lang }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="languageList"
|
|
|
+ v-click-outside="handleBlur"
|
|
|
+ v-if="languageShow"
|
|
|
+ >
|
|
|
+ <el-radio
|
|
|
+ v-for="(i, index) in languageList"
|
|
|
+ :key="index + 'lag'"
|
|
|
+ :class="i.label == languageRadio ? 'radioBg' : ''"
|
|
|
+ v-model.number="languageRadio"
|
|
|
+ :label.Num="i.label"
|
|
|
+ >{{ i.lang }}</el-radio
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="ca-b-o-h-l-btn"
|
|
|
+ @click.stop="uploadRecording()"
|
|
|
+ v-loading="uploadFileLoading"
|
|
|
+ >
|
|
|
+ <div class="ca-b-o-h-b-l-text">上传文件</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-h-right">
|
|
|
+ <div class="ca-b-o-h-r-radio">
|
|
|
+ <div
|
|
|
+ :class="
|
|
|
+ (index == 0 &&
|
|
|
+ (showIndexPage || [0, 1, 2].includes(controlsStatus))) ||
|
|
|
+ (index == 1 &&
|
|
|
+ !showIndexPage &&
|
|
|
+ ![0, 1, 2].includes(controlsStatus))
|
|
|
+ ? 'TapeCss'
|
|
|
+ : ''
|
|
|
+ "
|
|
|
+ class="tapeSty"
|
|
|
+ @click="cutTape(index)"
|
|
|
+ v-for="(i, index) in tapeList"
|
|
|
+ :key="index + 'b'"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ :src="
|
|
|
+ (index == 0 &&
|
|
|
+ (showIndexPage || [0, 1, 2].includes(controlsStatus))) ||
|
|
|
+ (index == 1 &&
|
|
|
+ !showIndexPage &&
|
|
|
+ ![0, 1, 2].includes(controlsStatus))
|
|
|
+ ? i.ico
|
|
|
+ : i.ico1
|
|
|
+ "
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- <span @click.stop="changeContinuousDialogue(!continuousDialogue)"
|
|
|
+ >连续对话</span
|
|
|
+ >
|
|
|
+ <el-switch
|
|
|
+ v-model="continuousDialogue"
|
|
|
+ active-color="#3681FC"
|
|
|
+ inactive-color="#b2bfc3"
|
|
|
+ >
|
|
|
+ </el-switch> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-main">
|
|
|
+ <div
|
|
|
+ class="ca-b-o-m-tape"
|
|
|
+ v-show="controlsStatus == 0"
|
|
|
+ @click.stop="recordedStart()"
|
|
|
+ v-loading="uploadFileLoading"
|
|
|
+ >
|
|
|
+ <span class="el-icon-microphone"></span>
|
|
|
+ <div class="ca-b-o-m-t-text">点击开始录音</div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ca-b-o-m-tapeTwo"
|
|
|
+ v-show="controlsStatus == 2"
|
|
|
+ v-loading="uploadFileLoading"
|
|
|
+ >
|
|
|
+ <mini-audio
|
|
|
+ v-if="audioUrl"
|
|
|
+ :audio-source="audioUrl"
|
|
|
+ class="audio_class"
|
|
|
+ ></mini-audio>
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ margin-left: 20px;
|
|
|
+ cursor: pointer;
|
|
|
+ background-color: #3681fc;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ "
|
|
|
+ @click="recordedStart()"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ style="width: 10px; height: 16px"
|
|
|
+ src="../../../../assets/icon/classroomObservation/mai1.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ca-b-o-m-inputAre"
|
|
|
+ v-show="controlsStatus == 3"
|
|
|
+ v-loading="textareaLoading"
|
|
|
+ >
|
|
|
+ <div class="ca-b-o-m-left">
|
|
|
+ <textarea
|
|
|
+ id="myTextarea"
|
|
|
+ ref="textareaRef"
|
|
|
+ min-rows="1"
|
|
|
+ max-rows="5"
|
|
|
+ v-model="textareaValue"
|
|
|
+ placeholder="在此输入您想了解的内容"
|
|
|
+ autosize="none"
|
|
|
+ @input="textareaChange"
|
|
|
+ @change="textareaChange"
|
|
|
+ @keydown="textareaKeydown"
|
|
|
+ ></textarea>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-m-right">
|
|
|
+ <!-- <span @click.stop="tapeSubmit()"></span> -->
|
|
|
+ <!-- <div :class="sendBtnDsiable ? 'ca-b-o-m-r-dsiableBtn' : ''">
|
|
|
+ 发送
|
|
|
+ </div> -->
|
|
|
+ <el-button
|
|
|
+ :disabled="textareaValue.trim().length == 0"
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ @click="send()"
|
|
|
+ >发送</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ ref="roleListRef"
|
|
|
+ v-click-outside="noShowRoleList"
|
|
|
+ class="ca_b_o_m_roleList"
|
|
|
+ v-if="showRoleList && choseRoleList.length != 0"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ 'ca_b_o_m_rl_item',
|
|
|
+ roleListIndex == index ? 'ca_b_o_m_rl_itemActive' : '',
|
|
|
+ ]"
|
|
|
+ v-for="(item, index) in choseRoleList"
|
|
|
+ :key="item.assistant_id"
|
|
|
+ @click="choseRole(item)"
|
|
|
+ @mouseover="() => (roleListIndex = index)"
|
|
|
+ >
|
|
|
+ <div class="ca_b-o_m_rl_i_top">
|
|
|
+ <el-avatar
|
|
|
+ size="medium"
|
|
|
+ :src="
|
|
|
+ item.headUrl
|
|
|
+ ? item.headUrl
|
|
|
+ : require('@/assets/icon/classroomObservation/aiAvatar.png')
|
|
|
+ "
|
|
|
+ ></el-avatar>
|
|
|
+ <div>
|
|
|
+ <div>{{ item.assistantName }}</div>
|
|
|
+ <span v-if="item.username">作者:{{ item.username }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca_b-o_m_rl_i_bottom">
|
|
|
+ <span>{{ item.description }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ca-b-o-m-TapeArea"
|
|
|
+ v-show="controlsStatus == 1"
|
|
|
+ v-loading="uploadFileLoading"
|
|
|
+ >
|
|
|
+ <div class="ca-b-o-m-i-left">
|
|
|
+ <img
|
|
|
+ style="height: 120%"
|
|
|
+ src="@/assets/icon/classroomObservation/isTape.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <div>
|
|
|
+ <div v-if="recordedForm.status == 1" style="color: #ee3e3e">
|
|
|
+ 录音中...
|
|
|
+ </div>
|
|
|
+ <div v-if="recordedForm.status == 2" style="color: #6b798e">
|
|
|
+ 已暂停...
|
|
|
+ </div>
|
|
|
+ <span>{{ recordedForm.time }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <img
|
|
|
+ style="height: 120%"
|
|
|
+ src="@/assets/icon/classroomObservation/tapetime.png"
|
|
|
+ alt=""
|
|
|
+ /> -->
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ width: 100px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div class="lyStart" @click="stopRecorded()">
|
|
|
+ <img
|
|
|
+ style="width: 12px; height: 12px"
|
|
|
+ src="@/assets/icon/classroomObservation/lyStart.svg"
|
|
|
+ alt=""
|
|
|
+ v-if="recordedForm.status == 1"
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ style="width: 12px; height: 12px"
|
|
|
+ src="@/assets/icon/classroomObservation/start.png"
|
|
|
+ alt=""
|
|
|
+ v-if="recordedForm.status == 2"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="lyStart" @click="finishRecorded()">
|
|
|
+ <img
|
|
|
+ style="width: 12px; height: 12px"
|
|
|
+ src="@/assets/icon/classroomObservation/lyStop.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="ca-b-o-m-left">
|
|
|
+ <textarea :value="textareaValue" autosize="none"></textarea>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-m-right">
|
|
|
+ <span @click.stop="tapeSubmit()"></span>
|
|
|
+ <div :class="sendBtnDsiable ? 'ca-b-o-m-r-dsiableBtn' : ''">
|
|
|
+ 发送
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </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>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+import startPage from "./startPage.vue";
|
|
|
+import transcription from "./transcription.vue";
|
|
|
+import tape from "./tape.vue";
|
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
+import Recorder from "js-audio-recorder";
|
|
|
import MarkdownIt from "markdown-it";
|
|
|
+import EditorBar from "./wangEnduit.vue";
|
|
|
+const lamejs = require("lamejs");
|
|
|
+import vpdf from "./vpdf";
|
|
|
+const recorder = new Recorder({
|
|
|
+ sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
|
|
|
+ sampleRate: 48000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
|
|
|
+ numChannels: 1, // 声道,支持 1 或 2, 默认是1
|
|
|
+ // compiling: false,(0.x版本中生效,1.x增加中) // 是否边录边转换,默认是false
|
|
|
+});
|
|
|
+
|
|
|
+// 绑定事件-打印的是当前录音数据
|
|
|
+// recorder.onprogress = function (params) {
|
|
|
+// console.log('--------------START---------------')
|
|
|
+// console.log('录音时长(秒)', params.duration);
|
|
|
+// console.log('录音大小(字节)', params.fileSize);
|
|
|
+// console.log('录音音量百分比(%)', params.vol);
|
|
|
+// console.log('当前录音的总数据([DataView, DataView...])', params.data);
|
|
|
+// console.log('--------------END---------------')
|
|
|
+// };
|
|
|
+
|
|
|
+// 自定义指令,用于处理点击外部区域的事件
|
|
|
+const clickOutside = {
|
|
|
+ bind(el, binding) {
|
|
|
+ // 在元素上绑定一个点击事件监听器
|
|
|
+ el.clickOutsideEvent = function (event) {
|
|
|
+ // 检查点击事件是否发生在元素的内部
|
|
|
+ if (!(el === event.target || el.contains(event.target))) {
|
|
|
+ // 如果点击事件发生在元素的外部,则触发指令绑定的方法,将点击的event数据传过去
|
|
|
+ binding.value(event);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 在文档上添加点击事件监听器
|
|
|
+ document.addEventListener("click", el.clickOutsideEvent);
|
|
|
+ },
|
|
|
+ unbind(el) {
|
|
|
+ // 在元素上解除点击事件监听器
|
|
|
+ document.removeEventListener("click", el.clickOutsideEvent);
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+const getFile = (url) => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ var credentials = {
|
|
|
+ accessKeyId: "AKIATLPEDU37QV5CHLMH",
|
|
|
+ secretAccessKey: "Q2SQw37HfolS7yeaR1Ndpy9Jl4E2YZKUuuy2muZR",
|
|
|
+ }; //秘钥形式的登录上传
|
|
|
+ window.AWS.config.update(credentials);
|
|
|
+ window.AWS.config.region = "cn-northwest-1"; //设置区域
|
|
|
+ let url2 = url;
|
|
|
+ let _url2 = "";
|
|
|
+ if (
|
|
|
+ url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
|
|
|
+ ) {
|
|
|
+ _url2 = url2.split(
|
|
|
+ "https://view.officeapps.live.com/op/view.aspx?src="
|
|
|
+ )[1];
|
|
|
+ } else {
|
|
|
+ _url2 = url2;
|
|
|
+ }
|
|
|
+ var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
|
|
|
+ let name = decodeURIComponent(
|
|
|
+ _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
|
|
|
+ );
|
|
|
+ var params = {
|
|
|
+ Bucket: "ccrb",
|
|
|
+ Key: name,
|
|
|
+ };
|
|
|
+ s3.getObject(params, function (err, data) {
|
|
|
+ if (err) {
|
|
|
+ console.log(err, err.stack);
|
|
|
+ resolve({ data: 1 });
|
|
|
+ } else {
|
|
|
+ const fileContent = data.Body.toString("utf-8");
|
|
|
+ resolve({ data: fileContent });
|
|
|
+ } // sxuccessful response
|
|
|
+ });
|
|
|
+ // axios({
|
|
|
+ });
|
|
|
+};
|
|
|
export default {
|
|
|
- data() {
|
|
|
- return {
|
|
|
- loading: false,
|
|
|
- chatLoading: false,
|
|
|
- userId: this.$route.query["userid"],
|
|
|
- chatList: [],
|
|
|
- textValue: ""
|
|
|
- };
|
|
|
- },
|
|
|
- methods: {
|
|
|
- // 发送消息
|
|
|
- send() {
|
|
|
- if (this.chatLoading || this.loading)
|
|
|
- return this.$message.info("请稍等...");
|
|
|
- if (!this.textValue.trim()) return this.$message.info("请输入内容");
|
|
|
- const _uuid = uuidv4();
|
|
|
- this.chatLoading = true;
|
|
|
- this.chatList.push({
|
|
|
- role: "user",
|
|
|
- content: `${this.textValue}`,
|
|
|
- uid: _uuid,
|
|
|
- AI: "AI",
|
|
|
- aiContent: "",
|
|
|
- oldContent: "",
|
|
|
- filename: "",
|
|
|
- index: this.chatList.length,
|
|
|
- createtime: new Date().toLocaleString().replaceAll("/", "-"),
|
|
|
- loading: true
|
|
|
- });
|
|
|
+ emits: ["updateFileId", "changeAudioUrl", "updateTranscription"],
|
|
|
+ props: {
|
|
|
+ tid: {
|
|
|
+ type: String,
|
|
|
+ require: true,
|
|
|
+ },
|
|
|
+ fileId: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ fileIdId: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ createTime:{
|
|
|
+ type:String,
|
|
|
+ default:new Date().toLocaleString().replaceAll('/','-')
|
|
|
+ },
|
|
|
+ },
|
|
|
+ components: {
|
|
|
+ startPage,
|
|
|
+ transcription,
|
|
|
+ tape,
|
|
|
+ EditorBar,
|
|
|
+ vpdf,
|
|
|
+ },
|
|
|
+ directives: {
|
|
|
+ "click-outside": clickOutside, // 注册自定义指令
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // continuousDialogue: true,
|
|
|
+ controlsStatus: 0, //0--点击开始录音 1--录音中 2--录音完毕预览 3--文字输入
|
|
|
+ pageStatus: 0, //0--ai对话 1--原文文稿 2--转录文稿
|
|
|
+ showIndexPage: true, //是否显示初始页面
|
|
|
+ languageRadio: 1, //设置选择语言
|
|
|
+ languageShow: false, //控制显示
|
|
|
+ loading: false,
|
|
|
+ chatLoading: false,
|
|
|
+ transcriptionLoading: false,
|
|
|
+ uploadFileLoading: false,
|
|
|
+ editorBarLoading: false,
|
|
|
+ textareaValue: "",
|
|
|
+ textareaLoading: false,
|
|
|
+ showRoleList: false,
|
|
|
+ showGetTextLoading: false,
|
|
|
+ roleListIndex: 0,
|
|
|
+ userId:this.$route.query['userid'],
|
|
|
+ recordedForm: {
|
|
|
+ time: "00:00:00", //时间
|
|
|
+ status: 0, //0--未录音 1--正在录音 2--暂停 3--录音结束
|
|
|
+ },
|
|
|
+ roleList: [],
|
|
|
+ publicRoleList: [],
|
|
|
+ audioUrl: "",
|
|
|
+ editorBarData: {
|
|
|
+ type: "0", //0---文字 1-文件
|
|
|
+ content: "",
|
|
|
+ url: "",
|
|
|
+ },
|
|
|
+ fileUrl:
|
|
|
+ "https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/%E8%BD%AC%E5%BD%95%E6%96%87%E7%A8%BF1713172600896.xlsx",
|
|
|
+ // 设置list
|
|
|
+ languageList: [
|
|
|
+ { label: 1, lang: "普通话" },
|
|
|
+ { label: 2, lang: "广东话" },
|
|
|
+ { label: 3, lang: "英语" },
|
|
|
+ ],
|
|
|
+ // 语音文字list
|
|
|
+ tapeList: [
|
|
|
+ {
|
|
|
+ ico: require("@/assets/icon/classroomObservation/mai1.svg"),
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/mai2.svg"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ ico: require("@/assets/icon/classroomObservation/wen1.svg"),
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/wen2.svg"),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ titBarList: [
|
|
|
+ {
|
|
|
+ title: "Al对话",
|
|
|
+ ico: require("@/assets/icon/classroomObservation/Group9101.svg"),
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/Group9102.svg"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "原文速览",
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/Vector.svg"),
|
|
|
+ ico: require("@/assets/icon/classroomObservation/Vector2.svg"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "转录文稿",
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/zhuanlu.svg"),
|
|
|
+ ico: require("@/assets/icon/classroomObservation/zhuanlu2.svg"),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ transcriptionData: {
|
|
|
+ content: "",
|
|
|
+ },
|
|
|
+ chatList: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 选择可以@的角色
|
|
|
+ choseRoleList() {
|
|
|
+ let result = [...this.roleList, ...this.publicRoleList];
|
|
|
+ const _index = this.textareaValue.lastIndexOf("@");
|
|
|
+ if (_index !== -1) {
|
|
|
+ let roleName = this.textareaValue.substring(_index + 1);
|
|
|
+ result = result.filter((i) => i.assistantName.indexOf(roleName) != -1);
|
|
|
+ } else {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ choseRoleList() {
|
|
|
+ this.roleListIndex = 0;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleBlur(event) {
|
|
|
+ // console.log("点击其它区域啦", event);
|
|
|
+ this.languageShow = !this.languageShow;
|
|
|
+ },
|
|
|
+ // 上传录音
|
|
|
+ uploadRecording() {
|
|
|
+ if (this.uploadFileLoading) return this.$message.info("请稍等...");
|
|
|
+ let input = document.createElement("input");
|
|
|
+ input.type = "file";
|
|
|
+ // input.accept = ".wav";
|
|
|
+ // input.accept = "audio/*, .txt, .pdf, .xlsx";
|
|
|
+ input.accept = ".wav,.txt,.pdf,.xlsx,.doc,.docx";
|
|
|
+ input.click();
|
|
|
+ input.onchange = () => {
|
|
|
+ this.uploadFileLoading = true;
|
|
|
+ let file = input.files[0];
|
|
|
+ if (!/\.(wav|txt|pdf|xlsx|doc|docx)$/i.test(file.name)) {
|
|
|
+ this.uploadFileLoading = false;
|
|
|
+ return this.$message.info(
|
|
|
+ "请上传.wav,.txt,.pdf,.xlsx,.doc,.docx格式的文件"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ this.uploadFile(file);
|
|
|
+ // this.uploadWavFileAndGetText(file);
|
|
|
+ };
|
|
|
+ },
|
|
|
+ cutBar(val) {
|
|
|
+ this.pageStatus = val;
|
|
|
+ if (this.pageStatus == 0) {
|
|
|
+ //ai对话
|
|
|
+ this.controlsStatus = 3;
|
|
|
+ } else if (this.pageStatus == 1 || this.pageStatus == 2) {
|
|
|
+ // 原文速览&&转录文稿
|
|
|
+
|
|
|
+ if ([1, 2].includes(this.recordedForm.status)) {
|
|
|
+ this.controlsStatus = 1;
|
|
|
+ } else {
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.showIndexPage = false;
|
|
|
+ },
|
|
|
+ cutTape(val) {
|
|
|
+ if (val == 0) {
|
|
|
+ if ([1, 2].includes(this.recordedForm.status)) {
|
|
|
+ this.controlsStatus = 1;
|
|
|
+ this.showIndexPage = true;
|
|
|
+ } else if (this.audioUrl) {
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ this.pageStatus = 1;
|
|
|
+ } else {
|
|
|
+ this.controlsStatus = 0;
|
|
|
+ this.showIndexPage = true;
|
|
|
+ }
|
|
|
+ } else if (val == 1) {
|
|
|
+ // if (this.pageStatus == 0) {
|
|
|
+ //ai对话
|
|
|
+ this.pageStatus = 0;
|
|
|
+ this.controlsStatus = 3;
|
|
|
+ // } else if (this.pageStatus == 1 || this.pageStatus == 2) {
|
|
|
+ // // 原文速览&&转录文稿
|
|
|
+ // this.controlsStatus = 2;
|
|
|
+ // }
|
|
|
+ this.showIndexPage = false;
|
|
|
+ } else if (val == 2) {
|
|
|
+ this.controlsStatus = 0;
|
|
|
+ this.showIndexPage = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ recordedStart() {
|
|
|
+ if (this.uploadFileLoading) return this.$message.info("请稍等...");
|
|
|
+ // 开始录音
|
|
|
+ if (this.audioUrl) {
|
|
|
+ this.$confirm("再次录音会顶替掉原先的录音,您确定吗", "提醒", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning",
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.recordedForm.status = 0;
|
|
|
+ this.audioUrl = "";
|
|
|
+ recorder.initRecorder(); //初始化录音
|
|
|
+ recorder.destroy(); // 销毁录音
|
|
|
+ this.recordedStart();
|
|
|
+ })
|
|
|
+ .catch((_) => {
|
|
|
+ console.log("不顶替");
|
|
|
+ });
|
|
|
+ } else if (this.controlsStatus != 1 && this.recordedForm.status == 0) {
|
|
|
+ recorder.initRecorder(); //初始化录音
|
|
|
+ recorder.destroy(); // 销毁录音
|
|
|
+ // 开始录音
|
|
|
+ recorder.start().then(
|
|
|
+ () => {
|
|
|
+ this.controlsStatus = 1;
|
|
|
+ this.recordedForm.status = 1;
|
|
|
+ recorder.onprogress = this.updateRecordedTime;
|
|
|
+ this.$message.success("录音已开始");
|
|
|
+ },
|
|
|
+ (error) => {
|
|
|
+ this.controlsStatus = 0;
|
|
|
+ this.recordedForm.status = 0;
|
|
|
+ // _this.$message.error(`${error.name} : ${error.message}`);
|
|
|
+ this.$message.error(
|
|
|
+ `没有找到可使用的麦克风,或者您没有允许此网页使用麦克风`
|
|
|
+ );
|
|
|
+ // 出错了
|
|
|
+ console.log(`${error.name} : ${error.message}`);
|
|
|
+ // if (_this.calcTimer) {
|
|
|
+ // clearInterval(_this.calcTimer)
|
|
|
+ // _this.calcTimer = null;
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ } else if ([1, 2].includes(this.recordedForm.status)) {
|
|
|
+ this.controlsStatus = 1;
|
|
|
+ this.$message.info("还在录音中");
|
|
|
+ }
|
|
|
+ // this.controlsStatus = 1;
|
|
|
+ },
|
|
|
+ updateRecordedTime({ duration }) {
|
|
|
+ // 更新currentTime,将秒数转换为时分秒格式
|
|
|
+ let hours = Math.floor(duration / 3600);
|
|
|
+ let minutes = Math.floor((duration % 3600) / 60);
|
|
|
+ let seconds = Math.floor(duration % 60);
|
|
|
+ this.recordedForm.time = `${hours.toString().padStart(2, "0")}:${minutes
|
|
|
+ .toString()
|
|
|
+ .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
|
+ },
|
|
|
+ //切换观察
|
|
|
+ // changeAnalysis() {
|
|
|
+ // this.$message.info("切换观察");
|
|
|
+ // },
|
|
|
+ // 切换连续对话
|
|
|
+ changeContinuousDialogue(newValue) {
|
|
|
+ this.continuousDialogue = newValue;
|
|
|
+ },
|
|
|
+ // 点击发送旁的录音
|
|
|
+ // tapeSubmit() {
|
|
|
+ // this.$message.info("发送旁的录音");
|
|
|
+ // this.mainBtnStatus = 0;
|
|
|
+ // this.pageStatus = 1;
|
|
|
+ // this.TapeNum = 0;
|
|
|
+ // },
|
|
|
+ async finishRecorded() {
|
|
|
+ this.uploadFileLoading = true;
|
|
|
+ recorder.stop();
|
|
|
+ this.$message.success("已结束录音");
|
|
|
+ this.showIndexPage = false;
|
|
|
+ this.pageStatus = 1;
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ this.recordedForm.status = 3;
|
|
|
+ // let file = this.convertToMp3(recorder.getWAV());
|
|
|
+ const mp3Blob = recorder.getWAVBlob();
|
|
|
+ let audioFile = this.dataURLtoAudio(mp3Blob, "wav");
|
|
|
+ this.uploadFile(audioFile);
|
|
|
+ // this.uploadWavFileAndGetText(audioFile);
|
|
|
+ },
|
|
|
+ stopRecorded() {
|
|
|
+ if (!recorder.ispause) {
|
|
|
+ recorder.pause();
|
|
|
+ this.recordedForm.status = 2;
|
|
|
+ this.$message.warning("已暂停录音");
|
|
|
+ } else {
|
|
|
+ recorder.resume();
|
|
|
+ this.recordedForm.status = 1;
|
|
|
+ this.$message.success("已继续录音");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeAudioUrl(newValue) {
|
|
|
+ if (!newValue) return;
|
|
|
+ this.audioUrl = newValue;
|
|
|
+ if (![1, 2].includes(this.pageStatus)) this.pageStatus = 1;
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ this.showIndexPage = false;
|
|
|
+ },
|
|
|
+ // 发送消息
|
|
|
+ send(_text = this.textareaValue) {
|
|
|
+ this.textareaValue = "";
|
|
|
+ // 判断输入的文本是否为空
|
|
|
+ if (!_text.trim()) return;
|
|
|
+ // 这里处理@的角色
|
|
|
+ let _atRoleList = [];
|
|
|
+ let _roleList = [...this.roleList, ...this.publicRoleList];
|
|
|
+ _roleList.forEach((i) => {
|
|
|
+ if (_text.indexOf(`@${i.assistantName}`) != -1) {
|
|
|
+ _atRoleList.push(i);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (_atRoleList.length > 0) {
|
|
|
+ //有@角色
|
|
|
+ let _replaceText = _text;
|
|
|
+ let _htmlText = _text;
|
|
|
+ _atRoleList.forEach((_i) => {
|
|
|
+ _replaceText = _replaceText.replaceAll(`@${_i.assistantName}`, ``);
|
|
|
+ _htmlText = _htmlText.replaceAll(
|
|
|
+ `@${_i.assistantName}`,
|
|
|
+ `<span class='aite-name'>@${_i.assistantName}</span>`
|
|
|
+ );
|
|
|
+ });
|
|
|
+ _atRoleList.forEach((_item, _index) => {
|
|
|
+ const _uid = uuidv4();
|
|
|
+ if (_index == 0) {
|
|
|
+ this.chatList.push({
|
|
|
+ loading: true,
|
|
|
+ role: "user",
|
|
|
+ content: _htmlText,
|
|
|
+ uid: _uid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: _item.headUrl,
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ fileid: _item.assistantName,
|
|
|
+ createtime: new Date().toLocaleString().replaceAll("/", "-"),
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.chatList.push({
|
|
|
+ loading: true,
|
|
|
+ role: "user",
|
|
|
+ content: "",
|
|
|
+ uid: _uid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: _item.headUrl,
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ fileid: _item.assistantName,
|
|
|
+ createtime: new Date().toLocaleString().replaceAll("/", "-"),
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.scrollBottom();
|
|
|
+ let params = {
|
|
|
+ assistant_id: _item.assistant_id,
|
|
|
+ userId: this.userId,
|
|
|
+ message: _replaceText,
|
|
|
+ session_name: `${this.tid}-classroomObservation`,
|
|
|
+ uid: _uid,
|
|
|
+ file_ids: this.fileId ? [this.fileId] : [],
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/ai_agent_park_chat_new", params)
|
|
|
+ .then((res) => {
|
|
|
+ if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
+ } else {
|
|
|
+ this.$message.warning(res.data.FunctionResponse.result);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(err);
|
|
|
+ });
|
|
|
+ this.getAtAuContent(
|
|
|
+ _uid,
|
|
|
+ _htmlText,
|
|
|
+ _item.headUrl,
|
|
|
+ _item.assistantName
|
|
|
+ );
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ //未@角色
|
|
|
+
|
|
|
+ let _uuid = uuidv4();
|
|
|
+ this.chatList.push({
|
|
|
+ role: "user",
|
|
|
+ content: `${_text}`,
|
|
|
+ uid: _uuid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: "",
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ createtime: new Date().toLocaleString().replaceAll("/", "-"),
|
|
|
+ loading: true,
|
|
|
+ });
|
|
|
+ this.scrollBottom();
|
|
|
+ // 连续对话设置
|
|
|
+ let _historyMessage = [];
|
|
|
+ // this.chatList.forEach(i=>{
|
|
|
|
|
|
- // let params = {
|
|
|
- // model: "gpt-3.5-turbo",
|
|
|
- // temperature: 0,
|
|
|
- // max_tokens: 4096,
|
|
|
- // top_p: 1,
|
|
|
- // frequency_penalty: 0,
|
|
|
- // presence_penalty: 0,
|
|
|
- // messages: [{role:"user",content:this.textValue}],
|
|
|
- // uid: _uuid,
|
|
|
- // mind_map_question: "",
|
|
|
- // }
|
|
|
- let params = JSON.stringify({
|
|
|
+ // })
|
|
|
+ _historyMessage.push({ role: "user", content: _text });
|
|
|
+ // let params = JSON.stringify({
|
|
|
+ // model: "gpt-3.5-turbo",
|
|
|
+ // temperature: 0,
|
|
|
+ // max_tokens: 4096,
|
|
|
+ // top_p: 1,
|
|
|
+ // frequency_penalty: 0,
|
|
|
+ // presence_penalty: 0,
|
|
|
+ // messages: _historyMessage,
|
|
|
+ // uid: _uuid,
|
|
|
+ // mind_map_question: "",
|
|
|
+ // });
|
|
|
+ let params = JSON.stringify({
|
|
|
message: {
|
|
|
anthropic_version: "bedrock-2023-05-31",
|
|
|
max_tokens: 4096,
|
|
|
temperature: 0,
|
|
|
top_p: 1,
|
|
|
- messages: [
|
|
|
- {
|
|
|
- role: "user",
|
|
|
- content: this.textValue
|
|
|
- }
|
|
|
- ]
|
|
|
+ messages: _historyMessage
|
|
|
},
|
|
|
uid: _uuid,
|
|
|
model: "Claude 3 Sonnet" // Claude 3 Sonnet或者Claude 3 Haiku
|
|
|
});
|
|
|
- this.scrollBottom();
|
|
|
- this.textValue = "";
|
|
|
- this.ajax
|
|
|
- // .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
- .post("https://claude3.cocorobo.cn/chat", params)
|
|
|
- .then(res => {
|
|
|
- if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
- } else {
|
|
|
- this.chatLoading = false;
|
|
|
- this.$message.warning(res.data.FunctionResponse.result);
|
|
|
- }
|
|
|
- })
|
|
|
- .catch(e => {
|
|
|
- this.chatLoading = false;
|
|
|
- console.log(e);
|
|
|
- });
|
|
|
- // this.$message.info(`发送:${this.textValue}`);
|
|
|
- // this.textValue = "";
|
|
|
- this.getAiContent(_uuid);
|
|
|
- },
|
|
|
- getAiContent(_uid) {
|
|
|
+ this.ajax
|
|
|
+ // .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ .post("https://claude3.cocorobo.cn/chat", params)
|
|
|
+ .then((res) => {
|
|
|
+ if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
+ } else {
|
|
|
+ this.$message.warning(res.data.FunctionResponse.result);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ console.log(e);
|
|
|
+ });
|
|
|
+ this.getAiContent(_uuid);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getAiContent(_uid) {
|
|
|
let _source = new EventSource(`https://claude3.cocorobo.cn/streamChat/${_uid}`);
|
|
|
- // let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
- let _allText = "";
|
|
|
- let _mdText = "";
|
|
|
- const md = new MarkdownIt();
|
|
|
- _source.onmessage = _e => {
|
|
|
- if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
- //对话已经完成
|
|
|
- _mdText = _mdText.replace("_", "");
|
|
|
- _source.close();
|
|
|
- this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
|
|
|
- this.chatList.find(i => i.uid == _uid).isalltext = true;
|
|
|
- this.chatList.find(i => i.uid == _uid).isShowSynchronization = true;
|
|
|
- this.chatList.find(i => i.uid == _uid).loading = false;
|
|
|
- this.chatLoading = false;
|
|
|
- this.insertChat(_uid);
|
|
|
- return;
|
|
|
- } else {
|
|
|
- //对话还在继续
|
|
|
- let _text = "";
|
|
|
- _text = _e.data.replaceAll("'", "");
|
|
|
- if (_allText == "") {
|
|
|
- _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
|
|
|
- } else {
|
|
|
- _allText += _text;
|
|
|
- }
|
|
|
- _mdText = _allText + "_";
|
|
|
- _mdText = _mdText.replace(/\\n/g, "\n");
|
|
|
- _mdText = _mdText.replace(/\\/g, "");
|
|
|
- if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
|
|
|
- //转化返回的回复流数据
|
|
|
- _mdText = md.render(_mdText);
|
|
|
- this.chatList.find(i => i.uid == _uid).aiContent = _mdText;
|
|
|
- this.chatList.find(i => i.uid == _uid).loading = false;
|
|
|
- this.scrollBottom();
|
|
|
- // 处理流数据
|
|
|
- }
|
|
|
- };
|
|
|
- },
|
|
|
- // 复制
|
|
|
- copyText(_html) {
|
|
|
- const div = document.createElement("div");
|
|
|
- div.innerHTML = _html;
|
|
|
- const _text = div.innerText;
|
|
|
- navigator.clipboard.writeText(_text).then(
|
|
|
- _ => {
|
|
|
- this.$message.success("复制成功");
|
|
|
- },
|
|
|
- function(err) {
|
|
|
- this.$message.error(`无法复制:${err}`);
|
|
|
- }
|
|
|
- );
|
|
|
- },
|
|
|
- // 保存对话
|
|
|
- //保存消息
|
|
|
- insertChat(_uid) {
|
|
|
- let _data = this.chatList.find(i => i.uid == _uid);
|
|
|
- if (!_data) return;
|
|
|
- let params = {
|
|
|
- userId: this.userId,
|
|
|
- userName: "qgt",
|
|
|
- groupId: "602def61-005d-11ee-91d8-005056b8q12w",
|
|
|
- answer: _data.aiContent,
|
|
|
- problem: _data.content,
|
|
|
- file_id: "",
|
|
|
- alltext: _data.aiContent,
|
|
|
- type: "chat",
|
|
|
- filename: _data.filename,
|
|
|
- session_name: `${this.userId}-pblCourse`
|
|
|
- };
|
|
|
- this.ajax
|
|
|
- .post("https://gpt4.cocorobo.cn/insert_chat", params)
|
|
|
- .then(res => {
|
|
|
- console.log("保存对话");
|
|
|
- });
|
|
|
- },
|
|
|
- // 获取对话记录
|
|
|
- getChatList() {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- this.chatList = [];
|
|
|
- this.loading = true;
|
|
|
- this.chatLoading = true;
|
|
|
- let params = {
|
|
|
- userid: this.userId,
|
|
|
- groupid: "602def61-005d-11ee-91d8-005056b8q12w",
|
|
|
- // session_name:``
|
|
|
- session_name: `${this.userId}-pblCourse`
|
|
|
- };
|
|
|
- this.ajax
|
|
|
- .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
|
|
|
- .then(res => {
|
|
|
- let _data = JSON.parse(res.data.FunctionResponse);
|
|
|
- if (_data.length > 0) {
|
|
|
- console.log(_data);
|
|
|
- let _chatList = [];
|
|
|
- for (let i = 0; i < _data.length; i++) {
|
|
|
- _chatList.push({
|
|
|
- loading: false,
|
|
|
- role: "user",
|
|
|
- content: _data[i].problem,
|
|
|
- uid: _data[i].id,
|
|
|
- AI: "AI",
|
|
|
- aiContent: _data[i].answer,
|
|
|
- oldContent: _data[i].answer,
|
|
|
- isShowSynchronization: false,
|
|
|
- filename: _data[i].filename,
|
|
|
- index: i,
|
|
|
- is_mind_map: false,
|
|
|
- fileid: _data[i].fileid,
|
|
|
- createtime: _data[i].createtime
|
|
|
- });
|
|
|
- }
|
|
|
- this.chatList = _chatList;
|
|
|
- this.chatLoading = false;
|
|
|
- this.loading = false;
|
|
|
- } else {
|
|
|
- //没有对话记录
|
|
|
- this.loading = false;
|
|
|
- this.chatLoading = false;
|
|
|
- }
|
|
|
- resolve();
|
|
|
- this.scrollBottom();
|
|
|
- })
|
|
|
- .catch(err => {
|
|
|
- console.log(err);
|
|
|
- this.$message.error("获取对话记录失败");
|
|
|
- this.chatLoading = false;
|
|
|
- this.scrollBottom();
|
|
|
- resolve();
|
|
|
- });
|
|
|
- });
|
|
|
- },
|
|
|
- //对话触底
|
|
|
- scrollBottom() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
|
|
|
- });
|
|
|
- },
|
|
|
- //清除对话
|
|
|
- clearChat() {
|
|
|
- this.chatList = [];
|
|
|
- this.scrollBottom();
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- mounted() {
|
|
|
- this.getChatList().then(_ => {
|
|
|
- this.scrollBottom();
|
|
|
- });
|
|
|
- }
|
|
|
+ // let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
+ let _allText = "";
|
|
|
+ let _mdText = "";
|
|
|
+ const md = new MarkdownIt();
|
|
|
+ _source.onmessage = (_e) => {
|
|
|
+ if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
+ //对话已经完成
|
|
|
+ _mdText = _mdText.replace("_", "");
|
|
|
+ _source.close();
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isalltext = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isShowSynchronization = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.insertChat(_uid);
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ //对话还在继续
|
|
|
+ let _text = "";
|
|
|
+ _text = _e.data.replaceAll("'", "");
|
|
|
+ if (_allText == "") {
|
|
|
+ _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
|
|
|
+ } else {
|
|
|
+ _allText += _text;
|
|
|
+ }
|
|
|
+ _mdText = _allText + "_";
|
|
|
+ _mdText = _mdText.replace(/\\n/g, "\n");
|
|
|
+ _mdText = _mdText.replace(/\\/g, "");
|
|
|
+ if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
|
|
|
+ //转化返回的回复流数据
|
|
|
+ _mdText = md.render(_mdText);
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ // 处理流数据
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ getAtAuContent(_uid, _text, _headUrl, _assistantName) {
|
|
|
+ let _source = new EventSource(
|
|
|
+ `https://gpt4.cocorobo.cn/question/${_uid}`
|
|
|
+ ); //http://gpt4.cocorobo.cn:8011/question/ https://gpt4.cocorobo.cn/question/
|
|
|
+ let _allText = "";
|
|
|
+ let _mdText = "";
|
|
|
+ const md = new MarkdownIt();
|
|
|
+ _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.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isalltext = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isShowSynchronization = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ this.insertChat(_uid);
|
|
|
+ } else {
|
|
|
+ let _text = _eData.content.replace("'", "").replace("'", "");
|
|
|
+ if (_allText == "") {
|
|
|
+ _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
|
|
|
+ } else {
|
|
|
+ _allText += _text;
|
|
|
+ }
|
|
|
+ _mdText = _allText + "_";
|
|
|
+ _mdText = _mdText.replace(/\\n/g, "\n");
|
|
|
+ _mdText = _mdText.replace(/\\/g, "");
|
|
|
+ if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
|
|
|
+ //转化返回的回复流数据
|
|
|
+ _mdText = md.render(_mdText);
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ // 处理流数据
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ textareaChange() {
|
|
|
+ if (this.textareaValue.at(-1) == "@") {
|
|
|
+ this.showRoleList = true;
|
|
|
+ }
|
|
|
+ this.$refs.textareaRef.style.height = "50px";
|
|
|
+ this.$refs.textareaRef.style.height =
|
|
|
+ this.$refs.textareaRef.scrollHeight + "px";
|
|
|
+ if (this.$refs.roleListRef) {
|
|
|
+ let roleListHeight =
|
|
|
+ this.$refs.textareaRef.scrollHeight >= 500
|
|
|
+ ? 520
|
|
|
+ : this.$refs.textareaRef.scrollHeight + 20;
|
|
|
+ this.$refs.roleListRef.style["margin-bottom"] = "70px";
|
|
|
+ this.$refs.roleListRef.style["margin-bottom"] = roleListHeight + "px";
|
|
|
+ this.$refs.roleListRef.style["max-height"] = `calc(100vh - ${
|
|
|
+ roleListHeight + 160
|
|
|
+ }px)`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 滚动条触底
|
|
|
+ scrollBottom() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.textareaChange();
|
|
|
+ this.$refs.tapeRef.$el.querySelector(".t-chartArea").scrollTop =
|
|
|
+ this.$refs.tapeRef.$el.querySelector(".t-chartArea").scrollHeight;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 点击了其他地方然后关闭角色列表
|
|
|
+ noShowRoleList() {
|
|
|
+ this.showRoleList = false;
|
|
|
+ },
|
|
|
+ convertToMp3(wavDataView) {
|
|
|
+ // 获取wav头信息
|
|
|
+ const wav = lamejs.WavHeader.readHeader(wavDataView); // 此处其实可以不用去读wav头信息,毕竟有对应的config配置
|
|
|
+ const { channels, sampleRate } = wav;
|
|
|
+ const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
|
|
|
+ // 获取左右通道数据
|
|
|
+ const result = recorder.getChannelData();
|
|
|
+ const buffer = [];
|
|
|
+ const leftData =
|
|
|
+ result.left &&
|
|
|
+ new Int16Array(result.left.buffer, 0, result.left.byteLength / 2);
|
|
|
+ const rightData =
|
|
|
+ result.right &&
|
|
|
+ new Int16Array(result.right.buffer, 0, result.right.byteLength / 2);
|
|
|
+ const remaining = leftData.length + (rightData ? rightData.length : 0);
|
|
|
+ const maxSamples = 1152;
|
|
|
+ for (let i = 0; i < remaining; i += maxSamples) {
|
|
|
+ const left = leftData.subarray(i, i + maxSamples);
|
|
|
+ let right = null;
|
|
|
+ let mp3buf = null;
|
|
|
+ if (channels === 2) {
|
|
|
+ right = rightData.subarray(i, i + maxSamples);
|
|
|
+ mp3buf = mp3enc.encodeBuffer(left, right);
|
|
|
+ } else {
|
|
|
+ mp3buf = mp3enc.encodeBuffer(left);
|
|
|
+ }
|
|
|
+ if (mp3buf.length > 0) {
|
|
|
+ buffer.push(mp3buf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const enc = mp3enc.flush();
|
|
|
+ if (enc.length > 0) {
|
|
|
+ buffer.push(enc);
|
|
|
+ }
|
|
|
+ return new Blob(buffer, { type: "audio/mp3" });
|
|
|
+ },
|
|
|
+ wavFileGetText(audioFile) {
|
|
|
+ let flag = true;
|
|
|
+ let textList = [];
|
|
|
+ // if (flag) {
|
|
|
+ // // 这里上传文件
|
|
|
+ // // _this.uploadWavFile(audioFile);
|
|
|
+ // this.controlsStatus = 2;
|
|
|
+ // this.showIndexPage = false;
|
|
|
+ // this.pageStatus = 1;
|
|
|
+ // this.editorBarData.type = "0";
|
|
|
+ // flag = false;
|
|
|
+ // this.uploadFileLoading = false;
|
|
|
+ // }
|
|
|
+ // let num = 0;
|
|
|
+ // let timer = null;
|
|
|
+ // this.showGetTextLoading = true;
|
|
|
+ // timer = setInterval(()=>{
|
|
|
+ // console.log(`这是第:${num}个`)
|
|
|
+ // let privText = `这是第- ${num} -个`
|
|
|
+ // textList.push({
|
|
|
+ // value:privText,
|
|
|
+ // startTime:"",
|
|
|
+ // endTime:"",
|
|
|
+ // time:"",
|
|
|
+ // })
|
|
|
+ // this.transcriptionData.content += privText;
|
|
|
+ // num++;
|
|
|
+ // let _result =`
|
|
|
+ // <table
|
|
|
+ // border="0"
|
|
|
+ // width="100%"
|
|
|
+ // cellpadding="0"
|
|
|
+ // cellspacing="0"
|
|
|
+ // style="text-align: center"
|
|
|
+ // >
|
|
|
+ // <tbody>
|
|
|
+ // <tr>
|
|
|
+ // <th>序号</th>
|
|
|
+ // <th>开始时间</th>
|
|
|
+ // <th>结束时间</th>
|
|
|
+ // <th>发言内容</th>
|
|
|
+ // <th>时长</th>
|
|
|
+ // <th>说话人身份</th>
|
|
|
+ // <th>行为编码</th>
|
|
|
+ // </tr>
|
|
|
+ // `
|
|
|
+ // textList.forEach((item,index)=>{
|
|
|
+ // _result += `<tr>
|
|
|
+ // <td>${index+1}</td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td>${item.value}</td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // </tr>`
|
|
|
+ // })
|
|
|
+
|
|
|
+ // _result+=`
|
|
|
+ // <tr>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // <td></td>
|
|
|
+ // </tr>
|
|
|
+ // </tbody>
|
|
|
+ // </table>`
|
|
|
+ // this.editorBarData.content = _result;
|
|
|
+ // if(num>=30)return clearInterval(timer);
|
|
|
+ // },2000)
|
|
|
+
|
|
|
+ // setTimeout(()=>{
|
|
|
+ // this.showGetTextLoading = false;
|
|
|
+
|
|
|
+ // },66000)
|
|
|
+ // return;
|
|
|
+ let iiframe = this.$refs["iiframe"];
|
|
|
+ let _this = this;
|
|
|
+
|
|
|
+ iiframe.contentWindow.window.document.getElementById(
|
|
|
+ "languageOptions"
|
|
|
+ ).selectedIndex = 2;
|
|
|
+ _this.transcriptionData.content = "";
|
|
|
+ iiframe.contentWindow.onRecognizedResult = function (e) {
|
|
|
+ if (flag) {
|
|
|
+ // 这里上传文件
|
|
|
+ // _this.uploadWavFile(audioFile);
|
|
|
+ _this.controlsStatus = 2;
|
|
|
+ _this.showIndexPage = false;
|
|
|
+ _this.pageStatus = 1;
|
|
|
+ _this.editorBarData.type = "0";
|
|
|
+ flag = false;
|
|
|
+ _this.uploadFileLoading = false;
|
|
|
+ _this.transcriptionData.content = "";
|
|
|
+ _this.editorBarData.content = "";
|
|
|
+ textList = [];
|
|
|
+ }
|
|
|
+ _this.showGetTextLoading = true;
|
|
|
+ let privText = e.privText;
|
|
|
+ console.log("👇转译对象👇");
|
|
|
+ console.log(e);
|
|
|
+ console.log("👇转译结果👇");
|
|
|
+ console.log(privText);
|
|
|
+ textList.push({
|
|
|
+ value: privText,
|
|
|
+ startTime: "",
|
|
|
+ endTime: "",
|
|
|
+ time: "",
|
|
|
+ });
|
|
|
+ _this.transcriptionData.content += privText;
|
|
|
+
|
|
|
+ let _result = `
|
|
|
+ <table
|
|
|
+ border="0"
|
|
|
+ width="100%"
|
|
|
+ cellpadding="0"
|
|
|
+ cellspacing="0"
|
|
|
+ style="text-align: center"
|
|
|
+ >
|
|
|
+ <tbody>
|
|
|
+ <tr>
|
|
|
+ <th>序号</th>
|
|
|
+ <th>开始时间</th>
|
|
|
+ <th>结束时间</th>
|
|
|
+ <th>发言内容</th>
|
|
|
+ <th>时长</th>
|
|
|
+ <th>说话人身份</th>
|
|
|
+ <th>行为编码</th>
|
|
|
+ </tr>
|
|
|
+ `;
|
|
|
+ textList.forEach((item, index) => {
|
|
|
+ _result += `<tr>
|
|
|
+ <td>${index+1}</td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td>${item.value}</td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ </tr>`;
|
|
|
+ });
|
|
|
+ _result += `
|
|
|
+ <tr>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ <td></td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>`;
|
|
|
+ _this.editorBarData.content = _result;
|
|
|
+ // _this.editorBarData.content += privText;
|
|
|
+ };
|
|
|
+
|
|
|
+ iiframe.contentWindow.onSessionStopped = function (e) {
|
|
|
+ console.log("转译完成");
|
|
|
+ console.log(e);
|
|
|
+ _this.$message.success("转译完成");
|
|
|
+ _this.showGetTextLoading = false;
|
|
|
+ _this.saveEditorBar();
|
|
|
+ };
|
|
|
+
|
|
|
+ iiframe.contentWindow.doContinuousPronunciationAssessment("", {
|
|
|
+ files: [audioFile],
|
|
|
+ });
|
|
|
+ },
|
|
|
+ uploadFile(file,flag = true) {
|
|
|
+ var credentials = {
|
|
|
+ accessKeyId: "AKIATLPEDU37QV5CHLMH",
|
|
|
+ secretAccessKey: "Q2SQw37HfolS7yeaR1Ndpy9Jl4E2YZKUuuy2muZR",
|
|
|
+ }; //秘钥形式的登录上传
|
|
|
+ window.AWS.config.update(credentials);
|
|
|
+ window.AWS.config.region = "cn-northwest-1"; //设置区域
|
|
|
+
|
|
|
+ var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
|
|
|
+ var _this = this;
|
|
|
+
|
|
|
+ if (file) {
|
|
|
+ this.loading = true;
|
|
|
+ var params = {
|
|
|
+ Key:
|
|
|
+ file.name.split(".")[0] +
|
|
|
+ new Date().getTime() +
|
|
|
+ "." +
|
|
|
+ file.name.split(".")[file.name.split(".").length - 1],
|
|
|
+ ContentType: file.type,
|
|
|
+ Body: file,
|
|
|
+ "Access-Control-Allow-Credentials": "*",
|
|
|
+ ACL: "public-read",
|
|
|
+ }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
|
|
|
+ var options = {
|
|
|
+ partSize: 2048 * 1024 * 1024,
|
|
|
+ queueSize: 2,
|
|
|
+ leavePartsOnError: true,
|
|
|
+ };
|
|
|
+ bucket
|
|
|
+ .upload(params, options)
|
|
|
+ .on("httpUploadProgress", function (evt) {
|
|
|
+ //这里可以写进度条
|
|
|
+ // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
|
|
|
+ })
|
|
|
+ .send(function (err, data) {
|
|
|
+ if (err) {
|
|
|
+ _this.$message.error("上传失败");
|
|
|
+ _this.uploadFileLoading = false;
|
|
|
+ _this.loading = false;
|
|
|
+ } else {
|
|
|
+ // 判断是不是音频文件
|
|
|
+ const audioRegex = /\.(mp3|wav|ogg|flac|m4a)$/i;
|
|
|
+ const txtRegex = /\.(txt)$/i;
|
|
|
+ const otherRegex = /\.(pdf|xlsx|doc|docx)$/i;
|
|
|
+ // if (audioRegex.test(data.Location)) {
|
|
|
+ // // console.log(data);
|
|
|
+ // _this.uploadWavFileAndGetText(file)
|
|
|
+ // _this.$emit("changeAudioUrl", data);
|
|
|
+
|
|
|
+ // // console.log("修改音频文件");
|
|
|
+ // // console.log(data)
|
|
|
+ // _this.uploadFileLoading = false;
|
|
|
+ // }else if(txtRegex.test(data.Location)){
|
|
|
+ // console.log("这hi是一个txt文件")
|
|
|
+ // } else if(otherRegex.test(data.Location)){
|
|
|
+ //
|
|
|
+ if (audioRegex.test(data.Location)) {
|
|
|
+ _this.wavFileGetText(file);
|
|
|
+ _this.$emit("changeAudioUrl", data);
|
|
|
+ _this.loading = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _this.ajax
|
|
|
+ .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
|
|
|
+ url: data.Location,
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ let _data = res.data.FunctionResponse;
|
|
|
+ if (_data.result && _data.result.id) {
|
|
|
+ _this.$emit("updateFileId", _data.result.id);
|
|
|
+ // _this.$message.success("成功获取fileId");
|
|
|
+ _this.uploadFileLoading = false;
|
|
|
+ //处理文件
|
|
|
+ if (txtRegex.test(data.Location)) {
|
|
|
+ //txt
|
|
|
+ getFile(data.Location).then((_res) => {
|
|
|
+ _this.controlsStatus = 2;
|
|
|
+ _this.showIndexPage = false;
|
|
|
+ _this.pageStatus = 2;
|
|
|
+ // _this.transcriptionData.content += _res.data;
|
|
|
+ _this.editorBarData.type = "0";
|
|
|
+ let _textData = _res.data;
|
|
|
+ if(flag){
|
|
|
+ let _result = `<table
|
|
|
+ border="0"
|
|
|
+ width="100%"
|
|
|
+ cellpadding="0"
|
|
|
+ cellspacing="0"
|
|
|
+ style="text-align: center"
|
|
|
+ >
|
|
|
+ <tbody>`
|
|
|
+ _textData.split("\n").forEach((item,index)=>{
|
|
|
+ if(index==_textData.split("\n").length-1)return;
|
|
|
+ if(index==0){
|
|
|
+ _result+=`<tr>`
|
|
|
+ if(item.split('').filter(char=>char===',').length>=6){
|
|
|
+ item.split(',').forEach((item2,index2)=>{
|
|
|
+ _result += `
|
|
|
+ <th>${item2}</th>
|
|
|
+ `;
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ item.trim().split(/\s+/).forEach((item2,index2)=>{
|
|
|
+ _result += `
|
|
|
+ <th>${item2}</td>
|
|
|
+ `;
|
|
|
+ })
|
|
|
+ }
|
|
|
+ _result+=`</tr>`
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _result+=`<tr>`
|
|
|
+ if(item.split('').filter(char=>char===',').length>=6){
|
|
|
+ item.split(',').forEach((item2,index2)=>{
|
|
|
+ _result += `
|
|
|
+ <td>${item2}</td>
|
|
|
+ `;
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ item.trim().split(/\s+/).forEach((item2,index2)=>{
|
|
|
+ _result += `
|
|
|
+ <td>${item2}</td>
|
|
|
+ `;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ _result+=`</tr>`
|
|
|
+ })
|
|
|
+ _result += `
|
|
|
+ </tbody>
|
|
|
+ </table>`;
|
|
|
+ _this.editorBarData.content = _result;
|
|
|
+ }else{
|
|
|
+ _this.editorBarData.content = _textData;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // _this.transcriptionData.content = _res.data;
|
|
|
+ _this.editorBarData.url = "";
|
|
|
+ _this.saveEditorBar();
|
|
|
+ });
|
|
|
+ } else if (otherRegex.test(data.Location)) {
|
|
|
+ //pdf、 docx、doc、xlxs
|
|
|
+
|
|
|
+ _this.editorBarData.type = "1";
|
|
|
+ _this.editorBarData.url = data.Location;
|
|
|
+ _this.editorBarData.content = "";
|
|
|
+ _this.saveEditorBar();
|
|
|
+ // console.log("pdf、xlsx、doc、docx文件处理");
|
|
|
+ }
|
|
|
+ _this.loading = false;
|
|
|
+ if (!_this.fileIdId) return;
|
|
|
+ let pram2 = {
|
|
|
+ id: _this.fileIdId,
|
|
|
+ json_data: JSON.stringify({
|
|
|
+ file_ids: _data.result.id,
|
|
|
+ }),
|
|
|
+ // json_data: JSON.stringify({file_ids:'file-r5phg4I2oFqly4WpW7oOOTnA'}),
|
|
|
+ };
|
|
|
+ _this.ajax
|
|
|
+ .post(
|
|
|
+ "https://gpt4.cocorobo.cn/update_classroom_observation",
|
|
|
+ pram2
|
|
|
+ )
|
|
|
+ .then((res) => {});
|
|
|
+ } else {
|
|
|
+ _this.$message.error("修改fileId失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // this.$emit("updateFileId", data.Location)
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ _this.uploadFileLoading = false;
|
|
|
+ console.log(e);
|
|
|
+ _this.$message.error("获取fileId失败");
|
|
|
+ });
|
|
|
+ // }
|
|
|
+
|
|
|
+ // console.log(data.Location)
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 录音转wav
|
|
|
+ dataURLtoAudio(blob, filename) {
|
|
|
+ return new File([blob], filename, { type: "audio/wav" });
|
|
|
+ },
|
|
|
+ getRoleList() {
|
|
|
+ this.roleList = [];
|
|
|
+ let params = {
|
|
|
+ userId: this.userId,
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/get_ai_agent_assistant_list", params)
|
|
|
+ .then((res) => {
|
|
|
+ let _data = res.data.FunctionResponse.result;
|
|
|
+ if (_data) {
|
|
|
+ this.roleList = JSON.parse(_data);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ this.$message.error("获取角色列表失败");
|
|
|
+ this.roleList = [];
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getPublicRoleList() {
|
|
|
+ this.publicRoleList = [];
|
|
|
+ let params = {
|
|
|
+ userId: this.userId,
|
|
|
+ organizeid: "45facc0a-1211-11ec-80ad-005056b86db5",
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post(
|
|
|
+ "https://gpt4.cocorobo.cn/get_ai_agent_assistant_share_list",
|
|
|
+ params
|
|
|
+ )
|
|
|
+ .then((res) => {
|
|
|
+ let _data = res.data.FunctionResponse.result;
|
|
|
+ if (_data) {
|
|
|
+ this.publicRoleList = JSON.parse(_data);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ this.publicRoleList = [];
|
|
|
+ console.log("获取公共角色失败", e);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 选择了@的角色
|
|
|
+ choseRole(_data) {
|
|
|
+ let _lastAtIndex = this.textareaValue.lastIndexOf("@");
|
|
|
+ this.textareaValue = `${this.textareaValue.slice(0, _lastAtIndex)}@${
|
|
|
+ _data.assistantName
|
|
|
+ } `;
|
|
|
+ this.$refs.textareaRef.focus();
|
|
|
+ this.showRoleList = false;
|
|
|
+ },
|
|
|
+ // 输入框键盘按下监听
|
|
|
+ textareaKeydown(_e) {
|
|
|
+ if (this.showRoleList && this.choseRoleList.length > 0) {
|
|
|
+ switch (_e.keyCode) {
|
|
|
+ case 38: //小键盘上
|
|
|
+ _e.preventDefault();
|
|
|
+ if (this.roleListIndex == 0) return;
|
|
|
+ this.roleListIndex--;
|
|
|
+ // 修改滚动条高度
|
|
|
+ this.$refs.roleListRef.scrollTop = this.roleListIndex * 105;
|
|
|
+ break;
|
|
|
+ case 40: //小键盘下
|
|
|
+ _e.preventDefault();
|
|
|
+ if (this.roleListIndex == this.choseRoleList.length - 1) return;
|
|
|
+ this.roleListIndex++;
|
|
|
+ this.$refs.roleListRef.scrollTop = this.roleListIndex * 105;
|
|
|
+ break;
|
|
|
+ case 13: //回车
|
|
|
+ _e.preventDefault();
|
|
|
+ this.choseRole(this.choseRoleList[this.roleListIndex]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (_e.key === "Enter") {
|
|
|
+ if (_e.altKey) {
|
|
|
+ // 如果按下的是Alt+Enter,那么换行
|
|
|
+ this.textareaValue += "\n";
|
|
|
+ } else {
|
|
|
+ this.send();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getData() {
|
|
|
+ this.loading = true;
|
|
|
+ this.getRoleList();
|
|
|
+ this.getPublicRoleList();
|
|
|
+ this.getChatList().then((_) => {
|
|
|
+ this.loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 保存转录文稿和原文速览
|
|
|
+ saveEditorBar(flag = false) {
|
|
|
+ if (
|
|
|
+ this.editorBarData.type == "0" &&
|
|
|
+ flag &&
|
|
|
+ this.editorBarData.content
|
|
|
+ ) {
|
|
|
+ // 如果是文本则转成txt并保存
|
|
|
+ let _result = JSON.parse(JSON.stringify(this.editorBarData))
|
|
|
+ var text = _result.content;
|
|
|
+
|
|
|
+ // 创建一个Blob实例
|
|
|
+ var blob = new Blob([text], { type: "text/plain;charset=utf-8" });
|
|
|
+ blob.lastModifiedDate = new Date();
|
|
|
+ blob.name = `${this.tid}-classroomObservation.txt`;
|
|
|
+ return this.uploadFile(blob,false);
|
|
|
+ } else {
|
|
|
+ this.loading = true;
|
|
|
+ // let div = document.createElement("div");
|
|
|
+ // div.innerHTML = this.editorBarData.content;
|
|
|
+ // return this.loading = false;
|
|
|
+ this.$emit(
|
|
|
+ "updateTranscription",
|
|
|
+ {
|
|
|
+ transcriptionData: this.transcriptionData.content,
|
|
|
+ editorBarData: this.editorBarData,
|
|
|
+ },
|
|
|
+ () => {
|
|
|
+ this.loading = false;
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeEditorBar({ transcriptionData, editorBarData }) {
|
|
|
+ this.transcriptionData.content = transcriptionData;
|
|
|
+ try {
|
|
|
+ let _result = JSON.parse(editorBarData)
|
|
|
+ this.editorBarData = _result;
|
|
|
+ } catch (error) {
|
|
|
+ this.editorBarData = editorBarData;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取对话记录
|
|
|
+ getChatList() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (this.chatLoading) return this.$message.info("请稍等...");
|
|
|
+ this.chatList = [];
|
|
|
+ if (!this.tid) return setTimeout(() => this.getChatList(), 100);
|
|
|
+ this.chatLoading = true;
|
|
|
+ let params = {
|
|
|
+ userid: this.userId,
|
|
|
+ groupid: "602def61-005d-11ee-91d8-005056b8q12w",
|
|
|
+ // session_name:``
|
|
|
+ session_name: `${this.tid}-classroomObservation`,
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
|
|
|
+ .then((res) => {
|
|
|
+ let _data = JSON.parse(res.data.FunctionResponse);
|
|
|
+ if (_data.length > 0) {
|
|
|
+ let _chatList = [];
|
|
|
+ for (let i = 0; i < _data.length; i++) {
|
|
|
+ _chatList.push({
|
|
|
+ loading: false,
|
|
|
+ role: "user",
|
|
|
+ content: _data[i].problem,
|
|
|
+ uid: _data[i].id,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: _data[i].answer,
|
|
|
+ oldContent: _data[i].answer,
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: _data[i].filename,
|
|
|
+ index: i,
|
|
|
+ is_mind_map: false,
|
|
|
+ fileid: _data[i].fileid,
|
|
|
+ createtime: _data[i].createtime,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.chatList = _chatList;
|
|
|
+ this.chatLoading = false;
|
|
|
+ } else {
|
|
|
+ //没有对话记录
|
|
|
+ this.chatLoading = false;
|
|
|
+ }
|
|
|
+ resolve();
|
|
|
+ this.scrollBottom();
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(err);
|
|
|
+ this.$message.error("获取对话记录失败");
|
|
|
+ this.chatLoading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //保存消息
|
|
|
+ insertChat(_uid) {
|
|
|
+ let _data = this.chatList.find((i) => i.uid == _uid);
|
|
|
+ if (!_data) return;
|
|
|
+ let params = {
|
|
|
+ userId: this.userId,
|
|
|
+ userName: "qgt",
|
|
|
+ groupId: "602def61-005d-11ee-91d8-005056b8q12w",
|
|
|
+ answer: _data.aiContent,
|
|
|
+ problem: _data.content,
|
|
|
+ file_id: _data.fileid ? _data.fileid : "",
|
|
|
+ alltext: _data.aiContent,
|
|
|
+ type: "chat",
|
|
|
+ filename: _data.filename,
|
|
|
+ session_name: `${this.tid}-classroomObservation`,
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/insert_chat", params)
|
|
|
+ .then((res) => {});
|
|
|
+ },
|
|
|
+ // 转录文稿修改
|
|
|
+ changeEditor(val){
|
|
|
+ console.log(val)
|
|
|
+ // this.editorBarData.content = val;
|
|
|
+ // console.log(this.editorBarData)
|
|
|
+ this.$forceUpdate();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.chat {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- background-color: #ffffff;
|
|
|
- border-radius: 12px;
|
|
|
- box-sizing: border-box;
|
|
|
- border: solid 1px #f3f7fd;
|
|
|
- box-shadow: 0 4px 10px 0 #1d388321;
|
|
|
+.chatArea {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ /* align-items: center; */
|
|
|
+ /* justify-content: center; */
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+.audio_class {
|
|
|
+ /* width: 100% !important; */
|
|
|
+ /* height: 100% !important; */
|
|
|
+ background: #ccc !important;
|
|
|
+ margin: 0 !important;
|
|
|
}
|
|
|
|
|
|
-.c_chat {
|
|
|
- width: 100%;
|
|
|
- height: calc(100% - 56px);
|
|
|
- box-sizing: border-box;
|
|
|
- padding: 15px;
|
|
|
- overflow: auto;
|
|
|
+.audio_class >>> .slider .process {
|
|
|
+ background: #000;
|
|
|
+}
|
|
|
+.tapeSty {
|
|
|
+ cursor: pointer;
|
|
|
+ width: 40px;
|
|
|
+ height: 25px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ /* padding: 10px 15px; */
|
|
|
+ border-radius: 20px;
|
|
|
+}
|
|
|
+.TapeCss {
|
|
|
+ background-color: #1467ee;
|
|
|
+}
|
|
|
+.titBar {
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ display: flex;
|
|
|
+ /* align-items: center; */
|
|
|
+ border-bottom: 1px #ccc solid;
|
|
|
+ z-index: 99;
|
|
|
+}
|
|
|
+.titBar > .titBarLeft {
|
|
|
+ width: 40%;
|
|
|
+ min-width: 400px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ cursor: pointer;
|
|
|
+ justify-content: flex-start;
|
|
|
+}
|
|
|
+.titBar > .titBarRig {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 22px;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+.titBar > .titBarRig > img {
|
|
|
+ margin-right: 5px;
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.titBarBorder {
|
|
|
+ font-weight: 600;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-bottom: 2px #1467ee solid;
|
|
|
+}
|
|
|
+.titBar > .titBarLeft > div {
|
|
|
+ height: 100%;
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 16px;
|
|
|
+ min-width: 75px;
|
|
|
+ margin-right: 30px;
|
|
|
+ text-align: left;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.titBar > .titBarLeft > div > img {
|
|
|
+ margin-right: 5px;
|
|
|
+}
|
|
|
+.m-operation {
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ display: flex;
|
|
|
+ font-size: 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-right: 30px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ align-items: baseline;
|
|
|
+}
|
|
|
+.m-operation :first-child {
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 26px;
|
|
|
+ text-align: left;
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+.m-operation :nth-child(2) {
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 400;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+.ca-top {
|
|
|
+ width: 100%;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.ca-bottom {
|
|
|
+ width: 100%;
|
|
|
+ height: 120px;
|
|
|
}
|
|
|
|
|
|
-.c_c_item {
|
|
|
- background-color: none;
|
|
|
+.ca-b-operation {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: flex-end;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+.ca-b-o-header {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_user {
|
|
|
- width: 100%;
|
|
|
- height: auto;
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 10px;
|
|
|
+.ca-b-o-h-left {
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_u_message {
|
|
|
- height: auto;
|
|
|
- width: auto;
|
|
|
- max-width: calc(100% - 50px - 40px);
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: flex-end;
|
|
|
- margin-right: 5px;
|
|
|
+.ca-b-o-h-l-select {
|
|
|
+ width: auto;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ position: relative;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin-right: 20px;
|
|
|
+ border-radius: 15px;
|
|
|
+ cursor: pointer;
|
|
|
+ background-color: white;
|
|
|
}
|
|
|
-.c_c_i_u_m_top {
|
|
|
- margin-bottom: 10px;
|
|
|
- display: flex;
|
|
|
- align-items: flex-end;
|
|
|
+
|
|
|
+/* .ca-b-o-h-l-select:hover .languageBlock{
|
|
|
+ display: block;
|
|
|
}
|
|
|
+.languageBlock {
|
|
|
+ display: none;
|
|
|
+} */
|
|
|
|
|
|
-.c_c_i_u_m_top > span {
|
|
|
- margin-left: 5px;
|
|
|
+.languageList {
|
|
|
+ position: absolute;
|
|
|
+ background-color: #fff;
|
|
|
+ top: calc(-100% - 100px);
|
|
|
+ left: 0%;
|
|
|
+ width: 120px;
|
|
|
+ /* padding: 0 10px; */
|
|
|
+ /* box-sizing: border-box; */
|
|
|
+ padding: 10px 0;
|
|
|
+ border-radius: 5px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ height: 100px;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_u_m_bottom {
|
|
|
- display: flex;
|
|
|
- align-items: flex-end;
|
|
|
+.languageList >>> .el-radio {
|
|
|
+ width: 70%;
|
|
|
+ /* margin-bottom: 10px; */
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin: 0;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+.radioBg {
|
|
|
+ background: rgba(243, 247, 253, 1);
|
|
|
}
|
|
|
|
|
|
-.coptText {
|
|
|
- min-width: 15px;
|
|
|
- min-height: 15px;
|
|
|
- display: block;
|
|
|
- background: url("../../../../assets/icon/pblCourse/copyIcon.png") no-repeat;
|
|
|
- background-size: 100% 100%;
|
|
|
- margin: 0px 10px 6px 10px;
|
|
|
- cursor: pointer;
|
|
|
+.ca-b-o-h-l-s-icon {
|
|
|
+ margin-right: 2px;
|
|
|
+ font-size: 16px;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_u_m_content {
|
|
|
- width: auto;
|
|
|
- height: auto;
|
|
|
- padding: 10px;
|
|
|
- background-color: #e2eeff;
|
|
|
- border-radius: 8px 2px 8px 8px;
|
|
|
- border: solid 1px #000000e5;
|
|
|
+.ca-b-o-h-s-l-icon2 {
|
|
|
+ margin-left: 5px;
|
|
|
+ font-size: 18px;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_u_avatar {
|
|
|
- width: 45px;
|
|
|
- height: 45px;
|
|
|
- margin: 0px 0 0 10px;
|
|
|
+.ca-b-o-h-l-btn {
|
|
|
+ width: auto;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin-right: 20px;
|
|
|
+ border-radius: 15px;
|
|
|
+ background-color: white;
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_ai {
|
|
|
- margin-top: 10px;
|
|
|
- width: 100%;
|
|
|
- height: auto;
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 10px;
|
|
|
+.ca-b-o-h-right {
|
|
|
+ width: auto;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_ai_avatar {
|
|
|
- width: 45px;
|
|
|
- height: 45px;
|
|
|
- margin: 0px 0 0 10px;
|
|
|
+.ca-b-o-h-r-radio {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ background-color: #e7e7e7;
|
|
|
+ border-radius: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.ca-b-o-h-r-radio > span {
|
|
|
+ margin-right: 5px;
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_ai_message {
|
|
|
- height: auto;
|
|
|
- width: auto;
|
|
|
- max-width: calc(100% - 50px - 40px);
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: flex-start;
|
|
|
- margin-left: 5px;
|
|
|
+.ca-b-o-main {
|
|
|
+ width: 100%;
|
|
|
+ /* flex: 1; */
|
|
|
+ height: 64px;
|
|
|
+
|
|
|
+ margin-top: 5px;
|
|
|
+ border-radius: 16px;
|
|
|
+ transition: 0.3s;
|
|
|
+ position: relative;
|
|
|
}
|
|
|
-.c_c_i_ai_m_top {
|
|
|
- display: flex;
|
|
|
- align-items: flex-end;
|
|
|
- margin-bottom: 10px;
|
|
|
+
|
|
|
+.ca-b-o-main:hover {
|
|
|
+ box-shadow: 0 5px 10px 10px #e1e8eb;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_ai_m_top > span {
|
|
|
- margin-left: 5px;
|
|
|
+.ca-b-o-m-tape {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 20px;
|
|
|
+ color: #3681fc;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+}
|
|
|
+.ca-b-o-m-tapeTwo {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 20px;
|
|
|
+ color: #3681fc;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 0 20px;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+}
|
|
|
+.ca-b-o-m-tapeTwo >>> .vueAudioBetter {
|
|
|
+ width: 90%;
|
|
|
+}
|
|
|
+.ca-b-o-m-tape > span {
|
|
|
+ margin-right: 10px;
|
|
|
+ font-size: 22px;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_ai_m_bottom {
|
|
|
- display: flex;
|
|
|
- align-items: flex-end;
|
|
|
+.ca-b-o-m-tape:hover {
|
|
|
+ color: #1467ee;
|
|
|
}
|
|
|
|
|
|
-.c_c_i_ai_m_content {
|
|
|
- min-width: 40px;
|
|
|
- min-height: 25px;
|
|
|
- width: auto;
|
|
|
- height: auto;
|
|
|
- padding: 10px;
|
|
|
- background-color: #ffffff;
|
|
|
- border-radius: 2px 8px 8px 8px;
|
|
|
- border: solid 1px #000000e5;
|
|
|
+.ca-b-o-m-inputAre {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 100%;
|
|
|
+ height: auto;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
}
|
|
|
|
|
|
-.chatContent >>> ol {
|
|
|
- margin-left: 25px;
|
|
|
+.ca-b-o-m-TapeArea {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: #f0f2f5;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+ align-items: center;
|
|
|
+ padding-right: 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
-.chatContent >>> ul {
|
|
|
- margin-left: 25px;
|
|
|
+.ca-b-o-m-i-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
-.chatTime {
|
|
|
- font-size: 14px;
|
|
|
- margin: 0 10px;
|
|
|
- color: #2c2f3b;
|
|
|
+.ca-b-o-m-i-left > div > div {
|
|
|
+ color: #ee3e3e;
|
|
|
+ font-weight: bold;
|
|
|
}
|
|
|
|
|
|
-.c_controls {
|
|
|
- width: 100%;
|
|
|
- height: 30px;
|
|
|
+.ca-b-o-m-i-left > div > span {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 5px;
|
|
|
}
|
|
|
|
|
|
-.c_controls > span {
|
|
|
- max-height: 30px;
|
|
|
- width: auto;
|
|
|
- padding: 5px 10px;
|
|
|
- font-size: 14px;
|
|
|
- border-radius: 15px;
|
|
|
- box-shadow: 0 0 2px 0px gray;
|
|
|
- margin-left: 10px;
|
|
|
- cursor: pointer;
|
|
|
+.ca-b-o-m-i-left > img {
|
|
|
+ margin-left: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 20px;
|
|
|
}
|
|
|
|
|
|
-.c_controls > span:hover {
|
|
|
- background-color: #f3f7fd;
|
|
|
+.ca-b-o-m-left {
|
|
|
+ flex: 1;
|
|
|
+ height: auto;
|
|
|
+ min-height: 64px;
|
|
|
+ display: flex;
|
|
|
+ /* justify-content: center; */
|
|
|
+ align-items: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-left: 20px;
|
|
|
}
|
|
|
|
|
|
-.c_bottom {
|
|
|
- width: 100%;
|
|
|
- height: 56px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- box-sizing: border-box;
|
|
|
- border-top: solid 0.5px #e7e7e7;
|
|
|
+.ca-b-o-m-left > textarea {
|
|
|
+ resize: none;
|
|
|
+ min-height: 50px;
|
|
|
+ margin: 7px 0;
|
|
|
+ max-height: 500px;
|
|
|
+ width: 100%;
|
|
|
+ font-size: 18px;
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ resize: none;
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+.ca-b-o-m-right {
|
|
|
+ width: 100px;
|
|
|
+ min-width: 80px;
|
|
|
+ height: 64px;
|
|
|
+ max-height: 64px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 10px;
|
|
|
}
|
|
|
|
|
|
-.c_b_record {
|
|
|
- width: 30px;
|
|
|
- height: 30px;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
+#myTextarea::-webkit-input-placeholder {
|
|
|
+ /* Chrome, Opera, Safari */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
}
|
|
|
|
|
|
-.c_b_record > span {
|
|
|
- width: 24px;
|
|
|
- height: 24px;
|
|
|
- background-image: url("../../../../assets/icon/pblCourse/recordIcon.png");
|
|
|
- background-size: 100% 100%;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
+#myTextarea:-moz-placeholder {
|
|
|
+ /* Firefox 18- */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
+ opacity: 1; /* 修复Firefox的透明度问题 */
|
|
|
}
|
|
|
|
|
|
-.c_b_inputArea {
|
|
|
- width: calc(100% - 100px);
|
|
|
- background-color: #f3f3f3;
|
|
|
- border-radius: 50px;
|
|
|
- height: 80%;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- margin: 0 15px;
|
|
|
+#myTextarea::-moz-placeholder {
|
|
|
+ /* Firefox 19+ */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
+ opacity: 1; /* 修复Firefox的透明度问题 */
|
|
|
}
|
|
|
|
|
|
-.c_b_input {
|
|
|
- width: calc(100% - 40px);
|
|
|
- margin-right: 10px;
|
|
|
+#myTextarea:-ms-input-placeholder {
|
|
|
+ /* Internet Explorer 10-11 */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
}
|
|
|
+/* .ca-b-o-m-right > span {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ background: url("../../../../assets/icon/classroomObservation/tapeIng.png")
|
|
|
+ no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 10px;
|
|
|
+} */
|
|
|
|
|
|
-.c_b_input >>> .el-input__inner {
|
|
|
- border: none;
|
|
|
- background-color: #f3f3f3;
|
|
|
- outline: none;
|
|
|
- border-radius: 50px 0 0 50px;
|
|
|
- font-size: 1.2em;
|
|
|
+.ca-b-o-m-right > div {
|
|
|
+ width: 52px;
|
|
|
+ height: 30px;
|
|
|
+
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: white;
|
|
|
+ font-size: 14px;
|
|
|
+ border-radius: 5px;
|
|
|
+ background-color: #1467ee;
|
|
|
+ margin-right: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-r-dsiableBtn {
|
|
|
+ /* 禁止手势 */
|
|
|
+ cursor: not-allowed !important;
|
|
|
+ background-color: #aeccfe !important;
|
|
|
+}
|
|
|
+.lyStart {
|
|
|
+ width: 38px;
|
|
|
+ height: 32px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.ca_b_o_m_roleList {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ max-height: calc(100vh - 230px);
|
|
|
+ margin-bottom: 70px;
|
|
|
+ overflow: auto;
|
|
|
+ background-color: white;
|
|
|
+ border-radius: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b_o_m_rl_item {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ background-color: #f3f7fd;
|
|
|
+ border-radius: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: 0.3s;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b_o_m_rl_itemActive {
|
|
|
+ background-color: #c3ddfa;
|
|
|
}
|
|
|
|
|
|
-.c_b_inputArea > span {
|
|
|
- width: 24px;
|
|
|
- height: 24px;
|
|
|
- background-image: url("../../../../assets/icon/pblCourse/fileIcon.png");
|
|
|
- background-size: 100% 100%;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- margin-right: 10px;
|
|
|
- cursor: pointer;
|
|
|
+.ca_b_o_m_rl_i_left {
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b-o_m_rl_i_top {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+.ca_b-o_m_rl_i_top > div {
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b-o_m_rl_i_top > div > span {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 5px;
|
|
|
+ color: #6b798e;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b-o_m_rl_i_bottom {
|
|
|
+ margin-top: 10px;
|
|
|
+ width: 90%;
|
|
|
+ overflow: hidden;
|
|
|
+ display: block;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+.ca-top >>> .editorBar {
|
|
|
+ height: 100%;
|
|
|
+ position: relative;
|
|
|
+ max-height: calc(100vh - 300px);
|
|
|
}
|
|
|
|
|
|
-.c_b_send {
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- border-radius: 50%;
|
|
|
- background-color: #3681fc;
|
|
|
- cursor: pointer;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-
|
|
|
-.c_b_send > span {
|
|
|
- width: 60%;
|
|
|
- height: 60%;
|
|
|
- background-image: url("../../../../assets/icon/pblCourse/sendIcon.png");
|
|
|
- background-size: 100% 100%;
|
|
|
+.ca-top >>> .editorBar .text {
|
|
|
+ height: calc(100% - 42px);
|
|
|
+ max-height: calc(100% - 42px);
|
|
|
+ overflow: auto;
|
|
|
}
|
|
|
</style>
|