TRANSCRIPTIONV4 / APP.PY
KIMOSSINO's picture
Create APP.PY
d5f394e verified
raw
history blame
9.64 kB
import gradio as gr
import whisper
import os
import asyncio
import edge_tts
from transformers import pipeline
from deep_translator import GoogleTranslator
from docx import Document
import tempfile
from datetime import datetime
import logging
import sys
from pydub import AudioSegment
import time
import torch
from concurrent.futures import ThreadPoolExecutor
from functools import lru_cache
# تكوين التسجيل
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__)
# تحديد الجهاز المستخدم (GPU إذا كان متاحاً)
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
logger.info(f"Using device: {DEVICE}")
# حجم النموذج - يمكن تغييره حسب الحاجة
MODEL_SIZE = "base"
# تخزين مؤقت للنماذج
_models = {}
# قائمة اللغات المدعومة
SUPPORTED_LANGUAGES = {
'ar': 'العربية',
'en': 'English',
'fr': 'Français',
'es': 'Español',
'de': 'Deutsch'
}
# تعيين أصوات لكل لغة
VOICE_MAPPINGS = {
'ar': {
'male': 'ar-EG-ShakirNeural',
'female': 'ar-EG-SalmaNeural'
},
'en': {
'male': 'en-US-ChristopherNeural',
'female': 'en-US-JennyNeural'
},
'fr': {
'male': 'fr-FR-HenriNeural',
'female': 'fr-FR-DeniseNeural'
},
'es': {
'male': 'es-ES-AlvaroNeural',
'female': 'es-ES-ElviraNeural'
},
'de': {
'male': 'de-DE-ConradNeural',
'female': 'de-DE-KatjaNeural'
}
}
RTL_LANGUAGES = ['ar']
def get_whisper_model():
"""الحصول على نموذج Whisper مع التخزين المؤقت"""
if 'whisper' not in _models:
_models['whisper'] = whisper.load_model(MODEL_SIZE, device=DEVICE)
return _models['whisper']
@lru_cache(maxsize=100)
async def generate_speech_cached(text, voice):
"""توليد الصوت مع التخزين المؤقت"""
try:
communicate = edge_tts.Communicate(text, voice)
audio_path = tempfile.mktemp(suffix='.mp3')
await communicate.save(audio_path)
return audio_path if os.path.exists(audio_path) and os.path.getsize(audio_path) > 0 else None
except Exception as e:
logger.error(f"خطأ في توليد الصوت: {str(e)}")
return None
def text_to_speech(text, lang, voice_gender='male', progress=gr.Progress()):
"""تحسين تحويل النص إلى صوت"""
if not text:
return None
try:
progress(0.2, desc="جاري تجهيز الصوت...")
voice = VOICE_MAPPINGS.get(lang, {}).get(voice_gender, VOICE_MAPPINGS['en']['male'])
# تقسيم النص إلى أجزاء أصغر للمعالجة المتوازية
chunk_size = 500
chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
audio_files = []
with ThreadPoolExecutor() as executor:
futures = []
for chunk in chunks:
future = asyncio.run(generate_speech_cached(chunk, voice))
futures.append(future)
for i, future in enumerate(futures):
progress((i + 1) / len(futures), desc=f"معالجة الجزء {i+1} من {len(futures)}...")
if future:
audio_files.append(future)
if not audio_files:
return None
if len(audio_files) == 1:
return audio_files[0]
# دمج الملفات الصوتية
final_audio = AudioSegment.from_mp3(audio_files[0])
for audio_file in audio_files[1:]:
final_audio += AudioSegment.from_mp3(audio_file)
final_path = tempfile.mktemp(suffix='.mp3')
final_audio.export(final_path, format="mp3")
# تنظيف الملفات المؤقتة
for file in audio_files:
try:
os.remove(file)
except:
pass
return final_path
except Exception as e:
logger.error(f"خطأ في تحويل النص إلى صوت: {str(e)}")
return None
@lru_cache(maxsize=50)
def translate_text_cached(text, source_lang, target_lang):
"""ترجمة النص مع التخزين المؤقت"""
if source_lang == target_lang:
return text
try:
translator = GoogleTranslator(source=source_lang, target=target_lang)
return translator.translate(text)
except Exception as e:
logger.error(f"خطأ في الترجمة: {str(e)}")
return f"خطأ في الترجمة: {str(e)}"
def translate_text(text, source_lang, target_lang, progress=gr.Progress()):
"""تحسين الترجمة باستخدام المعالجة المتوازية"""
if source_lang == target_lang:
return text
try:
progress(0.3, desc="جاري الترجمة...")
# تقسيم النص إلى أجزاء أصغر
chunk_size = 1000
chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
translated_chunks = []
with ThreadPoolExecutor() as executor:
futures = []
for chunk in chunks:
future = executor.submit(translate_text_cached, chunk, source_lang, target_lang)
futures.append(future)
for i, future in enumerate(futures):
progress((i + 1) / len(futures), desc=f"ترجمة الجزء {i+1} من {len(futures)}...")
translated_chunks.append(future.result())
return ' '.join(translated_chunks)
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
# تحميل نموذج Whisper
progress(0.3, desc="جاري تحميل نموذج التعرف على الكلام...")
model = get_whisper_model()
# استخراج النص مع التقسيم
progress(0.5, desc="جاري استخراج النص من الفيديو...")
result = model.transcribe(
temp_path,
language=source_lang,
fp16=torch.cuda.is_available(), # استخدام FP16 إذا كان متاحاً
task="transcribe"
)
transcribed_text = ""
for segment in result["segments"]:
start_time = format_timestamp(segment["start"])
text = segment["text"].strip()
transcribed_text += f"[{start_time}] {text}\n"
# ترجمة النص
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)
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 format_timestamp(seconds):
"""تنسيق الوقت بالثواني إلى الشكل HH:MM:SS"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
seconds = int(seconds % 60)
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
def create_document(original_text, translated_text, source_lang, target_lang):
"""إنشاء مستند DOCX يحتوي على النص الأصلي والترجمة"""
doc = Document()
doc.add_heading(f"النص الأصلي ({SUPPORTED_LANGUAGES.get(source_lang, 'غير معروف')})")
doc.add_paragraph(original_text)
doc.add_heading(f"الترجمة ({SUPPORTED_LANGUAGES.get(target_lang, 'غير معروف')})")
doc.add_paragraph(translated_text)
temp_path = tempfile.mktemp(suffix='.docx')
doc.save(temp_path)
return temp_path
# إنشاء واجهة المستخدم
demo = gr.Interface(
process_video,
[
gr.File(label="تحميل ملف الفيديو"),
gr.Radio(label="لغة المصدر", choices=list(SUPPORTED_LANGUAGES.keys()), value="en"),
gr.Radio(label="لغة الهدف", choices=list(SUPPORTED_LANGUAGES.keys()), value="ar"),
gr.Progress(label="التقدم")
],
[
gr.Textbox(label="النص الأصلي"),
gr.Textbox(label="الترجمة"),
gr.File(label="المستند")
],
title="تحويل الفيديو إلى نص وترجمة",
description="استخدم هذا الأداة لتحويل الفيديوهات إلى نصوص وترجمتها إلى لغات مختلفة."
)
if __name__ == "__main__":
demo.launch()