Luigi's picture
recover volume meter scale
69b815b
raw
history blame
4.34 kB
from fastapi import FastAPI, WebSocket
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse
from app.asr_worker import create_recognizer, stream_audio
import json
from starlette.websockets import WebSocketDisconnect
app = FastAPI()
app.mount("/static", StaticFiles(directory="app/static"), name="static")
@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!")
recognizer = None
stream = None
orig_sr = 48000 # default fallback
try:
while True:
data = await websocket.receive()
kind = data.get("type")
# Handle config messages
if kind not in ("websocket.receive", "websocket.receive_bytes"):
print(f"[DEBUG main] Received control/frame: {data}")
continue
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":
# 1) sample rate
orig_sr = int(config_msg["sampleRate"])
print(f"[INFO main] Set original sample rate to {orig_sr}")
# 2) model & precision
model_id = config_msg.get("model")
precision = config_msg.get("precision")
print(f"[INFO main] Selected model: {model_id}, precision: {precision}")
# 3) hotwords & boost score
hotwords = config_msg.get("hotwords", [])
hotwords_score = float(config_msg.get("hotwordsScore", 0.0))
print(f"[INFO main] Hotwords: {hotwords}, score: {hotwords_score}")
# 4) create recognizer with biasing
recognizer = create_recognizer(
model_id,
precision,
hotwords=hotwords,
hotwords_score=hotwords_score
)
stream = recognizer.create_stream()
print("[INFO main] WebSocket connection accepted; created a streaming context.")
continue
# Don't process audio until after config
if recognizer is None or stream is None:
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, 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 kind == "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, 1.0)
# print(f"[INFO main] Sending → partial='{result[:30]}…', volume={vol_to_send:.4f}")
await websocket.send_json({
"partial": result,
"volume": min(rms, 1.0)
})
except Exception as e:
print(f"[ERROR main] Unexpected exception: {e}")
try:
await websocket.close()
except:
pass
print("[INFO main] WebSocket closed, cleanup complete.")