dsh-audiogen 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/protocol.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  export const AUDIOGEN_SETTINGS_NAMESPACE = 'dsh-audiogen'
9
9
 
10
10
  /** Published package version shared by the host updater and the client UI. */
11
- export const PLUGIN_VERSION = '0.3.0'
11
+ export const PLUGIN_VERSION = '0.3.2'
12
12
 
13
13
  /** Same-origin route family (loopback-only, mirroring dsh-imagegen). */
14
14
  export const SETTINGS_API = {
@@ -94,6 +94,8 @@ export interface PresetProviderView {
94
94
  name: string
95
95
  apiUrl: string
96
96
  hint: string
97
+ /** Official vendor website, shown as a link in the channel editor. */
98
+ site?: string
97
99
  models: ModelMapping[]
98
100
  }
99
101
 
@@ -120,6 +122,38 @@ export interface GenerateAudioRequest {
120
122
  channel?: string
121
123
  /** Upstream model id actually sent (host-filled from alias mapping). */
122
124
  upstream?: string
125
+
126
+ // ---- MiniMax TTS 专属字段(其他厂商渠道忽略)——————
127
+ /** MiniMax 音色情绪,如 happy/sad/angry/nervous/fearful/bored;默认按音色自身。 */
128
+ emotion?: string
129
+ /** MiniMax 音量,范围 0-10,默认 1。 */
130
+ vol?: number
131
+ /** MiniMax 音调偏移(半音),范围 -12~12,默认 0。 */
132
+ pitch?: number
133
+ /** MiniMax 文本归一化处理开关(默认 true)。 */
134
+ textNormalization?: boolean
135
+ /** MiniMax 数学公式朗读开关(默认 false)。 */
136
+ latexRead?: boolean
137
+ /** MiniMax 发音词典 tone 条目,元素形如 "处理/(chu3)(li3)" 或 "危险/dangerous"。 */
138
+ pronunciationTone?: string[]
139
+ /** MiniMax 采样率:16000/24000/32000/44100/48000,默认 32000。 */
140
+ sampleRate?: number
141
+ /** MiniMax 码率(bps):64000-320000,默认 128000。 */
142
+ bitrate?: number
143
+ /** MiniMax 声道数:1 或 2,默认 1。 */
144
+ audioChannel?: number
145
+ /** MiniMax 强制 CBR 编码(avoid VBR),默认 false。 */
146
+ forceCbr?: boolean
147
+ /** MiniMax 字幕开关:true 时响应携带字幕内容/文件。 */
148
+ subtitleEnable?: boolean
149
+ /** MiniMax AIGC 水印开关。 */
150
+ aigcWatermark?: boolean
151
+ /** MiniMax 语言增强(language_boost),如"中英混读",按模型支持情况。 */
152
+ languageBoost?: string
153
+ /** MiniMax 变声参数(voice_modify,speech-2.8 等支持)。 */
154
+ voiceModify?: { pitch?: number; intensity?: number; timbre?: number; soundEffects?: string }
155
+ /** MiniMax 双音色混合权重(timbre_weights)。 */
156
+ timbreWeights?: Array<{ voiceId: string; weight: number }>
123
157
  }
124
158
 
125
159
  /** One generated audio, normalized host-side to base64. */
package/src/routes.ts CHANGED
@@ -93,16 +93,53 @@ function parseGenerateRequest(body: Record<string, unknown>): GenerateAudioReque
93
93
  const mode = body.mode === 'music' ? 'music' : body.mode === 'sfx' ? 'sfx' : body.mode === 'voice_design' ? 'voice_design' : 'tts'
94
94
  const prompt = typeof body.prompt === 'string' ? body.prompt.trim() : ''
95
95
  if (prompt === '') return undefined
96
+ const num = (value: unknown): number | undefined => typeof value === 'number' && Number.isFinite(value) ? value : undefined
97
+ const str = (value: unknown): string | undefined => typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined
98
+ const flag = (value: unknown): boolean | undefined => typeof value === 'boolean' ? value : undefined
99
+ const tone = Array.isArray(body.pronunciationTone)
100
+ ? body.pronunciationTone.filter((item): item is string => typeof item === 'string' && item.trim() !== '').map(item => item.trim())
101
+ : undefined
102
+ const voiceModifyRaw = body.voiceModify
103
+ const voiceModify = typeof voiceModifyRaw === 'object' && voiceModifyRaw !== null
104
+ ? {
105
+ ...(num((voiceModifyRaw as Record<string, unknown>).pitch) !== undefined ? { pitch: num((voiceModifyRaw as Record<string, unknown>).pitch)! } : {}),
106
+ ...(num((voiceModifyRaw as Record<string, unknown>).intensity) !== undefined ? { intensity: num((voiceModifyRaw as Record<string, unknown>).intensity)! } : {}),
107
+ ...(num((voiceModifyRaw as Record<string, unknown>).timbre) !== undefined ? { timbre: num((voiceModifyRaw as Record<string, unknown>).timbre)! } : {}),
108
+ ...(str((voiceModifyRaw as Record<string, unknown>).soundEffects) !== undefined ? { soundEffects: str((voiceModifyRaw as Record<string, unknown>).soundEffects)! } : {}),
109
+ }
110
+ : undefined
111
+ const timbreWeights = Array.isArray(body.timbreWeights)
112
+ ? body.timbreWeights
113
+ .filter((item): item is Record<string, unknown> => typeof item === 'object' && item !== null && typeof (item as Record<string, unknown>).voiceId === 'string' && typeof (item as Record<string, unknown>).weight === 'number')
114
+ .map(item => ({ voiceId: (item.voiceId as string).trim(), weight: item.weight as number }))
115
+ .filter(item => item.voiceId !== '')
116
+ : undefined
96
117
  return {
97
118
  mode,
98
119
  model: typeof body.model === 'string' ? body.model.trim() : '',
99
120
  prompt,
100
121
  ...(typeof body.voice === 'string' && body.voice.trim() !== '' ? { voice: body.voice.trim() } : {}),
101
122
  ...(typeof body.previewText === 'string' && body.previewText.trim() !== '' ? { previewText: body.previewText.trim() } : {}),
102
- ...(typeof body.speed === 'number' ? { speed: body.speed } : {}),
103
- ...(typeof body.duration === 'number' ? { duration: body.duration } : {}),
123
+ ...(num(body.speed) !== undefined ? { speed: num(body.speed)! } : {}),
124
+ ...(num(body.duration) !== undefined ? { duration: num(body.duration)! } : {}),
104
125
  ...(typeof body.format === 'string' && body.format.trim() !== '' ? { format: body.format.trim() } : {}),
105
126
  ...(typeof body.channelId === 'string' && body.channelId !== '' ? { channelId: body.channelId } : {}),
127
+ // ---- MiniMax TTS 专属字段(其他厂商忽略) ----
128
+ ...(str(body.emotion) !== undefined ? { emotion: str(body.emotion)! } : {}),
129
+ ...(num(body.vol) !== undefined ? { vol: num(body.vol)! } : {}),
130
+ ...(num(body.pitch) !== undefined ? { pitch: num(body.pitch)! } : {}),
131
+ ...(flag(body.textNormalization) !== undefined ? { textNormalization: flag(body.textNormalization)! } : {}),
132
+ ...(flag(body.latexRead) !== undefined ? { latexRead: flag(body.latexRead)! } : {}),
133
+ ...(tone !== undefined && tone.length > 0 ? { pronunciationTone: tone } : {}),
134
+ ...(num(body.sampleRate) !== undefined ? { sampleRate: num(body.sampleRate)! } : {}),
135
+ ...(num(body.bitrate) !== undefined ? { bitrate: num(body.bitrate)! } : {}),
136
+ ...(num(body.audioChannel) !== undefined ? { audioChannel: num(body.audioChannel)! } : {}),
137
+ ...(flag(body.forceCbr) !== undefined ? { forceCbr: flag(body.forceCbr)! } : {}),
138
+ ...(flag(body.subtitleEnable) !== undefined ? { subtitleEnable: flag(body.subtitleEnable)! } : {}),
139
+ ...(flag(body.aigcWatermark) !== undefined ? { aigcWatermark: flag(body.aigcWatermark)! } : {}),
140
+ ...(str(body.languageBoost) !== undefined ? { languageBoost: str(body.languageBoost)! } : {}),
141
+ ...(voiceModify !== undefined ? { voiceModify } : {}),
142
+ ...(timbreWeights !== undefined && timbreWeights.length > 0 ? { timbreWeights } : {}),
106
143
  }
107
144
  }
108
145
 
@@ -212,7 +249,9 @@ export function makeRoutes(deps: AudiogenRoutesDeps): WebRoute[] {
212
249
  ?? view.channels[0]
213
250
  const channel: AudioChannel = {
214
251
  id: stored?.id ?? 'preview',
215
- preset: stored?.preset ?? '',
252
+ // The draft's own preset wins (even when empty = custom): discovery
253
+ // must follow the vendor being configured, not the default channel.
254
+ preset: typeof body?.preset === 'string' ? body.preset.trim() : (stored?.preset ?? ''),
216
255
  name: stored?.name ?? '',
217
256
  apiUrl: typeof body?.apiUrl === 'string' && body.apiUrl.trim() !== '' ? body.apiUrl.trim() : (stored?.apiUrl ?? ''),
218
257
  apiKey: typeof body?.apiKey === 'string' && body.apiKey.trim() !== '' ? body.apiKey.trim() : (stored?.apiKey ?? ''),