Bladeren bron

1、新增提问类型,

liyanbo 2 maanden geleden
bovenliggende
commit
45f856d7ed
2 gewijzigde bestanden met toevoegingen van 127 en 12 verwijderingen
  1. 26 2
      src/views/bjdx/course/aiGenerate/VideoPreview.vue
  2. 101 10
      src/views/bjdx/course/aiGenerate/aiGengrate.vue

+ 26 - 2
src/views/bjdx/course/aiGenerate/VideoPreview.vue

@@ -27,9 +27,9 @@
               <strong>当前背景音:</strong> {{ currentSection.backgroundAudio.type }}
             </div>
             
-            <!-- 人物形象 - 数字人对话显示 -->
+            <!-- 人物形象 - 数字人和提问对话显示 -->
             <div
-              v-if="currentDialogue && currentDialogue.type === 'digital'"
+              v-if="currentDialogue && (currentDialogue.type === 'digital' || currentDialogue.type === 'quest')"
               :key="`character-${currentDialogue.roleName}-${currentDialogueIndex}`"
               class="character"
               :class="{
@@ -55,6 +55,22 @@
               <div class="dialogue-content" v-html="parseMarkdown(currentDialogue.content)"></div>
             </div>
 
+            <!-- 对话卡片 - 提问对话 -->
+            <div
+              v-if="currentDialogue && currentDialogue.type === 'quest'"
+              :key="`dialogue-${currentDialogueIndex}`"
+              class="dialogue-card"
+              :class="{
+                'left': getCharacterSide(currentDialogue.roleName) === 'left',
+                'right': getCharacterSide(currentDialogue.roleName) === 'right'
+              }"
+            >
+              <div class="dialogue-header quest-header">
+                <span class="role-name">{{ getRoleName(currentDialogue.roleName) }}</span>
+              </div>
+              <div class="dialogue-content" v-html="parseMarkdown(currentDialogue.content)"></div>
+            </div>
+
             <!-- 用户回答状态 -->
             <div v-if="currentDialogue && currentDialogue.type === 'user'" class="user-input-section">
               <!-- 麦克风图标 -->
@@ -685,6 +701,10 @@ onUnmounted(() => {
   left: 10px;
 }
 
+.dialogue-card.right .dialogue-header.quest-header {
+  left: 10px;
+}
+
 .role-name {
   font-weight: 600;
   color: white;
@@ -861,6 +881,10 @@ onUnmounted(() => {
   transform: translateX(-50%);
 }
 
+.dialogue-header.quest-header {
+  background: #E6A23C;
+}
+
 /* 控制栏 */
 .video-controls {
   position: absolute;

+ 101 - 10
src/views/bjdx/course/aiGenerate/aiGengrate.vue

@@ -179,8 +179,8 @@
                 >
                   <div class="dialogue-header">
                     <div class="dialogue-type-tag" :class="dialogue.type">
-                      {{ dialogue.type === 'digital' ? '数字人' : '用户' }}
-                    </div>
+                          {{ dialogue.type === 'digital' ? '数字人' : dialogue.type === 'user' ? '用户' : '提问' }}
+                        </div>
                   </div>
                   <div class="dialogue-row">
                     <!-- 数字人对话 -->
@@ -263,12 +263,66 @@
                         </div>
                       </div>
                     </template>
+                    
+                    <!-- 提问 -->
+                    <template v-else-if="dialogue.type === 'quest'">
+                      <div class="dialogue-role-select">
+                        <el-select v-model="dialogue.roleName" placeholder="选择角色" style="width: 140px" clearable>
+                          <el-option
+                            v-for="role in digitalHumans"
+                            :key="role.id"
+                            :label="role.name"
+                            :value="role.name"
+                          />
+                        </el-select>
+                      </div>
+                      <div class="dialogue-content-container">
+                        <el-input
+                          v-model="dialogue.content"
+                          type="textarea"
+                          class="dialogue-content"
+                          placeholder="提问内容..."
+                          :autosize="{ minRows: 2, maxRows: 4 }"
+                        />
+                      </div>
+                      <div class="action-buttons">
+                        <div class="action-buttons-row">
+                          <button
+                            v-if="dialogue.voiceoverUrl"
+                            class="play-btn"
+                            @click="playVoiceover(dialogue.voiceoverUrl)"
+                          >
+                            <span class="play-icon">{{ audioState.isPlaying && audioState.currentType === 'voice' && audioState.currentUrl === dialogue.voiceoverUrl ? '⏸' : '▶' }}</span>
+                          </button>
+                          <button class="remove-btn" @click="removeDialogue(sectionIndex, dialogueIndex)">×</button>
+                        </div>
+                        <div class="action-buttons-row">
+                          <button
+                            v-if="!dialogue.voiceoverUrl"
+                            class="generate-btn small"
+                            :disabled="!dialogue.content || !dialogue.roleName || dialogue.generatingVoiceover"
+                            @click="generateVoiceover(sectionIndex, dialogueIndex)"
+                          >
+                            <span class="voice-icon">{{ dialogue.generatingVoiceover ? '生成中...' : '生成语音' }}</span>
+                          </button>
+                          <button
+                            v-if="dialogue.voiceoverUrl"
+                            class="generate-btn small"
+                            :disabled="!dialogue.content || !dialogue.roleName || dialogue.generatingVoiceover"
+                            @click="generateVoiceover(sectionIndex, dialogueIndex)"
+                          >
+                            <span class="voice-icon">{{ dialogue.generatingVoiceover ? '生成中...' : '重新生成' }}</span>
+                          </button>
+                        </div>
+                      </div>
+                    </template>
                   </div>
                 </div>
 
                 <div class="add-dialogue-buttons">
                   <button class="add-dialogue-btn digital" @click="addDialogue(sectionIndex)">+ 添加对话</button>
                   <button class="add-dialogue-btn user" @click="addUserReply(sectionIndex)">+ 添加用户回复</button>
+                  <button class="add-dialogue-btn quest" @click="addQuestDialogue(sectionIndex)">+ 添加提问</button>
                 </div>
               </div>
             </div>
@@ -343,10 +397,10 @@
                     <div class="dialogue-header">
                       <div class="dialogue-header-left">
                         <div class="dialogue-type-tag" :class="dialogue.type">
-                          {{ dialogue.type === 'digital' ? '数字人' : '用户' }}
+                          {{ dialogue.type === 'digital' ? '数字人' : dialogue.type === 'user' ? '用户' : '提问' }}
                         </div>
                         <div class="dialogue-role">
-                          {{ dialogue.type === 'digital' ? getRoleName(dialogue.roleName) : '用户' }}:
+                          {{ dialogue.type !== 'user' ? getRoleName(dialogue.roleName) : '用户' }}:
                         </div>
                       </div>
                       <button
@@ -629,7 +683,7 @@ const generateScript = async () => {
     scriptDataTemp.value = null
 
     const role = digitalHumans.value.find(r => r.name === selectedMainTeacher.value)
-    let content = scriptPrompt.value + "(主讲人:" + role.name + "[" + role.description + "],助讲:"
+    let content = scriptPrompt.value + "(主讲人:" + role.name + ",主讲人角色定位:" + role.description + ";助讲有:"
     let zhujiang = []
 
     selectedAssistants.value.forEach((rName) => {
@@ -687,7 +741,7 @@ const doSendMessageStream = async (conversationId, content) => {
 
           receiveMessageFullText.value += data.receive.content
 
-          console.log("数据:", receiveMessageFullText.value)
+          console.log("数据加载中..")
           try {
             const parsedData = JSON.parse(receiveMessageFullText.value)
             scriptDataTemp.value = parsedData
@@ -706,7 +760,7 @@ const doSendMessageStream = async (conversationId, content) => {
           if (receiveMessageFullText.value) {
             console.log("最终数据:", receiveMessageFullText.value)
             const parsedData = JSON.parse(receiveMessageFullText.value)
-            console.log("最终数据--:", parsedData)
+            console.log("最终数据json:", parsedData)
 
             scriptDataTemp.value = parsedData
             Object.assign(scriptData, parsedData)
@@ -755,6 +809,17 @@ const addUserReply = (sectionIndex) => {
   })
 }
 
+// 步骤2:添加提问
+const addQuestDialogue = (sectionIndex) => {
+  scriptData.sections[sectionIndex].dialogues.push({
+    type: 'quest',
+    content: '',
+    roleName: '',
+    voiceoverUrl: '',
+    generatingVoiceover: false
+  })
+}
+
 // 步骤2:删除对话
 const removeDialogue = (sectionIndex, dialogueIndex) => {
   scriptData.sections[sectionIndex].dialogues.splice(dialogueIndex, 1)
@@ -922,8 +987,8 @@ const playBackgroundAudio = (musicType) => {
 const generateVoiceover = async (sectionIndex, dialogueIndex) => {
   const dialogue = scriptData.sections[sectionIndex].dialogues[dialogueIndex]
 
-  // 只处理数字人类型的对话
-  if (dialogue.type !== 'digital') {
+  // 只处理数字人和提问类型的对话
+  if (dialogue.type !== 'digital' && dialogue.type !== 'quest') {
     return
   }
 
@@ -991,7 +1056,9 @@ const validateScript = () => {
     isValid = false
     message = '存在未生成的背景图'
   } else if (!scriptData.sections.every(s =>
-    s.dialogues.every(d => (d.type === 'digital' && d.roleName && d.content.trim() && d.voiceoverUrl) || (d.type === 'user' && d.roleName && d.content.trim()))
+    s.dialogues.every(d =>
+      ((d.type === 'digital' || d.type === 'quest') && d.roleName && d.content.trim() && d.voiceoverUrl) ||
+      (d.type === 'user' && d.roleName && d.content.trim()))
   )) {
     isValid = false
     message = '存在未完成的对话或语音'
@@ -1039,6 +1106,7 @@ onMounted(async () => {
   if (props.initialScriptData) {
     try {
       const parsedData = JSON.parse(props.initialScriptData)
+      console.log("草稿json数据:",parsedData)
       Object.assign(scriptData, parsedData)
     } catch (error) {
       console.error('解析脚本数据失败:', error)
@@ -1304,6 +1372,10 @@ onUnmounted(() => {
   background-color: #67C23A;
 }
 
+.dialogue-type-tag.quest {
+  background-color: #E6A23C;
+}
+
 /* 对话项样式 */
 .dialogue-item {
   position: relative;
@@ -1327,6 +1399,10 @@ onUnmounted(() => {
   border-left: 4px solid #67C23A;
 }
 
+.dialogue-item.quest {
+  border-left: 4px solid #E6A23C;
+}
+
 /* 对话头部 */
 .dialogue-header {
   margin-bottom: 10px;
@@ -1396,12 +1472,23 @@ onUnmounted(() => {
   color: white;
 }
 
+.add-dialogue-btn.quest {
+  background-color: #E6A23C;
+  color: white;
+}
+
 .add-dialogue-btn.user:hover {
   background-color: #67C23A;
   border-color: #67C23A;
   color: white;
 }
 
+.add-dialogue-btn.quest:hover {
+  background-color: #cf9236;
+  border-color: #cf9236;
+  color: white;
+}
+
 /* 预览对话样式 */
 .preview-dialogue {
   position: relative;
@@ -1419,6 +1506,10 @@ onUnmounted(() => {
   border-left: 4px solid #67C23A;
 }
 
+.preview-dialogue.quest {
+  border-left: 4px solid #E6A23C;
+}
+
 .preview-dialogue .dialogue-header {
   display: flex;
   align-items: center;