|
|
@@ -94,12 +94,25 @@
|
|
|
/>
|
|
|
</el-select>
|
|
|
</div>
|
|
|
+
|
|
|
+ <div class="selection-item">
|
|
|
+ <label>主题类型</label>
|
|
|
+ <el-select
|
|
|
+ v-model="selectedThemeType"
|
|
|
+ size="large"
|
|
|
+ placeholder="请选择主题类型"
|
|
|
+ style="width: 300px"
|
|
|
+ >
|
|
|
+ <el-option label="课程通用" value=13 />
|
|
|
+ <el-option label="诗词课" value=101 />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<div class="button-group">
|
|
|
<button
|
|
|
class="generate-btn primary"
|
|
|
- :disabled="!scriptPrompt || !selectedMainTeacher || isGenerating"
|
|
|
+ :disabled="!scriptPrompt || !selectedMainTeacher || !selectedThemeType || isGenerating"
|
|
|
@click="generateScript"
|
|
|
>
|
|
|
{{ isGenerating ? '生成中...' : '生成课程脚本' }}
|
|
|
@@ -232,12 +245,14 @@
|
|
|
>
|
|
|
<div class="dialogue-header">
|
|
|
<div class="dialogue-type-tag" :class="dialogue.type">
|
|
|
- {{
|
|
|
+ {{
|
|
|
dialogue.type === 'digital'
|
|
|
? '数字人'
|
|
|
: dialogue.type === 'user'
|
|
|
? '用户'
|
|
|
- : '提问'
|
|
|
+ : dialogue.type === 'quest'
|
|
|
+ ? '提问'
|
|
|
+ : '诗词'
|
|
|
}}
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -438,6 +453,86 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
+
|
|
|
+ <!-- 诗词 -->
|
|
|
+ <template v-else-if="dialogue.type === 'poem'">
|
|
|
+ <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>
|
|
|
|
|
|
@@ -451,6 +546,9 @@
|
|
|
<button class="add-dialogue-btn quest" @click="addQuestDialogue(sectionIndex)"
|
|
|
>+ 添加提问</button
|
|
|
>
|
|
|
+ <button class="add-dialogue-btn poem" @click="addPoemDialogue(sectionIndex)"
|
|
|
+ >+ 添加诗词</button
|
|
|
+ >
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -531,13 +629,15 @@
|
|
|
<div class="dialogue-header">
|
|
|
<div class="dialogue-header-left">
|
|
|
<div class="dialogue-type-tag" :class="dialogue.type">
|
|
|
- {{
|
|
|
- dialogue.type === 'digital'
|
|
|
- ? '数字人'
|
|
|
- : dialogue.type === 'user'
|
|
|
- ? '用户'
|
|
|
- : '提问'
|
|
|
- }}
|
|
|
+ {{
|
|
|
+ dialogue.type === 'digital'
|
|
|
+ ? '数字人'
|
|
|
+ : dialogue.type === 'user'
|
|
|
+ ? '用户'
|
|
|
+ : dialogue.type === 'quest'
|
|
|
+ ? '提问'
|
|
|
+ : '诗词'
|
|
|
+ }}
|
|
|
</div>
|
|
|
<div class="dialogue-role">
|
|
|
{{
|
|
|
@@ -628,6 +728,7 @@ const currentStep = ref(1)
|
|
|
const scriptPrompt = ref('')
|
|
|
const selectedMainTeacher = ref('')
|
|
|
const selectedAssistants = ref([])
|
|
|
+const selectedThemeType = ref()
|
|
|
const isGenerating = ref(false)
|
|
|
|
|
|
// 对话框可见性
|
|
|
@@ -829,7 +930,7 @@ const audioInstances = new Map()
|
|
|
const canProceed = computed(() => {
|
|
|
switch (currentStep.value) {
|
|
|
case 1:
|
|
|
- return !!scriptPrompt.value && !!selectedMainTeacher.value
|
|
|
+ return !!scriptPrompt.value && !!selectedMainTeacher.value && !!selectedThemeType.value
|
|
|
case 2:
|
|
|
case 3:
|
|
|
return scriptData.sections.every(
|
|
|
@@ -837,7 +938,7 @@ const canProceed = computed(() => {
|
|
|
section.backgroundImage.url &&
|
|
|
section.dialogues.every(
|
|
|
(dialogue) =>
|
|
|
- ((dialogue.type === 'digital' || dialogue.type === 'quest') &&
|
|
|
+ ((dialogue.type === 'digital' || dialogue.type === 'quest' || dialogue.type === 'poem') &&
|
|
|
dialogue.roleName &&
|
|
|
dialogue.content.trim() &&
|
|
|
dialogue.voiceoverUrl) ||
|
|
|
@@ -909,7 +1010,7 @@ const generateScript = async () => {
|
|
|
})
|
|
|
content += zhujiang.join(',') + ')'
|
|
|
|
|
|
- await createAiRoleIdConversation(13)
|
|
|
+ await createAiRoleIdConversation(Number(selectedThemeType.value))
|
|
|
currentStep.value = 2
|
|
|
await doSendMessageStream(activeConversationId.value, content)
|
|
|
} catch (error) {
|
|
|
@@ -1053,6 +1154,17 @@ const addQuestDialogue = (sectionIndex) => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+// 步骤2:添加诗词
|
|
|
+const addPoemDialogue = (sectionIndex) => {
|
|
|
+ scriptData.sections[sectionIndex].dialogues.push({
|
|
|
+ type: 'poem',
|
|
|
+ content: '',
|
|
|
+ roleName: '',
|
|
|
+ voiceoverUrl: '',
|
|
|
+ generatingVoiceover: false
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
// 步骤2:删除对话
|
|
|
const removeDialogue = (sectionIndex, dialogueIndex) => {
|
|
|
scriptData.sections[sectionIndex].dialogues.splice(dialogueIndex, 1)
|
|
|
@@ -1234,8 +1346,8 @@ const playBackgroundAudio = (musicType) => {
|
|
|
const generateVoiceover = async (sectionIndex, dialogueIndex) => {
|
|
|
const dialogue = scriptData.sections[sectionIndex].dialogues[dialogueIndex]
|
|
|
|
|
|
- // 只处理数字人和提问类型的对话
|
|
|
- if (dialogue.type !== 'digital' && dialogue.type !== 'quest') {
|
|
|
+ // 只处理数字人、提问和诗词类型的对话
|
|
|
+ if (dialogue.type !== 'digital' && dialogue.type !== 'quest' && dialogue.type !== 'poem') {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -1317,7 +1429,7 @@ const validateScript = () => {
|
|
|
!scriptData.sections.every((s) =>
|
|
|
s.dialogues.every(
|
|
|
(d) =>
|
|
|
- ((d.type === 'digital' || d.type === 'quest') &&
|
|
|
+ ((d.type === 'digital' || d.type === 'quest' || d.type === 'poem') &&
|
|
|
d.roleName &&
|
|
|
d.content.trim() &&
|
|
|
d.voiceoverUrl) ||
|
|
|
@@ -1621,6 +1733,10 @@ onUnmounted(() => {
|
|
|
background-color: #e6a23c;
|
|
|
}
|
|
|
|
|
|
+.dialogue-type-tag.poem {
|
|
|
+ background-color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
/* 对话项样式 */
|
|
|
.dialogue-item {
|
|
|
position: relative;
|
|
|
@@ -1720,6 +1836,11 @@ onUnmounted(() => {
|
|
|
color: white;
|
|
|
}
|
|
|
|
|
|
+.add-dialogue-btn.poem {
|
|
|
+ background-color: #909399;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
.add-dialogue-btn.user:hover {
|
|
|
background-color: #67c23a;
|
|
|
border-color: #67c23a;
|
|
|
@@ -1732,6 +1853,12 @@ onUnmounted(() => {
|
|
|
color: white;
|
|
|
}
|
|
|
|
|
|
+.add-dialogue-btn.poem:hover {
|
|
|
+ background-color: #73767a;
|
|
|
+ border-color: #73767a;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
/* 预览对话样式 */
|
|
|
.preview-dialogue {
|
|
|
position: relative;
|
|
|
@@ -1753,6 +1880,10 @@ onUnmounted(() => {
|
|
|
border-left: 4px solid #e6a23c;
|
|
|
}
|
|
|
|
|
|
+.preview-dialogue.poem {
|
|
|
+ border-left: 4px solid #909399;
|
|
|
+}
|
|
|
+
|
|
|
.preview-dialogue .dialogue-header {
|
|
|
display: flex;
|
|
|
align-items: center;
|