Parcourir la source

课文与对话课文添加自动生成音频功能

natasha il y a 1 mois
Parent
commit
473a79c5db

+ 35 - 2
src/views/book/courseware/create/components/question/article/Article.vue

@@ -4,7 +4,10 @@
       <!-- eslint-disable max-len -->
       <div v-loading="loading" class="article-wrapper">
         <el-input v-model="data.content" placeholder="输入" type="textarea" />
-        <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
+        <div class="btn-box">
+          <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
+          <el-button @click="handleAutoAudio" :loading="autoLoading">自动生成音频</el-button>
+        </div>
         <div v-if="data.mp3_list.length > 0" class="upload-file">
           <div class="file-name">
             <span>
@@ -104,6 +107,7 @@ import Notes from './Notes.vue';
 import CheckPic from './CheckPic.vue';
 
 import { getArticleData } from '@/views/book/courseware/data/article';
+import { TextToAudioFile } from '@/api/app';
 import {
   segSentences,
   BatchSegContent,
@@ -141,6 +145,7 @@ export default {
       editWordsFlag: false,
       editWordIndex: 0,
       multilingualText: '',
+      autoLoading: false,
     };
   },
   watch: {
@@ -602,6 +607,34 @@ export default {
         this.$message.warning('请先生成分词');
       }
     },
+    // 自动生成音频
+    handleAutoAudio() {
+      this.autoLoading = true;
+      TextToAudioFile({
+        text: this.data.content,
+        voice_type: this.data.property.voice_type,
+        emotion: this.data.property.emotion,
+        speed_ratio: this.data.property.speed_ratio,
+      })
+        .then(({ status, file_id, file_url }) => {
+          this.autoLoading = false;
+          if (status === 1) {
+            this.data.mp3_list = [
+              {
+                name: '自动生成课文音频.mp3',
+                media_duration: 0,
+                temporary_url: file_url,
+                url: file_id,
+                file_id,
+              },
+            ];
+            this.data.file_id_list = [file_id];
+          }
+        })
+        .catch(() => {
+          this.autoLoading = false;
+        });
+    },
   },
 };
 </script>
@@ -646,7 +679,7 @@ export default {
 .btn-box {
   display: flex;
   flex-flow: wrap;
-  gap: 16px;
+  gap: 10px;
 
   a {
     padding: 5px 16px;

+ 41 - 1
src/views/book/courseware/create/components/question/article/ArticleSetting.vue

@@ -68,6 +68,26 @@
       <el-form-item label="内容高度">
         <el-input v-model="property.content_height" type="number" />
       </el-form-item>
+      <el-form-item label="音色">
+        <el-select v-model="property.voice_type" placeholder="请选择">
+          <el-option
+            v-for="{ voice_type, name } in voice_type_list"
+            :key="voice_type"
+            :label="name"
+            :value="voice_type"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="风格情感">
+        <el-select v-model="property.emotion">
+          <el-option v-for="{ emotion, name } in emotion_list" :key="emotion" :label="name" :value="emotion" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="语速">
+        <el-select v-model="property.speed_ratio">
+          <el-option v-for="{ value, label } in speedRatioList" :key="value" :label="label" :value="value" />
+        </el-select>
+      </el-form-item>
     </el-form>
   </div>
 </template>
@@ -83,6 +103,8 @@ import {
   pinyinPositionList,
   positionList,
 } from '@/views/book/courseware/data/article';
+import { GetTextToAudioConfParamList } from '@/api/app';
+import { speedRatioList } from '@/views/book/courseware/data/common';
 
 export default {
   name: 'ArticleSetting',
@@ -95,9 +117,27 @@ export default {
       pinyinPositionList,
       multilingualList,
       positionList,
+      voice_type_list: [],
+      emotion_list: [],
+      speedRatioList,
     };
   },
-  methods: {},
+  methods: {
+    // 得到文本转音频的配置参数列表
+    getTextToAudioConfParamList() {
+      GetTextToAudioConfParamList()
+        .then(({ status, voice_type_list, emotion_list }) => {
+          if (status === 1) {
+            this.voice_type_list = voice_type_list;
+            this.emotion_list = emotion_list;
+          }
+        })
+        .catch(() => {});
+    },
+  },
+  created() {
+    this.getTextToAudioConfParamList();
+  },
 };
 </script>
 

+ 40 - 4
src/views/book/courseware/create/components/question/dialogue_article/Article.vue

@@ -128,8 +128,10 @@
           <el-input v-model="noticeInput" placeholder="输入语境" style="width: 500px" />
           <el-button type="primary" size="small" @click="handleNotice">插入语境</el-button>
         </div>
-
-        <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
+        <div class="btn-box">
+          <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
+          <el-button @click="handleAutoAudio" :loading="autoLoading">自动生成音频</el-button>
+        </div>
         <div v-if="data.mp3_list.length > 0" class="upload-file">
           <div class="file-name">
             <span>
@@ -301,7 +303,7 @@ import NewWord from '../article/NewWord.vue';
 import Notes from '../article/Notes.vue';
 
 import { getArticleData } from '@/views/book/courseware/data/dialogueArticle';
-import { fileUpload } from '@/api/app';
+import { fileUpload, TextToAudioFile } from '@/api/app';
 import {
   segSentences,
   BatchSegContent,
@@ -343,6 +345,7 @@ export default {
       remark: null,
       paraIndex: 0,
       multilingualText: '',
+      autoLoading: false,
     };
   },
   watch: {
@@ -912,6 +915,39 @@ export default {
         this.$message.warning('请先生成分词');
       }
     },
+    // 自动生成音频
+    handleAutoAudio() {
+      this.autoLoading = true;
+      let text = '';
+      this.data.detail.forEach((item) => {
+        if (item.type === 'text') {
+          text += item.sentences.join('');
+        }
+      });
+      TextToAudioFile({
+        text: text,
+        voice_type: this.data.property.voice_type,
+        emotion: this.data.property.emotion,
+        speed_ratio: this.data.property.speed_ratio,
+      })
+        .then(({ status, file_id, file_url }) => {
+          this.autoLoading = false;
+          if (status === 1) {
+            this.data.mp3_list = [
+              {
+                name: '自动生成课文音频.mp3',
+                media_duration: 0,
+                temporary_url: file_url,
+                url: file_id,
+                file_id,
+              },
+            ];
+          }
+        })
+        .catch(() => {
+          this.autoLoading = false;
+        });
+    },
   },
 };
 </script>
@@ -1082,7 +1118,7 @@ export default {
 .btn-box {
   display: flex;
   flex-flow: wrap;
-  gap: 16px;
+  gap: 10px;
 
   a {
     padding: 5px 16px;

+ 39 - 0
src/views/book/courseware/create/components/question/dialogue_article/ArticleSetting.vue

@@ -133,6 +133,26 @@
       <el-form-item label="内容高度">
         <el-input v-model="property.content_height" type="number" />
       </el-form-item>
+      <el-form-item label="音色">
+        <el-select v-model="property.voice_type" placeholder="请选择">
+          <el-option
+            v-for="{ voice_type, name } in voice_type_list"
+            :key="voice_type"
+            :label="name"
+            :value="voice_type"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="风格情感">
+        <el-select v-model="property.emotion">
+          <el-option v-for="{ emotion, name } in emotion_list" :key="emotion" :label="name" :value="emotion" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="语速">
+        <el-select v-model="property.speed_ratio">
+          <el-option v-for="{ value, label } in speedRatioList" :key="value" :label="label" :value="value" />
+        </el-select>
+      </el-form-item>
     </el-form>
   </div>
 </template>
@@ -142,6 +162,7 @@ import SettingMixin from '@/views/book/courseware/create/components/common/Setti
 import { getToken } from '@/utils/auth';
 import { BatchSegContent } from '@/api/article';
 const Base64 = require('js-base64').Base64;
+import { speedRatioList } from '@/views/book/courseware/data/common';
 
 import {
   getArticleProperty,
@@ -153,6 +174,7 @@ import {
   multilingualList,
   pinyinPositionList,
 } from '@/views/book/courseware/data/dialogueArticle';
+import { GetTextToAudioConfParamList } from '@/api/app';
 import cnchar from 'cnchar';
 
 export default {
@@ -167,6 +189,9 @@ export default {
       roleTypeList,
       multilingualList,
       pinyinPositionList,
+      voice_type_list: [],
+      emotion_list: [],
+      speedRatioList,
     };
   },
   computed: {
@@ -254,6 +279,20 @@ export default {
         this.property.role_list[i].img_list.push(obj);
       }
     },
+    // 得到文本转音频的配置参数列表
+    getTextToAudioConfParamList() {
+      GetTextToAudioConfParamList()
+        .then(({ status, voice_type_list, emotion_list }) => {
+          if (status === 1) {
+            this.voice_type_list = voice_type_list;
+            this.emotion_list = emotion_list;
+          }
+        })
+        .catch(() => {});
+    },
+  },
+  created() {
+    this.getTextToAudioConfParamList();
   },
 };
 </script>

+ 1 - 1
src/views/book/courseware/preview/components/new_word/NewWordPreview.vue

@@ -1460,7 +1460,7 @@ export default {
           // flex-flow: wrap;
           justify-content: flex-start;
           padding: 8px 13px 8px 12px;
-          padding-right: 82px;
+          padding-right: 86px;
           cursor: pointer;
           border-radius: 8px;