Spaces:
Running
Running
File size: 8,117 Bytes
26f7136 4881f89 a3263de 5667739 d55f4c2 4881f89 6556fb7 ae68454 26f7136 6556fb7 60093c0 ae68454 d55f4c2 2e3b5a7 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 ae68454 4881f89 26f7136 6556fb7 4881f89 ae68454 26f7136 4881f89 26f7136 4881f89 26f7136 ae68454 4881f89 26f7136 4881f89 ae68454 26f7136 4881f89 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 4881f89 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 4881f89 ae68454 4806ae4 ae68454 26f7136 4806ae4 ae68454 4806ae4 ae68454 26f7136 4806ae4 60093c0 4806ae4 26f7136 ae68454 26f7136 4806ae4 26f7136 ae68454 4806ae4 26f7136 4806ae4 ae68454 26f7136 60093c0 ae68454 26f7136 4881f89 26f7136 4806ae4 26f7136 4806ae4 ae68454 26f7136 ae68454 540971d ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 ae68454 26f7136 ae68454 6556fb7 ae68454 6556fb7 ae68454 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# app.py
import gradio as gr
import yt_dlp
import tempfile
import os
import shutil
import speech_recognition as sr
from pydub import AudioSegment
import time
import warnings
import uuid
import logging
from threading import Lock
from fastapi import FastAPI
# تنظیمات لاگگیری سطح دیباگ
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
warnings.filterwarnings("ignore")
# ذخیره سشنها و متون استخراجشده
session_map = {}
transcriptions_db = {}
lock = Lock()
def convert_to_mp3_and_transcribe(video_url, language, progress=gr.Progress(), request: gr.Request = None):
"""
دانلود ویدیو، تبدیل به MP3 و استخراج متن به زبان انتخابی.
"""
session_hash = request.session_hash if request else str(uuid.uuid4())
logger.debug(f"[{session_hash}] شروع درخواست با زبان {language}")
if not video_url:
return None, None, "لینک ویدیو را وارد کنید."
try:
progress(0, desc="در حال دانلود ویدیو...")
logger.debug(f"[{session_hash}] در حال دانلود ویدیو از: {video_url}")
ydl_opts = {
'format': 'bestaudio[ext=m4a]/bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
'outtmpl': 'temp.%(ext)s',
'quiet': True,
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([video_url])
# پیدا کردن mp3
mp3_file = None
for file in os.listdir('.'):
if file.startswith('temp.') and file.endswith('.mp3'):
mp3_file = file
break
if not mp3_file:
logger.warning(f"[{session_hash}] MP3 دانلود نشد!")
return None, None, "خطا در دانلود یا تبدیل."
temp_mp3 = tempfile.NamedTemporaryFile(suffix='.mp3', delete=False)
temp_mp3.close()
shutil.copy2(mp3_file, temp_mp3.name)
os.remove(mp3_file)
logger.debug(f"[{session_hash}] MP3 آماده: {temp_mp3.name} | سایز: {os.path.getsize(temp_mp3.name)//1024}KB")
progress(0.3, desc="ویرایش صوت...")
text, error_msg = transcribe_audio(
temp_mp3.name, progress, language, session_hash
)
if text is None:
logger.warning(f"[{session_hash}] استخراج متن ناموفق بود: {error_msg}")
return temp_mp3.name, None, f"MP3 آماده. متن استخراج نشد. {error_msg or ''}"
logger.info(f"[{session_hash}] استخراج متن موفقیتآمیز: {text[:100]}...")
progress(1.0, desc="استخراج متن کامل شد!")
with lock:
transcriptions_db[session_hash] = text
return temp_mp3.name, text, f"Success - Session Hash: {session_hash}"
except Exception as e:
logger.error(f"[{session_hash}] خطای کلی: {str(e)}", exc_info=True)
return None, None, f"خطای سیستمی — لاگ لاگیرنده را ببینید."
def transcribe_audio(mp3_path, progress, language, session_hash, chunk_length_ms=55000, overlap_ms=5000):
recognizer = sr.Recognizer()
recognizer.energy_threshold = 300
recognizer.dynamic_energy_threshold = True
recognizer.pause_threshold = 0.6
full_text = []
bad_chunks = 0
total_chunks = 0
temp_wav_dir = tempfile.mkdtemp()
audio = AudioSegment.from_mp3(mp3_path)
duration_ms = len(audio)
if duration_ms == 0:
return None, "صدایی پیدا نشد."
step_size = chunk_length_ms - overlap_ms
if step_size <= 0:
step_size = chunk_length_ms // 2
num_chunks = max(1, (duration_ms // step_size) + 1)
logger.debug(f"[{session_hash}] مدت فایل: {duration_ms/1000:.2f}s، تعداد chunkها: {num_chunks}")
progress(0.5, desc="در حال تقسیم صوت...")
i = 0
chunk_idx = 1
while i < duration_ms:
end_pos = min(i + chunk_length_ms, duration_ms)
chunk = audio[i:end_pos]
if len(chunk) < 2000:
logger.debug(f"[{session_hash}] chunk {chunk_idx} خیلی کوتاه، متوقف میشود.")
break
temp_wav = os.path.join(temp_wav_dir, f"chunk_{i}.wav")
chunk.export(temp_wav, format="wav")
try:
progress(0.5 + (i / duration_ms) * 0.5, desc=f"در حال استخراج chunk {chunk_idx}/{num_chunks}...")
with sr.AudioFile(temp_wav) as source:
recognizer.adjust_for_ambient_noise(source, duration=0.5)
audio_data = recognizer.record(source)
text = recognizer.recognize_google(audio_data, language=language)
if not text.strip():
text = "[سکوت]"
logger.debug(f"[{session_hash}] chunk {chunk_idx}: {text[:50]}...")
full_text.append(text)
except sr.UnknownValueError:
logger.warning(f"[{session_hash}] chunk {chunk_idx} نامشخص.")
full_text.append("[نامشخص]")
except sr.RequestError as e:
logger.warning(f"[{session_hash}] chunk {chunk_idx} RequestError: {str(e)}")
full_text.append("[خطای شبکه]")
except Exception as e:
logger.error(f"[{session_hash}] chunk {chunk_idx} خطای داخلی: {str(e)}", exc_info=True)
full_text.append("[خطای داخلی]")
if os.path.exists(temp_wav):
os.remove(temp_wav)
i += step_size
chunk_idx += 1
shutil.rmtree(temp_wav_dir, ignore_errors=True)
final = " ".join(full_text).strip()
if not final:
return None, "هیچ متنی استخراج نشد."
return final, None
def query_transcription(session_hash):
if not session_hash:
return "لطفا session hash معتبر وارد کنید."
with lock:
text = transcriptions_db.get(session_hash)
if not text:
return "none"
logger.debug(f"[{session_hash}] درخواست استعلام متن.")
return text
# رابط گرافی Gradio
with gr.Blocks() as app:
with gr.Tab("تبدیل ویدیو به صوت و متن"):
gr.Interface(
fn=convert_to_mp3_and_transcribe,
inputs=[
gr.Textbox(label="لینک ویدیو", placeholder="YouTube یا MP4..."),
gr.Dropdown(
choices=[("پارسی", "fa-IR"), ("انگلیسی", "en-US")],
value="fa-IR",
label="زبان متن"
)
],
outputs=[
gr.File(label="دانلود MP3"),
gr.Textbox(label="متن استخراجشده", lines=10),
gr.Textbox(label="وضعیت")
],
title="تبدیل ویدیو به MP3 و استخراج متن",
examples=[
["https://www.youtube.com/watch?v=5qap5aO4i9A", "fa-IR"],
["https://www.youtube.com/watch?v=dQw4w9WgXcQ", "en-US"]
]
)
with gr.Tab("جستجوی متن بر اساس Session Hash"):
with gr.Row():
textbox = gr.Textbox(label="Session Hash")
btn = gr.Button("جستجوی متن")
output = gr.Textbox(label="نتیجه", lines=10)
btn.click(fn=query_transcription, inputs=textbox, outputs=output)
# افزودن endpoint API برای دسترسی سریع
@app.app.get("/api/text/{session_hash}")
async def get_text(session_hash: str):
with lock:
text = transcriptions_db.get(session_hash)
return {"session_hash": session_hash, "text": text or "Not Found"}
# اجرای اپ
if __name__ == "__main__":
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
debug=True # این کار را Gradio انجام میدهد.
) |