linnet/manage.sh
pyr0ball 7e14f9135e feat: Notation v0.1.x scaffold — full backend + frontend + tests
FastAPI backend (port 8522):
- Session lifecycle: POST /session/start, DELETE /session/{id}/end, GET /session/{id}
- SSE stream: GET /session/{id}/stream — per-subscriber asyncio.Queue fan-out, 15s heartbeat
- History: GET /session/{id}/history with min_confidence + limit filters
- Audio: WS /session/{id}/audio — binary PCM ingestion stub (real inference in v0.2.x)
- Export: GET /session/{id}/export — downloadable JSON session log
- ContextClassifier background task per session (CF_VOICE_MOCK=1 in dev)
- ToneEvent SSE wire format per cf-core#40 (locked field names)
- Tier gate: CFG-LNNT- prefix check, 402 for paid features

Vue 3 frontend (port 8521, Vite + UnoCSS + Pinia):
- NowPanel: affect-aware border tint, subtext, prosody flags, shift indicator
- HistoryStrip: horizontal scroll, last 8 events with affect color
- ComposeBar: start/stop session, SSE connection lifecycle
- useToneStream: EventSource composable
- useAudioCapture: AudioWorklet → Int16 PCM → WebSocket (v0.1.x stub)
- audio-processor.js: 100ms chunk accumulator in AudioWorklet thread
- Respects prefers-reduced-motion globally

26 tests passing, manage.sh, Dockerfile, compose.yml included.
2026-04-06 18:23:52 -07:00

72 lines
1.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# manage.sh — Linnet dev management script
set -euo pipefail
CMD=${1:-help}
API_PORT=${LINNET_PORT:-8522}
FE_PORT=${LINNET_FRONTEND_PORT:-8521}
_check_env() {
if [[ ! -f .env ]]; then
echo "No .env found — copying .env.example"
cp .env.example .env
fi
}
case "$CMD" in
start)
_check_env
echo "Starting Linnet API on :${API_PORT} (mock mode)…"
CF_VOICE_MOCK=1 conda run -n cf uvicorn app.main:app \
--host 0.0.0.0 --port "$API_PORT" --reload &
echo "Starting Linnet frontend on :${FE_PORT}"
cd frontend && npm install --silent && npm run dev &
echo "API: http://localhost:${API_PORT}"
echo "UI: http://localhost:${FE_PORT}"
wait
;;
stop)
echo "Stopping Linnet processes…"
pkill -f "uvicorn app.main:app" 2>/dev/null || true
pkill -f "vite.*${FE_PORT}" 2>/dev/null || true
echo "Stopped."
;;
status)
echo -n "API: "
curl -sf "http://localhost:${API_PORT}/health" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['status'])" || echo "not running"
echo -n "Frontend: "
curl -sf "http://localhost:${FE_PORT}" -o /dev/null && echo "running" || echo "not running"
;;
test)
_check_env
CF_VOICE_MOCK=1 conda run -n cf python -m pytest tests/ -v "${@:2}"
;;
logs)
echo "Use 'docker compose logs -f' in Docker mode, or check terminal for dev mode."
;;
docker-start)
_check_env
docker compose up -d
echo "API: http://localhost:${API_PORT}"
echo "UI: http://localhost:${FE_PORT}"
;;
docker-stop)
docker compose down
;;
open)
xdg-open "http://localhost:${FE_PORT}" 2>/dev/null \
|| open "http://localhost:${FE_PORT}" 2>/dev/null \
|| echo "Open http://localhost:${FE_PORT} in your browser"
;;
*)
echo "Usage: $0 {start|stop|status|test|logs|docker-start|docker-stop|open}"
;;
esac