suprimedev commited on
Commit
75a040f
·
verified ·
1 Parent(s): 45dd52a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -66
app.py CHANGED
@@ -5,40 +5,38 @@ import os
5
  import shutil
6
  import speech_recognition as sr
7
  from pydub import AudioSegment
8
- from pydub.silence import split_on_silence
9
- import io
10
  import warnings
11
- warnings.filterwarnings("ignore") # نادیده گرفتن هشدارهای غیرضروری
12
 
13
  def convert_to_mp3_and_transcribe(video_url):
14
  """
15
  دانلود ویدیو/صوت از لینک، تبدیل به MP3، و استخراج متن با Google Speech Recognition (رایگان).
16
- نوار پیشرفت برای مراحل مختلف.
17
  """
18
  if not video_url:
19
  return None, None, "لینک ویدیو را وارد کنید."
20
 
21
- progress = gr.Progress(track_tqdm=False) # نوار پیشرفت Gradio
22
 
23
  try:
24
  progress(0, desc="شروع دانلود...")
25
 
26
- # تنظیمات yt-dlp برای دانلود صوت و تبدیل مستقیم به MP3
27
  ydl_opts = {
28
- 'format': 'bestaudio/best', # بهترین کیفیت صوت
29
  'postprocessors': [{
30
- 'key': 'FFmpegExtractAudio', # استخراج صوت با FFmpeg
31
  'preferredcodec': 'mp3',
32
- 'preferredquality': '192', # کیفیت 192kbps
33
  }],
34
- 'outtmpl': 'temp.%(ext)s', # نام فایل موقت
35
  'quiet': True,
36
  }
37
 
38
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
39
  ydl.download([video_url])
40
 
41
- # پیدا کردن فایل MP3
42
  mp3_file = None
43
  for file in os.listdir('.'):
44
  if file.startswith('temp.') and file.endswith('.mp3'):
@@ -48,80 +46,93 @@ def convert_to_mp3_and_transcribe(video_url):
48
  if not mp3_file:
49
  return None, None, "خطا در دانلود یا تبدیل."
50
 
51
- progress(0.3, desc="دانلود کامل شد. کپی به فایل موقت...")
52
 
53
- # کپی به فایل موقت برای امنیت
54
  temp_mp3 = tempfile.NamedTemporaryFile(suffix='.mp3', delete=False)
55
  temp_mp3.close()
56
  shutil.copy2(mp3_file, temp_mp3.name)
57
- os.remove(mp3_file) # تمیز کردن
 
58
 
59
- progress(0.5, desc="تبدیل به MP3 کامل شد. شروع استخراج متن...")
60
 
61
- # استخراج متن با Google Speech Recognition
62
- text = transcribe_audio(temp_mp3.name)
63
 
64
  if text is None:
65
- return temp_mp3.name, None, "MP3 آماده است، اما استخراج متن با خطا مواجه شد (محدودیت گوگل یا فایل طولانی)."
66
 
67
  progress(1.0, desc="استخراج متن کامل شد!")
68
 
69
- return temp_mp3.name, text, "همه چیز با موفقیت انجام شد. متن استخراج شد."
70
 
71
  except Exception as e:
72
- progress(0, desc="خطا رخ داد.")
73
  return None, None, f"خطا: {str(e)}"
74
 
75
- def transcribe_audio(mp3_path, chunk_length_ms=60000, silence_threshold=-40):
76
  """
77
- استخراج متن از فایل MP3 با Google Speech Recognition (رایگان).
78
- برای فایل‌های طولانی، به chunkهای کوچک تقسیم می‌شود.
79
  """
80
  recognizer = sr.Recognizer()
81
- full_text = []
 
 
82
 
83
- # بارگذاری فایل صوتی با pydub
 
84
  audio = AudioSegment.from_mp3(mp3_path)
 
 
85
 
86
- # تقسیم به chunkهای ساکت (برای فایل‌های طولانی)
87
- chunks = split_on_silence(
88
- audio,
89
- min_silence_len=1000, # حداقل طول سکوت
90
- silence_thresh=silence_threshold, # آستانه سکوت
91
- keep_silence=500, # حفظ کمی سکوت
92
- )
93
-
94
- if not chunks:
95
- # اگر تقسیم نشد، کل فایل را امتحان کن (محدودیت گوگل ~60 ثانیه)
96
- if len(audio) > 60000: # بیش از 60 ثانیه
97
- return None # فایل خیلی طولانی برای STT رایگان
98
- chunk = audio
99
- chunks = [chunk]
100
 
101
- for i, chunk in enumerate(chunks):
102
- # تبدیل chunk به فرمت WAV در حافظه
103
- chunk_export = io.BytesIO()
104
- chunk.export(chunk_export, format="wav")
105
- chunk_export.seek(0)
106
 
107
- with sr.AudioFile(chunk_export) as source:
108
- # تنظیم برای نویز
109
- recognizer.adjust_for_ambient_noise(source, duration=0.5)
110
- audio_data = recognizer.record(source)
111
 
112
  try:
113
- # استفاده از Google Speech Recognition (رایگان، بدون API key)
114
- text = recognizer.recognize_google(audio_data, language='fa-IR') # برای پارسی، یا 'en-US' برای انگلیسی
115
- full_text.append(text)
116
- except sr.UnknownValueError:
117
- full_text.append("[نامشخص]")
118
- except sr.RequestError as e:
119
- full_text.append(f"[خطا در شناسایی: {e}]")
120
- return None # اگر خطای اتصال یا محدودیت، متوقف شو
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- return ' '.join(full_text)
123
 
124
- # رابط Gradio (با API فعال برای فراخوانی از PHP)
125
  iface = gr.Interface(
126
  fn=convert_to_mp3_and_transcribe,
127
  inputs=gr.Textbox(
@@ -133,16 +144,14 @@ iface = gr.Interface(
133
  gr.Textbox(label="متن استخراج‌شده", lines=10),
134
  gr.Textbox(label="پیام وضعیت")
135
  ],
136
- title="تبدیل ویدیو به MP3 و استخراج متن (STT با گوگل)",
137
- description="لینک ویدیو را وارد کنید تا صوت به MP3 تبدیل شود و متن آن استخراج گردد. از Google Speech Recognition رایگان استفاده می‌شود.",
138
  examples=[
139
- ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"]
140
  ],
141
- allow_flagging="never", # برای API تمیزتر
142
- cache_examples=False # غیرفعال برای API
143
  )
144
 
145
- # راه‌اندازی با API (برای فراخوانی از PHP با HTTP requests)
146
  if __name__ == "__main__":
147
- # در Hugging Face Spaces، launch() کافی است. API روی /api endpoint در دسترس است.
148
- iface.launch(server_name="0.0.0.0", server_port=7860, share=False) # share=True برای تست عمومی
 
5
  import shutil
6
  import speech_recognition as sr
7
  from pydub import AudioSegment
 
 
8
  import warnings
9
+ warnings.filterwarnings("ignore")
10
 
11
  def convert_to_mp3_and_transcribe(video_url):
12
  """
13
  دانلود ویدیو/صوت از لینک، تبدیل به MP3، و استخراج متن با Google Speech Recognition (رایگان).
14
+ فایل را به chunkهای زمانی کوچک (هر 30 ثانیه) تقسیم می‌کند برای جلوگیری از محدودیت گوگل.
15
  """
16
  if not video_url:
17
  return None, None, "لینک ویدیو را وارد کنید."
18
 
19
+ progress = gr.Progress(track_tqdm=False)
20
 
21
  try:
22
  progress(0, desc="شروع دانلود...")
23
 
24
+ # دانلود و تبدیل به MP3
25
  ydl_opts = {
26
+ 'format': 'bestaudio/best',
27
  'postprocessors': [{
28
+ 'key': 'FFmpegExtractAudio',
29
  'preferredcodec': 'mp3',
30
+ 'preferredquality': '192',
31
  }],
32
+ 'outtmpl': 'temp.%(ext)s',
33
  'quiet': True,
34
  }
35
 
36
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
37
  ydl.download([video_url])
38
 
39
+ # پیدا کردن MP3
40
  mp3_file = None
41
  for file in os.listdir('.'):
42
  if file.startswith('temp.') and file.endswith('.mp3'):
 
46
  if not mp3_file:
47
  return None, None, "خطا در دانلود یا تبدیل."
48
 
49
+ progress(0.3, desc="دانلود کامل. کپی MP3...")
50
 
51
+ # کپی به موقت
52
  temp_mp3 = tempfile.NamedTemporaryFile(suffix='.mp3', delete=False)
53
  temp_mp3.close()
54
  shutil.copy2(mp3_file, temp_mp3.name)
55
+ if os.path.exists(mp3_file):
56
+ os.remove(mp3_file)
57
 
58
+ progress(0.5, desc="MP3 آماده. شروع استخراج متن...")
59
 
60
+ # استخراج متن
61
+ text = transcribe_audio(temp_mp3.name, progress)
62
 
63
  if text is None:
64
+ return temp_mp3.name, None, "MP3 آماده است، اما استخراج متن با خطا مواجه شد."
65
 
66
  progress(1.0, desc="استخراج متن کامل شد!")
67
 
68
+ return temp_mp3.name, text, "همه چیز با موفقیت انجام شد."
69
 
70
  except Exception as e:
 
71
  return None, None, f"خطا: {str(e)}"
72
 
73
+ def transcribe_audio(mp3_path, progress, chunk_length_ms=30000, overlap_ms=5000):
74
  """
75
+ استخراج متن از MP3 با تقسیم به chunkهای زمانی ثابت (30 ثانیه با هم‌پوشانی 5 ثانیه).
76
+ هر chunk به فایل WAV موقت تبدیل و ارسال به Google STT می‌شود.
77
  """
78
  recognizer = sr.Recognizer()
79
+ recognizer.energy_threshold = 300 # تنظیم حساسیت به صدا
80
+ recognizer.dynamic_energy_threshold = True
81
+ recognizer.pause_threshold = 0.8
82
 
83
+ full_text = []
84
+ temp_wav_dir = tempfile.mkdtemp() # دایرکتوری موقت برای WAVها
85
  audio = AudioSegment.from_mp3(mp3_path)
86
+ duration_ms = len(audio)
87
+ num_chunks = (duration_ms // chunk_length_ms) + 1 if duration_ms % chunk_length_ms != 0 else (duration_ms // chunk_length_ms)
88
 
89
+ progress(0.5, desc=f"فایل {duration_ms/1000:.1f} ثانیه. تقسیم به {num_chunks} chunk...")
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ # تقسیم به chunkهای زمانی با هم‌پوشانی
92
+ for i in range(0, duration_ms, chunk_length_ms - overlap_ms):
93
+ chunk = audio[i:i + chunk_length_ms]
 
 
94
 
95
+ # ذخیره chunk به فایل WAV موقت
96
+ temp_wav = os.path.join(temp_wav_dir, f"chunk_{i}.wav")
97
+ chunk.export(temp_wav, format="wav")
 
98
 
99
  try:
100
+ chunk_progress = (i + chunk_length_ms) / duration_ms * 0.5 # 0.5 برای STT
101
+ progress(0.5 + chunk_progress, desc=f"پردازش chunk {i//1000 + 1}/{num_chunks}...")
102
+
103
+ with sr.AudioFile(temp_wav) as source:
104
+ recognizer.adjust_for_ambient_noise(source, duration=0.5)
105
+ audio_data = recognizer.record(source)
106
+ try:
107
+ # Google STT (رایگان)
108
+ text = recognizer.recognize_google(audio_data, language='fa-IR')
109
+ if text.strip(): # اگر متن خالی نبود
110
+ full_text.append(text)
111
+ else:
112
+ full_text.append("[سکوت یا نامشخص]")
113
+ except sr.UnknownValueError:
114
+ full_text.append("[نامشخص]")
115
+ except sr.RequestError as e:
116
+ full_text.append(f"[خطا: {e}]")
117
+ # ادامه دهیم، نه متوقف
118
+ except Exception as chunk_e:
119
+ full_text.append(f"[خطا در chunk: {chunk_e}]")
120
+ continue
121
+
122
+ # تمیز کردن فایل WAV
123
+ if os.path.exists(temp_wav):
124
+ os.remove(temp_wav)
125
+
126
+ # تمیز کردن دایرکتوری
127
+ shutil.rmtree(temp_wav_dir, ignore_errors=True)
128
+
129
+ final_text = ' '.join(full_text).strip()
130
+ if not final_text or "[خطا" in final_text or "[نامشخص" in final_text and len(full_text) == 1:
131
+ return None # اگر همه chunkها شکست خوردند
132
 
133
+ return final_text
134
 
135
+ # رابط Gradio
136
  iface = gr.Interface(
137
  fn=convert_to_mp3_and_transcribe,
138
  inputs=gr.Textbox(
 
144
  gr.Textbox(label="متن استخراج‌شده", lines=10),
145
  gr.Textbox(label="پیام وضعیت")
146
  ],
147
+ title="تبدیل ویدیو به MP3 و استخراج متن (STT با گوگل - chunked)",
148
+ description="لینک ویدیو را وارد کنید. فایل به chunkهای 30 ثانیه‌ای تقسیم و تکه‌تکه به Google STT ارسال می‌شود تا محدودیت‌ها دور زده شود.",
149
  examples=[
150
+ ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"] # مثال کوتاه برای تست
151
  ],
152
+ allow_flagging="never",
153
+ cache_examples=False
154
  )
155
 
 
156
  if __name__ == "__main__":
157
+ iface.launch(server_name="0.0.0.0", server_port=7860, share=False)