Ttspro / app.py
Hamed744's picture
Update app.py
88afdfa verified
raw
history blame
8.78 kB
# app.py
import gradio as gr
import google.generativeai as genai
# from google.generativeai import types # دیگر نیازی به types برای GenerationConfig با response_modalities نیست
import os
import io
from scipy.io.wavfile import write as write_wav
import numpy as np
import traceback
import json # برای parse کردن خطای JSON احتمالی
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
if not GOOGLE_API_KEY:
raise ValueError("GOOGLE_API_KEY not found in environment variables.")
genai.configure(api_key=GOOGLE_API_KEY)
# --- تغییر نام مدل به نسخه Pro TTS ---
TTS_MODEL_NAME = "gemini-2.5-pro-preview-tts"
# --- پایان تغییر ---
AVAILABLE_VOICES = ["پیش‌فرض (مدل انتخاب کند)"]
def generate_audio(text_to_speak, selected_voice_name="پیش‌فرض (مدل انتخاب کند)"):
if not text_to_speak:
raise gr.Error("لطفاً متنی را برای تبدیل به صدا وارد کنید.")
print(f"درخواست TTS برای متن: '{text_to_speak[:50]}...' با گوینده: {selected_voice_name} و مدل: models/{TTS_MODEL_NAME}")
try:
model = genai.GenerativeModel(f"models/{TTS_MODEL_NAME}")
generation_config_params = {} # فعلاً بدون پارامتر خاص برای generation_config
if selected_voice_name != "پیش‌فرض (مدل انتخاب کند)":
print(f"توجه: انتخاب گوینده ('{selected_voice_name}') هنوز به طور کامل پیاده‌سازی نشده است.")
generation_config_to_pass = None
if generation_config_params:
generation_config_to_pass = genai.types.GenerationConfig(**generation_config_params)
print(f"ارسال درخواست به Gemini با generation_config: {generation_config_params}")
else:
print("ارسال درخواست به Gemini بدون generation_config خاص (با تنظیمات پیش‌فرض مدل).")
response = model.generate_content(
text_to_speak,
generation_config=generation_config_to_pass
)
audio_bytes = None
generated_mime_type = None
sample_rate = 24000
if hasattr(response, 'candidates') and response.candidates and \
response.candidates[0].content and response.candidates[0].content.parts:
for part in response.candidates[0].content.parts:
if hasattr(part, 'inline_data') and part.inline_data and \
hasattr(part.inline_data, 'mime_type') and part.inline_data.mime_type.startswith("audio/"):
audio_bytes = part.inline_data.data
generated_mime_type = part.inline_data.mime_type
if ";rate=" in generated_mime_type:
try:
sample_rate = int(generated_mime_type.split(";rate=")[1])
print(f"نرخ نمونه‌برداری از MIME type استخراج شد: {sample_rate} Hz")
except:
print(f"خطا در استخراج نرخ نمونه‌برداری از MIME type: {generated_mime_type}. از پیش‌فرض {sample_rate} Hz استفاده می‌شود.")
print(f"داده صوتی با MIME type: {generated_mime_type} دریافت شد.")
break
if audio_bytes is None:
if hasattr(response, 'audio_content'):
audio_bytes = response.audio_content
generated_mime_type = "audio/wav"
print("داده صوتی از فیلد audio_content دریافت شد.")
else:
print("پاسخ کامل مدل (برای دیباگ):", response)
error_text = response.prompt_feedback if hasattr(response, 'prompt_feedback') else str(response)
raise gr.Error(f"پاسخ صوتی از مدل دریافت نشد. پاسخ مدل: {error_text}")
output_filename = "output.wav"
if "pcm" in (generated_mime_type or "").lower():
print(f"داده PCM خام ({len(audio_bytes)} بایت) با نرخ نمونه‌برداری {sample_rate} Hz دریافت شد، در حال تبدیل به WAV...")
audio_np = np.frombuffer(audio_bytes, dtype=np.int16)
wav_io = io.BytesIO()
write_wav(wav_io, sample_rate, audio_np)
wav_io.seek(0)
with open(output_filename, "wb") as f:
f.write(wav_io.read())
elif audio_bytes:
print(f"داده صوتی با فرمت {generated_mime_type} ({len(audio_bytes)} بایت) دریافت شد، مستقیم ذخیره می‌شود.")
with open(output_filename, "wb") as f:
f.write(audio_bytes)
else:
raise gr.Error("هیچ داده صوتی برای ذخیره وجود ندارد.")
print(f"فایل صوتی در {output_filename} ذخیره شد.")
return output_filename
except genai.types.BlockedPromptException as bpe:
print(f"درخواست توسط مدل بلاک شد: {bpe}")
raise gr.Error(f"محتوای شما توسط مدل پذیرفته نشد. لطفاً متن دیگری را امتحان کنید. دلیل: {bpe}")
except Exception as e:
print(f"خطای کلی در تولید صدا: {e}")
traceback.print_exc()
error_message_from_api = ""
# ... (بقیه کد مدیریت خطا که قبلاً داشتیم) ...
if hasattr(e, 'args') and e.args:
if isinstance(e.args[0], str) and "HttpError" in e.args[0]:
error_message_from_api = str(e.args[0])
try:
details_start = error_message_from_api.find('{')
if details_start != -1:
json_str_candidate = error_message_from_api[details_start:]
cleaned_json_str = ''.join(c for c in json_str_candidate if ord(c) >= 32 or c in ('\t','\r','\n')).strip()
error_obj = json.loads(cleaned_json_str)
if 'error' in error_obj and 'message' in error_obj['error']:
error_message_from_api = error_obj['error']['message']
elif 'message' in error_obj :
error_message_from_api = error_obj['message']
except Exception as json_e:
print(f"خطا در parse کردن جزئیات JSON از پیام خطای API: {json_e}")
else:
error_message_from_api = str(e.args[0])
elif hasattr(e, 'message') and isinstance(e.message, str):
error_message_from_api = e.message
final_error_message = f"خطا در ارتباط با Gemini API یا پردازش صدا: {str(e)}"
if error_message_from_api and error_message_from_api not in final_error_message :
final_error_message += f" | پیام دقیق‌تر API: {error_message_from_api}"
raise gr.Error(final_error_message)
# --- رابط کاربری Gradio بدون تغییر ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# تبدیل متن به صدا با Gemini ♊")
gr.Markdown("متن خود را وارد کنید تا با استفاده از مدل‌های جدید Gemini به صدا تبدیل شود.")
with gr.Row():
with gr.Column(scale=2):
text_input = gr.Textbox(lines=5, label="متن ورودی", placeholder="متن خود را اینجا بنویسید...")
submit_button = gr.Button("🔊 تبدیل به صدا", variant="primary")
with gr.Column(scale=1):
audio_output = gr.Audio(label="خروجی صدا", type="filepath")
gr.Examples(
examples=[
["سلام، حال شما چطور است؟"],
["به دنیای هوش مصنوعی خوش آمدید."],
["این یک تست برای تبدیل متن به صدا با استفاده از جیمینای است."]
],
inputs=[text_input]
)
submit_button.click(
fn=generate_audio,
inputs=[text_input],
outputs=[audio_output],
api_name="text_to_speech"
)
gr.Markdown("---")
gr.Markdown(f"مدل مورد استفاده: `models/{TTS_MODEL_NAME}`") # نام مدل به روز شده را نمایش می‌دهد
gr.Markdown("توجه: برای انتخاب گوینده‌های مختلف، نیاز به بررسی مستندات دقیق مدل TTS و بروزرسانی کد است.")
if __name__ == "__main__":
demo.launch(debug=True)