Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 55 additions & 53 deletions .github/PYPI_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**S**trategic **H**am **R**adio **A**utonomous **Q**uery and **K**ontrol System

An AI-powered orchestrator for ham radio operations, emergency communications, and field-to-HQ coordination. One install gives you the API, web UI, and optional remote SDR receiver.
AI-powered orchestration for ham radio operations, emergency communications, and field-to-HQ coordination. One install provides the FastAPI backend, bundled web UI, and optional remote SDR receiver. Supports REACT-style reasoning, specialized agents (radio TX/RX, whitelist, SMS/WhatsApp, GIS, propagation), and tools for relay, TTS, and callsign registration.

---

Expand All @@ -12,38 +12,39 @@ An AI-powered orchestrator for ham radio operations, emergency communications, a
pip install radioshaq
```

**Optional (for SDR hardware):** `pip install radioshaq[sdr]` (RTL-SDR) or `radioshaq[hackrf]` (HackRF).

**Requirements:** Python 3.11+

**License notice:** RadioShaq is distributed under GPL-2.0-only. Official CLI and web UI require explicit license acceptance before normal use.
**Optional extras:**

| Extra | Purpose |
|-------|---------|
| `radioshaq[sdr]` | RTL-SDR for remote listen-only receiver |
| `radioshaq[hackrf]` | HackRF for remote receiver (non-Windows) |
| `radioshaq[audio]` | Local ASR (Whisper, Voxtral) |
| `radioshaq[voice_tx]` | Play audio to rig (sounddevice, soundfile, pydub) |
| `radioshaq[voice_rx]` | Capture + VAD for voice pipeline |
| `radioshaq[tts_kokoro]` | Local TTS (Kokoro, no API key) |
| `radioshaq[metrics]` | Prometheus `/metrics` endpoint |

**License:** RadioShaq is distributed under **GPL-2.0-only**. The CLI and web UI require license acceptance before normal use (interactive prompt or `RADIOSHAQ_LICENSE_ACCEPTED=1`).

---

## Easiest way to get started: interactive setup
## Quick start

From a project directory (or the repo root), run:
**1. Interactive setup** (recommended)

```bash
radioshaq setup
```

This walks you through:

- **Mode** — field, hq, or receiver
- **Database** — use Docker Postgres or an existing URL
- **Secrets** — JWT secret, LLM API key (optional)
- **Config** — writes `.env` and `config.yaml`, can start Docker and run migrations
Guides you through mode (field / hq / receiver), database (Docker or URL), JWT secret, optional LLM API key, and radio/voice options. Writes `.env` and `config.yaml`, can start Docker Postgres and run migrations.

**Minimal prompts:** `radioshaq setup --quick` (mode + “use Docker?” then defaults).
- `radioshaq setup --quick` — minimal prompts (mode + Docker?), then defaults
- `radioshaq setup --no-input --mode field` — non-interactive (CI); optional `--db-url`, `--config-dir`
- `radioshaq setup --reconfigure` — update existing config without starting over

**Non-interactive (CI/scripts):** `radioshaq setup --no-input --mode field` (optionally `--db-url postgresql://...`).

**Reconfigure:** `radioshaq setup --reconfigure` to update existing config without starting over.

---

## Run the API and web UI
**2. Run API and web UI**

```bash
radioshaq run-api
Expand All @@ -53,21 +54,17 @@ radioshaq run-api
- **Web UI:** http://localhost:8000/
- **Health:** http://localhost:8000/health

Default host: `0.0.0.0`, port: `8000`. Override with `--host` and `--port`.

---
Default bind: `0.0.0.0:8000`. Use `--host` and `--port` to override.

## Get a token (auth)
**3. Get a token**

Most API calls need a Bearer JWT:

```bash
radioshaq token --subject op1 --role field --station-id STATION-01
```

Then set `RADIOSHAQ_TOKEN` to the printed value, or pass it in requests. Roles: `field`, `hq`, `receiver`.

**Check API from the CLI:**
Set `RADIOSHAQ_TOKEN` to the printed value. Roles: `field`, `hq`, `receiver`.

```bash
radioshaq health
Expand All @@ -76,64 +73,69 @@ radioshaq health --ready

---

## CLI at a glance
## CLI reference

API base URL: `RADIOSHAQ_API` (default `http://localhost:8000`). Commands that call the API require `RADIOSHAQ_TOKEN` unless noted.

| Command | What it does |
|--------|------------------|
| **setup** | |
| Command | Description |
|---------|-------------|
| **Setup** | |
| `radioshaq setup` | Interactive setup: .env, config.yaml, optional Docker and migrations |
| `radioshaq setup --quick` | Minimal prompts (mode, use Docker?), then defaults |
| `radioshaq setup --no-input --mode field` | Non-interactive for CI; optional `--db-url`, `--config-dir` |
| `radioshaq setup --reconfigure` | Update existing config (merge sections) |
| `radioshaq setup --quick` | Minimal prompts |
| `radioshaq setup --no-input --mode field` | Non-interactive; optional `--db-url`, `--config-dir` |
| `radioshaq setup --reconfigure` | Update existing config |
| **Server & auth** | |
| `radioshaq run-api` | Start FastAPI server (and web UI at /). Options: `--host`, `--port`, `--reload` |
| `radioshaq run-receiver` | Start remote SDR receiver (port 8765). Set `JWT_SECRET`, `STATION_ID`, `HQ_URL` |
| `radioshaq token` | Get JWT. Options: `--subject`, `--role`, `--station-id`, `--base-url` |
| `radioshaq health` | Liveness check; `radioshaq health --ready` for readiness |
| **Callsigns** (require `RADIOSHAQ_TOKEN`) | |
| `radioshaq token --subject X --role Y [--station-id Z]` | Get JWT; print `access_token` |
| `radioshaq health` | Liveness; `radioshaq health --ready` for readiness |
| **Callsigns** | |
| `radioshaq callsigns list` | List registered callsigns |
| `radioshaq callsigns add <callsign>` | Register a callsign |
| `radioshaq callsigns remove <callsign>` | Remove from whitelist |
| `radioshaq callsigns remove <callsign>` | Remove from registry |
| `radioshaq callsigns register-from-audio <file>` | Register from audio (ASR) |
| **Messages** | |
| `radioshaq message process <text>` | Send message through REACT orchestrator |
| `radioshaq message inject <text>` | Inject into RX path (demo). Options: `--band`, `--mode`, `--source-callsign` |
| `radioshaq message whitelist-request <text>` | Whitelist request (orchestrator + optional TTS) |
| `radioshaq message relay <msg> --source-band X --target-band Y` | Relay message between bands |
| `radioshaq message process "<text>"` | Send message through REACT orchestrator |
| `radioshaq message inject "<text>"` | Inject into RX path (demo). Options: `--band`, `--mode`, `--source-callsign`, `--destination-callsign` |
| `radioshaq message whitelist-request "<text>"` | Whitelist request (orchestrator; optional TTS reply) |
| `radioshaq message relay "<msg>" --source-band X --target-band Y` | Relay message between bands |
| **Transcripts** | |
| `radioshaq transcripts list` | List transcripts. Options: `--callsign`, `--band`, `--since`, `--limit` |
| `radioshaq transcripts list` | List transcripts. Options: `--callsign`, `--band`, `--mode`, `--since`, `--limit` |
| `radioshaq transcripts get <id>` | Get one transcript |
| `radioshaq transcripts play <id>` | Play transcript as TTS over radio |
| **Radio** | |
| `radioshaq radio bands` | List bands |
| `radioshaq radio send-tts <message>` | Send TTS over radio. Options: `--frequency-hz`, `--mode` |
| `radioshaq radio send-tts "<message>"` | Send TTS over radio. Options: `--frequency-hz`, `--mode` |
| **Config** | |
| `radioshaq config show` | Show LLM, memory, overrides from config file (keys redacted). Option: `--section llm|memory|overrides` |
| **Launch (dev)** | |
| `radioshaq launch docker` | Start Docker Compose (Postgres; optional `--hindsight`) |
| `radioshaq launch pm2` | Start Postgres + API under PM2 (optional `--hindsight`) |

Use `radioshaq --help` and `radioshaq <command> --help` for options. API base URL: `RADIOSHAQ_API` (default `http://localhost:8000`).
Use `radioshaq --help` and `radioshaq <command> --help` for options.

---

## Remote receiver (SDR listen-only)
## Remote receiver (SDR)

For a listen-only station (e.g. Raspberry Pi + RTL-SDR) that streams to HQ:

```bash
pip install radioshaq[sdr] # or radioshaq[hackrf] for HackRF
pip install radioshaq[sdr] # or radioshaq[hackrf] for HackRF (non-Windows)
export JWT_SECRET=your-secret
export STATION_ID=RECEIVER-01
export HQ_URL=http://your-hq:8000
radioshaq run-receiver
```

HQ accepts uploads at `POST /receiver/upload` (Bearer JWT). Default receiver port: `8765` (`--port` to change).
HQ accepts uploads at `POST /receiver/upload` (Bearer JWT). Receiver default port: `8765` (`--port` to change).

---

## After install (no interactive setup)

If you prefer to configure by hand:
## Manual configuration (no interactive setup)

1. **Database:** Set `DATABASE_URL` or `POSTGRES_*` (and run migrations with your Alembic config).
2. **Config:** Copy `config.example.yaml` to `config.yaml` and set `mode`, `database`, `auth`, etc. See [Configuration](https://radioshaq.readthedocs.io/configuration/).
1. **Database:** Set `DATABASE_URL` or `RADIOSHAQ_DATABASE__POSTGRES_URL`; run migrations with your Alembic config.
2. **Config:** Copy `config.example.yaml` to `config.yaml` and set `mode`, `database`, `auth`, `llm`, etc.
3. **Start:** `radioshaq run-api`.

---
Expand Down
71 changes: 49 additions & 22 deletions .github/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
# RadioShaq

Monorepo for **RadioShaq**: ham radio AI orchestration and remote SDR reception. One main app (single PyPI package); Python is managed with [uv](https://github.com/astral-sh/uv).
Monorepo for **RadioShaq**: AI-powered ham radio orchestration, emergency communications, and remote SDR reception. One main application (single PyPI package); Python is managed with [uv](https://github.com/astral-sh/uv).

**What this repo does**
**RadioShaq** — **S**trategic **H**am **R**adio **A**utonomous **Q**uery and **K**ontrol System — is an autonomous agent that understands natural language requests, plans steps, and delegates to specialized sub-agents and tools. It provides a FastAPI backend, React (Vite) web UI, PostgreSQL + PostGIS + Alembic, and optional real radios and SDR. The **remote receiver** (listen-only SDR station) is bundled; run it with `radioshaq run-receiver`.

- **RadioShaq** — AI-powered orchestrator for ham radio, emergency comms, and field–HQ coordination. FastAPI backend, React (Vite) web UI, Postgres + Alembic, optional real radios and SDR. The **remote receiver** (SDR listen-only station) is bundled; run with `radioshaq run-receiver`.
---

## What’s in this repo

- **radioshaq/** — Main application (single installable package)
- **radioshaq/** — Python package: API, REACT orchestrator, agents (radio_tx, radio_rx, radio_rx_audio, whitelist, sms, whatsapp, gis, propagation, scheduler), tools (send_audio_over_radio, relay_message_between_bands, callsign list/register), compliance (band plans, TX audit), voice pipeline (capture → VAD → ASR → MessageBus)
- **web-interface/** — React frontend (Vite + TypeScript): Map (operator/emergency locations), Transcripts, Callsigns, Messages, Radio, Emergency, Audio config, Settings
- **tests/** — pytest (unit + integration)
- **infrastructure/** — Docker Compose (Postgres, optional Hindsight), PM2, Alembic, AWS Lambda
- **scripts/** — Demos and utilities
- **docs/** — Quick start, configuration, API reference, radio usage, map configuration

---

## Features (from the implementation)

- **REACT loop** — Reasoning → Evaluation → Acting → Communicating → Tracking; Task Judge and turn/token limits
- **Modes** — `field`, `hq`, `receiver` (config-driven)
- **API** — Auth (JWT), health, messages (process, whitelist-request, inject, relay, from-audio), transcripts, callsigns (list, register, register-from-audio, contact preferences), radio (bands, status, send-tts, send-audio, propagation), GIS (location, operators-nearby, emergency-events), emergency (request, approve/reject, events stream), receiver upload, inject, internal bus, Twilio (SMS/WhatsApp), audio config, config overrides (LLM, memory), memory blocks/summaries, optional Prometheus metrics
- **Web UI** — License gate; pages: Audio config, Emergency, Callsigns, Messages, Transcripts, Radio, Map (OpenStreetMap or Google Maps, operator/emergency locations), Settings
- **Relay** — Band-to-band (and optional SMS/WhatsApp) with optional scheduled delivery and relay delivery worker
- **Compliance** — Region-based band restrictions (FCC, CEPT, etc.), band allowlist, TX audit

---

Expand Down Expand Up @@ -66,7 +87,7 @@ uv run alembic -c infrastructure/local/alembic.ini upgrade head
uv run python -m radioshaq.api.server
```

From **repo root**, Postgres and migrations can be run as:
From **repo root**:

```bash
cd radioshaq/infrastructure/local && docker compose up -d postgres && cd ../../..
Expand Down Expand Up @@ -103,15 +124,15 @@ Most endpoints require a Bearer JWT. Request a token (no prior auth in dev), the

```powershell
$r = Invoke-RestMethod -Method Post -Uri "http://localhost:8000/auth/token?subject=op1&role=field&station_id=STATION-01"
$env:TOKEN = $r.access_token
Invoke-RestMethod -Uri "http://localhost:8000/auth/me" -Headers @{ Authorization = "Bearer $env:TOKEN" }
$env:RADIOSHAQ_TOKEN = $r.access_token
Invoke-RestMethod -Uri "http://localhost:8000/auth/me" -Headers @{ Authorization = "Bearer $env:RADIOSHAQ_TOKEN" }
```

**Bash:**

```bash
TOKEN=$(curl -s -X POST "http://localhost:8000/auth/token?subject=op1&role=field&station_id=STATION-01" | jq -r .access_token)
curl -H "Authorization: Bearer $TOKEN" http://localhost:8000/auth/me
export RADIOSHAQ_TOKEN=$(curl -s -X POST "http://localhost:8000/auth/token?subject=op1&role=field&station_id=STATION-01" | jq -r .access_token)
curl -H "Authorization: Bearer $RADIOSHAQ_TOKEN" http://localhost:8000/auth/me
```

Roles: `field`, `hq`, `receiver`. Set `RADIOSHAQ_TOKEN` to use the CLI below.
Expand All @@ -125,9 +146,11 @@ Roles: `field`, `hq`, `receiver`. Set `RADIOSHAQ_TOKEN` to use the CLI below.
| `radioshaq message process "your request"` | Send message through REACT orchestrator |
| `radioshaq message inject "text"` | Inject into RX path (demo). Options: `--band`, `--source-callsign` |
| `radioshaq message relay "msg" --source-band 40m --target-band 2m` | Relay between bands |
| `radioshaq transcripts list` | List transcripts. Options: `--callsign`, `--band`, `--destination-only` |
| `radioshaq transcripts list` | List transcripts. Options: `--callsign`, `--band`, `--since`, `--limit` |
| `radioshaq callsigns list` | List registered callsigns |
| `radioshaq callsigns add <callsign>` | Register a callsign |
| `radioshaq radio bands` | List bands |
| `radioshaq radio send-tts "message"` | Send TTS over radio |

API base URL: `RADIOSHAQ_API` (default `http://localhost:8000`). Use `radioshaq --help` and `radioshaq <command> --help` for options.

Expand All @@ -139,13 +162,16 @@ With the API running, in a second terminal from **radioshaq/**:
uv run python scripts/demo/run_demo.py
```

Gets a token, injects on 40m, relays to 2m, and polls `/transcripts`. See [radioshaq/scripts/demo/README.md](radioshaq/scripts/demo/README.md).
Gets a token, injects on 40m, relays to 2m, and polls `/transcripts`. See [radioshaq/scripts/demo/README.md](radioshaq/scripts/demo/README.md) and docs under `radioshaq/scripts/demo/docs/`.

### API calls
### API highlights

- **Process a message:** `POST /messages/process` with JSON `{"message": "your request"}` and header `Authorization: Bearer <token>`.
- **Transcripts:** `GET /transcripts?callsign=<callsign>&destination_only=true&band=<band>` for messages for you on a band.
- See **http://localhost:8000/docs** for the full OpenAPI spec.
- **Transcripts:** `GET /transcripts?callsign=<callsign>&band=<band>&destination_only=true`.
- **Relay:** `POST /messages/relay` with message, source_band, target_band, optional target_channel (radio/sms/whatsapp).
- **GIS:** `POST /gis/location`, `GET /gis/location/{callsign}`, `GET /gis/operators-nearby`, `GET /gis/emergency-events`.
- **Emergency:** `POST /emergency/request`, `GET /emergency/events`, `POST /emergency/events/{id}/approve` or `/reject`.
- Full OpenAPI spec at **http://localhost:8000/docs**.

---

Expand All @@ -154,8 +180,7 @@ Gets a token, injects on 40m, relays to 2m, and polls `/transcripts`. See [radio
From **radioshaq/** (SDR listen-only station streaming to HQ):

```bash
uv sync --extra dev --extra test
# With hardware: uv sync --extra sdr # or --extra hackrf
uv sync --extra sdr # or --extra hackrf on non-Windows

# Set env then run
# JWT_SECRET=... STATION_ID=RECEIVER-01 HQ_URL=http://your-hq:8000
Expand Down Expand Up @@ -189,6 +214,8 @@ Frontend: `cd web-interface && npm install && npm run dev`.
| [docs/configuration.md](docs/configuration.md) | Config file, env vars, interactive setup |
| [docs/radio-usage.md](docs/radio-usage.md) | Rig models, CAT, hardware |
| [docs/api-reference.md](docs/api-reference.md) | API overview |
| [docs/index.md](docs/index.md) | Agent overview, REACT loop, agents, tools, modes |
| [radioshaq/docs/map-configuration.md](radioshaq/docs/map-configuration.md) | Map provider (OSM/Google), tile sources |
| [radioshaq/README.md](radioshaq/README.md) | App install, auth, demo, monitoring |

---
Expand All @@ -197,15 +224,15 @@ Frontend: `cd web-interface && npm install && npm run dev`.

```
radioshaq/ # Main application (single PyPI package)
├── radioshaq/ # Python package (API, radio, audio, orchestrator)
├── radioshaq/ # Python package (API, radio, audio, orchestrator, agents, tools)
│ └── remote_receiver/ # Bundled SDR receiver (radioshaq run-receiver)
├── web-interface/ # React frontend (Vite + TypeScript)
├── tests/ # pytest (unit + integration)
├── infrastructure/ # Docker, PM2, AWS Lambda, Alembic
└── scripts/ # Demo and utilities
├── web-interface/ # React frontend (Vite + TypeScript)
├── tests/ # pytest (unit + integration)
├── infrastructure/ # Docker, PM2, AWS Lambda, Alembic
└── scripts/ # Demo and utilities

docs/ # Quick-start, configuration, snippets
.github/ # Workflows, PYPI_README.md
docs/ # Quick-start, configuration, API, radio, index
.github/ # Workflows, PYPI_README.md
```

---
Expand Down
Loading