Spaces:
Runtime error
Runtime error
| """ | |
| Text-to-Speech Module | |
| Handles text-to-speech conversion with Vietnamese language support | |
| """ | |
| import logging | |
| import tempfile | |
| import os | |
| from pathlib import Path | |
| from gtts import gTTS | |
| import io | |
| import base64 | |
| logger = logging.getLogger(__name__) | |
| class VietnameseTTS: | |
| """Vietnamese Text-to-Speech class using gTTS""" | |
| def __init__(self, language='vi', slow=False): | |
| """ | |
| Initialize Vietnamese TTS | |
| Args: | |
| language (str): Language code (default: 'vi' for Vietnamese) | |
| slow (bool): Whether to speak slowly (default: False) | |
| """ | |
| self.language = language | |
| self.slow = slow | |
| def text_to_speech(self, text, output_path=None): | |
| """ | |
| Convert text to speech and save as audio file | |
| Args: | |
| text (str): Text to convert to speech | |
| output_path (str, optional): Path to save audio file. If None, returns temp file path | |
| Returns: | |
| str: Path to the generated audio file | |
| Raises: | |
| Exception: If TTS conversion fails | |
| """ | |
| try: | |
| if not text or not text.strip(): | |
| raise ValueError("Text cannot be empty") | |
| # Create gTTS object | |
| tts = gTTS(text=text.strip(), lang=self.language, slow=self.slow) | |
| # If no output path specified, create temporary file | |
| if output_path is None: | |
| temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp3') | |
| output_path = temp_file.name | |
| temp_file.close() | |
| # Save audio file | |
| tts.save(output_path) | |
| logger.info(f"TTS audio saved to: {output_path}") | |
| return output_path | |
| except Exception as e: | |
| logger.error(f"TTS conversion failed: {str(e)}") | |
| raise Exception(f"Không thể chuyển đổi văn bản thành giọng nói: {str(e)}") | |
| def text_to_speech_bytes(self, text): | |
| """ | |
| Convert text to speech and return as bytes | |
| Args: | |
| text (str): Text to convert to speech | |
| Returns: | |
| bytes: Audio data as bytes | |
| Raises: | |
| Exception: If TTS conversion fails | |
| """ | |
| try: | |
| if not text or not text.strip(): | |
| raise ValueError("Text cannot be empty") | |
| # Create gTTS object | |
| tts = gTTS(text=text.strip(), lang=self.language, slow=self.slow) | |
| # Save to BytesIO buffer | |
| audio_buffer = io.BytesIO() | |
| tts.write_to_fp(audio_buffer) | |
| audio_buffer.seek(0) | |
| return audio_buffer.getvalue() | |
| except Exception as e: | |
| logger.error(f"TTS conversion to bytes failed: {str(e)}") | |
| raise Exception(f"Không thể chuyển đổi văn bản thành giọng nói: {str(e)}") | |
| def text_to_speech_base64(self, text): | |
| """ | |
| Convert text to speech and return as base64 encoded string | |
| Args: | |
| text (str): Text to convert to speech | |
| Returns: | |
| str: Base64 encoded audio data | |
| Raises: | |
| Exception: If TTS conversion fails | |
| """ | |
| try: | |
| audio_bytes = self.text_to_speech_bytes(text) | |
| return base64.b64encode(audio_bytes).decode('utf-8') | |
| except Exception as e: | |
| logger.error(f"TTS conversion to base64 failed: {str(e)}") | |
| raise Exception(f"Không thể chuyển đổi văn bản thành giọng nói: {str(e)}") | |
| # Global TTS instance | |
| _tts_instance = None | |
| def get_tts_instance(): | |
| """Get or create global TTS instance""" | |
| global _tts_instance | |
| if _tts_instance is None: | |
| _tts_instance = VietnameseTTS() | |
| return _tts_instance | |
| def text_to_speech(text, output_path=None): | |
| """ | |
| Convenience function to convert text to speech | |
| Args: | |
| text (str): Text to convert to speech | |
| output_path (str, optional): Path to save audio file | |
| Returns: | |
| str: Path to the generated audio file | |
| """ | |
| tts = get_tts_instance() | |
| return tts.text_to_speech(text, output_path) | |
| def text_to_speech_bytes(text): | |
| """ | |
| Convenience function to convert text to speech bytes | |
| Args: | |
| text (str): Text to convert to speech | |
| Returns: | |
| bytes: Audio data as bytes | |
| """ | |
| tts = get_tts_instance() | |
| return tts.text_to_speech_bytes(text) | |
| def text_to_speech_base64(text): | |
| """ | |
| Convenience function to convert text to speech base64 | |
| Args: | |
| text (str): Text to convert to speech | |
| Returns: | |
| str: Base64 encoded audio data | |
| """ | |
| tts = get_tts_instance() | |
| return tts.text_to_speech_base64(text) | |
| def cleanup_temp_files(file_path): | |
| """ | |
| Clean up temporary audio files | |
| Args: | |
| file_path (str): Path to the file to delete | |
| """ | |
| try: | |
| if file_path and os.path.exists(file_path): | |
| os.unlink(file_path) | |
| logger.info(f"Cleaned up temp file: {file_path}") | |
| except Exception as e: | |
| logger.warning(f"Failed to cleanup temp file {file_path}: {str(e)}") | |
| def is_vietnamese_text(text): | |
| """ | |
| Check if text contains Vietnamese characters | |
| Args: | |
| text (str): Text to check | |
| Returns: | |
| bool: True if text contains Vietnamese characters | |
| """ | |
| vietnamese_chars = set('àáạảãâầấậẩẫăằắặẳẵèéẹẻẽêềếệểễìíịỉĩòóọỏõôồốộổỗơờớợởỡùúụủũưừứựửữỳýỵỷỹđ') | |
| vietnamese_chars.update('ÀÁẠẢÃÂẦẤẬẨẪĂẰẮẶẲẴÈÉẸẺẼÊỀẾỆỂỄÌÍỊỈĨÒÓỌỎÕÔỒỐỘỔỖƠỜỚỢỞỠÙÚỤỦŨƯỪỨỰỬỮỲÝỴỶỸĐ') | |
| return any(char in vietnamese_chars for char in text.lower()) | |
| def get_supported_languages(): | |
| """ | |
| Get list of supported languages for TTS | |
| Returns: | |
| dict: Dictionary of language codes and names | |
| """ | |
| return { | |
| 'vi': 'Tiếng Việt', | |
| 'en': 'English', | |
| 'zh': '中文', | |
| 'ja': '日本語', | |
| 'ko': '한국어', | |
| 'th': 'ไทย', | |
| 'fr': 'Français', | |
| 'de': 'Deutsch', | |
| 'es': 'Español', | |
| 'it': 'Italiano', | |
| 'pt': 'Português', | |
| 'ru': 'Русский' | |
| } | |