fix: ensure MP3 to WAV conversion creates file
- Add proper error handling around pydub conversion - Use absolute paths instead of relative paths - Ensure output directory exists before saving - Verify file was actually created before returning - Add fallback to MP3 if conversion fails - Update tts.py to handle both .wav and .mp3 extensions - Add detailed logging for debugging
This commit is contained in:
@@ -121,16 +121,28 @@ class TTS(Resource):
|
|||||||
seed_vc_model = current_app.config['SEED_VC_MODEL']
|
seed_vc_model = current_app.config['SEED_VC_MODEL']
|
||||||
seed_vc_repo = current_app.config['SEED_VC_REPO_PATH']
|
seed_vc_repo = current_app.config['SEED_VC_REPO_PATH']
|
||||||
vc_service = SeedVCService(model_name=seed_vc_model, repo_path=seed_vc_repo)
|
vc_service = SeedVCService(model_name=seed_vc_model, repo_path=seed_vc_repo)
|
||||||
vc_service.convert_voice(tts_output, reference_path, final_output)
|
actual_output = vc_service.convert_voice(tts_output, reference_path, final_output)
|
||||||
|
|
||||||
logger.info(f"TTS+VC complete: {final_output}")
|
# Verify the output file exists
|
||||||
|
if not os.path.exists(actual_output):
|
||||||
|
raise FileNotFoundError(f"Output file was not created: {actual_output}")
|
||||||
|
|
||||||
|
# Determine mimetype and download name based on actual output
|
||||||
|
if actual_output.endswith('.mp3'):
|
||||||
|
mimetype = 'audio/mpeg'
|
||||||
|
download_name = f"tts_{voice_id}.mp3"
|
||||||
|
else:
|
||||||
|
mimetype = 'audio/wav'
|
||||||
|
download_name = f"tts_{voice_id}.wav"
|
||||||
|
|
||||||
|
logger.info(f"TTS+VC complete: {actual_output} ({os.path.getsize(actual_output)} bytes)")
|
||||||
|
|
||||||
# Return audio file
|
# Return audio file
|
||||||
return send_file(
|
return send_file(
|
||||||
final_output,
|
actual_output,
|
||||||
mimetype='audio/wav',
|
mimetype=mimetype,
|
||||||
as_attachment=True,
|
as_attachment=True,
|
||||||
download_name=f"tts_{voice_id}.wav"
|
download_name=download_name
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -92,12 +92,7 @@ class SeedVCService:
|
|||||||
if self.model is None:
|
if self.model is None:
|
||||||
# Fallback: convert MP3 to WAV
|
# Fallback: convert MP3 to WAV
|
||||||
logger.warning("Seed-VC not available, using passthrough mode")
|
logger.warning("Seed-VC not available, using passthrough mode")
|
||||||
from pydub import AudioSegment
|
return self._passthrough_convert(source_audio_path, output_path)
|
||||||
# Load MP3 and convert to WAV
|
|
||||||
audio = AudioSegment.from_mp3(source_audio_path)
|
|
||||||
audio.export(output_path, format="wav")
|
|
||||||
logger.info(f"MP3 to WAV conversion complete: {output_path}")
|
|
||||||
return output_path
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Load audio files
|
# Load audio files
|
||||||
@@ -122,12 +117,77 @@ class SeedVCService:
|
|||||||
logger.error(f"Voice conversion failed: {e}")
|
logger.error(f"Voice conversion failed: {e}")
|
||||||
# Fallback: convert MP3 to WAV
|
# Fallback: convert MP3 to WAV
|
||||||
logger.warning("Fallback to MP3-to-WAV conversion")
|
logger.warning("Fallback to MP3-to-WAV conversion")
|
||||||
|
return self._passthrough_convert(source_audio_path, output_path)
|
||||||
|
|
||||||
|
def _passthrough_convert(self, source_audio_path: str, output_path: str) -> str:
|
||||||
|
"""
|
||||||
|
Convert MP3 to WAV as passthrough when Seed-VC is not available.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source_audio_path: Path to source MP3 audio
|
||||||
|
output_path: Path to save converted WAV audio
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path to the output file (may differ from output_path if MP3 is used)
|
||||||
|
"""
|
||||||
|
# Use absolute paths
|
||||||
|
source_audio_path = os.path.abspath(source_audio_path)
|
||||||
|
output_path = os.path.abspath(output_path)
|
||||||
|
|
||||||
|
logger.info(f"Passthrough convert: {source_audio_path} -> {output_path}")
|
||||||
|
|
||||||
|
# Verify source exists
|
||||||
|
if not os.path.exists(source_audio_path):
|
||||||
|
raise FileNotFoundError(f"Source audio file not found: {source_audio_path}")
|
||||||
|
|
||||||
|
# Ensure output directory exists
|
||||||
|
output_dir = os.path.dirname(output_path)
|
||||||
|
if output_dir:
|
||||||
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
logger.debug(f"Ensured output directory exists: {output_dir}")
|
||||||
|
|
||||||
|
try:
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
|
|
||||||
|
# Load MP3
|
||||||
|
logger.debug(f"Loading MP3 from: {source_audio_path}")
|
||||||
audio = AudioSegment.from_mp3(source_audio_path)
|
audio = AudioSegment.from_mp3(source_audio_path)
|
||||||
|
logger.debug(f"Audio loaded: {len(audio)}ms, {audio.channels} channels")
|
||||||
|
|
||||||
|
# Export as WAV
|
||||||
|
logger.debug(f"Exporting WAV to: {output_path}")
|
||||||
audio.export(output_path, format="wav")
|
audio.export(output_path, format="wav")
|
||||||
logger.info(f"MP3 to WAV conversion complete: {output_path}")
|
|
||||||
|
# Verify file was created
|
||||||
|
if not os.path.exists(output_path):
|
||||||
|
raise RuntimeError(f"WAV file was not created at {output_path}")
|
||||||
|
|
||||||
|
file_size = os.path.getsize(output_path)
|
||||||
|
if file_size == 0:
|
||||||
|
raise RuntimeError(f"WAV file is empty: {output_path}")
|
||||||
|
|
||||||
|
logger.info(f"MP3 to WAV conversion complete: {output_path} ({file_size} bytes)")
|
||||||
return output_path
|
return output_path
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"MP3 to WAV conversion failed: {e}")
|
||||||
|
|
||||||
|
# Fallback: return MP3 file directly (rename extension)
|
||||||
|
mp3_output = output_path.replace('.wav', '.mp3')
|
||||||
|
if source_audio_path != mp3_output:
|
||||||
|
import shutil
|
||||||
|
logger.warning(f"Using MP3 fallback: copying to {mp3_output}")
|
||||||
|
shutil.copy2(source_audio_path, mp3_output)
|
||||||
|
|
||||||
|
if not os.path.exists(mp3_output):
|
||||||
|
raise RuntimeError(f"Failed to create fallback MP3 file: {mp3_output}")
|
||||||
|
|
||||||
|
logger.info(f"Fallback MP3 created: {mp3_output}")
|
||||||
|
return mp3_output
|
||||||
|
else:
|
||||||
|
# Source is already the target
|
||||||
|
return source_audio_path
|
||||||
|
|
||||||
def preprocess_audio(self, input_path: str, output_path: str, target_sr: int = 22050) -> str:
|
def preprocess_audio(self, input_path: str, output_path: str, target_sr: int = 22050) -> str:
|
||||||
"""
|
"""
|
||||||
Preprocess audio to match Seed-VC requirements.
|
Preprocess audio to match Seed-VC requirements.
|
||||||
|
|||||||
Reference in New Issue
Block a user