script-line.js 1.76 KB
import * as v from 'valibot'

/**
 * TTS 提示:续写 LLM / 编排可附带的语音合成参数(全部可选)。
 * @typedef {{ instruction?: string, speech_rate?: number }} TtsHintT
 */
export const TtsHint = v.object({
  instruction: v.optional(v.string()),
  speech_rate: v.optional(v.number()),
})

/**
 * 剧本单行:播放引擎与续写 LLM 的共同语言。
 * `mode` 区分阻塞(说完才进下一行)与并行(与相邻行同时进行)语义。
 * @typedef {{
 *   speaker: string,
 *   text: string,
 *   emotion?: string,
 *   mode: 'block' | 'parallel',
 *   tts?: TtsHintT
 * }} ScriptLineT
 */
export const ScriptLine = v.object({
  speaker: v.string(),
  text: v.string(),
  emotion: v.optional(v.string()),
  mode: v.picklist(['block', 'parallel']),
  tts: v.optional(TtsHint),
})

/**
 * 单行配音请求体(POST /api/sk/drama/:id/line/tts 的入参契约)。
 *
 * `speaker` 必须由调用方传入有效音色 id(复刻音色形如 `S_aAB0nUX42`)——后端不再
 * 兜底为某个固定音色(旧实现兜底女声导致「钟爹也变女声」,见 TTS 链路修复)。
 * `instruction` 是语气指令(如「生气地说」),复刻音色靠它控语气;未传时后端按
 * `emotion` 派生默认语气词。`emotion` / `emotion_scale` 走普通音色情绪分支。
 *
 * @typedef {{
 *   text: string,
 *   speaker?: string,
 *   instruction?: string,
 *   emotion?: string,
 *   emotion_scale?: number,
 *   speech_rate?: number
 * }} TtsLineBodyT
 */
export const TtsLineBody = v.object({
  text: v.pipe(v.string(), v.minLength(1)),
  speaker: v.optional(v.string()),
  instruction: v.optional(v.string()),
  emotion: v.optional(v.string()),
  emotion_scale: v.optional(v.number()),
  speech_rate: v.optional(v.number()),
})