|
@@ -64,12 +64,12 @@
|
|
|
></div>
|
|
|
<div v-show="showTranscriptType == 1" class="editorBarData">
|
|
|
<template v-if="bmData.jsonData">
|
|
|
- <div class="ebd_save" v-if="false">
|
|
|
+ <div class="ebd_save">
|
|
|
<van-popover placement="left" v-model="showEditorBarDataPopover" trigger="click">
|
|
|
<div class="ebd_s_btnArea">
|
|
|
- <el-button size="small" type="primary" @click.stop="speakerCodingFn">说话人编码</el-button>
|
|
|
+ <!-- <el-button size="small" type="primary" @click.stop="speakerCodingFn">说话人编码</el-button> -->
|
|
|
|
|
|
- <el-button size="small" type="primary" @click.stop="behaviorCodingFn">行为编码</el-button>
|
|
|
+ <!-- <el-button size="small" type="primary" @click.stop="behaviorCodingFn">行为编码</el-button> -->
|
|
|
|
|
|
<el-button size="small" type="primary" @click.stop="saveEditorBarFn">保存</el-button>
|
|
|
</div>
|
|
@@ -295,6 +295,28 @@ import { upload_file_knowledgeRequest } from '@/api/classObserve.js'
|
|
|
let OpenCC = require('opencc-js')
|
|
|
import EditorBar from './components/wangEnduit.vue'
|
|
|
|
|
|
+const OPTIONS_GROUP = {
|
|
|
+ default: [
|
|
|
+ "老师讲课",
|
|
|
+ "老师提问或点名",
|
|
|
+ "老师板书或操作",
|
|
|
+ "老师评价或反馈",
|
|
|
+ "老师其他",
|
|
|
+ "学生发言",
|
|
|
+ "学生小组活动",
|
|
|
+ "学生自主学习",
|
|
|
+ "学生汇报分享",
|
|
|
+ "学生其他",
|
|
|
+ ],
|
|
|
+};
|
|
|
+const ATTENTION_GROUP = {
|
|
|
+ default:
|
|
|
+ "- 先根据说话人角色判断,再在对应角色的选项中选择选项\n- 如果没有合适的选项,默认使用`老师其他`或者`学生其他`",
|
|
|
+};
|
|
|
+const ROLE_OPTIONS_GROUP = {
|
|
|
+ default: ["老师", "学生"],
|
|
|
+};
|
|
|
+
|
|
|
const getFile = url => {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
var credentials = {
|
|
@@ -349,7 +371,11 @@ export default {
|
|
|
imageList: {
|
|
|
type: Object,
|
|
|
default: () => {}
|
|
|
- }
|
|
|
+ },
|
|
|
+ actionTypesMap:{
|
|
|
+ type:Object,
|
|
|
+ default:()=>{}
|
|
|
+ },
|
|
|
},
|
|
|
components: {
|
|
|
EditorBar
|
|
@@ -358,6 +384,7 @@ export default {
|
|
|
return {
|
|
|
isParse: false,
|
|
|
loading: false,
|
|
|
+ userId:this.$store.state.user.id,
|
|
|
showTranscriptType: 0, //0:原文速览 1;转录文稿
|
|
|
showEditorBarDataPopover: false,
|
|
|
recordedForm: {
|
|
@@ -382,7 +409,8 @@ export default {
|
|
|
{ index: 3, label: '粤语' },
|
|
|
{ index: 2, label: '普通话' }
|
|
|
],
|
|
|
- choiceLanguageIndex: 2
|
|
|
+ choiceLanguageIndex: 2,
|
|
|
+ jobContext:null,
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
@@ -395,8 +423,9 @@ export default {
|
|
|
message: `确定保存转录文稿?`
|
|
|
})
|
|
|
.then(() => {
|
|
|
- console.log('保存')
|
|
|
- this.showEditorBarDataPopover = false
|
|
|
+ this.$parent.saveEditorBar(true).then(_=>{
|
|
|
+ this.$toast.success("保存成功")
|
|
|
+ });
|
|
|
})
|
|
|
.catch(() => {
|
|
|
console.log('不保存')
|
|
@@ -410,6 +439,7 @@ export default {
|
|
|
})
|
|
|
.then(() => {
|
|
|
console.log('获取说话人编码')
|
|
|
+ this.startContinuousJobs('role');
|
|
|
this.showEditorBarDataPopover = false
|
|
|
})
|
|
|
.catch(() => {
|
|
@@ -424,12 +454,178 @@ export default {
|
|
|
})
|
|
|
.then(() => {
|
|
|
console.log('获取行为编码')
|
|
|
+ this.startContinuousJobs('actionType');
|
|
|
this.showEditorBarDataPopover = false
|
|
|
})
|
|
|
.catch(() => {
|
|
|
console.log('不获取')
|
|
|
this.showEditorBarDataPopover = true
|
|
|
})
|
|
|
+ },
|
|
|
+ async startContinuousJobs(type /* role, actionType */) {
|
|
|
+ const key = "default";
|
|
|
+ const { appToken, options, attention } = {
|
|
|
+ role: {
|
|
|
+ appToken: "app-TonzLPv7rPG0EtnFKszOWjwt",
|
|
|
+ options: ROLE_OPTIONS_GROUP[key],
|
|
|
+ attention: undefined,
|
|
|
+ },
|
|
|
+ actionType: {
|
|
|
+ appToken: "app-zOMxBqyEKoJSvW10e5SS0kgj",
|
|
|
+ options: OPTIONS_GROUP[key],
|
|
|
+ attention: ATTENTION_GROUP[key],
|
|
|
+ },
|
|
|
+ }[type];
|
|
|
+ const config = {
|
|
|
+ headers: {
|
|
|
+ Authorization: `Bearer ${appToken}`,
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ },
|
|
|
+ };
|
|
|
+ const content = this.bmData.jsonData.editorBarData.content;
|
|
|
+ const div = document.createElement("div");
|
|
|
+ div.innerHTML = content;
|
|
|
+ const tableRows = _.slice(div.querySelectorAll(`table tbody tr`), 1);
|
|
|
+ if (!tableRows.length || tableRows[0].cells.length < 7) {
|
|
|
+ this.$toast.fail("没有可编码的内容");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const ctrl = new AbortController();
|
|
|
+ this.jobContext = {
|
|
|
+ ctrl,
|
|
|
+ status: "running",
|
|
|
+ restart: () => {},
|
|
|
+ pause: () => {},
|
|
|
+ stop: () => {
|
|
|
+ const err = new Error();
|
|
|
+ err.name = "StopError";
|
|
|
+ this.jobContext.ctrl.abort(err);
|
|
|
+ },
|
|
|
+ progress: {
|
|
|
+ current: 0,
|
|
|
+ currentSize: 0,
|
|
|
+ total: tableRows.length,
|
|
|
+ percentage: 0,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ // large chunk size will cause token limit and slower
|
|
|
+ const chunkSize = 10;
|
|
|
+ this.actionTypesMap.jsonData[key] = Array.from({ length: tableRows.length }).fill(
|
|
|
+ ""
|
|
|
+ );
|
|
|
+
|
|
|
+ const jobsResult = [];
|
|
|
+ const jobs = _.chunk(tableRows, chunkSize).map((rows, index) => {
|
|
|
+ return async (pauseSignal) => {
|
|
|
+ this.jobContext.progress.current = index * chunkSize;
|
|
|
+ this.jobContext.progress.currentSize = rows.length;
|
|
|
+ this.jobContext.progress.percentage =
|
|
|
+ ((index * chunkSize) / tableRows.length) * 100;
|
|
|
+ const res = await fetch('https://dify.cocorobo.cn/v1/workflows/run',{
|
|
|
+ signal: AbortSignal.any([this.jobContext.ctrl.signal, pauseSignal]),
|
|
|
+ method: "POST",
|
|
|
+ body: JSON.stringify({
|
|
|
+ inputs: {
|
|
|
+ // PERF better to just include `role` and `content` to minimize token cost
|
|
|
+ rows: JSON.stringify(
|
|
|
+ rows.map((r) => ({
|
|
|
+ content: r.cells[3].textContent,
|
|
|
+ role: r.cells[5].textContent,
|
|
|
+ }))
|
|
|
+ ),
|
|
|
+ options: options.join(","),
|
|
|
+ attention,
|
|
|
+ },
|
|
|
+ response_mode: "blocking",
|
|
|
+ user: this.userId,
|
|
|
+ }),
|
|
|
+ ...config,
|
|
|
+ }).then((res) => res.json());
|
|
|
+ const error = _.get(res, ["data", "error"], null);
|
|
|
+ // test
|
|
|
+ // throw new Error('mock error');
|
|
|
+ if (error) {
|
|
|
+ const err = new Error(error);
|
|
|
+ err.name = "DifyError";
|
|
|
+ throw err;
|
|
|
+ }
|
|
|
+ const chunkResult = _.get(res, ["data", "outputs", "result"], []);
|
|
|
+ jobsResult.splice(
|
|
|
+ index * chunkSize,
|
|
|
+ rows.length,
|
|
|
+ ...Object.assign(new Array(rows.length), chunkResult.slice(0, rows.length))
|
|
|
+ );
|
|
|
+ // PERF dom更新太卡了
|
|
|
+ // this.changeEditorBar({
|
|
|
+ // transcriptionData: this.transcriptionData.content,
|
|
|
+ // editorBarData: this.editorBarData,
|
|
|
+ // });
|
|
|
+ };
|
|
|
+ });
|
|
|
+ while (!this.jobContext.ctrl.signal.aborted && jobs.length > 0) {
|
|
|
+ const job = jobs.shift();
|
|
|
+ while (!this.jobContext.ctrl.signal.aborted) {
|
|
|
+ const pauseCtrl = new AbortController();
|
|
|
+ this.jobContext.pause = () => {
|
|
|
+ const err = new Error();
|
|
|
+ err.name = "PauseError";
|
|
|
+ pauseCtrl.abort(err);
|
|
|
+ };
|
|
|
+ try {
|
|
|
+ await job(pauseCtrl.signal);
|
|
|
+ break;
|
|
|
+ } catch (err) {
|
|
|
+ // console.error(err);
|
|
|
+ if (err.name === "StopError") {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ this.jobContext.status = "paused";
|
|
|
+ if (err.name === "PauseError") {
|
|
|
+ this.jobContext.error = `用户暂停`;
|
|
|
+ } else {
|
|
|
+ this.jobContext.error = `部分生成失败。点击按钮可继续尝试生成`;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const restartPromise = new Promise((resolve, reject) => {
|
|
|
+ this.jobContext.restart = resolve;
|
|
|
+ this.jobContext.ctrl.signal.addEventListener("abort", reject);
|
|
|
+ });
|
|
|
+ await restartPromise;
|
|
|
+ this.jobContext.status = "running";
|
|
|
+ this.jobContext.error = null;
|
|
|
+ } catch (_err) {
|
|
|
+ // nothing to do, just continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (type === "actionType") {
|
|
|
+ this.actionTypesMap.jsonData[key] = jobsResult;
|
|
|
+ } else if (type === "role") {
|
|
|
+ const _div = document.createRange().createContextualFragment(this.bmData.jsonData.editorBarData.content);
|
|
|
+ const _table = _div.querySelector('table')
|
|
|
+ const _rows = _table.querySelectorAll(`tbody tr`);
|
|
|
+ const _actionTypes = []
|
|
|
+ _rows.forEach((i, index) => {
|
|
|
+ while (i.cells.length > 7) {
|
|
|
+ i.removeChild(i.lastElementChild);
|
|
|
+ }
|
|
|
+ if (index == 0) return;
|
|
|
+ const actionTypeCell = i.cells[6] && i.removeChild(i.cells[6]);
|
|
|
+ i.cells[5].textContent = jobsResult[index - 1]
|
|
|
+ _actionTypes.push(_.get(actionTypeCell, "textContent", ""));
|
|
|
+ });
|
|
|
+ this.actionTypesMap.jsonData[key] = _actionTypes;
|
|
|
+ this.bmData.jsonData.editorBarData.content = _table.outerHTML;
|
|
|
+ }
|
|
|
+ this.$parent.saveData(this.bmData).then(_=>{
|
|
|
+ console.log("保存成功")
|
|
|
+ })
|
|
|
+ // this.changeEditorBar({
|
|
|
+ // transcriptionData: this.transcriptionData.content,
|
|
|
+ // editorBarData: this.editorBarData,
|
|
|
+ // });
|
|
|
+ this.jobContext = null;
|
|
|
},
|
|
|
changeLanguageFn(newIndex) {
|
|
|
if (this.isParse) return this.$toast('正在录音中...')
|
|
@@ -437,7 +633,8 @@ export default {
|
|
|
this.changeLanguageShow = false
|
|
|
},
|
|
|
goChat() {
|
|
|
- this.$router.push({ path: '/aiChat', query: {} })
|
|
|
+ this.cutPage(9)
|
|
|
+ // this.$router.push({ path: '/aiChat', query: {} })
|
|
|
},
|
|
|
historyBtn() {
|
|
|
this.historyShow = true
|
|
@@ -445,7 +642,7 @@ export default {
|
|
|
// 绑定表单
|
|
|
cutPage(val) {
|
|
|
if (this.isParse) return
|
|
|
- if ([2, 3, 8].includes(val) && !this.tid) {
|
|
|
+ if ([2, 3, 8,9].includes(val) && !this.tid) {
|
|
|
return this.$toast('请先选择或创建课堂')
|
|
|
}
|
|
|
this.$emit('cutPage', val)
|
|
@@ -1048,7 +1245,7 @@ export default {
|
|
|
console.log(e)
|
|
|
this.$toast.success('转译完成')
|
|
|
// _this.showGetTextLoading = false;
|
|
|
- this.saveEditorBar()
|
|
|
+ this.$parent.saveEditorBar()
|
|
|
}
|
|
|
|
|
|
iiframe.contentWindow.doContinuousPronunciationAssessment('', {
|