Hamed744 commited on
Commit
169ec87
·
verified ·
1 Parent(s): 59d09f0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -33
app.py CHANGED
@@ -6,6 +6,7 @@ import os
6
  import io
7
  from scipy.io.wavfile import write as write_wav
8
  import numpy as np
 
9
 
10
  GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
11
  if not GOOGLE_API_KEY:
@@ -14,9 +15,6 @@ genai.configure(api_key=GOOGLE_API_KEY)
14
 
15
  TTS_MODEL_NAME = "gemini-2.5-flash-preview-tts"
16
 
17
- # نام‌های گوینده‌ها باید از مستندات دقیق مدل TTS گرفته شود.
18
- # این‌ها فقط مثال هستند و ممکن است برای این مدل معتبر نباشند.
19
- # فعلاً یک لیست ساده با "پیش‌فرض" می‌گذاریم.
20
  AVAILABLE_VOICES = ["پیش‌فرض (مدل انتخاب کند)"]
21
  # اگر نام‌های واقعی را پیدا کردید، اینجا اضافه کنید:
22
  # AVAILABLE_VOICES.extend(["voice-name-1", "voice-name-2"])
@@ -30,26 +28,20 @@ def generate_audio(text_to_speak, selected_voice_name="پیش‌فرض (مدل
30
  try:
31
  model = genai.GenerativeModel(f"models/{TTS_MODEL_NAME}")
32
 
33
- # --- اصلاح کلیدی: تنظیم صریح response_modalities ---
34
  generation_config_params = {
35
- "response_modalities": ["AUDIO"] # درخواست صریح خروجی صوتی
36
  }
37
 
38
- # اگر کاربر یک گوینده خاص انتخاب کرده "پیش‌فرض" نیست)
39
- # و ما نام پارامتر صحیح را برای voice در generation_config بدانیم:
40
  if selected_voice_name != "پیش‌فرض (مدل انتخاب کند)":
41
- # نام پارامتر برای voice ممکن است "voice_name", "voice", "speaker" یا چیز دیگری باشد.
42
- # این را باید از مستندات TTS API برای این مدل پیدا کنید.
43
- # فرض می‌کنیم "voice" است:
44
- # generation_config_params["voice"] = selected_voice_name
45
- # یا اگر ساختار speech_config مانند Live API است:
46
  # generation_config_params["speech_config"] = types.SpeechConfig(
47
  # voice_config=types.VoiceConfig(
48
  # prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=selected_voice_name)
49
  # )
50
  # )
51
- print(f"توجه: انتخاب گوینده هنوز پیاده‌سازی نشده است. از گوینده پیش‌فرض مدل استفاده می‌شود.")
52
-
53
 
54
  generation_config = genai.types.GenerationConfig(**generation_config_params)
55
 
@@ -59,21 +51,18 @@ def generate_audio(text_to_speak, selected_voice_name="پیش‌فرض (مدل
59
  text_to_speak,
60
  generation_config=generation_config
61
  )
62
- # --- پایان اصلاح ---
63
-
64
 
65
  audio_bytes = None
66
  generated_mime_type = None
67
- sample_rate = 24000 # پیش‌فرض برای TTS گوگل، از مستندات چک شود
68
 
69
  if hasattr(response, 'candidates') and response.candidates and \
70
  response.candidates[0].content and response.candidates[0].content.parts:
71
  for part in response.candidates[0].content.parts:
72
  if hasattr(part, 'inline_data') and part.inline_data and \
73
- part.inline_data.mime_type.startswith("audio/"):
74
  audio_bytes = part.inline_data.data
75
  generated_mime_type = part.inline_data.mime_type
76
- # برخی API ها ممکن است نرخ نمونه‌برداری را در mime_type بفرستند
77
  if ";rate=" in generated_mime_type:
78
  try:
79
  sample_rate = int(generated_mime_type.split(";rate=")[1])
@@ -83,10 +72,10 @@ def generate_audio(text_to_speak, selected_voice_name="پیش‌فرض (مدل
83
  print(f"داده صوتی با MIME type: {generated_mime_type} دریافت شد.")
84
  break
85
 
86
- if audio_bytes is None: # fallback اگر ساختار بالا نبود
87
  if hasattr(response, 'audio_content'):
88
  audio_bytes = response.audio_content
89
- generated_mime_type = "audio/wav" # فرض
90
  print("داده ��وتی از فیلد audio_content دریافت شد.")
91
  else:
92
  print("پاسخ کامل مدل (برای دیباگ):", response)
@@ -94,32 +83,66 @@ def generate_audio(text_to_speak, selected_voice_name="پیش‌فرض (مدل
94
  raise gr.Error(f"پاسخ صوتی از مدل دریافت نشد. پاسخ مدل: {error_text}")
95
 
96
  output_filename = "output.wav"
97
- # فرض می‌کنیم API بایت‌های خام PCM برمی‌گرداند اگر mime_type شامل pcm باشد
98
- # یا یک فایل WAV کامل.
99
  if "pcm" in (generated_mime_type or "").lower():
100
  print(f"داده PCM خام ({len(audio_bytes)} بایت) با نرخ نمونه‌برداری {sample_rate} Hz دریافت شد، در حال تبدیل به WAV...")
101
- audio_np = np.frombuffer(audio_bytes, dtype=np.int16) # فرض بر 16-bit PCM
102
  wav_io = io.BytesIO()
103
  write_wav(wav_io, sample_rate, audio_np)
104
  wav_io.seek(0)
105
  with open(output_filename, "wb") as f:
106
  f.write(wav_io.read())
107
- elif audio_bytes: # اگر PCM نیست، فرض می‌کنیم خود فایل صوتی است (مثلاً WAV از API)
108
  print(f"داده صوتی با فرمت {generated_mime_type} ({len(audio_bytes)} بایت) دریافت شد، مستقیم ذخیره می‌شود.")
109
  with open(output_filename, "wb") as f:
110
  f.write(audio_bytes)
111
  else:
112
  raise gr.Error("هیچ داده صوتی برای ذخیره وجود ندارد.")
113
 
114
-
115
  print(f"فایل صوتی در {output_filename} ذخیره شد.")
116
  return output_filename
117
 
118
- except genai.types.BlockedPromptException as bpe: # ... بدون تغییر ...
119
- except Exception as e: # ... بدون تغییر ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
 
122
- # ایجاد رابط کاربری Gradio
123
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
124
  gr.Markdown("# تبدیل متن به صدا ب�� Gemini ♊")
125
  gr.Markdown("متن خود را وارد کنید تا با استفاده از مدل‌های جدید Gemini به صدا تبدیل شود.")
@@ -127,12 +150,19 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
127
  with gr.Row():
128
  with gr.Column(scale=2):
129
  text_input = gr.Textbox(lines=5, label="متن ورودی", placeholder="متن خود را اینجا بنویسید...")
130
- # voice_dropdown = gr.Dropdown(choices=AVAILABLE_VOICES, value=AVAILABLE_VOICES[0], label="انتخاب گوینده") # فعال کردن Dropdown
131
  submit_button = gr.Button("🔊 تبدیل به صدا", variant="primary")
132
  with gr.Column(scale=1):
133
  audio_output = gr.Audio(label="خروجی صدا", type="filepath")
134
 
135
- gr.Examples( /* ... بدون تغییر ... */ )
 
 
 
 
 
 
 
136
 
137
  submit_button.click(
138
  fn=generate_audio,
@@ -146,6 +176,5 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
146
  gr.Markdown(f"مدل مورد استفاده: `models/{TTS_MODEL_NAME}`")
147
  gr.Markdown("توجه: برای انتخاب گوینده‌های مختلف، نیاز به بررسی مستندات دقیق مدل TTS و بروزرسانی کد است.")
148
 
149
-
150
  if __name__ == "__main__":
151
- demo.launch(debug=True)
 
6
  import io
7
  from scipy.io.wavfile import write as write_wav
8
  import numpy as np
9
+ import traceback # برای چاپ کامل خطا
10
 
11
  GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
12
  if not GOOGLE_API_KEY:
 
15
 
16
  TTS_MODEL_NAME = "gemini-2.5-flash-preview-tts"
17
 
 
 
 
18
  AVAILABLE_VOICES = ["پیش‌فرض (مدل انتخاب کند)"]
19
  # اگر نام‌های واقعی را پیدا کردید، اینجا اضافه کنید:
20
  # AVAILABLE_VOICES.extend(["voice-name-1", "voice-name-2"])
 
28
  try:
29
  model = genai.GenerativeModel(f"models/{TTS_MODEL_NAME}")
30
 
 
31
  generation_config_params = {
32
+ "response_modalities": ["AUDIO"]
33
  }
34
 
35
+ # برای انتخاب گوینده، این بخش نیاز به اطلاعات از مستندات دارد
 
36
  if selected_voice_name != "پیش‌فرض (مدل انتخاب کند)":
37
+ # مثال: generation_config_params["voice"] = selected_voice_name
38
+ # یا اگر ساختار speech_config لازم است:
 
 
 
39
  # generation_config_params["speech_config"] = types.SpeechConfig(
40
  # voice_config=types.VoiceConfig(
41
  # prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name=selected_voice_name)
42
  # )
43
  # )
44
+ print(f"توجه: انتخاب گوینده ('{selected_voice_name}') هنوز به طور کامل پیاده‌سازی نشده است. از تنظیمات پیش‌فرض مدل برای گوینده استفاده می‌شود.")
 
45
 
46
  generation_config = genai.types.GenerationConfig(**generation_config_params)
47
 
 
51
  text_to_speak,
52
  generation_config=generation_config
53
  )
 
 
54
 
55
  audio_bytes = None
56
  generated_mime_type = None
57
+ sample_rate = 24000 # پیش‌فرض، از مستندات چک شود
58
 
59
  if hasattr(response, 'candidates') and response.candidates and \
60
  response.candidates[0].content and response.candidates[0].content.parts:
61
  for part in response.candidates[0].content.parts:
62
  if hasattr(part, 'inline_data') and part.inline_data and \
63
+ hasattr(part.inline_data, 'mime_type') and part.inline_data.mime_type.startswith("audio/"):
64
  audio_bytes = part.inline_data.data
65
  generated_mime_type = part.inline_data.mime_type
 
66
  if ";rate=" in generated_mime_type:
67
  try:
68
  sample_rate = int(generated_mime_type.split(";rate=")[1])
 
72
  print(f"داده صوتی با MIME type: {generated_mime_type} دریافت شد.")
73
  break
74
 
75
+ if audio_bytes is None:
76
  if hasattr(response, 'audio_content'):
77
  audio_bytes = response.audio_content
78
+ generated_mime_type = "audio/wav"
79
  print("داده ��وتی از فیلد audio_content دریافت شد.")
80
  else:
81
  print("پاسخ کامل مدل (برای دیباگ):", response)
 
83
  raise gr.Error(f"پاسخ صوتی از مدل دریافت نشد. پاسخ مدل: {error_text}")
84
 
85
  output_filename = "output.wav"
 
 
86
  if "pcm" in (generated_mime_type or "").lower():
87
  print(f"داده PCM خام ({len(audio_bytes)} بایت) با نرخ نمونه‌برداری {sample_rate} Hz دریافت شد، در حال تبدیل به WAV...")
88
+ audio_np = np.frombuffer(audio_bytes, dtype=np.int16)
89
  wav_io = io.BytesIO()
90
  write_wav(wav_io, sample_rate, audio_np)
91
  wav_io.seek(0)
92
  with open(output_filename, "wb") as f:
93
  f.write(wav_io.read())
94
+ elif audio_bytes:
95
  print(f"داده صوتی با فرمت {generated_mime_type} ({len(audio_bytes)} بایت) دریافت شد، مستقیم ذخیره می‌شود.")
96
  with open(output_filename, "wb") as f:
97
  f.write(audio_bytes)
98
  else:
99
  raise gr.Error("هیچ داده صوتی برای ذخیره وجود ندارد.")
100
 
 
101
  print(f"فایل صوتی در {output_filename} ذخیره شد.")
102
  return output_filename
103
 
104
+ except genai.types.BlockedPromptException as bpe:
105
+ print(f"درخواست توسط مدل بلاک شد: {bpe}")
106
+ raise gr.Error(f"محتوای شما توسط مدل پذیرفته نشد. لطفاً متن دیگری را امتحان کنید. دلیل: {bpe}")
107
+ except Exception as e: # این بلوک except باید دارای بدنه با تورفتگی باشد
108
+ print(f"خطای کلی در تولید صدا: {e}")
109
+ traceback.print_exc() # چاپ کامل traceback برای دیباگ
110
+ error_message_from_api = ""
111
+ # تلاش برای استخراج پیام خطای دقیق‌تر از آبجکت خطای google-generativeai
112
+ if hasattr(e, 'args') and e.args:
113
+ # خطاهای API گوگل معمولاً جزئیات را در e.args[0] یا یک ساختار پیچیده‌تر دارند
114
+ # برای خطای 400 که قبلاً دیدیم، پیام در e.args[0] بود.
115
+ if isinstance(e.args[0], str) and "HttpError" in e.args[0]:
116
+ try:
117
+ # پیام خطا ممکن است شامل یک رشته JSON باشد
118
+ msg_str = str(e.args[0])
119
+ # استخراج بخش JSON مانند قبل
120
+ details_start = msg_str.find('{')
121
+ if details_start != -1:
122
+ error_details_json = msg_str[details_start:]
123
+ # حذف کاراکترهای کنترلی احتمالی و تلاش برای parse
124
+ cleaned_json_str = ''.join(c for c in error_details_json if ord(c) >= 32 or c in ('\t', '\n', '\r'))
125
+ error_obj = json.loads(cleaned_json_str)
126
+ if 'error' in error_obj and 'message' in error_obj['error']:
127
+ error_message_from_api = error_obj['error']['message']
128
+ elif 'message' in error_obj: # گاهی اوقات پیام مستقیم در آبجکت خطا است
129
+ error_message_from_api = error_obj['message']
130
+ except Exception as json_e:
131
+ print(f"خطا در parse کردن جزئیات خطای API: {json_e}")
132
+ error_message_from_api = str(e.args[0]) # اگر parse نشد، خود پیام اصلی را بگیر
133
+ else:
134
+ error_message_from_api = str(e.args[0])
135
+
136
+ final_error_message = f"خطا در ارتباط با Gemini API یا پردازش صدا: {str(e)}"
137
+ if error_message_from_api and error_message_from_api not in final_error_message:
138
+ final_error_message += f" | پیام دقیق‌تر API: {error_message_from_api}"
139
+ elif not error_message_from_api and hasattr(e, 'message') and isinstance(e.message, str): # fallback
140
+ final_error_message += f" | {e.message}"
141
+
142
+
143
+ raise gr.Error(final_error_message)
144
 
145
 
 
146
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
147
  gr.Markdown("# تبدیل متن به صدا ب�� Gemini ♊")
148
  gr.Markdown("متن خود را وارد کنید تا با استفاده از مدل‌های جدید Gemini به صدا تبدیل شود.")
 
150
  with gr.Row():
151
  with gr.Column(scale=2):
152
  text_input = gr.Textbox(lines=5, label="متن ورودی", placeholder="متن خود را اینجا بنویسید...")
153
+ # voice_dropdown = gr.Dropdown(choices=AVAILABLE_VOICES, value=AVAILABLE_VOICES[0], label="انتخاب گوینده") # در آینده فعال شود
154
  submit_button = gr.Button("🔊 تبدیل به صدا", variant="primary")
155
  with gr.Column(scale=1):
156
  audio_output = gr.Audio(label="خروجی صدا", type="filepath")
157
 
158
+ gr.Examples(
159
+ examples=[
160
+ ["سلام، حال شما چطور است؟"],
161
+ ["به دنیای هوش مصنوعی خوش آمدید."],
162
+ ["این یک تست برای تبدیل متن به صدا با استفاده از جیمینای است."]
163
+ ],
164
+ inputs=[text_input]
165
+ )
166
 
167
  submit_button.click(
168
  fn=generate_audio,
 
176
  gr.Markdown(f"مدل مورد استفاده: `models/{TTS_MODEL_NAME}`")
177
  gr.Markdown("توجه: برای انتخاب گوینده‌های مختلف، نیاز به بررسی مستندات دقیق مدل TTS و بروزرسانی کد است.")
178
 
 
179
  if __name__ == "__main__":
180
+ demo.launch(debug=True) # debug=True برای دیدن لاگ‌های دقیق‌تر در کنسول هاگینگ فیس