Generate TTS audio and optionally convert to a different format.
(text, voice, response_format, speed)
| 27 | return False |
| 28 | |
| 29 | async def _generate_audio(text, voice, response_format, speed): |
| 30 | """Generate TTS audio and optionally convert to a different format.""" |
| 31 | # Determine if the voice is an OpenAI-compatible voice or a direct edge-tts voice |
| 32 | edge_tts_voice = voice_mapping.get(voice, voice) # Use mapping if in OpenAI names, otherwise use as-is |
| 33 | |
| 34 | # Generate the TTS output in mp3 format first |
| 35 | temp_output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") |
| 36 | |
| 37 | # Convert speed to SSML rate format |
| 38 | try: |
| 39 | speed_rate = speed_to_rate(speed) # Convert speed value to "+X%" or "-X%" |
| 40 | except Exception as e: |
| 41 | print(f"Error converting speed: {e}. Defaulting to +0%.") |
| 42 | speed_rate = "+0%" |
| 43 | |
| 44 | # Generate the MP3 file |
| 45 | communicator = edge_tts.Communicate(text=text, voice=edge_tts_voice, rate=speed_rate) |
| 46 | await communicator.save(temp_output_file.name) |
| 47 | |
| 48 | # If the requested format is mp3, return the generated file directly |
| 49 | if response_format == "mp3": |
| 50 | return temp_output_file.name |
| 51 | |
| 52 | # Check if FFmpeg is installed |
| 53 | if not is_ffmpeg_installed(): |
| 54 | print("FFmpeg is not available. Returning unmodified mp3 file.") |
| 55 | return temp_output_file.name |
| 56 | |
| 57 | # Create a new temporary file for the converted output |
| 58 | converted_output_file = tempfile.NamedTemporaryFile(delete=False, suffix=f".{response_format}") |
| 59 | |
| 60 | # Build the FFmpeg command |
| 61 | ffmpeg_command = [ |
| 62 | "ffmpeg", |
| 63 | "-i", temp_output_file.name, # Input file |
| 64 | "-c:a", { |
| 65 | "aac": "aac", |
| 66 | "mp3": "libmp3lame", |
| 67 | "wav": "pcm_s16le", |
| 68 | "opus": "libopus", |
| 69 | "flac": "flac" |
| 70 | }.get(response_format, "aac"), # Default to AAC if unknown |
| 71 | "-b:a", "192k" if response_format != "wav" else None, # Bitrate not needed for WAV |
| 72 | "-f", { |
| 73 | "aac": "mp4", # AAC in MP4 container |
| 74 | "mp3": "mp3", |
| 75 | "wav": "wav", |
| 76 | "opus": "ogg", |
| 77 | "flac": "flac" |
| 78 | }.get(response_format, response_format), # Default to matching format |
| 79 | "-y", # Overwrite without prompt |
| 80 | converted_output_file.name # Output file |
| 81 | ] |
| 82 | |
| 83 | try: |
| 84 | # Run FFmpeg command and ensure no errors occur |
| 85 | subprocess.run(ffmpeg_command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 86 | except subprocess.CalledProcessError as e: |
no test coverage detected