File size: 2,098 Bytes
68b18cf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""
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"