Spaces:
Sleeping
Sleeping
import gradio as gr | |
import torch | |
from transformers import pipeline, AutoModelForSeq2SeqLM, AutoTokenizer | |
from moviepy.video.io.VideoFileClip import VideoFileClip | |
import librosa | |
import soundfile as sf | |
import numpy as np | |
import re | |
from gtts import gTTS | |
from langdetect import detect | |
import os | |
# ====================== | |
# 1. الإعدادات الأساسية | |
# ====================== | |
device = "cuda" if torch.cuda.is_available() else "cpu" | |
# ====================== | |
# 2. تحميل النماذج | |
# ====================== | |
pipe = pipeline("automatic-speech-recognition", model="openai/whisper-medium", device=0 if device == "cuda" else -1) | |
bart_model = AutoModelForSeq2SeqLM.from_pretrained("ahmedabdo/arabic-summarizer-bart") | |
bart_tokenizer = AutoTokenizer.from_pretrained("ahmedabdo/arabic-summarizer-bart") | |
# تحميل نموذج الإجابة بالعربية | |
qa_model_name = "ZeyadAhmed/AraElectra-Arabic-SQuADv2-QA" | |
qa_pipeline = pipeline("question-answering", model=qa_model_name, tokenizer=qa_model_name, device=0 if device == "cuda" else -1) | |
# ====================== | |
# 3. التخصيصات | |
# ====================== | |
PRIMARY_COLOR = "#2A4D6E" # اللون الكحلي | |
EXAMPLE_AUDIO_PATH = "_ما_هو_الذكاء_الإصطناعي_؟_فِهموجرافيك_١.m4a" | |
# ====================== | |
# 4. الدوال المساعدة | |
# ====================== | |
def clean_text_advanced(text): | |
"""تنظيف النص مع الحفاظ على الهيكل الأساسي""" | |
text = re.sub(r'\b\d+[.)]\s*', '', text) # إزالة الترقيم الرقمي | |
text = re.sub(r'[ـ\-_*#@&]', ' ', text) # إزالة الرموز الخاصة | |
text = re.sub(r'\s+', ' ', text).strip() # تقليل الفراغات | |
return text | |
def prepare_context(text, max_length=1024): | |
"""تحضير السياق مع الحفاظ على الجمل الكاملة""" | |
cleaned = clean_text_advanced(text) | |
sentences = [s.strip() for s in cleaned.split('.') if s.strip()] | |
selected = [] | |
total_len = 0 | |
for sentence in reversed(sentences): | |
if total_len + len(sentence.split()) > max_length: | |
break | |
selected.append(sentence) | |
total_len += len(sentence.split()) | |
return '. '.join(reversed(selected)) | |
def convert_audio_to_text(uploaded_file): | |
try: | |
if not uploaded_file: | |
return "⛔ الرجاء رفع ملف أولاً" | |
input_path = uploaded_file if isinstance(uploaded_file, str) else uploaded_file.name | |
output_path = "/tmp/processed.wav" | |
# معالجة ملفات الفيديو | |
if input_path.split('.')[-1].lower() in ['mp4', 'avi', 'mov', 'mkv']: | |
video = VideoFileClip(input_path) | |
if video.audio: | |
video.audio.write_audiofile(output_path, codec='pcm_s16le') | |
else: | |
return "⛔ لا يوجد صوت في الفيديو!" | |
else: | |
output_path = input_path | |
audio, rate = librosa.load(output_path, sr=16000) | |
transcripts = [] | |
# تقسيم الصوت إلى مقاطع للتعامل مع الملفات الكبيرة | |
for start in np.arange(0, len(audio)/rate, 30): | |
end = min(start + 30, len(audio)/rate) | |
segment = audio[int(start*rate):int(end*rate)] | |
sf.write(f"/tmp/segment_{int(start)}.wav", segment, rate) | |
transcripts.append(pipe(f"/tmp/segment_{int(start)}.wav")["text"]) | |
return " ".join(transcripts) | |
except Exception as e: | |
return f"⛔ خطأ: {str(e)}" | |
def process_example_audio(): | |
try: | |
if not os.path.exists(EXAMPLE_AUDIO_PATH): | |
return "⛔ الملف التجريبي غير موجود" | |
return convert_audio_to_text(EXAMPLE_AUDIO_PATH) | |
except Exception as e: | |
return f"⛔ خطأ في معالجة المثال: {str(e)}" | |
def summarize_text(text): | |
cleaned_text = clean_text_advanced(text) | |
inputs = bart_tokenizer(cleaned_text, return_tensors="pt", max_length=1024, truncation=True).to(device) | |
summary_ids = bart_model.generate( | |
inputs.input_ids, | |
max_length=150, | |
num_beams=4, | |
early_stopping=True | |
) | |
return bart_tokenizer.decode(summary_ids[0], skip_special_tokens=True) | |
def answer_question(text, question): | |
if not question.strip() or not text.strip(): | |
return "⛔️ الرجاء إدخال النص والسؤال بشكل صحيح" | |
# تقسيم النص إلى شرائح صغيرة بحيث لا تزيد كل شريحة عن 256 كلمة | |
words = text.split() | |
chunk_size = 256 | |
segments = [" ".join(words[i:i+chunk_size]) for i in range(0, len(words), chunk_size)] | |
best_answer = None | |
best_score = -1 | |
# تطبيق نموذج الإجابة على كل شريحة واختيار الإجابة ذات أعلى score | |
for seg in segments: | |
result = qa_pipeline({'question': question, 'context': seg}) | |
if result['score'] > best_score: | |
best_score = result['score'] | |
best_answer = result['answer'] | |
return best_answer | |
def text_to_speech(text): | |
if not text.strip(): | |
return None | |
try: | |
tts = gTTS(text=text, lang='ar' if detect(text) == 'ar' else 'en', slow=False) | |
output = "/tmp/tts.wav" | |
tts.save(output) | |
return output | |
except Exception as e: | |
return f"⛔ خطأ في توليد الصوت: {str(e)}" | |
# ====================== | |
# 5. واجهة المستخدم (التصميم المحسّن) | |
# ====================== | |
with gr.Blocks(css=f""" | |
.gradio-container {{ | |
background: #f8f9fa; | |
font-family: 'Noto Sans Arabic', sans-serif; | |
}} | |
.header-section {{ | |
background: {PRIMARY_COLOR}; | |
padding: 2rem; | |
border-radius: 10px; | |
color: white; | |
text-align: center; | |
margin-bottom: 2rem; | |
}} | |
.tab-buttons {{ | |
border-bottom: 3px solid {PRIMARY_COLOR} !important; | |
}} | |
.tab-buttons button {{ | |
color: {PRIMARY_COLOR} !important; | |
background: #f8f9fa !important; | |
transition: all 0.3s !important; | |
}} | |
.tab-buttons button.selected {{ | |
border-top: 3px solid {PRIMARY_COLOR} !important; | |
background: rgba(42, 77, 110, 0.1) !important; | |
}} | |
.custom-button {{ | |
background: {PRIMARY_COLOR} !important; | |
color: white !important; | |
border-radius: 8px; | |
padding: 12px 25px; | |
margin: 5px; | |
}} | |
.custom-button:hover {{ | |
transform: translateY(-2px); | |
box-shadow: 0 5px 15px rgba(42, 77, 110, 0.3); | |
}} | |
audio {{ | |
width: 100%; | |
margin: 1rem 0; | |
}} | |
""") as demo: | |
gr.Markdown(""" | |
<div class="header-section"> | |
<h1>فهـــيم 🧠</h1> | |
<p>منصة الذكاء الاصطناعي المتكاملة لفهم المحتوى المرئي والسمعي</p> | |
</div> | |
""") | |
with gr.Tabs(): | |
# تبويب استخراج النص | |
with gr.TabItem("🎤 استخراج النص"): | |
gr.Markdown("### <span style='color:#2A4D6E'>🔊 مثال تجريبي</span>") | |
gr.Audio(EXAMPLE_AUDIO_PATH) | |
example_btn = gr.Button("تجربة المثال ⚡", elem_classes="custom-button") | |
gr.Markdown("<div style='color:#2A4D6E; margin-top:10px'>اضغط على الزر أعلاه أو ارفع ملفك الخاص</div>") | |
file_input = gr.File(file_types=[".wav", ".mp3", ".mp4"]) | |
gr.Markdown("<span style='color:#2A4D6E'>🖱️ يدعم الصوت والفيديو (MP3, WAV, MP4)</span>") | |
with gr.Row(): | |
extract_btn = gr.Button("بدء التحليل 🚀", elem_classes="custom-button") | |
clear_btn = gr.Button("مسح الكل 🗑️", elem_classes="custom-button") | |
extracted_text = gr.Textbox(label="📝 النص المستخرج", lines=8) | |
# تبويب التلخيص | |
with gr.TabItem("📃 التلخيص"): | |
with gr.Row(): | |
summarize_btn = gr.Button("توليد الملخص ✨", elem_classes="custom-button") | |
tts_btn = gr.Button("تحويل للصوت 🔊", elem_classes="custom-button") | |
summary_output = gr.Textbox(label="📌 الملخص المكثف", lines=6) | |
audio_output = gr.Audio() | |
# تبويب الأسئلة | |
with gr.TabItem("❓ الأسئلة"): | |
gr.Markdown("### <span style='color:#2A4D6E'>💡 الأسئلة الذكية</span>") | |
with gr.Row(): | |
q1_btn = gr.Button("الموضوع الرئيسي", elem_classes="custom-button") | |
q2_btn = gr.Button("الأفكار المفتاحية", elem_classes="custom-button") | |
q3_btn = gr.Button("الاستنتاجات", elem_classes="custom-button") | |
question_input = gr.Textbox(placeholder="...اكتب سؤالك هنا") | |
with gr.Row(): | |
answer_btn = gr.Button("الحصول على إجابة 🎯", elem_classes="custom-button") | |
clear_answer_btn = gr.Button("مسح الإجابة 🗑️", elem_classes="custom-button") | |
answer_output = gr.Textbox(label="💡 الإجابة الدقيقة", lines=4) | |
# ====================== | |
# توصيل الأحداث | |
# ====================== | |
extract_btn.click(convert_audio_to_text, inputs=file_input, outputs=extracted_text) | |
example_btn.click(process_example_audio, outputs=extracted_text) | |
clear_btn.click(lambda: [None, "", ""], outputs=[file_input, extracted_text, summary_output]) | |
summarize_btn.click(summarize_text, inputs=extracted_text, outputs=summary_output) | |
tts_btn.click(text_to_speech, inputs=summary_output, outputs=audio_output) | |
q1_btn.click(lambda: "ما هو الموضوع الرئيسي للنص؟", outputs=question_input) | |
q2_btn.click(lambda: "ما هي أهم النقاط في النص؟", outputs=question_input) | |
q3_btn.click(lambda: "ما هي الاستنتاجات الرئيسية؟", outputs=question_input) | |
answer_btn.click(answer_question, inputs=[extracted_text, question_input], outputs=answer_output) | |
clear_answer_btn.click(lambda: "", outputs=answer_output) | |
if __name__ == "__main__": | |
demo.launch() |