diff --git a/backend/main.py b/backend/main.py index 4ea607e..53dd9f6 100644 --- a/backend/main.py +++ b/backend/main.py @@ -414,6 +414,10 @@ async def preview_voice(request: VoicePreviewRequest): else: raise ValueError(f"Unknown engine: {tts_service.engine_name}") + # Check if audio was generated + if audio is None or len(audio) == 0: + raise ValueError("No audio generated - voice model may be missing") + # Convert to WAV bytes buffer = io.BytesIO() sf.write(buffer, audio, sample_rate, format='WAV') @@ -427,7 +431,31 @@ async def preview_voice(request: VoicePreviewRequest): media_type="audio/wav", headers={"Content-Disposition": "inline; filename=preview.wav"} ) - + + except FileNotFoundError as e: + logger.error(f"Voice model not found: {str(e)}") + return JSONResponse( + status_code=status.HTTP_404_NOT_FOUND, + content={ + "error": "VoiceModelNotFound", + "message": f"Voice model '{request.voice}' not found. Please download Piper voice models manually.", + "details": { + "voice": request.voice, + "engine": tts_service.engine_name, + "setup_guide": "See backend/PIPER_SETUP.md for instructions" + } + } + ) + except ValueError as e: + logger.error(f"Validation error during preview: {str(e)}") + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content={ + "error": "ValidationError", + "message": str(e), + "details": {"voice": request.voice, "engine": tts_service.engine_name} + } + ) except Exception as e: logger.error(f"Error during voice preview: {str(e)}", exc_info=True) return JSONResponse( diff --git a/backend/piper_models/en_US-lessac-medium.onnx.json b/backend/piper_models/en_US-lessac-medium.onnx.json new file mode 100644 index 0000000..a05a475 --- /dev/null +++ b/backend/piper_models/en_US-lessac-medium.onnx.json @@ -0,0 +1 @@ +Entry not found \ No newline at end of file diff --git a/frontend/src/components/VoiceAssignmentSection.tsx b/frontend/src/components/VoiceAssignmentSection.tsx index a19d352..d60518e 100644 --- a/frontend/src/components/VoiceAssignmentSection.tsx +++ b/frontend/src/components/VoiceAssignmentSection.tsx @@ -262,6 +262,11 @@ export default function VoiceAssignmentSection({ } catch (error) { console.error('Preview failed:', error); setPreviewingRole(null); + + // Show user-friendly error message + if (error instanceof Error) { + alert(`Voice preview failed: ${error.message}\n\nIf using Piper TTS, make sure voice models are downloaded. See backend/PIPER_SETUP.md for instructions.`); + } } }; @@ -350,10 +355,19 @@ export default function VoiceAssignmentSection({ {currentEngine === 'piper' && ( -
-

- ✨ Pitch Control: Piper allows you to adjust voice pitch per character (coming soon in UI) -

+
+
+

+ ✨ Pitch Control: Piper allows you to adjust voice pitch per character (coming soon in UI) +

+
+
+

+ ⚠️ Setup Required: Piper voice models must be downloaded manually. + See backend/PIPER_SETUP.md for instructions. + If voices don't work, you may need to download the model files first. +

+
)}