From 211b7dc2725873dca83728baa1ef022b846a6f2c Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Mon, 18 May 2026 12:50:59 +0200 Subject: [PATCH] fix(minimax): correct API payload and add TTS debug logging - Fix model name: speech-2.8-hd -> speech-02-hd - Fix bitrate: 128 -> 128000 bps - Add channel, speed, pitch, vol to voice/audio settings - Handle binary audio response (Content-Type: audio/*) - Fallback audio field lookup: data.data.audio || data.audio - Add background job log: ttsProvider + hasMinimaxKey - Log full FFmpeg request body (text truncated, key masked) --- ffmpeg-service/main.py | 41 ++++++++++++++++++++++++++++++--------- server/routes/reels.ts | 4 ++++ server/services/ffmpeg.ts | 4 +++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/ffmpeg-service/main.py b/ffmpeg-service/main.py index cf8e10b..456ca11 100644 --- a/ffmpeg-service/main.py +++ b/ffmpeg-service/main.py @@ -202,21 +202,44 @@ def generate_tts_minimax(text: str, voice_id: str, api_key: str, audio_path: Pat "Content-Type": "application/json", } payload = { - "model": "speech-2.8-hd", + "model": "speech-02-hd", "text": text, - "voice_setting": {"voice_id": voice_id}, - "audio_setting": {"format": "mp3", "sample_rate": 24000, "bitrate": 128}, + "voice_setting": { + "voice_id": voice_id, + "speed": 1.0, + "pitch": 0, + "vol": 1.0, + }, + "audio_setting": { + "format": "mp3", + "sample_rate": 32000, + "bitrate": 128000, + "channel": 1, + }, } + print(f"🔊 Minimax API request: voice_id={voice_id}, model=speech-02-hd, text_len={len(text)}") response = requests.post(url, headers=headers, json=payload, timeout=60) + print(f"🔊 Minimax API response: status={response.status_code}, content_type={response.headers.get('Content-Type', '?')}") response.raise_for_status() - data = response.json() - base_resp = data.get("base_resp", {}) - if base_resp.get("status_code") != 0: - raise Exception(f"Minimax API error: {base_resp.get('status_msg', 'unknown error')}") + content_type = response.headers.get("Content-Type", "") + if "audio" in content_type: + # Direct binary audio response + audio_bytes = response.content + print(f"🔊 Minimax returned binary audio directly ({len(audio_bytes)} bytes)") + else: + data = response.json() + print(f"🔊 Minimax JSON response keys: {list(data.keys())}") + + base_resp = data.get("base_resp", {}) + if base_resp.get("status_code") != 0: + raise Exception(f"Minimax API error: {base_resp.get('status_msg', 'unknown error')}") + + audio_raw = data.get("data", {}).get("audio") or data.get("audio") + if not audio_raw: + raise Exception(f"Minimax API: no audio field in response. Keys: {list(data.keys())}") + audio_bytes = bytes.fromhex(audio_raw) - audio_hex = data["data"]["audio"] - audio_bytes = bytes.fromhex(audio_hex) with open(audio_path, "wb") as f: f.write(audio_bytes) print(f"✅ Minimax TTS audio saved: {audio_path.stat().st_size} bytes") diff --git a/server/routes/reels.ts b/server/routes/reels.ts index 6a4e64a..bb1b70a 100644 --- a/server/routes/reels.ts +++ b/server/routes/reels.ts @@ -614,9 +614,13 @@ async function processReelBackground( const minimaxCfg = await storage.getMinimaxConfig(userId); if (minimaxCfg?.apiKey) { minimaxApiKeyBg = minimaxCfg.apiKey; + } else { + console.error('❌ [Background] Minimax API key not found in DB for user:', userId); } } + console.log('🔊 [Background] TTS config:', { ttsEnabled, ttsProvider, ttsVoice, hasMinimaxKey: !!minimaxApiKeyBg }); + const ffmpegResult = await ffmpegService.processReelFromUrl(resolveInternalUrl(media.originalUrl), { text: overlayText, musicUrl: finalMusicUrl, diff --git a/server/services/ffmpeg.ts b/server/services/ffmpeg.ts index da0650b..124200d 100644 --- a/server/services/ffmpeg.ts +++ b/server/services/ffmpeg.ts @@ -229,7 +229,9 @@ export class FFmpegService { drawText: options.drawText, }); - console.log('📤 Sending to FFmpeg API:', JSON.stringify(requestBody, null, 2).substring(0, 500) + '...'); + const debugBody = { ...requestBody }; + if (debugBody.minimax_api_key) debugBody.minimax_api_key = '***'; + console.log('📤 Sending to FFmpeg API:', JSON.stringify({ ...debugBody, text: debugBody.text ? `[${debugBody.text.length} chars]` : undefined })); try { const response = await fetch(`${config.apiUrl}/process-reel`, {