|
import os |
|
import sys |
|
import logging |
|
import warnings |
|
import torch |
|
from typing import Optional, Dict, Any |
|
|
|
|
|
logging.basicConfig( |
|
level=logging.INFO, |
|
format='%(asctime)s - %(levelname)s - %(message)s' |
|
) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
warnings.filterwarnings("ignore", category=UserWarning) |
|
|
|
try: |
|
import gradio as gr |
|
from pyannote.audio import Pipeline |
|
except ImportError as e: |
|
logger.error(f"שגיאה בטעינת הספריות הנדרשות: {str(e)}") |
|
sys.exit(1) |
|
|
|
def initialize_pipeline() -> Optional[Pipeline]: |
|
"""אתחול מודל הדיאריזציה עם טיפול שגיאות""" |
|
try: |
|
hf_token = os.getenv('HF_TOKEN') |
|
if not hf_token: |
|
raise ValueError("לא נמצא HF_TOKEN במשתני הסביבה") |
|
|
|
pipeline = Pipeline.from_pretrained( |
|
"pyannote/[email protected]", |
|
use_auth_token=hf_token |
|
) |
|
|
|
|
|
if torch.cuda.is_available(): |
|
pipeline = pipeline.to(torch.device("cuda")) |
|
logger.info("המודל הועבר ל-GPU") |
|
else: |
|
logger.info("רץ על CPU") |
|
|
|
return pipeline |
|
|
|
except Exception as e: |
|
logger.error(f"שגיאה באתחול המודל: {str(e)}") |
|
return None |
|
|
|
def process_audio(audio_path: str, min_speakers: int = None, max_speakers: int = None) -> Dict[str, Any]: |
|
"""עיבוד קובץ האודיו וזיהוי דוברים""" |
|
try: |
|
|
|
if not audio_path or not os.path.exists(audio_path): |
|
return {"error": "לא נבחר קובץ אודיו תקין"} |
|
|
|
file_size_mb = os.path.getsize(audio_path) / (1024 * 1024) |
|
if file_size_mb > 100: |
|
return {"error": f"גודל הקובץ ({file_size_mb:.1f}MB) גדול מדי. המקסימום הוא 100MB"} |
|
|
|
|
|
pipeline = initialize_pipeline() |
|
if pipeline is None: |
|
return {"error": "שגיאה באתחול המודל"} |
|
|
|
|
|
diarization_options = {} |
|
if min_speakers and min_speakers > 0: |
|
diarization_options['min_speakers'] = min_speakers |
|
if max_speakers and max_speakers > 0: |
|
diarization_options['max_speakers'] = max_speakers |
|
|
|
|
|
diarization = pipeline(audio_path, **diarization_options) |
|
|
|
|
|
results = [] |
|
speakers = set() |
|
total_duration = 0 |
|
|
|
for turn, _, speaker in diarization.itertracks(yield_label=True): |
|
segment = { |
|
"start": turn.start, |
|
"end": turn.end, |
|
"duration": turn.duration, |
|
"speaker": speaker |
|
} |
|
results.append(segment) |
|
speakers.add(speaker) |
|
total_duration += turn.duration |
|
|
|
|
|
output = [ |
|
"תוצאות זיהוי הדוברים:", |
|
"=" * 30, |
|
"" |
|
] |
|
|
|
for segment in results: |
|
output.append( |
|
f"[{segment['start']:.1f}s -> {segment['end']:.1f}s] " |
|
f"{segment['speaker']}" |
|
) |
|
|
|
output.extend([ |
|
"", |
|
"=" * 30, |
|
"סיכום:", |
|
f"• מספר דוברים שזוהו: {len(speakers)}", |
|
f"• משך כולל: {total_duration:.1f} שניות", |
|
f"• גודל הקובץ: {file_size_mb:.1f}MB", |
|
]) |
|
|
|
if min_speakers or max_speakers: |
|
constraints = [] |
|
if min_speakers: |
|
constraints.append(f"מינימום {min_speakers} דוברים") |
|
if max_speakers: |
|
constraints.append(f"מקסימום {max_speakers} דוברים") |
|
output.append(f"• הגבלות: {', '.join(constraints)}") |
|
|
|
return {"text": "\n".join(output)} |
|
|
|
except Exception as e: |
|
logger.error(f"שגיאה בעיבוד האודיו: {str(e)}") |
|
return {"error": f"שגיאה בעיבוד: {str(e)}"} |
|
|
|
def create_gradio_interface() -> gr.Interface: |
|
"""יצירת ממשק המשתמש""" |
|
return gr.Interface( |
|
fn=lambda audio, min_spk, max_spk: process_audio(audio, min_spk, max_spk).get("text", "שגיאה בעיבוד"), |
|
inputs=[ |
|
gr.Audio( |
|
label="קובץ אודיו", |
|
type="filepath" |
|
), |
|
gr.Number( |
|
label="מינימום דוברים (אופציונלי)", |
|
value=None, |
|
minimum=0, |
|
step=1 |
|
), |
|
gr.Number( |
|
label="מקסימום דוברים (אופציונלי)", |
|
value=None, |
|
minimum=0, |
|
step=1 |
|
) |
|
], |
|
outputs=gr.Textbox( |
|
label="תוצאות הזיהוי", |
|
lines=10 |
|
), |
|
title="זיהוי דוברים בהקלטות", |
|
description=""" |
|
העלה קובץ אודיו לזיהוי הדוברים השונים והזמנים שלהם. |
|
|
|
הערות: |
|
• תומך בפורמטים: WAV, MP3, FLAC |
|
• גודל קובץ מקסימלי: 100MB |
|
• מומלץ להשתמש בהקלטות באיכות טובה |
|
• אם ידוע מספר הדוברים, ציון שלו יכול לשפר את הדיוק |
|
""", |
|
article=""" |
|
שים לב: |
|
1. הזיהוי הכי מדויק בהקלטות ללא רעשי רקע |
|
2. לפעמים המודל יכול לזהות את אותו דובר פעמיים |
|
3. הזמנים מוצגים בשניות |
|
""", |
|
examples=[ |
|
["example.wav", 2, 4], |
|
["interview.mp3", 2, 2] |
|
] |
|
) |
|
|
|
if __name__ == "__main__": |
|
try: |
|
|
|
logger.info(f"Python version: {sys.version}") |
|
logger.info(f"PyTorch version: {torch.__version__}") |
|
logger.info(f"Space ID: {os.getenv('SPACE_ID', 'unknown')}") |
|
logger.info(f"GPU available: {torch.cuda.is_available()}") |
|
|
|
if torch.cuda.is_available(): |
|
logger.info(f"GPU model: {torch.cuda.get_device_name(0)}") |
|
|
|
|
|
demo = create_gradio_interface() |
|
demo.launch( |
|
share=True |
|
) |
|
|
|
except Exception as e: |
|
logger.error(f"שגיאה קריטית: {str(e)}") |
|
sys.exit(1) |
|
|
|
|