|
|
@@ -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;
|