Spaces:
Paused
Paused
| """ | |
| ASR + Audio Diarizer β speaker-separated evidence ledger | |
| A_t = {S_0(t), S_1(t), S_2(t), N(t), E(t)} | |
| S_0 = user, S_1 = TV/background, S_2 = other speaker, N = noise, E = events | |
| Browser-side speech recognition provides the transcript. | |
| This module assigns speaker labels and confidence. | |
| """ | |
| import hashlib | |
| import time | |
| from .stream_state import AudioChunk, sha256_text | |
| def process_transcript(text: str, state) -> AudioChunk: | |
| """Process a transcript chunk from the browser. | |
| The browser sends transcript text (from SpeechRecognition API). | |
| We assign speaker label "user" by default since it's the primary mic. | |
| """ | |
| chunk = AudioChunk( | |
| ts=time.time(), | |
| chunk_id=f"chunk_{int(time.time() * 1000)}", | |
| duration_ms=len(text) * 50, # rough estimate | |
| speaker="user", | |
| transcript=text.strip(), | |
| confidence=0.85, # browser ASR confidence placeholder | |
| sha256=sha256_text(text), | |
| is_speech=bool(text.strip()), | |
| ) | |
| return chunk | |
| def assign_speaker(text: str, existing_speakers: dict) -> str: | |
| """Heuristic speaker assignment. | |
| In a full system, this would use pyannote/WhisperX diarization. | |
| For now, we use simple heuristics: | |
| - If text matches known user patterns β "user" | |
| - If text seems like TV/background β "background" | |
| - Otherwise β "unknown" | |
| """ | |
| text_lower = text.lower() | |
| # Check if this looks like user instruction | |
| instruction_words = ["build", "make", "generate", "create", "show", "run", "fix", "code"] | |
| if any(w in text_lower for w in instruction_words): | |
| return "user" | |
| # Check if it matches existing user transcript patterns | |
| if "user" in existing_speakers: | |
| user_text = existing_speakers["user"].get("transcript", "").lower() | |
| # Simple word overlap check | |
| user_words = set(user_text.split()) | |
| text_words = set(text_lower.split()) | |
| overlap = len(user_words & text_words) | |
| if overlap > 2: | |
| return "user" | |
| # Default to unknown (could be TV, background, another person) | |
| return "unknown" | |