|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
|
- <div class="chatArea" v-loading="loading">
|
|
|
+ <div class="chatArea" v-loading="loading" :element-loading-text="loadingText">
|
|
|
<div class="m-operation">
|
|
|
<div>实时转录</div>
|
|
|
<div>{{ createTime }}</div>
|
|
@@ -59,6 +59,12 @@
|
|
|
v-loading="uploadFileLoading"
|
|
|
@change="changeEditor"
|
|
|
>
|
|
|
+ <el-button
|
|
|
+ style="position: absolute; bottom: 70px; right: 20px; z-index: 10002"
|
|
|
+ type="primary"
|
|
|
+ @click.stop="generateActionTypesMap"
|
|
|
+ >自动编码</el-button
|
|
|
+ >
|
|
|
<el-button
|
|
|
style="position: absolute; bottom: 20px; right: 20px; z-index: 10002"
|
|
|
type="primary"
|
|
@@ -385,6 +391,7 @@ import MarkdownIt from "markdown-it";
|
|
|
import EditorBar from "./wangEnduit";
|
|
|
const lamejs = require("lamejs");
|
|
|
import vpdf from "./vpdf";
|
|
|
+import _ from 'lodash'
|
|
|
// const recorder = new Recorder({
|
|
|
// sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
|
|
|
// sampleRate: 48000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
|
|
@@ -496,6 +503,7 @@ export default {
|
|
|
languageRadio: 2, //设置选择语言
|
|
|
languageShow: false, //控制显示
|
|
|
loading: false,
|
|
|
+ loadingText: undefined,
|
|
|
chatLoading: false,
|
|
|
transcriptionLoading: false,
|
|
|
uploadFileLoading: false,
|
|
@@ -567,6 +575,7 @@ export default {
|
|
|
content: "",
|
|
|
},
|
|
|
chatList: [],
|
|
|
+ actionTypesMap: {},
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
@@ -587,6 +596,22 @@ export default {
|
|
|
choseRoleList() {
|
|
|
this.roleListIndex = 0;
|
|
|
},
|
|
|
+ tid: {
|
|
|
+ async handler(tid) {
|
|
|
+ console.log('tid handle: ', tid)
|
|
|
+ if (!tid) {
|
|
|
+ this.actionTypesMap = undefined
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.actionTypesMap = await this.loadActionTypesMap()
|
|
|
+ console.log('result: ', this.actionTypesMap)
|
|
|
+ if (!this.actionTypesMap) {
|
|
|
+ const res = await this.insertActionTypes()
|
|
|
+ console.log('res: ', res)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
handleBlur(event) {
|
|
@@ -769,8 +794,7 @@ export default {
|
|
|
<th>发言内容</th>
|
|
|
<th>时长</th>
|
|
|
<th>说话人身份</th>
|
|
|
- <th>行为编码</th>
|
|
|
- </tr>
|
|
|
+ </tr>
|
|
|
`;
|
|
|
this.recordedForm.textList.forEach((item, index) => {
|
|
|
_result += `<tr>
|
|
@@ -780,7 +804,6 @@ export default {
|
|
|
<td>${item.value}</td>
|
|
|
<td>${item.time}</td>
|
|
|
<td></td>
|
|
|
- <td></td>
|
|
|
</tr>`;
|
|
|
});
|
|
|
_result += `
|
|
@@ -791,7 +814,6 @@ export default {
|
|
|
<td></td>
|
|
|
<td></td>
|
|
|
<td></td>
|
|
|
- <td></td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
|
</table>`;
|
|
@@ -1374,7 +1396,7 @@ export default {
|
|
|
let _msg = `Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
|
|
|
ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
|
|
|
Instruction: Based on the context, follow "Format example", write content
|
|
|
-
|
|
|
+
|
|
|
请你基于以下{用户给定的文本},执行以下任务,按要求输出对应内容。
|
|
|
|
|
|
## 角色
|
|
@@ -2012,32 +2034,41 @@ ${JSON.stringify(_list)}
|
|
|
|
|
|
let _sentence = 0;
|
|
|
let _words = 0;
|
|
|
+ let _editorBarDataContentRows = []
|
|
|
+ let _actionTypes = []
|
|
|
|
|
|
if (this.editorBarData.type == 0) {
|
|
|
let _data = this.editorBarData.content;
|
|
|
let _div = document.createElement("div");
|
|
|
_div.innerHTML = _data;
|
|
|
- let _test = [];
|
|
|
let _tableRows = _div.querySelectorAll(`table tbody tr`);
|
|
|
_tableRows.forEach((i, index) => {
|
|
|
+ while (i.cells.length > 7) {
|
|
|
+ i.removeChild(i.lastElementChild)
|
|
|
+ }
|
|
|
+ const actionTypeCell = i.cells[6] && i.removeChild(i.cells[6])
|
|
|
+ _editorBarDataContentRows.push(i.outerHTML)
|
|
|
if (index == 0) return;
|
|
|
- let obj = {
|
|
|
- index: i.cells[0].textContent,
|
|
|
- startTime: i.cells[1].textContent,
|
|
|
- endTime: i.cells[2].textContent,
|
|
|
- message: i.cells[3].textContent,
|
|
|
- time: i.cells[4].textContent,
|
|
|
- role: i.cells[5].textContent,
|
|
|
- behavior: i.cells[6].textContent,
|
|
|
- };
|
|
|
- _test.push(obj);
|
|
|
if (i.cells[3].textContent != "") {
|
|
|
_sentence += 1;
|
|
|
_words += i.cells[3].textContent.length;
|
|
|
}
|
|
|
+ _actionTypes.push(_.get(actionTypeCell, 'textContent', ''))
|
|
|
});
|
|
|
- // this.getBehaviorCoding(_test)
|
|
|
}
|
|
|
+ const _editorBarDataContent =
|
|
|
+ `<table
|
|
|
+ border="0"
|
|
|
+ width="100%"
|
|
|
+ cellpadding="0"
|
|
|
+ cellspacing="0"
|
|
|
+ style="text-align: center"
|
|
|
+ >
|
|
|
+ <tbody>
|
|
|
+ ${_editorBarDataContentRows.join('')}
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ `
|
|
|
|
|
|
this.editorBarData.sentenceNum = _sentence;
|
|
|
this.editorBarData.wordsNum = _words;
|
|
@@ -2046,23 +2077,65 @@ ${JSON.stringify(_list)}
|
|
|
"updateTranscription",
|
|
|
{
|
|
|
transcriptionData: this.transcriptionData.content,
|
|
|
- editorBarData: this.editorBarData,
|
|
|
+ editorBarData: { ...this.editorBarData, content: _editorBarDataContent },
|
|
|
},
|
|
|
() => {
|
|
|
this.progressData.uploadLoading = false;
|
|
|
this.loading = false;
|
|
|
}
|
|
|
);
|
|
|
+ // TODO 不同板块用id做key
|
|
|
+ this.actionTypesMap.jsonData['default'] = _actionTypes
|
|
|
+ this.saveActionTypesMap()
|
|
|
}
|
|
|
},
|
|
|
changeEditorBar({ transcriptionData, editorBarData }) {
|
|
|
this.transcriptionData.content = transcriptionData;
|
|
|
+ let _editorBarData = editorBarData
|
|
|
try {
|
|
|
- let _result = JSON.parse(editorBarData);
|
|
|
- this.editorBarData = _result;
|
|
|
+ if (typeof _editorBarData === 'string' ) {
|
|
|
+ _editorBarData = JSON.parse(_editorBarData);
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
- this.editorBarData = editorBarData;
|
|
|
+ console.error(error)
|
|
|
}
|
|
|
+ const _div = document.createElement('div')
|
|
|
+ _div.innerHTML = _editorBarData.content
|
|
|
+ const _rows = _div.querySelectorAll('table tbody tr')
|
|
|
+ let _content = ''
|
|
|
+ if (_rows.length) {
|
|
|
+ const _actionTypeColumn = [
|
|
|
+ '行为编码',
|
|
|
+ ..._.get(this.actionTypesMap,['jsonData','default'], [])
|
|
|
+ ]
|
|
|
+ _content =
|
|
|
+ `<table
|
|
|
+ border="0"
|
|
|
+ width="100%"
|
|
|
+ cellpadding="0"
|
|
|
+ cellspacing="0"
|
|
|
+ style="text-align: center"
|
|
|
+ >
|
|
|
+ <tbody>
|
|
|
+ ${_.zip(_rows, _actionTypeColumn).map(( [ _row, _actionType ], index ) => {
|
|
|
+ while (_row.cells.length >= 7) {
|
|
|
+ _row.removeChild(_row.lastElementChild)
|
|
|
+ }
|
|
|
+ let cellname = 'td'
|
|
|
+ if (index === 0) {
|
|
|
+ cellname = 'th'
|
|
|
+ }
|
|
|
+ const ch = document.createElement(cellname)
|
|
|
+ ch.innerHTML = _actionType || ''
|
|
|
+ _row.appendChild(ch)
|
|
|
+ return _row.outerHTML
|
|
|
+ }).join('')}
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ `
|
|
|
+ }
|
|
|
+ console.log(_content)
|
|
|
+ this.editorBarData = { ..._editorBarData, content: _content };
|
|
|
},
|
|
|
// 获取对话记录
|
|
|
getChatList() {
|
|
@@ -2070,7 +2143,6 @@ ${JSON.stringify(_list)}
|
|
|
if (!this.tid) return;
|
|
|
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,
|
|
@@ -2155,6 +2227,88 @@ ${JSON.stringify(_list)}
|
|
|
};
|
|
|
this.audioUrl = "";
|
|
|
},
|
|
|
+ async loadActionTypesMap() {
|
|
|
+ const res = await this.ajax.post("https://gpt4.cocorobo.cn/get_classroom_observation_new", {tid: this.tid, type: '11'})
|
|
|
+ const result = _.get(res,[ 'data','FunctionResponse','result' ], '[]')
|
|
|
+ if (result instanceof Array) {
|
|
|
+ return undefined
|
|
|
+ }
|
|
|
+ const data = _.get(JSON.parse( result ), 0)
|
|
|
+ return {...data, jsonData: JSON.parse( data.jsonData )}
|
|
|
+ },
|
|
|
+ async insertActionTypes() {
|
|
|
+ return await this.ajax.post("https://gpt4.cocorobo.cn/insert_classroom_observation", {tid: this.tid, type: '11', json_data: JSON.stringify( {default: []} ), index: 0,userid: this.userId})
|
|
|
+ },
|
|
|
+ async saveActionTypesMap() {
|
|
|
+ try {
|
|
|
+ return await this.ajax.post(
|
|
|
+ "https://gpt4.cocorobo.cn/update_classroom_observation",
|
|
|
+ {id: this.actionTypesMap.id, json_data: JSON.stringify(this.actionTypesMap.jsonData)}
|
|
|
+ )
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e)
|
|
|
+ this.$message.error(e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async generateActionTypesMap() {
|
|
|
+ const key = 'default'
|
|
|
+ const appToken = 'app-zOMxBqyEKoJSvW10e5SS0kgj'
|
|
|
+ // the default options
|
|
|
+ const options = ['老师讲课','老师提问或点名','老师板书或操作','老师评价或反馈','老师其他','学生发言','学生小组活动','学生自主学习','学生汇报分享','学生其他']
|
|
|
+ const config = {
|
|
|
+ headers: { Authorization: `Bearer ${appToken}`, 'Content-Type': 'application/json' }
|
|
|
+ }
|
|
|
+ const content = this.editorBarData.content;
|
|
|
+ const div = document.createElement("div");
|
|
|
+ div.innerHTML = content;
|
|
|
+ const tableRows = _.slice(div.querySelectorAll(`table tbody tr`), 1);
|
|
|
+ if (!tableRows.length) {
|
|
|
+ this.$notify.info('没有可编码的内容')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ tableRows.forEach((i) => {
|
|
|
+ while (i.cells.length >= 7) {
|
|
|
+ i.removeChild(i.lastElementChild)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.loading = true
|
|
|
+ this.loadingText = `0/${tableRows.length}`
|
|
|
+ try {
|
|
|
+ const chunkSize = 2
|
|
|
+ this.actionTypesMap.jsonData[key] = Array.from({length: tableRows.length})
|
|
|
+ // action type fetch by every { chunkSize } rows
|
|
|
+ for (const [ index, rows ] of _.chunk(tableRows, chunkSize).entries()) {
|
|
|
+ const res = await fetch('http://dify.cocorobo.cn/v1/workflows/run', {
|
|
|
+ method: 'POST',
|
|
|
+ body: JSON.stringify({
|
|
|
+ inputs: {
|
|
|
+ // PERF better to just include `role` and `content` to minimize token cost
|
|
|
+ rows: rows.map(r => `${ r.cells[3].textContent }\t${ r.cells[5].textContent }`).join('\n'),
|
|
|
+ options: options.join(',')
|
|
|
+ },
|
|
|
+ response_mode: 'blocking',
|
|
|
+ user: this.userId,
|
|
|
+ }),
|
|
|
+ ...config
|
|
|
+ }).then(res => res.json())
|
|
|
+ const error = _.get(res, ['data', 'error'], null)
|
|
|
+ if (error) {
|
|
|
+ this.$notify.error(error)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const chunkResult = _.get(res, ['data', 'outputs', 'result'], [])
|
|
|
+ this.actionTypesMap.jsonData[key].splice(index * chunkSize, rows.length, ...chunkResult)
|
|
|
+ this.changeEditorBar({transcriptionData: this.transcriptionData.content, editorBarData: this.editorBarData })
|
|
|
+ this.loadingText = `${index*chunkSize + rows.length}/${tableRows.length}`
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error(err)
|
|
|
+ this.$notify.error(err)
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ this.loadingText = undefined
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
mounted() {},
|
|
|
};
|