Skip to content

njbrake/porchsongs

Repository files navigation

porchsongs

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 -- use any LLM provider you want.


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 full control over your LLM provider, 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
uv run uvicorn app.main:app --reload

Open http://localhost:8000. Configure your LLM API key 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 in production and SQLite for local development/testing.

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

# Local dev with SQLite
DATABASE_URL=sqlite:///dev.db

# 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
OPENAI_API_KEY (none) OpenAI API key
ANTHROPIC_API_KEY (none) Anthropic API key

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 Providers -- Powered by any-llm

porchsongs uses any-llm as its LLM backbone -- a unified interface to 38+ providers including OpenAI, Anthropic, Google, Mistral, Groq, and Ollama. Swap providers by changing a single setting; no code changes needed.

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

any-llm gives porchsongs:

  • Provider flexibility -- use whichever LLM API you already have a key for
  • Local/offline support -- run fully offline with llamafile or Ollama
  • Consistent interface -- streaming, async, and tool use work the same across all providers

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