suprimedev commited on
Commit
ba6b9e4
·
verified ·
1 Parent(s): 7271ac7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -52
app.py CHANGED
@@ -2,8 +2,8 @@ import gradio as gr
2
  from pydub import AudioSegment
3
  import requests
4
  import os
5
- import uuid # برای تولید نام فایل منحصر به فرد
6
- import re # برای تجزیه متن
7
 
8
  # مسیر ذخیره فایل‌های موقت
9
  TEMP_DIR = "temp_audio"
@@ -14,7 +14,7 @@ def download_file(url, output_path):
14
  """فایل را از یک URL دانلود می‌کند."""
15
  try:
16
  response = requests.get(url, stream=True)
17
- response.raise_for_status() # خطایی رخ داد، آن را بالا ببر
18
  with open(output_path, 'wb') as f:
19
  for chunk in response.iter_content(chunk_size=8192):
20
  f.write(chunk)
@@ -27,24 +27,18 @@ def download_file(url, output_path):
27
  return False
28
 
29
  def get_audio_from_input(input_source):
30
- """
31
- منبع ورودی را پردازش کرده و یک شی AudioSegment برمی‌گرداند.
32
- می‌تواند یک فایل محلی یا یک URL باشد.
33
- """
34
  unique_filename = os.path.join(TEMP_DIR, str(uuid.uuid4()))
35
 
36
  if input_source.startswith("http://") or input_source.startswith("https://"):
37
- # این یک URL است، دانلودش کن
38
- # سعی می کنیم پسوند فایل را از URL تشخیص دهیم، در غیر این صورت از .mp3 استفاده می کنیم.
39
  file_extension = os.path.splitext(input_source.split('?')[0])[1]
40
- if not file_extension: # اگر پسوندی در URL نباشد (مثلا برای APIها)
41
- file_extension = ".mp3"
42
  temp_filepath = unique_filename + "_downloaded" + file_extension
43
  if not download_file(input_source, temp_filepath):
44
  return None, f"خطا در دانلود فایل از لینک: {input_source}"
45
  audio_path = temp_filepath
46
  else:
47
- # فرض می‌شود یک مسیر فایل محلی است
48
  audio_path = input_source
49
 
50
  try:
@@ -53,21 +47,14 @@ def get_audio_from_input(input_source):
53
  except Exception as e:
54
  return None, f"خطا در بارگذاری فایل صوتی ({audio_path}): {e}. مطمئن شوید فایل MP3 یا WAV معتبر است."
55
  finally:
56
- # اگر فایل از URL دانلود شده بود، آن را پاک کن
57
  if 'temp_filepath' in locals() and os.path.exists(temp_filepath):
58
- # اگر فایل بعداً توسط pydub پردازش و لود شده باشد، می‌توانیم آن را حذف کنیم.
59
- # در غیر این صورت، ممکن است در حال استفاده باشد.
60
  try:
61
  os.remove(temp_filepath)
62
  except OSError as e:
63
  print(f"Error removing temporary file {temp_filepath}: {e}")
64
 
65
-
66
  def merge_audio_files(input_sources):
67
- """
68
- چندین فایل صوتی را (از لینک یا فایل) ادغام می‌کند و یک فایل MP3 خروجی می‌دهد.
69
- input_sources: یک لیست از URLها یا مسیرهای فایل‌ها.
70
- """
71
  if not input_sources:
72
  return None, "لیست ورودی‌های صوتی خالی است."
73
 
@@ -80,7 +67,7 @@ def merge_audio_files(input_sources):
80
  combined_audio += audio_segment
81
  else:
82
  errors.append(error)
83
- print(f"Skipping {source} due to error: {error}") # برای debugging کنسول
84
 
85
  if not combined_audio.duration_seconds > 0:
86
  return None, "هیچ فایل صوتی معتبری برای ادغام پیدا نشد. " + "\n".join(errors) if errors else ""
@@ -92,15 +79,48 @@ def merge_audio_files(input_sources):
92
  except Exception as e:
93
  return None, f"خطا در ذخیره فایل خروجی: {e}"
94
 
95
- def tts_and_merge(text_input):
96
- """
97
- متن ورودی را تجزیه می‌کند، با Talkbot API صدا تولید می‌کند و سپس آن‌ها را ادغام می‌کند.
98
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  if not text_input.strip():
100
  return None, "لطفاً متنی برای پردازش وارد کنید."
101
 
102
- # الگو برای تشخیص شماره و متن پرانتزی: (شماره)متن
103
- # این الگو همچنین newline را برای پردازش خط به خط در نظر می‌گیرد.
104
  lines = text_input.strip().split('\n')
105
 
106
  audio_urls_to_merge = []
@@ -117,22 +137,16 @@ def tts_and_merge(text_input):
117
  continue
118
 
119
  # ساخت URL برای Talkbot API
120
- # متن باید URL-encoded شود، اما requests.get این کار را به طور خودکار برای پارامترها انجام می‌دهد.
121
  tts_url = f"https://talkbot.ir/api/TTS-S{speaker_number}?text={text_for_tts}"
122
 
123
- print(f"درخواست TTS برای گوینده {speaker_number}: {tts_url}") # برای debugging
124
 
125
  try:
126
- # درخواست به Talkbot API
127
  response = requests.get(tts_url)
128
- response.raise_for_status() # برای خطاهای HTTP
 
129
 
130
- # فرض بر این است که پاسخ مستقیم لینک MP3 است
131
- # اگر API لینک را در JSON برمی‌گرداند، باید آن را parse کنید.
132
- # در مثال شما، فرض می‌شود پاسخ مستقیم لینک MP3 است.
133
- audio_link = response.text.strip()
134
-
135
- if audio_link.startswith("http"): # مطمئن شوید لینک معتبر است
136
  audio_urls_to_merge.append(audio_link)
137
  else:
138
  errors.append(f"API برای گوینده {speaker_number} لینک معتبری برنگرداند: '{audio_link}'")
@@ -142,22 +156,37 @@ def tts_and_merge(text_input):
142
  except Exception as e:
143
  errors.append(f"خطای غیرمنتظره در پردازش Talkbot API برای گوینده {speaker_number}: {e}")
144
  else:
145
- if line.strip(): # اگر خط خالی نباشد، اما مطابق الگو نباشد
146
  errors.append(f"فرمت نامعتبر در خط: '{line}'. انتظار می‌رود (شماره)متن.")
147
 
148
-
149
  if not audio_urls_to_merge:
150
  return None, "هیچ فایل صوتی برای ادغام تولید نشد." + "\n".join(errors) if errors else ""
151
 
152
- # حالا لینک‌های تولید شده را به تابع merge_audio_files اصلی می‌فرستیم
153
- merged_output_path, merge_message = merge_audio_files(audio_urls_to_merge)
 
 
154
 
155
- final_message = merge_message
156
- if errors:
157
- final_message += "\n\nخطاهای رخ داده:\n" + "\n".join(errors)
158
 
159
- return merged_output_path, final_message
 
 
 
 
 
 
 
 
160
 
 
 
 
 
 
 
 
161
 
162
  # ایجاد رابط کاربری Gradio
163
  with gr.Blocks() as demo:
@@ -184,7 +213,7 @@ with gr.Blocks() as demo:
184
  merge_button = gr.Button("ادغام فایل‌های صوتی")
185
 
186
  merge_button.click(
187
- fn=lambda x: merge_audio_files([s.strip() for s in x.split('\n') if s.strip()]), # تبدیل ورودی رشته‌ای به لیست برای تابع
188
  inputs=[audio_links_input],
189
  outputs=[audio_merge_output_audio, audio_merge_output_message]
190
  )
@@ -192,8 +221,6 @@ with gr.Blocks() as demo:
192
  gr.Examples(
193
  examples=[
194
  ["https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3\nhttps://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3"],
195
- # اگر فایل‌های واقعی داشته باشید، می‌توانید این خط را فعال کنید:
196
- # ["./path/to/your/local_audio.mp3\n./path/to/another/local_audio.wav"]
197
  ],
198
  inputs=audio_links_input,
199
  label="نمونه‌ها"
@@ -211,7 +238,7 @@ with gr.Blocks() as demo:
211
  tts_merge_button = gr.Button("تولید و ادغام صدا")
212
 
213
  tts_merge_button.click(
214
- fn=tts_and_merge,
215
  inputs=[tts_text_input],
216
  outputs=[tts_output_audio, tts_output_message]
217
  )
@@ -225,7 +252,6 @@ with gr.Blocks() as demo:
225
  label="نمونه‌ها"
226
  )
227
 
228
-
229
  if __name__ == "__main__":
230
- demo.launch() # برای اجرا در لوکال
231
- # demo.launch(share=True) # برای اشتراک‌گذاری موقت در یک لینک عمومی (برای هوش مصنوعی)
 
2
  from pydub import AudioSegment
3
  import requests
4
  import os
5
+ import uuid
6
+ import re
7
 
8
  # مسیر ذخیره فایل‌های موقت
9
  TEMP_DIR = "temp_audio"
 
14
  """فایل را از یک URL دانلود می‌کند."""
15
  try:
16
  response = requests.get(url, stream=True)
17
+ response.raise_for_status()
18
  with open(output_path, 'wb') as f:
19
  for chunk in response.iter_content(chunk_size=8192):
20
  f.write(chunk)
 
27
  return False
28
 
29
  def get_audio_from_input(input_source):
30
+ """منبع ورودی را پردازش کرده و یک شی AudioSegment برمی‌گرداند."""
 
 
 
31
  unique_filename = os.path.join(TEMP_DIR, str(uuid.uuid4()))
32
 
33
  if input_source.startswith("http://") or input_source.startswith("https://"):
 
 
34
  file_extension = os.path.splitext(input_source.split('?')[0])[1]
35
+ if not file_extension:
36
+ file_extension = ".mp3"
37
  temp_filepath = unique_filename + "_downloaded" + file_extension
38
  if not download_file(input_source, temp_filepath):
39
  return None, f"خطا در دانلود فایل از لینک: {input_source}"
40
  audio_path = temp_filepath
41
  else:
 
42
  audio_path = input_source
43
 
44
  try:
 
47
  except Exception as e:
48
  return None, f"خطا در بارگذاری فایل صوتی ({audio_path}): {e}. مطمئن شوید فایل MP3 یا WAV معتبر است."
49
  finally:
 
50
  if 'temp_filepath' in locals() and os.path.exists(temp_filepath):
 
 
51
  try:
52
  os.remove(temp_filepath)
53
  except OSError as e:
54
  print(f"Error removing temporary file {temp_filepath}: {e}")
55
 
 
56
  def merge_audio_files(input_sources):
57
+ """چندین فایل صوتی را ادغام می‌کند و یک فایل MP3 خروجی می‌دهد."""
 
 
 
58
  if not input_sources:
59
  return None, "لیست ورودی‌های صوتی خالی است."
60
 
 
67
  combined_audio += audio_segment
68
  else:
69
  errors.append(error)
70
+ print(f"Skipping {source} due to error: {error}")
71
 
72
  if not combined_audio.duration_seconds > 0:
73
  return None, "هیچ فایل صوتی معتبری برای ادغام پیدا نشد. " + "\n".join(errors) if errors else ""
 
79
  except Exception as e:
80
  return None, f"خطا در ذخیره فایل خروجی: {e}"
81
 
82
+ def add_intro_outro_and_background(podcast_audio, intro_audio_url, background_audio_url, outro_audio_url):
83
+ """افکت‌های صوتی را به پادکست اضافه می‌کند."""
84
+ # دانلود صدای ابتدایی (intro)
85
+ intro_audio, _ = get_audio_from_input(intro_audio_url)
86
+ if not intro_audio:
87
+ return None, "خطا در دانلود یا بارگذاری صدای ابتدایی"
88
+
89
+ # دانلود موزیک پس‌زمینه
90
+ background_audio, _ = get_audio_from_input(background_audio_url)
91
+ if not background_audio:
92
+ return None, "خطا در دانلود یا بارگذاری موزیک پس‌زمینه"
93
+
94
+ # دانلود صدای انتهایی (outro)
95
+ outro_audio, _ = get_audio_from_input(outro_audio_url)
96
+ if not outro_audio:
97
+ return None, "خطا در دانلود یا بارگذاری صدای انتهایی"
98
+
99
+ # طول پادکست اصلی
100
+ podcast_duration = len(podcast_audio)
101
+
102
+ # اضافه کردن صدای ابتدایی
103
+ final_audio = intro_audio
104
+
105
+ # اضافه کردن موزیک پس‌زمینه
106
+ background_audio = background_audio[:podcast_duration + 2000] # موزیک به اندازه پادکست + 2 ثانیه
107
+ background_audio = background_audio.fade_in(2000).fade_out(2000) # fade-in و fade-out
108
+ final_audio = final_audio.overlay(background_audio, position=0) # موزیک پس‌زمینه از ابتدا شروع می‌شود
109
+
110
+ # اضافه کردن پادکست اصلی
111
+ final_audio = final_audio + podcast_audio
112
+
113
+ # اضافه کردن صدای انتهایی
114
+ final_audio = final_audio + outro_audio
115
+
116
+ return final_audio, None
117
+
118
+ def tts_and_merge_with_effects(text_input):
119
+ """متن ورودی را پردازش کرده و فایل صوتی با افکت‌های صوتی تولید می‌کند."""
120
  if not text_input.strip():
121
  return None, "لطفاً متنی برای پردازش وارد کنید."
122
 
123
+ # تجزیه متن و تولید پادکست اصلی
 
124
  lines = text_input.strip().split('\n')
125
 
126
  audio_urls_to_merge = []
 
137
  continue
138
 
139
  # ساخت URL برای Talkbot API
 
140
  tts_url = f"https://talkbot.ir/api/TTS-S{speaker_number}?text={text_for_tts}"
141
 
142
+ print(f"درخواست TTS برای گوینده {speaker_number}: {tts_url}")
143
 
144
  try:
 
145
  response = requests.get(tts_url)
146
+ response.raise_for_status()
147
+ audio_link = response.text.strip()
148
 
149
+ if audio_link.startswith("http"):
 
 
 
 
 
150
  audio_urls_to_merge.append(audio_link)
151
  else:
152
  errors.append(f"API برای گوینده {speaker_number} لینک معتبری برنگرداند: '{audio_link}'")
 
156
  except Exception as e:
157
  errors.append(f"خطای غیرمنتظره در پردازش Talkbot API برای گوینده {speaker_number}: {e}")
158
  else:
159
+ if line.strip():
160
  errors.append(f"فرمت نامعتبر در خط: '{line}'. انتظار می‌رود (شماره)متن.")
161
 
 
162
  if not audio_urls_to_merge:
163
  return None, "هیچ فایل صوتی برای ادغام تولید نشد." + "\n".join(errors) if errors else ""
164
 
165
+ # ادغام فایل‌های صوتی تولید شده
166
+ podcast_audio_path, merge_message = merge_audio_files(audio_urls_to_merge)
167
+ if not podcast_audio_path:
168
+ return None, merge_message
169
 
170
+ # بارگذاری پادکست اصلی
171
+ podcast_audio = AudioSegment.from_file(podcast_audio_path)
 
172
 
173
+ # افزودن افکت‌های صوتی
174
+ final_audio, error = add_intro_outro_and_background(
175
+ podcast_audio,
176
+ intro_audio_url="https://talkbot.ir/example/effect-podcast/wk.mp3",
177
+ background_audio_url="https://example.com/path/to/background_music.mp3", # مسیر موزیک پس‌زمینه
178
+ outro_audio_url="https://talkbot.ir/example/effect-podcast/outro.mp3" # مسیر صدای انتهایی
179
+ )
180
+ if not final_audio:
181
+ return None, error
182
 
183
+ # ذخیره فایل نهایی
184
+ output_filename = os.path.join(TEMP_DIR, f"final_podcast_{uuid.uuid4()}.mp3")
185
+ try:
186
+ final_audio.export(output_filename, format="mp3")
187
+ return output_filename, "پادکست با افکت‌های صوتی با موفقیت تولید شد!"
188
+ except Exception as e:
189
+ return None, f"خطا در ذخیره پادکست نهایی: {e}"
190
 
191
  # ایجاد رابط کاربری Gradio
192
  with gr.Blocks() as demo:
 
213
  merge_button = gr.Button("ادغام فایل‌های صوتی")
214
 
215
  merge_button.click(
216
+ fn=lambda x: merge_audio_files([s.strip() for s in x.split('\n') if s.strip()]),
217
  inputs=[audio_links_input],
218
  outputs=[audio_merge_output_audio, audio_merge_output_message]
219
  )
 
221
  gr.Examples(
222
  examples=[
223
  ["https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3\nhttps://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3"],
 
 
224
  ],
225
  inputs=audio_links_input,
226
  label="نمونه‌ها"
 
238
  tts_merge_button = gr.Button("تولید و ادغام صدا")
239
 
240
  tts_merge_button.click(
241
+ fn=tts_and_merge_with_effects,
242
  inputs=[tts_text_input],
243
  outputs=[tts_output_audio, tts_output_message]
244
  )
 
252
  label="نمونه‌ها"
253
  )
254
 
 
255
  if __name__ == "__main__":
256
+ demo.launch() # برای اجرا در لوکال
257
+ # demo.launch(share=True) # برای اشتراک‌گذاری موقت در یک لینک عمومی