dsh-audiogen 0.3.0 → 0.3.3
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/lib/client.js +1069 -550
- package/lib/client.js.map +1 -1
- package/lib/index.js +483 -118
- package/package.json +1 -1
- package/skills/music/SKILL.md +30 -7
- package/skills/tts/SKILL.md +42 -4
- package/src/agent-audio-tools.ts +80 -3
- package/src/audio-engine.ts +185 -26
- package/src/audio-models.ts +132 -24
- package/src/audio-presets.ts +27 -33
- package/src/client/AudioGenPanel.tsx +92 -3
- package/src/client/SettingsCard.tsx +520 -176
- package/src/client/audio-panel.module.css +36 -0
- package/src/client/locales.ts +84 -16
- package/src/client/settings-card.module.css +424 -607
- package/src/protocol.ts +39 -1
- package/src/routes.ts +44 -3
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.
|
|
11
|
+
export const PLUGIN_VERSION = '0.3.3'
|
|
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
|
|
|
@@ -112,6 +114,10 @@ export interface GenerateAudioRequest {
|
|
|
112
114
|
speed?: number
|
|
113
115
|
/** Requested duration in seconds (music/sfx). */
|
|
114
116
|
duration?: number
|
|
117
|
+
/** MiniMax 音乐生成歌词;music-3.0 / music-cover 在非纯音乐模式下必填。 */
|
|
118
|
+
lyrics?: string
|
|
119
|
+
/** MiniMax 是否生成纯音乐(无歌词/人声);true 时 lyrics 可为空。 */
|
|
120
|
+
isInstrumental?: boolean
|
|
115
121
|
/** Output format, e.g. mp3, wav, pcm. */
|
|
116
122
|
format?: string
|
|
117
123
|
/** Channel this request targets (host falls back to default). */
|
|
@@ -120,6 +126,38 @@ export interface GenerateAudioRequest {
|
|
|
120
126
|
channel?: string
|
|
121
127
|
/** Upstream model id actually sent (host-filled from alias mapping). */
|
|
122
128
|
upstream?: string
|
|
129
|
+
|
|
130
|
+
// ---- MiniMax TTS 专属字段(其他厂商渠道忽略)——————
|
|
131
|
+
/** MiniMax 音色情绪,如 happy/sad/angry/nervous/fearful/bored;默认按音色自身。 */
|
|
132
|
+
emotion?: string
|
|
133
|
+
/** MiniMax 音量,范围 0-10,默认 1。 */
|
|
134
|
+
vol?: number
|
|
135
|
+
/** MiniMax 音调偏移(半音),范围 -12~12,默认 0。 */
|
|
136
|
+
pitch?: number
|
|
137
|
+
/** MiniMax 文本归一化处理开关(默认 true)。 */
|
|
138
|
+
textNormalization?: boolean
|
|
139
|
+
/** MiniMax 数学公式朗读开关(默认 false)。 */
|
|
140
|
+
latexRead?: boolean
|
|
141
|
+
/** MiniMax 发音词典 tone 条目,元素形如 "处理/(chu3)(li3)" 或 "危险/dangerous"。 */
|
|
142
|
+
pronunciationTone?: string[]
|
|
143
|
+
/** MiniMax 采样率:16000/24000/32000/44100/48000,默认 32000。 */
|
|
144
|
+
sampleRate?: number
|
|
145
|
+
/** MiniMax 码率(bps):64000-320000,默认 128000。 */
|
|
146
|
+
bitrate?: number
|
|
147
|
+
/** MiniMax 声道数:1 或 2,默认 1。 */
|
|
148
|
+
audioChannel?: number
|
|
149
|
+
/** MiniMax 强制 CBR 编码(avoid VBR),默认 false。 */
|
|
150
|
+
forceCbr?: boolean
|
|
151
|
+
/** MiniMax 字幕开关:true 时响应携带字幕内容/文件。 */
|
|
152
|
+
subtitleEnable?: boolean
|
|
153
|
+
/** MiniMax AIGC 水印开关。 */
|
|
154
|
+
aigcWatermark?: boolean
|
|
155
|
+
/** MiniMax 语言增强(language_boost),如"中英混读",按模型支持情况。 */
|
|
156
|
+
languageBoost?: string
|
|
157
|
+
/** MiniMax 变声参数(voice_modify,speech-2.8 等支持)。 */
|
|
158
|
+
voiceModify?: { pitch?: number; intensity?: number; timbre?: number; soundEffects?: string }
|
|
159
|
+
/** MiniMax 双音色混合权重(timbre_weights)。 */
|
|
160
|
+
timbreWeights?: Array<{ voiceId: string; weight: number }>
|
|
123
161
|
}
|
|
124
162
|
|
|
125
163
|
/** One generated audio, normalized host-side to base64. */
|
package/src/routes.ts
CHANGED
|
@@ -93,16 +93,55 @@ 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
|
-
...(
|
|
103
|
-
...(
|
|
123
|
+
...(num(body.speed) !== undefined ? { speed: num(body.speed)! } : {}),
|
|
124
|
+
...(num(body.duration) !== undefined ? { duration: num(body.duration)! } : {}),
|
|
125
|
+
...(typeof body.lyrics === 'string' && body.lyrics.trim() !== '' ? { lyrics: body.lyrics.trim() } : {}),
|
|
126
|
+
...(typeof body.isInstrumental === 'boolean' ? { isInstrumental: body.isInstrumental } : {}),
|
|
104
127
|
...(typeof body.format === 'string' && body.format.trim() !== '' ? { format: body.format.trim() } : {}),
|
|
105
128
|
...(typeof body.channelId === 'string' && body.channelId !== '' ? { channelId: body.channelId } : {}),
|
|
129
|
+
// ---- MiniMax TTS 专属字段(其他厂商忽略) ----
|
|
130
|
+
...(str(body.emotion) !== undefined ? { emotion: str(body.emotion)! } : {}),
|
|
131
|
+
...(num(body.vol) !== undefined ? { vol: num(body.vol)! } : {}),
|
|
132
|
+
...(num(body.pitch) !== undefined ? { pitch: num(body.pitch)! } : {}),
|
|
133
|
+
...(flag(body.textNormalization) !== undefined ? { textNormalization: flag(body.textNormalization)! } : {}),
|
|
134
|
+
...(flag(body.latexRead) !== undefined ? { latexRead: flag(body.latexRead)! } : {}),
|
|
135
|
+
...(tone !== undefined && tone.length > 0 ? { pronunciationTone: tone } : {}),
|
|
136
|
+
...(num(body.sampleRate) !== undefined ? { sampleRate: num(body.sampleRate)! } : {}),
|
|
137
|
+
...(num(body.bitrate) !== undefined ? { bitrate: num(body.bitrate)! } : {}),
|
|
138
|
+
...(num(body.audioChannel) !== undefined ? { audioChannel: num(body.audioChannel)! } : {}),
|
|
139
|
+
...(flag(body.forceCbr) !== undefined ? { forceCbr: flag(body.forceCbr)! } : {}),
|
|
140
|
+
...(flag(body.subtitleEnable) !== undefined ? { subtitleEnable: flag(body.subtitleEnable)! } : {}),
|
|
141
|
+
...(flag(body.aigcWatermark) !== undefined ? { aigcWatermark: flag(body.aigcWatermark)! } : {}),
|
|
142
|
+
...(str(body.languageBoost) !== undefined ? { languageBoost: str(body.languageBoost)! } : {}),
|
|
143
|
+
...(voiceModify !== undefined ? { voiceModify } : {}),
|
|
144
|
+
...(timbreWeights !== undefined && timbreWeights.length > 0 ? { timbreWeights } : {}),
|
|
106
145
|
}
|
|
107
146
|
}
|
|
108
147
|
|
|
@@ -212,7 +251,9 @@ export function makeRoutes(deps: AudiogenRoutesDeps): WebRoute[] {
|
|
|
212
251
|
?? view.channels[0]
|
|
213
252
|
const channel: AudioChannel = {
|
|
214
253
|
id: stored?.id ?? 'preview',
|
|
215
|
-
|
|
254
|
+
// The draft's own preset wins (even when empty = custom): discovery
|
|
255
|
+
// must follow the vendor being configured, not the default channel.
|
|
256
|
+
preset: typeof body?.preset === 'string' ? body.preset.trim() : (stored?.preset ?? ''),
|
|
216
257
|
name: stored?.name ?? '',
|
|
217
258
|
apiUrl: typeof body?.apiUrl === 'string' && body.apiUrl.trim() !== '' ? body.apiUrl.trim() : (stored?.apiUrl ?? ''),
|
|
218
259
|
apiKey: typeof body?.apiKey === 'string' && body.apiKey.trim() !== '' ? body.apiKey.trim() : (stored?.apiKey ?? ''),
|