import asyncio import os from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends from api.state import state, Status from config import load as load_config from output import list_transcripts router = APIRouter() _ws_clients: list[WebSocket] = [] # --------------------------------------------------------------------------- # Auth stub — replaced by auth.py in Task 13. # current_user() returns a dict with at least {"username": str, "output_dir": str}. # Until auth is wired up, every request runs as an anonymous guest using the # global output path from config. # --------------------------------------------------------------------------- def _guest_user() -> dict: cfg = load_config() return {"username": "guest", "output_dir": cfg["output"]["path"]} def current_user(user: dict = Depends(_guest_user)) -> dict: return user # --------------------------------------------------------------------------- # Endpoints # --------------------------------------------------------------------------- @router.get("/status") async def get_status(): return {"status": state.status} @router.post("/toggle") async def toggle_recording(user: dict = Depends(current_user)): from api.pipeline import run_pipeline if state.status == Status.RECORDING: asyncio.create_task(run_pipeline()) return {"action": "stopped"} if state.status == Status.IDLE: from audio import AudioRecorder state._recorder = AudioRecorder() state._recorder.start() state.recording_user = user["username"] state._recording_output_dir = user["output_dir"] state._recording_instructions = user.get("instructions", "") await state.set_status(Status.RECORDING) return {"action": "started"} return {"action": "busy", "status": state.status} @router.post("/instructions") async def set_instructions(body: dict, user: dict = Depends(current_user)): # Instructions are per-user; stored on state only for the active recording. # Full per-user persistence comes in Task 13. user["instructions"] = body.get("instructions", "") return {"ok": True} @router.get("/transcripts") async def get_transcripts(user: dict = Depends(current_user)): return list_transcripts(user["output_dir"]) @router.get("/config") async def get_config(): return load_config() @router.put("/config") async def put_config(body: dict): cfg = load_config() cfg.update(body) return cfg @router.post("/open") async def open_file(body: dict): import subprocess path = body.get("path", "") if path and os.path.exists(path): subprocess.Popen(["xdg-open", path]) return {"ok": True} @router.websocket("/ws") async def websocket_endpoint(ws: WebSocket): await ws.accept() _ws_clients.append(ws) try: while True: await ws.receive_text() except WebSocketDisconnect: if ws in _ws_clients: _ws_clients.remove(ws) async def broadcast(message: dict): for ws in list(_ws_clients): try: await ws.send_json(message) except Exception: if ws in _ws_clients: _ws_clients.remove(ws)