Explorar o código

feat(speaking): integrate dialogue defaults from backend to enhance AI configuration

jimmylee hai 1 mes
pai
achega
a19a695301

+ 20 - 9
src/store/speaking.ts

@@ -6,6 +6,7 @@ import type {
   EvalDimensions,
   PreviewDialogueState,
 } from '@/types/englishSpeaking'
+import type { DialogueDefaultsResponse } from '@/services/speaking'
 
 const DEFAULT_CONFIG: TopicDiscussionConfig = {
   topic: 'How I get to school',
@@ -98,17 +99,21 @@ export const useSpeakingStore = defineStore('speaking', {
     resetSignal: 0,
     // 请求打开配置面板的递增信号(由画布点击 77 型 frame 触发 → CollapsibleToolbar + SpeakingPanel 监听)
     openConfigSignal: 0,
+    // 后端托管的 AI 配置默认值,首次拉取后缓存,供 applyDialogueDefaults 反复补空槽
+    dialogueDefaults: null as DialogueDefaultsResponse | null,
   }),
 
   actions: {
     // 重置为默认配置
     resetConfig() {
       this.config = JSON.parse(JSON.stringify(DEFAULT_CONFIG))
+      this.applyDialogueDefaults()
     },
 
     // 重置为空白配置(手动创建用)
     resetConfigEmpty() {
       this.config = JSON.parse(JSON.stringify(EMPTY_CONFIG))
+      this.applyDialogueDefaults()
     },
 
     setPreviewState(state: PreviewDialogueState) {
@@ -187,22 +192,28 @@ export const useSpeakingStore = defineStore('speaking', {
       this.config.videoScene.enabled = !this.config.videoScene.enabled
     },
 
-    hydrateDefaults(payload: {
-      videoScene: { systemPrompt: string; greeting: string }
-      nonVideoScene: { systemPrompt: string; greeting: string }
-    }) {
-      // Fill only empty slots — preserve any teacher edits already present.
+    // 拉到后端默认值后调用:缓存一份,并立即补一次空槽。
+    hydrateDefaults(payload: DialogueDefaultsResponse) {
+      this.dialogueDefaults = payload
+      this.applyDialogueDefaults()
+    },
+
+    // 用缓存的默认值填充 AI 配置里的空槽 —— 只填空槽,保留老师已编辑的值。
+    // 在 $patch / resetConfig 等会把槽位冲空的操作之后调用,保证默认值不丢。
+    applyDialogueDefaults() {
+      const d = this.dialogueDefaults
+      if (!d) return
       if (!this.config.videoScene.systemPrompt) {
-        this.config.videoScene.systemPrompt = payload.videoScene.systemPrompt
+        this.config.videoScene.systemPrompt = d.videoScene.systemPrompt
       }
       if (!this.config.videoScene.greeting) {
-        this.config.videoScene.greeting = payload.videoScene.greeting
+        this.config.videoScene.greeting = d.videoScene.greeting
       }
       if (!this.config.nonVideoScene.systemPrompt) {
-        this.config.nonVideoScene.systemPrompt = payload.nonVideoScene.systemPrompt
+        this.config.nonVideoScene.systemPrompt = d.nonVideoScene.systemPrompt
       }
       if (!this.config.nonVideoScene.greeting) {
-        this.config.nonVideoScene.greeting = payload.nonVideoScene.greeting
+        this.config.nonVideoScene.greeting = d.nonVideoScene.greeting
       }
     },
   },

+ 12 - 2
src/views/Editor/EnglishSpeaking/configs/TopicDiscussionConfig.vue

@@ -379,13 +379,13 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, nextTick } from 'vue'
+import { ref, computed, nextTick, onMounted } from 'vue'
 import { storeToRefs } from 'pinia'
 import { lang } from '@/main'
 import { useSpeakingStore } from '@/store/speaking'
 import { useSlidesStore } from '@/store'
 import useCreateElement from '@/hooks/useCreateElement'
-import { createSpeakingConfig, updateSpeakingConfig } from '@/services/speaking'
+import { createSpeakingConfig, updateSpeakingConfig, getDialogueDefaults } from '@/services/speaking'
 import message from '@/utils/message'
 
 const emit = defineEmits<{
@@ -427,6 +427,16 @@ function onSystemPromptInput(value: string) {
   }
 }
 
+// 配置面板挂载时拉一次后端默认值,填充 AI 配置里的空槽(不覆盖老师已改的值)
+onMounted(async () => {
+  try {
+    const defaults = await getDialogueDefaults()
+    store.hydrateDefaults(defaults)
+  } catch (err) {
+    console.error('[speaking] failed to load dialogue defaults', err)
+  }
+})
+
 // 词汇新增
 const isAddingVocab = ref(false)
 const newVocab = ref('')