GitHub - Brake-Labs/porchsongs: Make it your own

4 min read Original article ↗

porchsongs

Try it live

Python React FastAPI any-llm License

A personal song lyric rewriter. Edit and refine your lyrics with AI -- workshop them into something that actually sounds like you.
Powered by any-llm -- routed through a single LLM gateway.


PorchSongs demo

porchsongs preserves meter, rhyme scheme, chord alignment, and emotional meaning -- it only swaps out the imagery that doesn't fit.

Try It Live

porchsongs.ai is the hosted version of porchsongs. Sign in with Google, pick a plan, and start rewriting. No setup, no API keys to manage.

If you prefer to self-host or want to point porchsongs at your own LLM gateway, follow the Quick Start below.

How It Works

  1. Paste your lyrics -- with or without chords, any format works
  2. Chat to workshop the lyrics -- tell the AI what to change ("swap the truck for my bike," "make verse 2 about coding") and iterate in a live conversation
  3. Play and enjoy -- chords are automatically realigned above your new lyrics

Quick Start

pip install uv
uv sync
cd frontend && npm install && npm run build && cd ..
cd backend
LLM_API_BASE=https://your-gateway/v1 LLM_API_KEY=your-key \
  uv run uvicorn app.main:app --reload

Open http://localhost:8000. porchsongs routes all AI traffic through a single LLM gateway; set LLM_API_BASE and LLM_API_KEY (see the environment variables below), then pick a model in Settings.

By default, porchsongs runs in zero-config dev mode -- no login required, a local user is auto-created. See Authentication below for production setups.

For frontend development with hot reload:

# Terminal 1: backend
cd backend && uv run uvicorn app.main:app --reload

# Terminal 2: frontend (proxies /api to backend)
cd frontend && npm run dev

Docker

cp .env.example .env
# Edit .env -- set JWT_SECRET to a long random string
docker compose up --build

This starts PostgreSQL + runs database migrations + serves the app on port 8000.

Authentication

porchsongs supports three auth modes, controlled by environment variables:

Zero-config dev mode (default)

No env vars needed. The app is open to anyone who can reach it. A local user is auto-created.

Single-user password protection

Set APP_SECRET to gate the app behind a password:

APP_SECRET=your-secret-password
JWT_SECRET=a-long-random-string-at-least-32-chars

You can also use a bcrypt hash for APP_SECRET:

# Generate a hash
python3 -c "import bcrypt; print(bcrypt.hashpw(b'mypassword', bcrypt.gensalt()).decode())"

# Use it in .env
APP_SECRET='$2b$12$...'

Premium plugin

For Google OAuth and other premium features, see the porchsongs-premium repo.

PREMIUM_PLUGIN=porchsongs_premium.plugin

Database

porchsongs uses PostgreSQL everywhere (production, development, and testing).

# Production (set in .env or environment)
DATABASE_URL=postgresql://porchsongs:porchsongs@localhost:5432/porchsongs

# Local dev / testing
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/porchsongs_test

# Quick PostgreSQL setup via Docker
docker run --name porchsongs-pg -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=porchsongs_test -p 5432:5432 -d postgres:16

# Apply migrations
uv run alembic upgrade head

Docker Compose includes a PostgreSQL service and runs migrations automatically on startup.

Environment Variables

Variable Default Description
DATABASE_URL postgresql://...localhost.../porchsongs Database connection string
JWT_SECRET change-me-in-production Secret for signing JWT tokens (use 32+ chars)
AUTH_BACKEND app_secret Auth mode: app_secret (premium plugins can add others)
APP_SECRET (none) Password gate (app_secret mode). Supports plaintext or bcrypt hash
CORS_ORIGINS * Allowed CORS origins (comma-separated)
JWT_EXPIRY_MINUTES 15 Access token lifetime
REFRESH_TOKEN_DAYS 30 Refresh token lifetime
PREMIUM_PLUGIN (none) Module path for premium auth backend
LLM_API_BASE (none) LLM gateway base URL (OpenAI-compatible, e.g. https://your-gateway/v1). Required for AI features
LLM_API_KEY (none) LLM gateway API key (read server-side, never sent to the browser)
LLM_PROVIDER otari any-llm provider name for the gateway

See .env.example for the full list.

Testing

# Backend tests (118 tests)
uv run pytest
uv run pytest -v                    # verbose
uv run pytest tests/test_auth.py    # auth tests only

# Frontend tests (39 tests)
cd frontend && npx vitest run

# Lint & type check
uv run ruff check backend/
uv run ruff format --check backend/
cd frontend && npx eslint src/
cd frontend && npm run typecheck

LLM gateway -- Powered by any-llm

porchsongs routes all AI traffic through a single LLM gateway using any-llm. Point LLM_API_BASE / LLM_API_KEY at any OpenAI-compatible gateway (an Otari deployment by default) and pick a model in Settings; the model catalog is discovered from the gateway. Keys live only on the server and are never sent from the browser.

Website any-llm.ai
GitHub mozilla-ai/any-llm

Routing everything through one gateway gives porchsongs:

  • One place to manage credentials, models, and spend -- no per-provider keys in the app
  • Model discovery -- the Settings model picker is populated from the gateway's catalog
  • Consistent interface -- streaming, async, and reasoning work the same regardless of the model behind the gateway

Bring your own API key, configure it in Settings, and start rewriting.