docs: split CLAUDE.md into path-scoped .claude/rules; fix dev/test commands
- CLAUDE.md trimmed to whole-repo facts (58 lines); subsystem guidance
moved to .claude/rules/{startos-package,fastapi-image,redaction,
audio-speech}.md with paths: frontmatter so each loads only when
matching files are touched
- .gitignore: track .claude/rules/ while keeping the rest of .claude/
(settings.local.json) ignored
- test-audio-with-speakers.sh: require audio-file arg in docs, replace
owner-specific SPARK_CONTROL/VLLM defaults with generic ones
(localhost dev server + Spark Control vLLM proxy), discover the
loaded LLM via /api/status since /v1/models lists audio models only
- document REDACTION_MAP_DB + CONNECTIVITY_LOG as required for local
dev (/data only exists in the container)
- prettier pass over startos/actions (formatting drift)
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
paths:
|
||||||
|
- "image/app/audio_proxy.py"
|
||||||
|
- "image/app/speech_models.py"
|
||||||
|
- "image/app/deep_health.py"
|
||||||
|
- "image/parakeet_patches/**"
|
||||||
|
- "scripts/test-audio-with-speakers.sh"
|
||||||
|
- "docs/AUDIO_API.md"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Audio / speech stack (Parakeet STT + Sortformer diarizer + Kokoro TTS on Spark 2)
|
||||||
|
|
||||||
|
## Changing the parakeet-asr container
|
||||||
|
|
||||||
|
- `image/parakeet_patches/` (`main.py`, `diarizer.py`) is an overlay copied into the `parakeet-asr` container by the "Reapply speech-model patches" dashboard action (`image/app/speech_models.py`). This is the **only** durable way to change that container — `docker exec` / pip changes inside it die on `docker rm`.
|
||||||
|
- **Never install `cuda-python` in parakeet-asr** to "fix" the startup warning about CUDA graphs being disabled. The warning is harmless; enabling the graph path crashes real decode with illegal memory access on this GPU/CUDA-13 stack (GB10/sm_121). The slow path served 11k+ requests with zero failures — leave it alone.
|
||||||
|
- Pin/constrain torch versions when pip-installing anything into NGC-based containers on the Sparks (ABI breaks otherwise); expect ARM64 wheel gaps and source builds (`--no-build-isolation` for torchaudio). Applies to `spark_embed` too.
|
||||||
|
|
||||||
|
## Testing audio endpoints
|
||||||
|
|
||||||
|
- Test with **real speech** (e.g. `say -o /tmp/t.wav --data-format=LEI16@16000 "<a couple of sentences>"`), not tones/silence — zero-token audio skips the decoder paths where crashes live.
|
||||||
|
- Send audio requests to Spark 2 **sequentially** in tests/scripts. Parallel audio requests can race (cuFFT → 503), and the single GPU serializes them anyway.
|
||||||
|
- End-to-end suite (hits the LIVE cluster):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/test-audio-with-speakers.sh <audio-file> # from repo root
|
||||||
|
```
|
||||||
|
|
||||||
|
`SPARK_CONTROL` defaults to `http://127.0.0.1:9999` (a running local dev server); point it at the installed package URL otherwise.
|
||||||
|
|
||||||
|
## API quirk
|
||||||
|
|
||||||
|
Spark Control's `/v1/models` lists *audio* models (STT model + Kokoro voices) by design — **not** the loaded LLM. Discover the LLM via `/api/status` (`vllm.current_model`).
|
||||||
|
|
||||||
|
Diarizer caps at 4 speakers (Sortformer `diar_sortformer_4spk-v1`).
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
paths:
|
||||||
|
- "image/**"
|
||||||
|
---
|
||||||
|
|
||||||
|
# FastAPI image (`image/`)
|
||||||
|
|
||||||
|
Standalone FastAPI app (Python ≥3.11; ships on `python:3.12-slim`; UI on port 9999; vanilla HTML/CSS/JS, no framework). Python has no configured linter/formatter — match the style of the file you're editing.
|
||||||
|
|
||||||
|
## Local dev (no StartOS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd image
|
||||||
|
python3 -m venv .venv && source .venv/bin/activate # one-time
|
||||||
|
pip install -e .
|
||||||
|
export SPARK1_HOST=<ip> SPARK1_USER=<user> SPARK2_HOST=<ip> SPARK2_USER=<user> SSH_KEY_PATH=<private-key>
|
||||||
|
# Required outside the container — these default to paths under /data, which only exists in the image
|
||||||
|
# (missing REDACTION_MAP_DB crashes startup; missing CONNECTIVITY_LOG 500s /api/status):
|
||||||
|
export REDACTION_MAP_DB=/tmp/redaction_maps.db CONNECTIVITY_LOG=/tmp/connectivity.json
|
||||||
|
uvicorn app.server:app --host 0.0.0.0 --port 9999 --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Other env vars: `BIND_PORT`, `MODELS_YAML`, `SSH_DIR`, `SSH_KNOWN_HOSTS`, `MODELS_OVERRIDES`, `SERVICES_OVERRIDES`.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
No pytest harness — each suite is a standalone script run with the `image/.venv` interpreter (system python3 has no deps). See the redaction and audio rules for the suites themselves.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Pydantic request models go at **module scope**, never inside a `build_router()` body (FastAPI silently 422s otherwise).
|
||||||
|
- New external-facing endpoints get documented in `docs/` (`AUDIO_API.md`, `EMBEDDINGS.md`, `REDACTION_GATEWAY.md`) and noted in release notes.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
- `image/app/server.py` — FastAPI entry; routers live in sibling modules (`audio_proxy.py`, `llm_proxy.py`, `embeddings_proxy.py`, `redaction_gateway.py`, `swap.py`, `health.py`, `deep_health.py`, `connectivity.py`, …).
|
||||||
|
- `image/app/static/` — the dashboard UI.
|
||||||
|
- `image/models.yaml` — vLLM model catalog bundled into the image.
|
||||||
|
- `image/spark_embed/` — Dockerfile + app for the embeddings container; built ON a Spark (ARM64, NGC PyTorch base — see the audio/cluster rule for NGC torch-pinning caveats).
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
paths:
|
||||||
|
- "image/app/redaction/**"
|
||||||
|
- "image/app/redaction_gateway.py"
|
||||||
|
- "docs/REDACTION_GATEWAY.md"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Redaction (`/scrub` + `/rehydrate`)
|
||||||
|
|
||||||
|
- `image/app/redaction/scrub.py` + `test_scrub_leak.py` are vendored **byte-for-byte** from the CRM repo (sha recorded in `redaction/__init__.py`). **Never edit them here** — change them in the CRM repo, re-vendor (`cp`), update the sha, re-run the leak test.
|
||||||
|
- The gateway around the vendored scrubber is `image/app/redaction_gateway.py`. Its token-map store lives on `/data` (`REDACTION_MAP_DB`, default `/data/redaction_maps.db`) and fails closed if it can't open — set the env var when running outside the container.
|
||||||
|
|
||||||
|
## Test suites — both must pass before shipping ANY redaction change
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd image
|
||||||
|
.venv/bin/python -m app.redaction.test_gateway # /scrub + /rehydrate acceptance; offline, no cluster needed
|
||||||
|
.venv/bin/python app/redaction/test_scrub_leak.py # vendored golden-file leak test; offline
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep the leak test green against the vendored `scrub.py` after any re-vendor.
|
||||||
|
|
||||||
|
Policy context: scrubbed text via `/scrub` is the **only** sanctioned path toward frontier/cloud models — see the whole-repo privacy rule in CLAUDE.md.
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
paths:
|
||||||
|
- "package/**"
|
||||||
|
---
|
||||||
|
|
||||||
|
# StartOS package (`package/`)
|
||||||
|
|
||||||
|
TypeScript wrapper that ships the Docker image as an s9pk. `@start9labs/start-sdk` pinned `1.3.3`, Node ≥22, bundled by `@vercel/ncc`.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd package
|
||||||
|
npm i # one-time
|
||||||
|
make x86 # typecheck + ncc bundle + docker build + pack → spark-control_x86_64.s9pk
|
||||||
|
make install # sideload to the Start9 server; needs "host: http(s)://<server>.local" in ~/.startos/config.yaml
|
||||||
|
npm run check # tsc --noEmit — run after any startos/ edit; make x86 also runs it
|
||||||
|
npm run prettier # prettier --write startos (no semicolons, single quotes, trailing commas)
|
||||||
|
```
|
||||||
|
|
||||||
|
`make aarch64` for ARM Start9 servers. `make install` picks the newest `*.s9pk` in `package/` and restarts the live spark-control service — get a go/no-go first.
|
||||||
|
|
||||||
|
## Versioning & release notes
|
||||||
|
|
||||||
|
- Version format is `X.Y.Z:N` (`:N` = revision). Bump in `package/startos/versions/v0_1_0.ts`; **replace** the release notes — never leave old notes behind under an extra key (any unknown key fails `tsc`).
|
||||||
|
- New external-facing endpoints get noted in release notes for downstream app developers (Recap Relay, Ten31 Transcripts, CRM, Signal Engine consume these APIs).
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
- `package/startos/` — manifest, interfaces, actions (`configureSparks`, `showPublicKey`), `versions/v0_1_0.ts` (current version string + release notes).
|
||||||
|
- The "Reapply speech-model patches" action is **not** a StartOS action — it's a dashboard action implemented in `image/app/speech_models.py`.
|
||||||
+2
-1
@@ -11,4 +11,5 @@ node_modules/
|
|||||||
dist/
|
dist/
|
||||||
build/
|
build/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.claude/
|
.claude/*
|
||||||
|
!.claude/rules/
|
||||||
|
|||||||
@@ -1,95 +1,52 @@
|
|||||||
# CLAUDE.md
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
Browser-based StartOS 0.4 package controlling a dual NVIDIA DGX Spark AI cluster: one-click vLLM model swaps, plus health, proxying, and APIs for speech (STT/diarization/TTS), embeddings, and redaction.
|
Browser-based StartOS 0.4 package controlling a dual NVIDIA DGX Spark AI cluster: one-click vLLM model swaps, plus health, proxying, and APIs for speech (STT/diarization/TTS), embeddings, and redaction.
|
||||||
|
|
||||||
|
Subsystem guidance lives in `.claude/rules/` and loads when matching files are touched: `startos-package.md` (build/versioning, `package/**`), `fastapi-image.md` (dev server/env/layout, `image/**`), `redaction.md` (vendoring + test gates), `audio-speech.md` (parakeet patches, cluster-container footguns, audio testing). **Read `audio-speech.md` before touching the Sparks' containers over SSH** — ops sessions don't trip the path scoping.
|
||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
|
|
||||||
- Two halves, always coordinated:
|
- Two halves, always coordinated:
|
||||||
- `image/` — standalone FastAPI app (Python ≥3.11; ships on `python:3.12-slim`; UI on port 9999; vanilla HTML/CSS/JS, no framework).
|
- `image/` — standalone FastAPI app (Python ≥3.11; UI on port 9999; vanilla HTML/CSS/JS).
|
||||||
- `package/` — StartOS 0.4 wrapper (TypeScript, `@start9labs/start-sdk` pinned `1.3.3`, Node ≥22, bundled by `@vercel/ncc`).
|
- `package/` — StartOS 0.4 wrapper (TypeScript) that ships the Docker image as an s9pk.
|
||||||
- Build host needs `start-cli`, Node ≥22 + npm, and Docker (the s9pk embeds the Docker image).
|
- Build host needs `start-cli`, Node ≥22 + npm, and Docker.
|
||||||
- Cluster runtimes live **on the Sparks, not in this repo** (`spark-vllm-docker`, the parakeet/kokoro/embeddings containers). This repo is the controller; it reaches them over SSH + HTTP.
|
- Cluster runtimes live **on the Sparks, not in this repo** (`spark-vllm-docker`, the parakeet/kokoro/embeddings containers). This repo is the controller; it reaches them over SSH + HTTP.
|
||||||
- Sparks are ARM64 (GB10 Grace-Blackwell, sm_121, CUDA 13). Services: vLLM `:8888` (Spark 1); `parakeet-asr` `:8000` (Parakeet TDT 0.6B v3 + Sortformer diarizer + TitaNet voiceprints), Kokoro TTS `:8880`, bge-m3 embeddings + Qdrant (Spark 2). See `docs/` for API contracts.
|
- Sparks are ARM64 (GB10 Grace-Blackwell, sm_121, CUDA 13). Services: vLLM `:8888` (Spark 1); `parakeet-asr` `:8000`, Kokoro TTS `:8880`, bge-m3 embeddings + Qdrant (Spark 2). See `docs/` for API contracts.
|
||||||
|
|
||||||
## Commands
|
## Commands (headlines — details in the scoped rules)
|
||||||
|
|
||||||
### Build & deploy the s9pk
|
|
||||||
```bash
|
```bash
|
||||||
cd package
|
(cd package && make x86) # build the s9pk; make install sideloads (restarts live service — ask first)
|
||||||
npm i # one-time
|
(cd image && uvicorn app.server:app --port 9999) # local dev — needs env vars, see fastapi-image rule
|
||||||
make x86 # typecheck + ncc bundle + docker build + pack → spark-control_x86_64.s9pk
|
(cd image && .venv/bin/python -m app.redaction.test_gateway) # offline redaction suite 1
|
||||||
make install # sideload to the Start9 server; needs "host: http://<server>.local" in ~/.startos/config.yaml
|
(cd image && .venv/bin/python app/redaction/test_scrub_leak.py) # offline redaction suite 2
|
||||||
|
./scripts/test-audio-with-speakers.sh <audio-file> # e2e audio — hits the LIVE cluster
|
||||||
```
|
```
|
||||||
`make aarch64` for ARM Start9 servers. `make install` picks the newest `*.s9pk` in `package/`.
|
|
||||||
|
|
||||||
### Local dev (FastAPI only, no StartOS)
|
|
||||||
```bash
|
|
||||||
cd image
|
|
||||||
python3 -m venv .venv && source .venv/bin/activate
|
|
||||||
pip install -e .
|
|
||||||
export SPARK1_HOST=<ip> SPARK1_USER=<user> SPARK2_HOST=<ip> SPARK2_USER=<user> SSH_KEY_PATH=<private-key>
|
|
||||||
uvicorn app.server:app --host 0.0.0.0 --port 9999 --reload
|
|
||||||
```
|
|
||||||
Other env vars: `BIND_PORT`, `MODELS_YAML`, `SSH_DIR`, `SSH_KNOWN_HOSTS`.
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
No pytest harness — each suite is a standalone script (that *is* how you run a single test):
|
|
||||||
```bash
|
|
||||||
cd image
|
|
||||||
python3 -m app.redaction.test_gateway # /scrub + /rehydrate acceptance; offline, no cluster needed
|
|
||||||
python3 app/redaction/test_scrub_leak.py # vendored golden-file leak test; offline
|
|
||||||
./scripts/test-audio-with-speakers.sh # (from repo root) end-to-end audio pipeline — hits the LIVE cluster
|
|
||||||
```
|
|
||||||
Both Python suites must pass before shipping anything touching redaction.
|
|
||||||
|
|
||||||
### Typecheck / format (TypeScript)
|
|
||||||
```bash
|
|
||||||
cd package
|
|
||||||
npm run check # tsc --noEmit — run after any startos/ edit; make x86 also runs it
|
|
||||||
npm run prettier # prettier --write startos (no semicolons, single quotes, trailing commas)
|
|
||||||
```
|
|
||||||
Python has no configured linter/formatter — match the style of the file you're editing.
|
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `image/app/server.py` — FastAPI entry; routers live in sibling modules (`audio_proxy.py`, `llm_proxy.py`, `embeddings_proxy.py`, `redaction_gateway.py`, `swap.py`, `health.py`, `deep_health.py`, `connectivity.py`, …).
|
- `image/app/` — FastAPI app (`server.py` entry, routers in sibling modules, `static/` dashboard UI).
|
||||||
- `image/app/static/` — the dashboard UI.
|
- `package/startos/` — StartOS manifest, interfaces, actions, version + release notes.
|
||||||
- `image/models.yaml` — vLLM model catalog bundled into the image.
|
- `docs/` — `AUDIO_API.md`, `EMBEDDINGS.md`, `REDACTION_GATEWAY.md` (consumer-facing API refs; update with API changes).
|
||||||
- `image/parakeet_patches/` — overlay (`main.py`, `diarizer.py`) copied into the `parakeet-asr` container on Spark 2 by the "Reapply speech-model patches" action. The **only** durable way to change that container.
|
- `README.md` (overview), `HANDOFF.md` (fresh-user install guide), `runbook.md` (ops notes), `known-issues.md`, `ROADMAP.md` (longer-term backlog — items move into "Current state" below when picked up).
|
||||||
- `image/app/redaction/` — `scrub.py` + `test_scrub_leak.py` vendored byte-for-byte from the CRM repo (sha in `__init__.py`). The gateway around it is `redaction_gateway.py`.
|
|
||||||
- `image/spark_embed/` — Dockerfile + app for the embeddings container; built ON a Spark (ARM64, NGC PyTorch base).
|
|
||||||
- `package/startos/` — manifest, interfaces, actions (`configureSparks`, `showPublicKey`), `versions/v0_1_0.ts` (current version string + release notes).
|
|
||||||
- `docs/` — `AUDIO_API.md`, `EMBEDDINGS.md`, `REDACTION_GATEWAY.md` (consumer-facing API refs; update them with API changes).
|
|
||||||
- `README.md` (overview), `HANDOFF.md` (fresh-user install guide), `runbook.md` (ops notes), `known-issues.md`.
|
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
- Version format is `X.Y.Z:N` (`:N` = revision). Bump in `package/startos/versions/v0_1_0.ts`; **replace** the release notes — never leave old notes behind under an extra key (any unknown key fails `tsc`).
|
- Every shipped change = version bump + release notes + rebuilt s9pk (version format `X.Y.Z:N`; details in the startos-package rule).
|
||||||
- Commit messages: `vX.Y.Z:N - short lowercase summary`. **Never add a Co-Authored-By / Claude attribution trailer.**
|
- Commit messages: `vX.Y.Z:N - short lowercase summary`. **Never add a Co-Authored-By / Claude attribution trailer.**
|
||||||
- Every shipped change = version bump + release notes + rebuilt s9pk (`make x86 && make install`).
|
|
||||||
- The package owner is non-technical: explain infra effects in plain English and get an explicit go/no-go before mutating the cluster.
|
- The package owner is non-technical: explain infra effects in plain English and get an explicit go/no-go before mutating the cluster.
|
||||||
- Pydantic request models go at **module scope**, never inside a `build_router()` body (FastAPI silently 422s otherwise).
|
|
||||||
- New external-facing endpoints get documented in `docs/` and noted in release notes for downstream app developers (Recap Relay, Ten31 Transcripts, CRM, Signal Engine consume these APIs).
|
- New external-facing endpoints get documented in `docs/` and noted in release notes for downstream app developers (Recap Relay, Ten31 Transcripts, CRM, Signal Engine consume these APIs).
|
||||||
|
|
||||||
## Always / Never
|
## Always / Never (cluster-wide)
|
||||||
|
|
||||||
**Always**
|
- **Always** confirm with the user before swap/stop/restart of anything on the live cluster. Read-only probes and dry-runs are fine without asking.
|
||||||
- Confirm with the user before swap/stop/restart of anything on the live cluster. Read-only probes and dry-runs are fine without asking.
|
- **Always** use the Spark's **IP** for HTTP probes — `.local` mDNS names can resolve IPv6-first and hang httpx (vLLM and friends bind IPv4 only). Never trust `.local` hostnames inside HTTP client code.
|
||||||
- Use the Spark's **IP** for HTTP probes — `.local` mDNS names can resolve IPv6-first and hang httpx (vLLM and friends bind IPv4 only).
|
- **Always** pass `SSH_KEY_PATH` / `-i <key>` explicitly in scripted SSH; non-interactive shells have no ssh-agent identities.
|
||||||
- Pass `SSH_KEY_PATH` / `-i <key>` explicitly in scripted SSH; non-interactive shells have no ssh-agent identities.
|
- **Never** route audio or transcripts to cloud services — speech stays on the LAN. (Scrubbed text via `/scrub` is the only sanctioned path toward frontier models.)
|
||||||
- Make parakeet-container changes via `image/parakeet_patches/` + the Reapply action. `docker exec` / pip changes inside the container die on `docker rm`.
|
- **Never** commit owner-specific hostnames, IPs, usernames, or names into package strings, UI text, or docs — this package gets shared; use placeholders (`<spark-1-ip>` style).
|
||||||
- Test audio endpoints with **real speech** (e.g. macOS `say`), not tones/silence — zero-token audio skips the decoder paths where crashes live.
|
- **Never** install `cuda-python` in `parakeet-asr` — crashes real decode on this GPU/CUDA-13 stack; full story in the audio-speech rule.
|
||||||
- Send audio requests to Spark 2 **sequentially** in tests/scripts. Parallel audio requests can race (cuFFT → 503), and the single GPU serializes them anyway.
|
|
||||||
- Pin/constrain torch versions when pip-installing anything into NGC-based containers on the Sparks (ABI breaks otherwise); expect ARM64 wheel gaps and source builds (`--no-build-isolation` for torchaudio).
|
|
||||||
- Keep the redaction leak tests green against the vendored `scrub.py` after any re-vendor.
|
|
||||||
|
|
||||||
**Never**
|
|
||||||
- Never install `cuda-python` in `parakeet-asr` to "fix" the startup warning about CUDA graphs being disabled. The warning is harmless; enabling the graph path crashes real decode with illegal memory access on this GPU/CUDA-13 stack. Leave it alone — the slow path served 11k+ requests with zero failures.
|
|
||||||
- Never edit `image/app/redaction/scrub.py` or `test_scrub_leak.py` here — change them in the CRM repo, re-vendor (`cp`), update the sha in `redaction/__init__.py`, re-run the leak test.
|
|
||||||
- Never commit owner-specific hostnames, IPs, usernames, or names into package strings, UI text, or docs — this package gets shared; use placeholders (`<spark-1-ip>` style).
|
|
||||||
- Never route audio or transcripts to cloud services — speech stays on the LAN. (Scrubbed text via `/scrub` is the only sanctioned path toward frontier models.)
|
|
||||||
- Never trust `.local` hostnames inside HTTP client code (see IPv6 note above) and never assume the ssh-agent is loaded.
|
|
||||||
- Never ship a redaction change without both redaction suites passing.
|
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
|
|
||||||
@@ -97,5 +54,5 @@ Python has no configured linter/formatter — match the style of the file you're
|
|||||||
- **In progress — Signal Engine "flakiness":** diagnosed, not a server bug — transient 1–4s unresponsiveness while the single GPU is continuously busy. Remedy is client-side; a drafted message (in-flight cap 2, hard ceiling 3 global across audio endpoints, retry-with-backoff on timeout/503) is with the owner to forward to that dev.
|
- **In progress — Signal Engine "flakiness":** diagnosed, not a server bug — transient 1–4s unresponsiveness while the single GPU is continuously busy. Remedy is client-side; a drafted message (in-flight cap 2, hard ceiling 3 global across audio endpoints, retry-with-backoff on timeout/503) is with the owner to forward to that dev.
|
||||||
- **Decided, not implemented:** remote access stays WireGuard/Tailscale split-tunnel — no public interface, so no API auth built; an empirical concurrency sweep is offered but needs the owner's explicit OK in a quiet window.
|
- **Decided, not implemented:** remote access stays WireGuard/Tailscale split-tunnel — no public interface, so no API auth built; an empirical concurrency sweep is offered but needs the owner's explicit OK in a quiet window.
|
||||||
- **Known limits:** `/health` blips while the GPU is busy (mitigated client-side); dual-channel can miss a quiet local word under loud remote bleed; the connectivity log misses sub-5s outages between 5s polls; diarizer caps at 4 speakers.
|
- **Known limits:** `/health` blips while the GPU is busy (mitigated client-side); dual-channel can miss a quiet local word under loud remote bleed; the connectivity log misses sub-5s outages between 5s polls; diarizer caps at 4 speakers.
|
||||||
- **Repo wart:** HEAD's message says `v0.13.0:4` but the commit contains everything through v0.18.0:0 — per-version commits for v0.14–v0.18 are missing. Keep commit messages accurate going forward.
|
- **Repo wart:** commit `367d986` is labeled `v0.13.0:4` but actually contains everything through v0.18.0:0 — per-version commits for v0.14–v0.18 are missing. Keep commit messages accurate going forward.
|
||||||
- **Next:** (1) owner forwards the concurrency note to the Signal Engine dev; (2) commit CLAUDE.md + ROADMAP.md; (3) run the concurrency sweep if the dev wants the measured knee; (4) add the `--memory` cap to parakeet-asr via the Reapply-patches action; (5) pick the next item from ROADMAP.md.
|
- **Next:** (1) owner forwards the concurrency note to the Signal Engine dev; (2) run the concurrency sweep if the dev wants the measured knee; (3) add the `--memory` cap to parakeet-asr via the Reapply-patches action; (4) pick the next item from ROADMAP.md.
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const inputSpec = InputSpec.of({
|
|||||||
parakeet_host: Value.text({
|
parakeet_host: Value.text({
|
||||||
name: 'Parakeet host (optional)',
|
name: 'Parakeet host (optional)',
|
||||||
description:
|
description:
|
||||||
'Override the host running the Parakeet STT container. Leave blank if Parakeet runs on Spark 2 — that\'s the default. Set this if you run Parakeet on Spark 1 or a different machine.',
|
"Override the host running the Parakeet STT container. Leave blank if Parakeet runs on Spark 2 — that's the default. Set this if you run Parakeet on Spark 1 or a different machine.",
|
||||||
required: false,
|
required: false,
|
||||||
default: null,
|
default: null,
|
||||||
placeholder: 'leave blank to use Spark 2',
|
placeholder: 'leave blank to use Spark 2',
|
||||||
@@ -69,8 +69,7 @@ const inputSpec = InputSpec.of({
|
|||||||
}),
|
}),
|
||||||
kokoro_container: Value.text({
|
kokoro_container: Value.text({
|
||||||
name: 'Kokoro container name (optional)',
|
name: 'Kokoro container name (optional)',
|
||||||
description:
|
description: 'Docker container name for Kokoro. Defaults to "kokoro-tts".',
|
||||||
'Docker container name for Kokoro. Defaults to "kokoro-tts".',
|
|
||||||
required: false,
|
required: false,
|
||||||
default: null,
|
default: null,
|
||||||
placeholder: 'kokoro-tts',
|
placeholder: 'kokoro-tts',
|
||||||
@@ -87,7 +86,8 @@ const inputSpec = InputSpec.of({
|
|||||||
}),
|
}),
|
||||||
embed_container: Value.text({
|
embed_container: Value.text({
|
||||||
name: 'Embedding container name (optional)',
|
name: 'Embedding container name (optional)',
|
||||||
description: 'Docker container name for the embedding server. Defaults to "spark-embed".',
|
description:
|
||||||
|
'Docker container name for the embedding server. Defaults to "spark-embed".',
|
||||||
required: false,
|
required: false,
|
||||||
default: null,
|
default: null,
|
||||||
placeholder: 'spark-embed',
|
placeholder: 'spark-embed',
|
||||||
|
|||||||
@@ -16,11 +16,7 @@ export const showPublicKey = sdk.Action.withoutInput(
|
|||||||
}),
|
}),
|
||||||
async ({ effects }) => {
|
async ({ effects }) => {
|
||||||
// The container generates the key under /data/ssh/id_ed25519.pub on first boot.
|
// The container generates the key under /data/ssh/id_ed25519.pub on first boot.
|
||||||
const pubKeyPath = path.join(
|
const pubKeyPath = path.join(sdk.volumes.main.path, 'ssh', 'id_ed25519.pub')
|
||||||
sdk.volumes.main.path,
|
|
||||||
'ssh',
|
|
||||||
'id_ed25519.pub',
|
|
||||||
)
|
|
||||||
let key: string
|
let key: string
|
||||||
try {
|
try {
|
||||||
key = (await fs.readFile(pubKeyPath, 'utf8')).trim()
|
key = (await fs.readFile(pubKeyPath, 'utf8')).trim()
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
# Usage:
|
# Usage:
|
||||||
# bash scripts/test-audio-with-speakers.sh <audio-file> [--people "Name1, Name2"]
|
# bash scripts/test-audio-with-speakers.sh <audio-file> [--people "Name1, Name2"]
|
||||||
#
|
#
|
||||||
|
# Env:
|
||||||
|
# SPARK_CONTROL — base URL of a running Spark Control instance
|
||||||
|
# (default http://127.0.0.1:9999, i.e. a local dev server;
|
||||||
|
# point it at your installed package URL otherwise)
|
||||||
|
# VLLM — /v1 base URL used for chat/completions
|
||||||
|
# (default $SPARK_CONTROL/v1 — Spark Control proxies vLLM)
|
||||||
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# # No participants list (LLM will only resolve speakers it can verify from audio cues)
|
# # No participants list (LLM will only resolve speakers it can verify from audio cues)
|
||||||
# bash scripts/test-audio-with-speakers.sh ~/Library/Application\ Support/hyprnote/sessions/*/audio.mp3
|
# bash scripts/test-audio-with-speakers.sh ~/Library/Application\ Support/hyprnote/sessions/*/audio.mp3
|
||||||
@@ -33,8 +40,8 @@ if [ ! -f "$AUDIO" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SPARK_CONTROL="${SPARK_CONTROL:-https://spark.satsflows.com}"
|
SPARK_CONTROL="${SPARK_CONTROL:-http://127.0.0.1:9999}"
|
||||||
VLLM="${VLLM:-http://<spark-1-ip>:8888/v1}"
|
VLLM="${VLLM:-$SPARK_CONTROL/v1}"
|
||||||
|
|
||||||
echo "════════════════════════════════════════════════════════════════"
|
echo "════════════════════════════════════════════════════════════════"
|
||||||
echo "Audio: $AUDIO ($(du -h "$AUDIO" | cut -f1))"
|
echo "Audio: $AUDIO ($(du -h "$AUDIO" | cut -f1))"
|
||||||
@@ -86,7 +93,9 @@ head -3 /tmp/transcript-formatted.txt | sed 's/^/ /'
|
|||||||
# ───────── Stage 3: discover current LLM ─────────
|
# ───────── Stage 3: discover current LLM ─────────
|
||||||
echo
|
echo
|
||||||
echo "▶ Stage 3: discover current vLLM model..."
|
echo "▶ Stage 3: discover current vLLM model..."
|
||||||
MODEL=$(curl -sS $VLLM/models | python3 -c "import json,sys; print(json.load(sys.stdin)['data'][0]['id'])")
|
# Note: Spark Control's /v1/models lists *audio* models (STT + TTS voices),
|
||||||
|
# not the LLM — ask /api/status for the currently loaded vLLM model instead.
|
||||||
|
MODEL=$(curl -sSk "$SPARK_CONTROL/api/status" | python3 -c "import json,sys; print(json.load(sys.stdin)['vllm']['current_model'])")
|
||||||
echo " Model: $MODEL"
|
echo " Model: $MODEL"
|
||||||
|
|
||||||
# ───────── Stage 4: build LLM request ─────────
|
# ───────── Stage 4: build LLM request ─────────
|
||||||
|
|||||||
Reference in New Issue
Block a user