File size: 3,846 Bytes
2318eae
 
 
 
0d6899b
2318eae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1d28d11
2318eae
1d28d11
2318eae
1d28d11
 
7c3f2af
1d28d11
7c3f2af
2318eae
 
7c3f2af
1d28d11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7c3f2af
 
 
0d6899b
1d28d11
 
 
7c3f2af
1d28d11
7c3f2af
 
1d28d11
 
 
 
 
 
 
 
 
 
7c3f2af
 
1d28d11
 
 
7c3f2af
1d28d11
 
 
 
7c3f2af
 
1d28d11
7c3f2af
 
1d28d11
2318eae
 
 
1d28d11
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from fastapi import FastAPI, WebSocket
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse
from app.asr_worker import create_recognizer, stream_audio, finalize_stream
import json

app = FastAPI()

app.mount("/static", StaticFiles(directory="app/static"), name="static")

recognizer = create_recognizer()

@app.get("/")
async def root():
    with open("app/static/index.html") as f:
        return HTMLResponse(f.read())


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    print("[DEBUG main] ▶ Attempting to accept WebSocket…")
    await websocket.accept()
    print("[DEBUG main] ▶ WebSocket.accept() returned → client is connected!")

    # Immediately create a new stream per client
    stream = recognizer.create_stream()
    orig_sr = 48000  # default fallback
    print("[INFO main] WebSocket connection accepted; created a streaming context.")

    try:
        while True:
            data = await websocket.receive()
            kind = data.get("type")

            # Debug: log any event we don't handle explicitly
            if kind not in ("websocket.receive", "websocket.receive_bytes"):
                print(f"[DEBUG main] Received control/frame: {data}")
                # If client cleanly disconnected, finalize and break
                if kind == "websocket.disconnect":
                    print(f"[INFO main] Client disconnected (code={data.get('code')}). Flushing final transcript...")
                    final = finalize_stream(stream, recognizer)
                    await websocket.send_json({"final": final})
                    break
                continue

            # Handle text (config) frame
            if kind == "websocket.receive" and "text" in data:
                raw = data["text"]
                try:
                    config_msg = json.loads(raw)
                except Exception as e:
                    print(f"[ERROR main] JSON parse failed: {e}")
                    continue
                if config_msg.get("type") == "config":
                    orig_sr = int(config_msg["sampleRate"])
                    print(f"[INFO main] Set original sample rate to {orig_sr}")
                    continue

            # If it’s a text payload but with bytes (some FastAPI versions put audio under 'text'!)  
            if kind == "websocket.receive" and "bytes" in data:
                raw_audio = data["bytes"]
                print(f"[INFO main] (text+bytes) Received audio chunk: {len(raw_audio)} bytes")
                result, rms = stream_audio(raw_audio, stream, recognizer, orig_sr)
                vol_to_send = min(rms * 20.0, 1.0)
                print(f"[INFO main] Sending → partial='{result[:30]}…', volume={vol_to_send:.4f}")
                await websocket.send_json({"partial": result, "volume": vol_to_send})
                continue

            elif isinstance(data, dict) and data.get("type") == "websocket.receive_bytes":
                raw_audio = data["bytes"]
                print(f"[INFO main] Received audio chunk: {len(raw_audio)} bytes")

                # This will also print its own debug info (see asr_worker.py)
                result, rms = stream_audio(raw_audio, stream, recognizer, orig_sr)

                vol_to_send = min(rms * 20.0, 1.0)
                print(f"[INFO main] Sending → partial='{result[:30]}…', volume={vol_to_send:.4f}")

                await websocket.send_json({
                    "partial": result,
                    "volume": vol_to_send
                })
    except Exception as e:
        print(f"[ERROR main] Unexpected exception: {e}")
        final = finalize_stream(stream, recognizer)
        await websocket.send_json({"final": final})
        await websocket.close()
        print("[INFO main] WebSocket closed, cleanup complete.")