Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import openai | |
| import numpy as np | |
| import re | |
| import time | |
| import emoji | |
| import os | |
| from transformers import pipeline | |
| from deep_translator import GoogleTranslator | |
| # Initialize emotion detection model | |
| emotion_classifier = pipeline( | |
| "text-classification", | |
| model="j-hartmann/emotion-english-distilroberta-base", | |
| top_k=1 | |
| ) | |
| # Emotion to emoji mapping | |
| EMOTION_EMOJI_MAP = { | |
| "anger": "😠", | |
| "disgust": "🤢", | |
| "fear": "😨", | |
| "joy": "😄", | |
| "neutral": "😐", | |
| "sadness": "😢", | |
| "surprise": "😲" | |
| } | |
| # OpenAI TTS voices | |
| VOICES = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"] | |
| DEFAULT_SPEED = 1.0 | |
| def detect_emotion(text): | |
| """Detect emotion from text and return corresponding emoji""" | |
| if not text.strip(): | |
| return "📝" # Return pencil emoji for empty text | |
| # Handle case where text is too long | |
| truncated_text = text[:512] | |
| # Safe emotion detection | |
| try: | |
| result = emotion_classifier(truncated_text) | |
| emotion = result[0][0]['label'].lower() | |
| return EMOTION_EMOJI_MAP.get(emotion, "❓") | |
| except Exception: | |
| return "❓" # Question mark if detection fails | |
| def translate_text(text, target_lang="en"): | |
| """Translate text to target language""" | |
| if not text.strip(): | |
| return "" | |
| try: | |
| return GoogleTranslator(source='auto', target=target_lang).translate(text) | |
| except Exception: | |
| return text # Return original if translation fails | |
| def text_to_speech(api_key, text, voice, speed, translate, emotion_boost): | |
| """Convert text to speech with emotion detection""" | |
| # Validate inputs | |
| if not api_key.strip(): | |
| raise gr.Error("🔑 Please enter your OpenAI API key") | |
| if not text.strip(): | |
| raise gr.Error("📝 Please enter some text") | |
| openai.api_key = api_key | |
| # Translation - FIXED: Check if translate is True (boolean) | |
| translated_text = text | |
| if translate is True: # Explicitly check if it's True | |
| translated_text = translate_text(text) | |
| # Emotion detection | |
| emoji_icon = detect_emotion(translated_text) | |
| # Emotion-based speed adjustment | |
| try: | |
| # Ensure values are numbers | |
| speed_val = float(speed) | |
| boost_val = float(emotion_boost) | |
| adjusted_speed = max(0.25, min(2.0, speed_val * boost_val)) | |
| except (TypeError, ValueError): | |
| adjusted_speed = DEFAULT_SPEED | |
| # Generate speech | |
| try: | |
| response = openai.audio.speech.create( | |
| model="tts-1", | |
| voice=voice, | |
| input=translated_text, | |
| speed=adjusted_speed | |
| ) | |
| # Create audio file | |
| timestamp = int(time.time()) | |
| filename = f"tts_output_{timestamp}.wav" | |
| response.stream_to_file(filename) | |
| return filename, emoji_icon, f"Speed: {adjusted_speed:.2f}x" | |
| except Exception as e: | |
| error_msg = f"⚠️ Error: {str(e)}" | |
| if "rate limit" in str(e).lower(): | |
| error_msg += "\n🚨 You've hit the rate limit. Please try again later." | |
| raise gr.Error(error_msg) | |
| # Gradio UI Components | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Advanced OpenAI TTS") as demo: | |
| gr.Markdown("# <center>🎤 Advanced Text-to-Speech Generator</center>") | |
| gr.Markdown("<center>Convert text to natural-sounding speech with emotion detection</center>") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| api_key = gr.Textbox( | |
| label="OpenAI API Key", | |
| type="password", | |
| placeholder="Enter your OpenAI API key...", | |
| info="Get your API key from [OpenAI Platform](https://platform.openai.com/account/api-keys)" | |
| ) | |
| with gr.Accordion("⚙️ Advanced Settings", open=False): | |
| voice = gr.Dropdown( | |
| label="Voice Style", | |
| choices=VOICES, | |
| value="nova", | |
| interactive=True | |
| ) | |
| speed = gr.Slider( | |
| label="Speech Speed", | |
| minimum=0.25, | |
| maximum=2.0, | |
| value=DEFAULT_SPEED, | |
| step=0.05 | |
| ) | |
| emotion_boost = gr.Slider( | |
| label="Emotion Intensity", | |
| minimum=0.8, | |
| maximum=1.5, | |
| value=1.0, | |
| step=0.1, | |
| info="Adjust speed based on emotion" | |
| ) | |
| translate = gr.Checkbox( | |
| label="Auto-translate to English", | |
| value=True, | |
| info="Supports 100+ languages" | |
| ) | |
| input_text = gr.TextArea( | |
| label="Input Text", | |
| placeholder="Enter text to convert to speech...", | |
| lines=5, | |
| max_lines=10 | |
| ) | |
| btn_generate = gr.Button( | |
| "✨ Generate Speech", | |
| variant="primary" | |
| ) | |
| with gr.Column(scale=1): | |
| emoji_output = gr.Textbox( | |
| label="Detected Emotion", | |
| interactive=False, | |
| placeholder="Emoji will appear here..." | |
| ) | |
| speed_info = gr.Textbox( | |
| label="Adjusted Speed", | |
| interactive=False | |
| ) | |
| audio_output = gr.Audio( | |
| label="Generated Speech", | |
| interactive=False, | |
| format="wav" | |
| ) | |
| # FIXED: Simplified examples without booleans | |
| gr.Examples( | |
| examples=[ | |
| ["I'm absolutely thrilled about this amazing opportunity!", "nova", 1.0, 1.2], | |
| ["This situation makes me feel anxious and worried.", "onyx", 1.0, 1.3], | |
| ["Je suis très heureux de vous rencontrer aujourd'hui.", "echo", 1.0, 1.0] | |
| ], | |
| inputs=[input_text, voice, speed, emotion_boost], | |
| label="Example Inputs" | |
| ) | |
| # Event handling | |
| btn_generate.click( | |
| fn=text_to_speech, | |
| inputs=[api_key, input_text, voice, speed, translate, emotion_boost], | |
| outputs=[audio_output, emoji_output, speed_info] | |
| ) | |
| # Footer | |
| gr.Markdown("---") | |
| gr.HTML(""" | |
| <div style="text-align: center"> | |
| <p>🚀 Powered by OpenAI TTS • Emotion Detection • Real-time Translation</p> | |
| <p>⚠️ Your API key is only used for TTS generation and not stored</p> | |
| </div> | |
| """) | |
| # Launch with error handling | |
| try: | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |
| except Exception as e: | |
| print(f"Error launching app: {str(e)}") | |
| # Create a simple fallback interface | |
| gr.Interface( | |
| lambda: "Please check the logs for errors", | |
| inputs=None, | |
| outputs=gr.Textbox(label="Error") | |
| ).launch() |