Update app.py
Browse files
app.py
CHANGED
|
@@ -11,7 +11,8 @@ from f5_tts.api import F5TTS
|
|
| 11 |
# ========================================== #
|
| 12 |
# 1. System Setup & Configuration #
|
| 13 |
# ========================================== #
|
| 14 |
-
|
|
|
|
| 15 |
voice_file = "my_voice_fixed.wav"
|
| 16 |
|
| 17 |
if not os.path.exists(voice_file):
|
|
@@ -48,6 +49,10 @@ print("All Speech Systems Fully Active!")
|
|
| 48 |
# ========================================== #
|
| 49 |
def get_ai_answer(question):
|
| 50 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
chat_completion = groq_client.chat.completions.create(
|
| 52 |
messages=[
|
| 53 |
{"role": "system", "content": "You are a professional voice simulation assistant. Keep answers ultra short, under 10 words."},
|
|
@@ -55,30 +60,32 @@ def get_ai_answer(question):
|
|
| 55 |
],
|
| 56 |
model="llama-3.3-7b-versatile",
|
| 57 |
max_tokens=40,
|
| 58 |
-
timeout=15
|
| 59 |
)
|
| 60 |
-
# CRITICAL FIX: Added [0] index to resolve list object structural extraction crashes
|
| 61 |
return chat_completion.choices[0].message.content.strip()
|
| 62 |
except Exception as e:
|
| 63 |
print(f"⚠️ Groq API issue detected: {e}")
|
| 64 |
-
|
|
|
|
| 65 |
|
| 66 |
# ========================================== #
|
| 67 |
# 3. Native Voice Synthesis Processing #
|
| 68 |
# ========================================== #
|
| 69 |
def clone_and_speak(text):
|
| 70 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
unique_filename = f"voice_output_{uuid.uuid4().hex[:8]}.wav"
|
| 72 |
print(f"🔊 Rendering voice cloning track for text: '{text}'")
|
| 73 |
|
| 74 |
-
# Invoke inference engine
|
| 75 |
result = f5tts.infer(
|
| 76 |
ref_file=voice_file,
|
| 77 |
ref_text=auto_reference_text,
|
| 78 |
gen_text=text
|
| 79 |
)
|
| 80 |
|
| 81 |
-
# Robust tuple extraction safely mapping elements
|
| 82 |
if isinstance(result, tuple):
|
| 83 |
if len(result) == 2:
|
| 84 |
audio_data, sample_rate = result
|
|
@@ -89,16 +96,12 @@ def clone_and_speak(text):
|
|
| 89 |
else:
|
| 90 |
audio_data, sample_rate = result, 24000
|
| 91 |
|
| 92 |
-
# Convert Torch tensors safely to standard numpy array structures
|
| 93 |
if hasattr(audio_data, "cpu"):
|
| 94 |
audio_data = audio_data.cpu().numpy()
|
| 95 |
elif hasattr(audio_data, "numpy"):
|
| 96 |
audio_data = audio_data.numpy()
|
| 97 |
|
| 98 |
-
# Flatten structural multi-dimensional arrays safely for soundfile
|
| 99 |
audio_data = np.squeeze(audio_data)
|
| 100 |
-
|
| 101 |
-
# Write clean output wave file natively
|
| 102 |
sf.write(unique_filename, audio_data, sample_rate, format='WAV')
|
| 103 |
|
| 104 |
if os.path.exists(unique_filename) and os.path.getsize(unique_filename) > 0:
|
|
@@ -124,7 +127,6 @@ def chatbot_engine(text_input, audio_input):
|
|
| 124 |
ai_text_response = get_ai_answer(question)
|
| 125 |
generated_audio_track = clone_and_speak(ai_text_response)
|
| 126 |
|
| 127 |
-
# Return outputs AND clear the input fields simultaneously
|
| 128 |
return ai_text_response, generated_audio_track, gr.update(value=""), gr.update(value=None)
|
| 129 |
|
| 130 |
# ========================================== #
|
|
@@ -151,7 +153,6 @@ with gr.Blocks(title="Rabbani A I voice clone") as interface:
|
|
| 151 |
interactive=False
|
| 152 |
)
|
| 153 |
|
| 154 |
-
# Connect UI outputs and reset input elements instantly upon submission
|
| 155 |
submit_btn.click(
|
| 156 |
fn=chatbot_engine,
|
| 157 |
inputs=[text_prompt_box, audio_prompt_box],
|
|
@@ -160,4 +161,4 @@ with gr.Blocks(title="Rabbani A I voice clone") as interface:
|
|
| 160 |
|
| 161 |
clear_btn.add([text_prompt_box, audio_prompt_box, text_output_box, audio_output_player])
|
| 162 |
|
| 163 |
-
interface.queue().launch(
|
|
|
|
| 11 |
# ========================================== #
|
| 12 |
# 1. System Setup & Configuration #
|
| 13 |
# ========================================== #
|
| 14 |
+
# SECURE FIX: Automatically look for the Hugging Face Space Secret first
|
| 15 |
+
GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "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")
|
| 16 |
voice_file = "my_voice_fixed.wav"
|
| 17 |
|
| 18 |
if not os.path.exists(voice_file):
|
|
|
|
| 49 |
# ========================================== #
|
| 50 |
def get_ai_answer(question):
|
| 51 |
try:
|
| 52 |
+
# Quick validation check to warn you in the UI
|
| 53 |
+
if not GROQ_API_KEY or GROQ_API_KEY.startswith("gsk_21Y7DDN"):
|
| 54 |
+
return "Error: Your Groq API key is expired or invalid. Please add a valid GROQ_API_KEY to your Hugging Face Space Settings -> Secrets."
|
| 55 |
+
|
| 56 |
chat_completion = groq_client.chat.completions.create(
|
| 57 |
messages=[
|
| 58 |
{"role": "system", "content": "You are a professional voice simulation assistant. Keep answers ultra short, under 10 words."},
|
|
|
|
| 60 |
],
|
| 61 |
model="llama-3.3-7b-versatile",
|
| 62 |
max_tokens=40,
|
| 63 |
+
timeout=15
|
| 64 |
)
|
|
|
|
| 65 |
return chat_completion.choices[0].message.content.strip()
|
| 66 |
except Exception as e:
|
| 67 |
print(f"⚠️ Groq API issue detected: {e}")
|
| 68 |
+
# DIAGNOSTIC FIX: Returns the actual error string so you can see exactly why it is failing
|
| 69 |
+
return f"API Connection Error: {str(e)}"
|
| 70 |
|
| 71 |
# ========================================== #
|
| 72 |
# 3. Native Voice Synthesis Processing #
|
| 73 |
# ========================================== #
|
| 74 |
def clone_and_speak(text):
|
| 75 |
try:
|
| 76 |
+
# Don't waste compute resources if text generation failed
|
| 77 |
+
if "Error:" in text or "Connection Error:" in text:
|
| 78 |
+
return None
|
| 79 |
+
|
| 80 |
unique_filename = f"voice_output_{uuid.uuid4().hex[:8]}.wav"
|
| 81 |
print(f"🔊 Rendering voice cloning track for text: '{text}'")
|
| 82 |
|
|
|
|
| 83 |
result = f5tts.infer(
|
| 84 |
ref_file=voice_file,
|
| 85 |
ref_text=auto_reference_text,
|
| 86 |
gen_text=text
|
| 87 |
)
|
| 88 |
|
|
|
|
| 89 |
if isinstance(result, tuple):
|
| 90 |
if len(result) == 2:
|
| 91 |
audio_data, sample_rate = result
|
|
|
|
| 96 |
else:
|
| 97 |
audio_data, sample_rate = result, 24000
|
| 98 |
|
|
|
|
| 99 |
if hasattr(audio_data, "cpu"):
|
| 100 |
audio_data = audio_data.cpu().numpy()
|
| 101 |
elif hasattr(audio_data, "numpy"):
|
| 102 |
audio_data = audio_data.numpy()
|
| 103 |
|
|
|
|
| 104 |
audio_data = np.squeeze(audio_data)
|
|
|
|
|
|
|
| 105 |
sf.write(unique_filename, audio_data, sample_rate, format='WAV')
|
| 106 |
|
| 107 |
if os.path.exists(unique_filename) and os.path.getsize(unique_filename) > 0:
|
|
|
|
| 127 |
ai_text_response = get_ai_answer(question)
|
| 128 |
generated_audio_track = clone_and_speak(ai_text_response)
|
| 129 |
|
|
|
|
| 130 |
return ai_text_response, generated_audio_track, gr.update(value=""), gr.update(value=None)
|
| 131 |
|
| 132 |
# ========================================== #
|
|
|
|
| 153 |
interactive=False
|
| 154 |
)
|
| 155 |
|
|
|
|
| 156 |
submit_btn.click(
|
| 157 |
fn=chatbot_engine,
|
| 158 |
inputs=[text_prompt_box, audio_prompt_box],
|
|
|
|
| 161 |
|
| 162 |
clear_btn.add([text_prompt_box, audio_prompt_box, text_output_box, audio_output_player])
|
| 163 |
|
| 164 |
+
interface.queue().launch()
|