jdbolter commited on
Commit
244b8f2
·
verified ·
1 Parent(s): b98623a

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +124 -0
  2. requirements.txt +63 -0
app.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import base64
3
+ import uuid
4
+ import gradio as gr
5
+ from openai import OpenAI
6
+ from speechify import Speechify
7
+ from dotenv import load_dotenv
8
+
9
+ # Detect Hugging Face environment
10
+ RUNNING_IN_SPACES = os.getenv("SYSTEM") == "spaces"
11
+
12
+ # Load API keys
13
+ if not RUNNING_IN_SPACES:
14
+ load_dotenv()
15
+ openai_api_key = os.getenv("OPENAI_API_KEY")
16
+ speechify_api_key = os.getenv("SPEECHIFY_API_KEY")
17
+
18
+ # Sanity check (but don't print full keys)
19
+ print(f"✅ OPENAI_API_KEY loaded: {'✅' if openai_api_key else '❌ MISSING'}")
20
+ print(f"✅ SPEECHIFY_API_KEY loaded: {'✅' if speechify_api_key else '❌ MISSING'}")
21
+
22
+ # Initialize clients
23
+ openai_client = OpenAI(api_key=openai_api_key)
24
+ speechify_client = Speechify(token=speechify_api_key)
25
+
26
+ # Voice config
27
+ language_config = {
28
+ "Portuguese": {
29
+ "voice_id": "joao",
30
+ "language": "pt-PT",
31
+ "model": "simba-multilingual",
32
+ "audio_format": "mp3"
33
+ },
34
+ "French": {
35
+ "voice_id": "leo",
36
+ "language": "fr-FR",
37
+ "model": "simba-multilingual",
38
+ "audio_format": "mp3"
39
+ },
40
+ "Spanish": {
41
+ "voice_id": "danna-sofia",
42
+ "language": "es-MX",
43
+ "model": "simba-multilingual",
44
+ "audio_format": "mp3"
45
+ },
46
+ }
47
+
48
+ # Function for chat + TTS
49
+ def chat_and_speak(user_input, language_choice):
50
+ gpt_response = ""
51
+ audio_output_path = None
52
+ try:
53
+ if not user_input or not user_input.strip():
54
+ return "Please enter some text to process.", None
55
+
56
+ print(f"🧠 User input: {user_input}")
57
+ print(f"🗣️ Language choice: {language_choice}")
58
+
59
+ # Step 1: Get GPT response
60
+ system_message = f"You are a friendly {language_choice} language tutor. Respond only in {language_choice}."
61
+ completion = openai_client.chat.completions.create(
62
+ model="gpt-4",
63
+ messages=[
64
+ {"role": "system", "content": system_message},
65
+ {"role": "user", "content": user_input}
66
+ ]
67
+ )
68
+ gpt_response = completion.choices[0].message.content
69
+ print(f"💬 GPT response: {gpt_response}")
70
+
71
+ # Step 2: Use Speechify to generate audio
72
+ config = language_config.get(language_choice)
73
+ if not config:
74
+ error_msg = f"⚠️ Language '{language_choice}' not supported."
75
+ print(error_msg)
76
+ return f"{gpt_response}\n\n{error_msg}", None
77
+
78
+ tts_response = speechify_client.tts.audio.speech(
79
+ input=gpt_response,
80
+ voice_id=config["voice_id"],
81
+ model=config["model"],
82
+ audio_format=config["audio_format"]
83
+ )
84
+
85
+ if hasattr(tts_response, "audio_data") and isinstance(tts_response.audio_data, str) and tts_response.audio_data:
86
+ try:
87
+ audio_bytes = base64.b64decode(tts_response.audio_data)
88
+ os.makedirs("speech_files", exist_ok=True)
89
+ audio_output_path = os.path.join("speech_files", f"speech_{uuid.uuid4().hex}.mp3")
90
+ with open(audio_output_path, "wb") as f:
91
+ f.write(audio_bytes)
92
+ except Exception as audio_err:
93
+ print(f"🔥 Error processing audio data: {audio_err}")
94
+ return f"{gpt_response}\n\n⚠️ Error saving audio: {audio_err}", None
95
+ else:
96
+ print("⚠️ No audio data received from Speechify or audio_data is not a string.")
97
+ return f"{gpt_response}\n\n⚠️ No audio data received from Speechify.", None
98
+
99
+ return gpt_response, audio_output_path
100
+
101
+ except Exception as e:
102
+ print(f"🔥 An unexpected error occurred: {e}")
103
+ error_message = f"⚠️ An unexpected error occurred: {e}"
104
+ if gpt_response:
105
+ return f"{gpt_response}\n\n{error_message}", None
106
+ return error_message, None
107
+
108
+ # Gradio interface
109
+ iface = gr.Interface(
110
+ fn=chat_and_speak,
111
+ inputs=[
112
+ gr.Textbox(label="Say something"),
113
+ gr.Dropdown(choices=["Portuguese", "French", "Spanish"], value="Portuguese", label="Language"),
114
+ ],
115
+ outputs=[
116
+ gr.Textbox(label="GPT Response"),
117
+ gr.Audio(label="TTS Playback", type="filepath")
118
+ ],
119
+ title="Language Tutor with GPT and Speechify",
120
+ allow_flagging="never"
121
+ )
122
+
123
+ if __name__ == "__main__":
124
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ annotated-types==0.7.0
3
+ anyio==4.9.0
4
+ audioop-lts==0.2.1
5
+ certifi==2024.6.2
6
+ charset-normalizer==3.3.2
7
+ click==8.1.8
8
+ distro==1.9.0
9
+ fastapi==0.115.13
10
+ ffmpy==0.6.0
11
+ filelock==3.18.0
12
+ fsspec==2025.5.1
13
+ gradio==5.34.0
14
+ gradio_client==1.10.3
15
+ groovy==0.1.2
16
+ gTTS==2.5.4
17
+ h11==0.16.0
18
+ hf-xet==1.1.4
19
+ httpcore==1.0.9
20
+ httpx==0.28.1
21
+ huggingface-hub==0.33.0
22
+ idna==3.7
23
+ Jinja2==3.1.6
24
+ jiter==0.10.0
25
+ markdown-it-py==3.0.0
26
+ MarkupSafe==3.0.2
27
+ mdurl==0.1.2
28
+ numpy==2.3.0
29
+ openai==1.88.0
30
+ orjson==3.10.18
31
+ packaging==25.0
32
+ pandas==2.3.0
33
+ pillow==11.2.1
34
+ pydantic==2.11.7
35
+ pydantic_core==2.33.2
36
+ pydub==0.25.1
37
+ Pygments==2.19.1
38
+ python-dateutil==2.9.0.post0
39
+ python-dotenv==1.1.0
40
+ python-multipart==0.0.20
41
+ pytz==2025.2
42
+ PyYAML==6.0.2
43
+ requests==2.32.3
44
+ rich==14.0.0
45
+ ruff==0.12.0
46
+ safehttpx==0.1.6
47
+ semantic-version==2.10.0
48
+ shellingham==1.5.4
49
+ six==1.17.0
50
+ sniffio==1.3.1
51
+ speechify==0.0.0
52
+ speechify-api==1.2.0
53
+ starlette==0.46.2
54
+ tabulate==0.9.0
55
+ tomlkit==0.13.3
56
+ tqdm==4.67.1
57
+ typer==0.16.0
58
+ typing-inspection==0.4.1
59
+ typing_extensions==4.14.0
60
+ tzdata==2025.2
61
+ urllib3==2.2.2
62
+ uvicorn==0.34.3
63
+ websockets==15.0.1