Ttspro / app.py
Hamed744's picture
Create app.py
2fa8637 verified
raw
history blame
10.7 kB
# app.py
import gradio as gr
import google.generativeai as genai
import os
import io
from scipy.io.wavfile import write as write_wav # برای ذخیره فایل صوتی
# دریافت API Key از Secrets هاگینگ فیس
# مطمئن شوید که یک Secret به نام GOOGLE_API_KEY در اسپیس خود تعریف کرده‌اید
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
if not GOOGLE_API_KEY:
raise ValueError("GOOGLE_API_KEY not found in environment variables. Please set it in Hugging Face Secrets.")
genai.configure(api_key=GOOGLE_API_KEY)
# انتخاب مدل TTS
# گزینه ها: "gemini-2.5-flash-preview-tts" یا "gemini-2.5-pro-preview-tts"
# برای شروع، از flash استفاده می‌کنیم
TTS_MODEL_NAME = "gemini-2.5-flash-preview-tts" # یا "tts-1" اگر نام‌های ساده‌تر هم کار می‌کنند (باید مستندات دقیق را چک کرد)
# بر اساس مستندات جدید، نام دقیق مدل‌ها به این شکل است.
# لیستی از صداهای موجود (این لیست ممکن است نیاز به بروزرسانی بر اساس مستندات دقیق مدل TTS داشته باشد)
# این فقط یک مثال است، باید نام‌های دقیق voice ها را از مستندات پیدا کنید.
# مستندات قبلی برای Live API صداهایی مانند Puck, Charon, Kore, Fenrir, Aoede, Leda, Orus, and Zephyr را ذکر کرده بود.
# اما برای مدل‌های TTS اختصاصی، ممکن است لیست متفاوت باشد یا اصلاً نیازی به انتخاب voice نباشد و مدل خودش بهینه عمل کند.
# فعلاً این بخش را ساده نگه می‌داریم و به مدل اجازه می‌دهیم voice را انتخاب کند.
AVAILABLE_VOICES = ["Default"] # یا لیستی از نام‌های واقعی voice اگر دارید
def generate_audio(text_to_speak, voice_selection="Default"):
"""
متن را به صدا تبدیل می‌کند با استفاده از Gemini API.
"""
if not text_to_speak:
raise gr.Error("لطفاً متنی را برای تبدیل به صدا وارد کنید.")
print(f"درخواست TTS برای متن: '{text_to_speak[:50]}...' با voice: {voice_selection}")
try:
# ایجاد مدل
# توجه: نحوه فراخوانی مدل TTS ممکن است با generate_content متفاوت باشد.
# باید مستندات دقیق را برای "Text-to-speech (TTS)" با Gemini 2.5 Flash/Pro بررسی کنیم.
# فرض می‌کنیم که می‌توانیم با generate_content و ارسال متن، خروجی صوتی بگیریم.
# این بخش احتمالاً نیاز به اصلاح بر اساس API دقیق TTS دارد.
# بر اساس مستندات قیمت‌گذاری، مدل‌های TTS ورودی متن و خروجی صدا دارند.
# نحوه دقیق فراخوانی برای دریافت بایت‌های صوتی ممکن است به این شکل باشد:
model = genai.GenerativeModel(TTS_MODEL_NAME)
# برای مدل‌های TTS، "prompt" همان متنی است که می‌خواهیم به صدا تبدیل شود.
# ممکن است نیاز به پارامترهای خاصی در generation_config برای صدا باشد.
response = model.generate_content(
text_to_speak,
# generation_config=genai.types.GenerationConfig(
# # پارامترهای خاص TTS در اینجا قرار می‌گیرند، اگر وجود داشته باشد
# # مثلاً voice، سرعت، لحن و ...
# # response_mime_type="audio/wav" or "audio/mp3" ???
# )
)
# پاسخ مدل‌های TTS معمولاً شامل بایت‌های صوتی است.
# باید بررسی کنیم که پاسخ در چه فرمتی است.
# فرض می‌کنیم پاسخ دارای یک پراپرتی audio_content یا مشابه است که بایت‌ها را دارد.
# این بخش کاملاً به خروجی واقعی API بستگی دارد.
# --- این بخش حدسی است و باید با مستندات API تطبیق داده شود ---
if hasattr(response, 'audio_content') and response.audio_content:
audio_bytes = response.audio_content
elif hasattr(response, 'candidates') and response.candidates[0].content.parts[0].inline_data:
# این ساختار برای inline_data در پاسخ‌های چندوجهی است
audio_part = response.candidates[0].content.parts[0]
if audio_part.inline_data.mime_type.startswith("audio/"):
audio_bytes = audio_part.inline_data.data
else:
raise gr.Error(f"فرمت پاسخ صوتی نامعتبر: {audio_part.inline_data.mime_type}")
elif hasattr(response, 'text'): # اگر به اشتباه پاسخ متنی گرفتیم
raise gr.Error(f"مدل پاسخ متنی برگرداند به جای صدا: {response.text}")
else:
print("پاسخ کامل مدل:", response) # برای دیباگ
raise gr.Error("پاسخ صوتی از مدل دریافت نشد یا فرمت آن ناشناخته است.")
# --- پایان بخش حدسی ---
# ذخیره بایت‌های صوتی در یک فایل WAV موقت
# ما به نرخ نمونه‌برداری (sample rate) صدای خروجی نیاز داریم.
# مدل‌های TTS معمولاً با نرخ نمونه‌برداری مشخصی خروجی می‌دهند (مثلاً 24000 Hz).
# این مقدار باید از مستندات API گرفته شود. فرض می‌کنیم 24000 Hz است.
sample_rate = 24000 # هرتز - این را از مستندات API برای مدل TTS خود چک کنید!
# تبدیل بایت‌ها به فرمتی که Gradio بتواند پخش کند (فایل WAV)
# کتابخانه google-generativeai ممکن است مستقیماً فایل صوتی برنگرداند، بلکه بایت‌های خام PCM.
# یا ممکن است یک آبجکت خاص Audio برگرداند.
# ساده‌ترین حالت این است که API مستقیماً بایت‌های یک فایل WAV را برگرداند.
# اگر بایت‌های خام PCM برمی‌گرداند، باید آنها را به WAV تبدیل کنیم.
# فرض می‌کنیم audio_bytes حاوی داده‌های یک فایل WAV کامل است
# یا باید با استفاده از scipy.io.wavfile یا wave آن را بسازیم.
# اگر audio_bytes داده خام PCM16 است:
# import numpy as np
# audio_np = np.frombuffer(audio_bytes, dtype=np.int16)
# wav_io = io.BytesIO()
# write_wav(wav_io, sample_rate, audio_np)
# output_audio_path = wav_io # Gradio می‌تواند BytesIO را به عنوان فایل صوتی بپذیرد
# برای سادگی، فرض می‌کنیم audio_bytes بایت‌های یک فایل صوتی قابل پخش است (مثلاً WAV)
# و Gradio می‌تواند آن را مستقیماً به عنوان (sample_rate, np_array) یا مسیر فایل یا BytesIO بپذیرد.
# اگر API یک آبجکت خاص برمی‌گرداند، باید آن را مطابق مستندات پردازش کنید.
# برای اینکه Gradio بتواند پخش کند، ما به (sample_rate, numpy_array) نیاز داریم
# یا مسیر یک فایل. اگر بایت‌های خام PCM داریم:
# این بخش نیاز به کار بیشتری دارد اگر API بایت‌های خام PCM برمی‌گرداند.
# فعلاً فرض می‌کنیم API یک فرمت قابل قبول برای Gradio برمی‌گرداند یا ما آن را تبدیل می‌کنیم.
# ساده‌ترین راه برای تست اولیه: ذخیره بایت‌ها در فایل و برگرداندن مسیر فایل
output_filename = "output_audio.wav"
with open(output_filename, "wb") as f:
f.write(audio_bytes)
print(f"فایل صوتی در {output_filename} ذخیره شد.")
return output_filename # Gradio می‌تواند مسیر فایل را برای Audio output بگیرد
except Exception as e:
print(f"خطا در تولید صدا: {e}")
# نمایش جزئیات بیشتر خطا برای دیباگ
import traceback
traceback.print_exc()
raise gr.Error(f"خطا در ارتباط با Gemini API یا پردازش صدا: {str(e)}")
# ایجاد رابط کاربری 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="متن خود را اینجا بنویسید...")
# voice_dropdown = gr.Dropdown(choices=AVAILABLE_VOICES, value="Default", label="انتخاب صدا (اختیاری)") # فعلاً ساده
submit_button = gr.Button("🔊 تبدیل به صدا", variant="primary")
with gr.Column(scale=1):
audio_output = gr.Audio(label="خروجی صدا", type="filepath") # یا type="numpy" اگر آرایه برمی‌گردانید
gr.Examples(
examples=[
["سلام، حال شما چطور است؟"],
["به دنیای هوش مصنوعی خوش آمدید."],
["این یک تست برای تبدیل متن به صدا با استفاده از جیمینای است."]
],
inputs=[text_input]
)
submit_button.click(
fn=generate_audio,
inputs=[text_input], # voice_dropdown اگر فعال بود
outputs=[audio_output],
api_name="text_to_speech"
)
gr.Markdown("---")
gr.Markdown(f"مدل مورد استفاده: `{TTS_MODEL_NAME}`")
if __name__ == "__main__":
demo.launch(debug=True) # debug=True برای دیدن لاگ‌های بیشتر در کنسول