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()), })