transciptio / app.py
KIMOSSINO's picture
Update app.py
f628a74 verified
raw
history blame
15.6 kB
import gradio as gr
import whisper
import os
import torch
import torchaudio
from transformers import pipeline, AutoProcessor, AutoModelForCausalLM
from transformers import SpeechT5Model, SpeechT5Processor
from deep_translator import GoogleTranslator
from docx import Document
import tempfile
from datetime import datetime
import logging
import sys
# إعداد التسجيل
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('app.log'),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
# قائمة اللغات المدعومة
SUPPORTED_LANGUAGES = {
'ar': 'العربية',
'en': 'English',
'fr': 'Français',
'es': 'Español',
'de': 'Deutsch'
}
# تعيين نماذج الصوت
TTS_MODELS = {
'ar': {
'male': "facebook/mms-tts-ara",
'female': "facebook/mms-tts-ara"
},
'en': {
'male': "microsoft/speecht5_tts",
'female': "microsoft/speecht5_tts"
},
'fr': {
'male': "facebook/mms-tts-fra",
'female': "facebook/mms-tts-fra"
},
'es': {
'male': "facebook/mms-tts-spa",
'female': "facebook/mms-tts-spa"
},
'de': {
'male': "facebook/mms-tts-deu",
'female': "facebook/mms-tts-deu"
}
}
# تعريف أنماط الصوت
VOICE_STYLES = {
'normal': {'speed_factor': 1.0, 'pitch_shift': 0},
'excited': {'speed_factor': 1.2, 'pitch_shift': 2},
'calm': {'speed_factor': 0.9, 'pitch_shift': -1},
'angry': {'speed_factor': 1.1, 'pitch_shift': -2},
'broadcaster': {'speed_factor': 1.1, 'pitch_shift': 1}
}
# تحديد اللغات RTL
RTL_LANGUAGES = ['ar']
class TTSGenerator:
def __init__(self):
self.models = {}
self.processors = {}
def get_model(self, lang, gender):
key = f"{lang}_{gender}"
if key not in self.models:
model_name = TTS_MODELS[lang][gender]
self.processors[key] = AutoProcessor.from_pretrained(model_name)
self.models[key] = AutoModelForTextToSpeech.from_pretrained(model_name)
return self.processors[key], self.models[key]
tts_generator = TTSGenerator()
def generate_speech(text, lang, gender='male', style='normal'):
"""توليد الصوت باستخدام نماذج Hugging Face"""
try:
if not text:
logger.warning("لم يتم تقديم نص للتحويل إلى صوت")
return None
processor, model = tts_generator.get_model(lang, gender)
style_params = VOICE_STYLES[style]
# تحويل النص إلى توكنز
inputs = processor(text=text, return_tensors="pt")
# توليد الصوت
speech = model.generate_speech(inputs["input_ids"], processor)
# تطبيق التأثيرات الصوتية
if style != 'normal':
speech = torchaudio.functional.speed(speech, style_params['speed_factor'])
if style_params['pitch_shift'] != 0:
speech = torchaudio.functional.pitch_shift(
speech,
sample_rate=16000,
n_steps=style_params['pitch_shift']
)
# حفظ الصوت في ملف مؤقت
audio_path = tempfile.mktemp(suffix='.wav')
torchaudio.save(audio_path, speech.unsqueeze(0), 16000)
return audio_path
except Exception as e:
logger.error(f"خطأ في توليد الصوت: {str(e)}")
return None
def text_to_speech(text, lang, gender='male', style='normal', progress=gr.Progress()):
"""واجهة لتحويل النص إلى صوت"""
if not text:
logger.warning("لم يتم تقديم نص للتحويل إلى صوت")
return None
try:
progress(0.2, desc="جاري تجهيز الصوت...")
logger.info(f"بدء تحويل النص إلى صوت باللغة: {lang}")
# تقسيم النص إلى جمل
sentences = text.split('.')
sentences = [s.strip() + '.' for s in sentences if s.strip()]
audio_files = []
for i, sentence in enumerate(sentences):
progress((i + 1) / len(sentences), desc=f"معالجة الجملة {i+1} من {len(sentences)}...")
audio_path = generate_speech(sentence, lang, gender, style)
if audio_path:
audio_files.append(audio_path)
if not audio_files:
logger.error("لم يتم إنشاء أي ملفات صوتية")
return None
if len(audio_files) == 1:
return audio_files[0]
# دمج الملفات الصوتية
from pydub import AudioSegment
final_audio = AudioSegment.from_wav(audio_files[0])
for audio_file in audio_files[1:]:
final_audio += AudioSegment.from_wav(audio_file)
final_path = tempfile.mktemp(suffix='.wav')
final_audio.export(final_path, format="wav")
# تنظيف الملفات المؤقتة
for file in audio_files:
try:
os.remove(file)
except:
pass
progress(1.0, desc="تم إنشاء الصوت بنجاح!")
return final_path
except Exception as e:
logger.error(f"خطأ في تحويل النص إلى صوت: {str(e)}")
return None
def create_document(original_text, translated_text, source_lang, target_lang, progress=gr.Progress()):
"""إنشاء ملف Word يحتوي على النص الأصلي والترجمة"""
try:
progress(0, desc="جاري إنشاء المستند...")
doc = Document()
doc.add_heading('النص الأصلي والترجمة', 0)
progress(0.3, desc="جاري إضافة المحتوى...")
doc.add_paragraph(f'تم الإنشاء في: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
doc.add_heading(f'النص الأصلي ({SUPPORTED_LANGUAGES[source_lang]})', level=1)
doc.add_paragraph(original_text)
progress(0.6, desc="جاري إضافة الترجمة...")
doc.add_heading(f'الترجمة ({SUPPORTED_LANGUAGES[target_lang]})', level=1)
doc.add_paragraph(translated_text)
progress(0.9, desc="جاري حفظ المستند...")
temp_path = tempfile.mktemp(suffix='.docx')
doc.save(temp_path)
progress(1.0, desc="تم إنشاء المستند بنجاح!")
logger.info(f"تم إنشاء مستند Word: {temp_path}")
return temp_path
except Exception as e:
logger.error(f"خطأ في إنشاء المستند: {str(e)}")
return None
def translate_text(text, source_lang, target_lang, progress=gr.Progress()):
"""ترجمة النص باستخدام deep-translator"""
if source_lang == target_lang:
return text
try:
progress(0.3, desc="جاري الترجمة...")
logger.info(f"بدء الترجمة من {source_lang} إلى {target_lang}")
translator = GoogleTranslator(source=source_lang, target=target_lang)
# تقسيم النص إلى أجزاء
max_length = 5000
text_parts = [text[i:i+max_length] for i in range(0, len(text), max_length)]
translated_parts = []
for i, part in enumerate(text_parts):
progress((i + 1) / len(text_parts), desc=f"ترجمة الجزء {i+1} من {len(text_parts)}...")
translated_part = translator.translate(part)
translated_parts.append(translated_part)
translated_text = ' '.join(translated_parts)
progress(1.0, desc="تمت الترجمة بنجاح!")
return translated_text
except Exception as e:
logger.error(f"خطأ في الترجمة: {str(e)}")
return f"خطأ في الترجمة: {str(e)}"
def process_video(video, source_lang="en", target_lang="ar", progress=gr.Progress()):
"""معالجة الفيديو واستخراج النص وترجمته"""
if video is None:
return {
"error": "الرجاء رفع ملف فيديو",
"original": "",
"translated": "",
"document": None
}
try:
progress(0.1, desc="جاري تحميل الفيديو...")
temp_path = video.name
logger.info(f"تم استلام ملف فيديو: {temp_path}")
progress(0.3, desc="جاري تحميل نموذج التعرف على الكلام...")
model = whisper.load_model("base")
progress(0.5, desc="جاري استخراج النص من الفيديو...")
result = model.transcribe(temp_path, language=source_lang)
transcribed_text = result["text"]
logger.info("تم استخراج النص بنجاح")
progress(0.7, desc="جاري ترجمة النص...")
translated_text = translate_text(transcribed_text, source_lang, target_lang)
progress(0.9, desc="جاري إنشاء المستند...")
doc_path = create_document(transcribed_text, translated_text, source_lang, target_lang)
progress(1.0, desc="تمت المعالجة بنجاح!")
return {
"error": None,
"original": transcribed_text,
"translated": translated_text,
"document": doc_path
}
except Exception as e:
logger.error(f"خطأ في معالجة الفيديو: {str(e)}")
return {
"error": f"حدث خطأ: {str(e)}",
"original": "",
"translated": "",
"document": None
}
def create_ui():
"""إنشاء واجهة المستخدم"""
with gr.Blocks(theme=gr.themes.Soft(
primary_hue="blue",
secondary_hue="indigo",
)) as demo:
gr.Markdown(
"""
# 🎥 منصة تحويل الفيديو إلى نص مع الترجمة
### قم برفع فيديو للحصول على النص والترجمة مع إمكانية تحويل النص إلى صوت
"""
)
with gr.Row():
with gr.Column(scale=2):
video_input = gr.File(
label="📁 رفع فيديو",
file_types=["video"],
elem_id="video_input"
)
with gr.Column(scale=1):
source_lang = gr.Dropdown(
choices=list(SUPPORTED_LANGUAGES.keys()),
value="en",
label="🗣️ لغة الفيديو الأصلية"
)
target_lang = gr.Dropdown(
choices=list(SUPPORTED_LANGUAGES.keys()),
value="ar",
label="🌐 لغة الترجمة"
)
process_btn = gr.Button("🎯 معالجة الفيديو", variant="primary")
with gr.Row():
error_output = gr.Textbox(label="⚠️ الأخطاء", visible=False)
with gr.Tabs():
with gr.TabItem("📝 النص الأصلي"):
original_text = gr.Textbox(
label="النص المستخرج من الفيديو",
lines=10,
elem_classes=["ltr"]
)
with gr.Row():
with gr.Column():
original_gender = gr.Radio(
choices=["male", "female"],
value="male",
label="🧑 جنس المتحدث",
info="اختر جنس المتحدث"
)
original_style = gr.Dropdown(
choices=list(VOICE_STYLES.keys()),
value="normal",
label="🎭 نمط الصوت",
info="اختر نمط الصوت المناسب"
)
with gr.Column():
generate_original_audio = gr.Button("🔊 توليد الصوت", variant="secondary")
original_audio = gr.Audio(label="الصوت", visible=True)
with gr.TabItem("🔄 النص المترجم"):
translated_text = gr.Textbox(
label="النص المترجم",
lines=10,
elem_classes=["rtl"]
)
with gr.Row():
with gr.Column():
translated_gender = gr.Radio(
choices=["male", "female"],
value="male",
label="🧑 جنس المتحدث",
info="اختر جنس المتحدث"
)
translated_style = gr.Dropdown(
choices=list(VOICE_STYLES.keys()),
value="normal",
label="🎭 نمط الصوت",
info="اختر نمط الصوت المناسب"
)
with gr.Column():
generate_translated_audio = gr.Button("🔊 توليد الصوت", variant="secondary")
translated_audio = gr.Audio(label="الصوت", visible=True)
with gr.Row():
download_btn = gr.File(
label="📥 تحميل المستند (Word)",
interactive=False
)
def update_ui(video, src_lang, tgt_lang):
result = process_video(video, src_lang, tgt_lang)
original_classes = "rtl" if src_lang in RTL_LANGUAGES else "ltr"
translated_classes = "rtl" if tgt_lang in RTL_LANGUAGES else "ltr"
return {
error_output: gr.update(value=result["error"], visible=bool(result["error"])),
original_text: gr.update(value=result["original"], elem_classes=[original_classes]),
translated_text: gr.update(value=result["translated"], elem_classes=[translated_classes]),
download_btn: result["document"]
}
process_btn.click(
fn=update_ui,
inputs=[video_input, source_lang, target_lang],
outputs=[error_output, original_text, translated_text, download_btn]
)
generate_original_audio.click(
fn=text_to_speech,
inputs=[original_text, source_lang, original_gender, original_style],
outputs=[original_audio]
)
generate_translated_audio.click(
fn=text_to_speech,
inputs=[translated_text, target_lang, translated_gender, translated_style],
outputs=[translated_audio]
)
return demo
if __name__ == "__main__":
try:
logger.info("بدء تشغيل التطبيق")
demo = create_ui()
demo.launch()
except Exception as e:
logger.error(f"خطأ في تشغيل التطبيق: {str(e)}")