helo-ayush/Diarization_VoiceFingerprinted
0
1# ==============================================================================
2# DEEPGRAM PROCESSOR (LEGACY / UTILITIES)
3# Originally used for STT, now primarily holds `build_raw_transcript` helper
4# to group word-level data cleanly by speaker segments.
5# ==============================================================================
6import os
7import time
8import asyncio
9from deepgram import DeepgramClient, PrerecordedOptions
10
11
12deepgram = DeepgramClient(os.getenv("DEEPGRAM_API_KEY"))
13
14
15async def transcribe_with_diarization(audio_bytes: bytes) -> dict:
16 """
17 Transcribe audio with speaker diarization using Deepgram Nova-3.
18 Returns word-level data with speaker assignments.
19 """
20 size_kb = len(audio_bytes) / 1024
21 print(f"๐๏ธ Sending {size_kb:.1f}KB to Deepgram...")
22
23 start_time = time.time()
24
25 options = PrerecordedOptions(
26 model="nova-3",
27 language="multi",
28 diarize=True,
29 smart_format=True,
30 punctuate=True,
31 utterances=True,
32 multichannel=False,
33 )
34
35 source = {"buffer": audio_bytes}
36
37 # Run with 120s timeout
38 try:
39 response = await asyncio.wait_for(
40 asyncio.to_thread(
41 deepgram.listen.rest.v("1").transcribe_file,
42 source,
43 options,
44 ),
45 timeout=120
46 )
47 except asyncio.TimeoutError:
48 raise TimeoutError("Deepgram timed out after 120s")
49
50 processing_time = int((time.time() - start_time) * 1000)
51 print(f"โ
Deepgram completed in {processing_time}ms")
52
53 utterances = response.results.utterances
54 channel = response.results.channels[0] if response.results.channels else None
55 words_raw = channel.alternatives[0].words if channel and channel.alternatives else []
56
57 # No speech detected
58 if not utterances or len(utterances) == 0:
59 transcript = channel.alternatives[0].transcript if channel and channel.alternatives else ""
60 return {
61 "words": [],
62 "transcript": transcript,
63 "has_speech": False,
64 "processing_time": processing_time
65 }
66
67 # Build word-level array with speaker info
68 words = [
69 {
70 "word": w.punctuated_word or w.word,
71 "speaker": w.speaker,
72 "confidence": getattr(w, "speaker_confidence", None) or w.confidence or 0,
73 "start": w.start,
74 "end": w.end,
75 }
76 for w in words_raw
77 ]
78
79 return {"words": words, "has_speech": True, "processing_time": processing_time}
80
81
82def build_raw_transcript(words: list, agent_map: dict = None) -> dict:
83 """
84 Filter out background noise speakers (< 5% word share)
85 and build a raw transcript string from valid words.
86 """
87 total_words = len(words)
88
89 # Count words per speaker
90 speaker_counts = {}
91 for w in words:
92 speaker_counts[w["speaker"]] = speaker_counts.get(w["speaker"], 0) + 1
93
94 # Filter speakers with < 5% word share
95 valid_speakers = [
96 int(s) for s, count in speaker_counts.items()
97 if (count / total_words) > 0.05
98 ]
99
100 print(f"๐ฅ Speakers detected: {len(speaker_counts)}, valid: {len(valid_speakers)}")
101 for spk, count in speaker_counts.items():
102 pct = (count / total_words) * 100
103 valid = int(spk) in valid_speakers
104 print(f" Speaker {spk}: {count} words ({pct:.1f}%) {'โ
' if valid else 'โ filtered'}")
105
106 # Filter words and group into speaker segments
107 valid_words = [w for w in words if w["speaker"] in valid_speakers]
108 segments = []
109 current_seg = None
110
111 for w in valid_words:
112 if current_seg is None or current_seg["speaker"] != w["speaker"]:
113 if current_seg:
114 segments.append(current_seg)
115 current_seg = {"speaker": w["speaker"], "words": [w["word"]], "start": w.get("start", 0), "end": w.get("end", 0)}
116 else:
117 current_seg["words"].append(w["word"])
118 current_seg["end"] = w.get("end", current_seg["end"])
119 if current_seg:
120 segments.append(current_seg)
121
122 agent_map = agent_map or {}
123
124 formatted_segments = []
125 for s in segments:
126 spk_id = s.get("speaker")
127 speaker_name = agent_map.get(spk_id, f"Speaker {spk_id}")
128 words_text = " ".join(s["words"])
129 formatted_segments.append(f"{speaker_name}: {words_text}")
130
131 raw_transcript = "\n".join(formatted_segments)
132
133 # Confidence stats
134 avg_confidence = sum(w["confidence"] for w in valid_words) / len(valid_words) if valid_words else 0
135 low_conf_words = sum(1 for w in valid_words if w["confidence"] < 0.7)
136 print(f"๐ Deepgram confidence: avg={avg_confidence:.3f}, low-conf words={low_conf_words}/{len(valid_words)}")
137
138 return {
139 "raw_transcript": raw_transcript,
140 "valid_words": valid_words,
141 "valid_speakers": valid_speakers,
142 "segments": segments,
143 "avg_confidence": avg_confidence,
144 "low_conf_words": low_conf_words,
145 }
146 