Carson преди 8 месеца
родител
ревизия
6919b4605d
променени са 3 файла, в които са добавени 180 реда и са изтрити 26 реда
  1. 2 3
      package-lock.json
  2. 1 0
      package.json
  3. 177 23
      src/components/pages/classroomObservation/components/chatArea.vue

+ 2 - 3
package-lock.json

@@ -6825,9 +6825,8 @@
     },
     "lodash": {
       "version": "4.17.21",
-      "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1613835838133&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.21.tgz",
-      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=",
-      "dev": true
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
     "lodash-es": {
       "version": "4.17.21",

+ 1 - 0
package.json

@@ -35,6 +35,7 @@
     "jszip": "^3.10.1",
     "lamejs": "^1.2.1",
     "language-hk-loader": "^1.0.1",
+    "lodash": "^4.17.21",
     "markdown-it": "^13.0.2",
     "opencc-js": "^1.0.5",
     "pdfjs-dist": "^2.5.207",

+ 177 - 23
src/components/pages/classroomObservation/components/chatArea.vue

@@ -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() {},
 };