Seicas commited on
Commit
f631cbd
·
verified ·
1 Parent(s): 6a4e9e3

Update diarization.py

Browse files
Files changed (1) hide show
  1. diarization.py +114 -87
diarization.py CHANGED
@@ -1,101 +1,128 @@
1
  from pyannote.audio import Pipeline
 
 
 
2
  from config import settings
3
 
4
- _diar_pipeline = Pipeline.from_pretrained(settings.DIAR_MODEL)
5
 
6
- def diarize_segments(audio_path, segments):
7
- """
8
- Konuşma segmentlerini konuşmacılara göre ayırır
 
 
9
 
10
- Parameters:
11
- -----------
12
- audio_path : str
13
- Ses dosyasının tam yolu
14
- segments : list
15
- ASR tarafından oluşturulan zaman damgalı segmentler
16
 
17
- Returns:
18
- --------
19
- list
20
- Konuşmacı bilgisi eklenmiş segmentler
21
- """
22
- try:
23
- # Pyannote modelini yükle
24
- import os
25
- import torch
26
- from pyannote.audio import Pipeline
27
-
28
- # HuggingFace token kontrolü
29
- token = os.environ.get("HF_TOKEN")
30
- if not token:
31
- print("UYARI: HF_TOKEN bulunamadı, diyarizasyon atlanıyor.")
32
- # Tüm segmentleri Konuşmacı 1 olarak işaretle
33
- for seg in segments:
34
- seg["speaker"] = "Konuşmacı 1"
35
- return segments
36
 
37
- # Pyannote pipeline'ını oluştur
38
- pipeline = Pipeline.from_pretrained(
39
- settings.DIAR_MODEL,
40
- use_auth_token=token
41
- )
 
 
 
 
 
 
 
 
42
 
43
- # GPU varsa kullan
44
- if torch.cuda.is_available():
45
- pipeline = pipeline.to(torch.device("cuda"))
 
 
 
 
 
 
 
 
 
 
46
 
47
- # Diyarizasyon yap
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  diarization = pipeline(audio_path)
 
49
 
50
- # Konuşmacı etiketlerini oluştur (Hekim, Asistan, vs.)
51
- speaker_labels = {}
52
-
53
- # Segmentlere konuşmacı bilgisi ekle
54
- for seg in segments:
55
- seg_start = seg["start"]
56
- seg_end = seg["end"]
57
-
58
- # Bu segment için en çok konuşan kişiyi bul
59
- speaker_times = {}
60
- for turn, _, speaker in diarization.itertracks(yield_label=True):
61
- # Segment ve konuşma turu arasındaki çakışmayı hesapla
62
- overlap_start = max(seg_start, turn.start)
63
- overlap_end = min(seg_end, turn.end)
64
 
65
- if overlap_end > overlap_start: # Çakışma varsa
66
- duration = overlap_end - overlap_start
67
- speaker_times[speaker] = speaker_times.get(speaker, 0) + duration
68
-
69
- # En uzun konuşan kişiyi bul
70
- if speaker_times:
71
- max_speaker = max(speaker_times, key=speaker_times.get)
72
-
73
- # Konuşmacıyı etiketle
74
- if max_speaker not in speaker_labels:
75
- # Yeni konuşmacı tespit edildi
76
- # Pediatri bağlamında etiketler belirle (ilk konuşmacı genelde hekim)
77
- idx = len(speaker_labels) + 1
78
- if idx == 1:
79
- label = "Hekim"
80
- elif idx == 2:
81
- label = "Asistan"
82
- elif idx == 3:
83
- label = "Ebeveyn"
84
- else:
85
- label = f"Konuşmacı {idx}"
86
-
87
- speaker_labels[max_speaker] = label
88
-
89
- seg["speaker"] = speaker_labels[max_speaker]
90
- else:
91
- # Diyarizasyon bilgisi yoksa
92
- seg["speaker"] = "Bilinmeyen Konuşmacı"
93
-
94
  return segments
95
-
96
  except Exception as e:
97
- # Hata durumunda basit etiketleme yap
98
- print(f"Diyarizasyon hatası: {str(e)}")
99
- for seg in segments:
100
- seg["speaker"] = "Konuşmacı"
101
- return segments
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from pyannote.audio import Pipeline
2
+ from typing import List, Dict, Any
3
+ import torch
4
+ import os
5
  from config import settings
6
 
7
+ # HF_TOKEN hardcoded assignment removed for security
8
 
9
+ _diarization_pipeline = None
10
+
11
+ def get_diarization_pipeline():
12
+ """Diarization pipeline singleton with fallback"""
13
+ global _diarization_pipeline
14
 
15
+ if not os.getenv("HF_TOKEN"):
16
+ print("Warning: HF_TOKEN not set! Diarization will be disabled.")
17
+ return None
 
 
 
18
 
19
+ if _diarization_pipeline is None:
20
+ try:
21
+ device = "cuda" if torch.cuda.is_available() else "cpu"
22
+ _diarization_pipeline = Pipeline.from_pretrained(
23
+ settings.DIARIZATION_MODEL,
24
+ use_auth_token=os.environ.get("HF_TOKEN"),
25
+ device=device
26
+ )
27
+ except Exception as e:
28
+ print(f"Error loading diarization pipeline: {e}")
29
+ return None
 
 
 
 
 
 
 
 
30
 
31
+ return _diarization_pipeline
32
+
33
+ def rename_speakers_for_pediatrics(segments: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
34
+ """
35
+ Konuşmacıları pediatri bağlamına göre yeniden isimlendirir
36
+ """
37
+ # Konuşmacıları basit bir şekilde yeniden isimlendiriyoruz
38
+ # Gerçek bir uygulamada ses özellikleri analizi ile daha sofistike olabilir
39
+ renamed_segments = []
40
+
41
+ speaker_mapping = {}
42
+ for segment in segments:
43
+ speaker = segment["speaker"]
44
 
45
+ if speaker not in speaker_mapping:
46
+ # İlk konuşmacıyı bölüm başkanı olarak kabul ediyoruz
47
+ if len(speaker_mapping) == 0:
48
+ speaker_mapping[speaker] = "Bölüm_Başkanı"
49
+ # İkinci konuşmacıyı hekim olarak kabul ediyoruz
50
+ elif len(speaker_mapping) == 1:
51
+ speaker_mapping[speaker] = "Hekim"
52
+ # Üçüncü konuşmacıyı asistan olarak kabul ediyoruz
53
+ elif len(speaker_mapping) == 2:
54
+ speaker_mapping[speaker] = "Asistan"
55
+ # Diğer konuşmacılar
56
+ else:
57
+ speaker_mapping[speaker] = f"Konuşmacı_{len(speaker_mapping) + 1}"
58
 
59
+ # Segment kopyası oluştur ve konuşmacı ismini güncelle
60
+ new_segment = segment.copy()
61
+ new_segment["speaker"] = speaker_mapping[speaker]
62
+ renamed_segments.append(new_segment)
63
+
64
+ return renamed_segments
65
+
66
+ def diarize_audio(audio_path: str) -> List[Dict[str, Any]]:
67
+ """Diarize audio with fallback to single speaker"""
68
+ try:
69
+ pipeline = get_diarization_pipeline()
70
+ if pipeline is None:
71
+ # Fallback: Return single speaker for entire duration
72
+ return [{"speaker": "Speaker 1", "start": 0.0, "end": float("inf")}]
73
+
74
  diarization = pipeline(audio_path)
75
+ segments = []
76
 
77
+ for turn, _, speaker in diarization.itertracks(yield_label=True):
78
+ if turn.duration >= settings.MIN_SPEAKER_DURATION:
79
+ segments.append({
80
+ "speaker": f"Speaker {speaker.split('_')[-1]}",
81
+ "start": turn.start,
82
+ "end": turn.end
83
+ })
 
 
 
 
 
 
 
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  return segments
86
+
87
  except Exception as e:
88
+ print(f"Diarization error: {e}")
89
+ # Fallback: Return single speaker
90
+ return [{"speaker": "Speaker 1", "start": 0.0, "end": float("inf")}]
91
+
92
+ def diarize_segments(audio_file: str, is_pediatrics: bool = True) -> List[Dict[str, Any]]:
93
+ """
94
+ Ses dosyasındaki konuşmacıları ayırt eder
95
+
96
+ Args:
97
+ audio_file: Ses dosyasının yolu
98
+
99
+ Returns:
100
+ Konuşmacı segmentleri listesi
101
+ [
102
+ {"speaker": "speaker_0", "start": 0.5, "end": 2.3, "text": "..."},
103
+ {"speaker": "speaker_1", "start": 2.4, "end": 5.1, "text": "..."},
104
+ ...
105
+ ]
106
+ """
107
+ # Pipeline'ı al
108
+ pipeline = get_diarization_pipeline()
109
+
110
+ # Diyarizasyon gerçekleştir
111
+ diarization = pipeline(audio_file)
112
+
113
+ # Sonuçları formatlayalım
114
+ results = []
115
+ for turn, _, speaker in diarization.itertracks(yield_label=True):
116
+ segment = {
117
+ "speaker": speaker,
118
+ "start": turn.start,
119
+ "end": turn.end,
120
+ "text": "" # Bu alanı transcribe işlemi sonrası dolduracağız
121
+ }
122
+ results.append(segment)
123
+
124
+ # Pediatri bağlamı için konuşmacı isimlerini güncelle
125
+ if is_pediatrics:
126
+ results = rename_speakers_for_pediatrics(results)
127
+
128
+ return results