# VoxCast Server

A self-hostable transcription server for VoxCast. Run it on a machine with a
strong GPU (or CPU) and point the VoxCast desktop client at it to offload
dictation, file conversion, meeting transcription, and live captions.

It speaks the OpenAI wire protocol, so any OpenAI-compatible client also works:
`POST /v1/audio/transcriptions` for batch, a small job API for long files, and
a WebSocket at `/v1/realtime` for streaming.

## What runs where

The transcription engine and model manager are the exact modules the desktop
client ships (imported from `../src`). Models are selected, downloaded, and
kept **on the server** — the client never needs a local model in remote mode.

## Endpoints

| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | `/healthz` | none | liveness |
| GET | `/v1/status` | Bearer | version, readiness, active + available models, GPU |
| GET | `/v1/models` | Bearer | list tiers (downloaded / loaded) |
| POST | `/v1/models/{tier}/download` | Bearer | download a tier onto the server |
| POST | `/v1/models/{tier}/select` | Bearer | make a tier the active model |
| POST | `/v1/audio/transcriptions` | Bearer | OpenAI sync transcription (short audio) |
| POST | `/v1/jobs` | Bearer | submit a long file → `{id}` |
| GET | `/v1/jobs/{id}` | Bearer | poll progress / fetch result |
| WS | `/v1/realtime` | Bearer | streaming transcription |

## Threat model (read before exposing beyond a trusted LAN)

VoxCast Server v1 is designed for a **trusted local network**:

- Transport is plain HTTP on the LAN (the client shows an "unencrypted"
  warning). Anyone who can capture LAN traffic can read audio and the API
  key. For anything beyond a trusted LAN, put a TLS reverse proxy in front.
- Discovery has no server identity: any machine on the network can answer
  the probe and pose as a server. The picker shows name AND ip:port —
  verify the IP matches your server before clicking. A wrong click would
  send the API key and audio to that machine.
- The API key is a single shared secret. On Windows it lives in
  `server.toml` under Program Files, which every LOCAL user of the server
  machine can read (standard Program Files ACLs) — acceptable when the
  server machine's users are trusted; do not host it on a shared
  multi-user box you do not trust.
- Docker host networking exposes the port on EVERY interface of the host.
  Do not use the host-networking compose file on an internet-facing machine
  without a firewall.

## Discovery ("Find server")

The desktop client's Settings → Remote server → "Find server" broadcasts a
UDP probe (port 8590); every server on the subnet answers with its name and
HTTP endpoint (never the API key). The responder only runs on a non-loopback
bind and is disabled with `VOXCAST_SERVER_DISCOVERY_ENABLED=false`. The
discovery port is fixed even when the HTTP port is customized — the reply
carries the real port. Broadcasts do not cross subnets or VPNs; enter the
address manually in that case.

## Auth

A Bearer API key is generated on first start and persisted into `server.toml`
(the Windows installer pre-generates it at install time). Paste it into the
VoxCast client (Settings → Remote server) — on Windows the Start menu entry
"VoxCast Server API key" opens it. Set a fixed key via
`VOXCAST_SERVER_API_KEY` to override.

## Configuration

Environment (`VOXCAST_SERVER_*`) or `server.toml` next to the exe / in
`/etc/voxcast-server/`. Keys: `host`, `port`, `api_key`, `model` (auto | base |
small | medium | large-v3-turbo), `device` (auto | cuda | cpu), `data_dir`,
`max_upload_mb`, `max_sync_audio_s`, `queue_size`, `discovery_enabled`.

## Run it

### Docker (recommended on Linux)

```bash
cd compute_server/deploy
docker compose up -d
docker compose logs | grep "API key"
```

Requires the NVIDIA driver + nvidia-container-toolkit for GPU. Install as a
service with `voxcast-server-docker.service`.

### Native Linux (systemd)

```bash
sudo compute_server/deploy/install.sh
journalctl -u voxcast-server | grep -A2 "API key"
```

Uses the NVIDIA pip wheels (driver-only host, no CUDA toolkit).

### Windows

Install `VoxCast-Server-Setup.exe`. The wizard asks for the port (default
8590), writes `server.toml` (LAN bind + fresh API key), registers the Windows
service (bundled WinSW) and opens the Windows Firewall — service and firewall
are on by default. Afterwards: on the desktop PC, VoxCast → Settings →
Remote server → "Find server"; the API key sits in the Start menu
("VoxCast Server API key"). TLS on a public FQDN is terminated by a reverse
proxy (the LAN default is plain HTTP, and the client warns about it).

## Development

```bash
# from the repo root, with the client venv
venv312\Scripts\python.exe compute_server\server_main.py
venv312\Scripts\python.exe -m pytest compute_server/tests -q
```
