Trollgorithm Theme Song Booth - customer-facing request form, admin dashboard, kiosk queue, and delivery pipeline for AI-generated theme songs.
This repository has been archived on 2026-09-04. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
Find a file
2026-08-04 20:46:47 +00:00
static Add public kiosk page with QR/pricing cycle and configurable slide timing 2026-08-04 17:41:33 +00:00
templates Move revision history above operator notes, move cancel button next to status with confirmation 2026-08-04 18:58:49 +00:00
.env.example feat: Hermes prompt callback endpoint + API key management 2026-08-03 17:16:56 +00:00
.gitignore Initial prototype for theme song booth 2026-07-31 19:47:52 +00:00
app.py Add Cancelled status and cancel request button 2026-08-04 17:56:02 +00:00
config.py feat: Hermes prompt callback endpoint + API key management 2026-08-03 17:16:56 +00:00
docker-compose.yml feat: Hermes prompt callback endpoint + API key management 2026-08-03 17:16:56 +00:00
Dockerfile docs: update comments, docstrings, README, REVIEW, and env docs to match current features 2026-08-03 00:11:41 +00:00
init_db.py docs: update comments, docstrings, README, REVIEW, and env docs to match current features 2026-08-03 00:11:41 +00:00
models.py Add revision history log and music files ZIP backup 2026-08-04 16:54:51 +00:00
README.md Update README and REVIEW with all new features (kiosk, pricing, cancelled status, revision history, stems, sales, backups) 2026-08-04 20:46:47 +00:00
requirements.txt docs: update comments and README to reflect current feature set 2026-08-02 00:07:24 +00:00
REVIEW.md Update README and REVIEW with all new features (kiosk, pricing, cancelled status, revision history, stems, sales, backups) 2026-08-04 20:46:47 +00:00

Theme Song Booth

A Flask web app for a convention booth where visitors request a custom AI-generated theme song, the operator manages the queue, and the final MP3(s) are delivered by email after payment.

Customer-facing

  • Request form (/request) — visitors enter name, email, hobbies, notable facts, preferred style/genre, vocal gender preference, and extra requests. A branded banner image is shown. Email is validated to reduce delivery problems. If the operator marks the booth as closed, this page shows a closed banner and message instead.
  • Closed page (/request) — when the booth is marked closed from /admin/settings, visitors see the closed banner and a friendly "goblin engineers are on a break" message.
  • Order status lookup (/status) — customers enter their email to see all their requests, current status, and the private player link once songs are uploaded.
  • Confirmation page (/thanks/<id>) — shows the request number after submission.
  • FAQ page (/faq) — answers common customer questions.
  • Private player page (/play/<token>) — customer receives an email with a unique link. They can stream Version A and Version B, pick one (or both), or request a limited number of revisions.
  • Revision workflow — when a customer asks for changes, the current MP3s are archived and the operator sees the request as Revisions Requested in the dashboard.
  • Rate limiting — the public request form is capped at 5 submissions per minute per IP.

Operator / admin

  • Admin login (/admin/login) — simple session-based login protected by ADMIN_PASSWORD.
  • Dashboard queue (/admin) — filter by status and auto-refresh at a configurable interval.
  • Per-request detail page (/admin/request/<id>):
    • Generate and save a Suno prompt from customer info.
    • One-click copy of request details + a signed callback URL for Hermes.
    • Hermes POSTs back the generated Title/Style/Lyrics; status becomes Prompt Ready automatically.
    • Edit all customer info fields (name, email, hobbies, notable facts, style/genre, vocal gender, extra requests).
    • View revision history for the request.
    • Mark the request as Cancelled.
    • Internal operator notes.
    • Upload Version A and Version B MP3s with automatic ID3 metadata tagging.
    • Send a preview email with a private player link.
    • Mark paid, enter a Square payment reference, and deliver selected MP3 attachments.
    • Save a Stems / Extras share link that appears on the customer player page after delivery.
  • Pricing page (/admin/pricing) — configure fixed prices (One Song, Both Songs, WAV per song, STEMs per song) and up to 5 custom named items.
  • Sales report (/admin/sales) — list all delivered requests with customer details and Square payment references.
  • Public kiosk (/kiosk) — full-screen display for a booth tablet. Cycles between the request-form QR code and the price list. Banner switches based on booth open/closed state. Slide timing is configurable in settings.
  • Settings / maintenance page (/admin/settings):
    • Database health check with optional schema repair.
    • Database statistics, size, upload counts.
    • Configure customer revision limit.
    • Configure dashboard auto-refresh interval.
    • Configure public kiosk cycle mode (QR only, pricing only, or N seconds per slide).
    • Configure SMTP host/port/user/from; store the SMTP password encrypted.
    • Configure default MP3 metadata tags (artist, album, year, comment).
    • Generate/regenerate the Hermes API key used by the prompt callback endpoint (shown once, otherwise masked).
    • Download or restore the SQLite database backup.
    • Download all uploaded music files as a ZIP backup.
    • Send a test email.
    • Reset the entire system for a new event.
  • Per-request delete and system reset — remove requests and uploaded files; reset auto-increment back to 1.

Status flow

pending → prompt_ready → songs_uploaded → awaiting_payment → paid → delivered
Status Meaning
pending Customer submitted a request; operator has not saved a prompt yet.
prompt_ready Hermes POSTed back the generated Suno prompt, or the operator saved it manually.
songs_uploaded Both MP3s uploaded; preview link can be sent.
revisions_requested Customer asked for changes; current files were archived.
awaiting_payment Customer approved a version; waiting for operator to collect payment and deliver.
paid Payment recorded internally.
delivered MP3 attachment(s) emailed to the customer.
cancelled Request was cancelled by the operator.

File layout

File Purpose
app.py Flask routes, helpers, email layer, runtime settings, MP3 tagging, rate limiting, DB maintenance, Hermes callback endpoint, kiosk route, pricing route, sales report, and ZIP backup.
config.py Environment-variable based configuration; defines defaults for DB, uploads, SMTP, secrets, and HERMES_API_KEY.
models.py SQLite schema + CRUD. player_token is a secret URL-safe token. Includes revision history table.
init_db.py Run once after deploy: python init_db.py.
templates/admin/dashboard.html Queue table + filters + auto-refresh + topbar links to Kiosk, Pricing, Sales, Settings.
templates/admin/request.html Single-request detail page: customer info editing, revision history, operator notes, prompt fields, upload/delivery, cancel action.
templates/admin/settings.html Maintenance, settings, backup/restore, reset, kiosk mode, Hermes API key display.
templates/admin/pricing.html Configure fixed and custom pricing items.
templates/admin/sales.html Delivered request sales report.
templates/status.html Customer order status lookup.
templates/faq.html Customer FAQ page.
templates/player.html Customer audio player, approval, revision form, stems download button.
templates/kiosk.html Public full-screen kiosk page with QR/pricing cycling and open/closed banner.
templates/admin/login.html Admin login page.
static/Trollgorithm_booth.jpg Banner image shown when booth is open.
static/Booth_closed.png Banner image shown when booth is closed.
static/DM-Logo_email.png Inline Dionysis Media logo attached to emails.
static/qr-code.png QR code displayed on the kiosk page.
Dockerfile Production container image.
docker-compose.yml Portainer stack definition.
requirements.txt Python dependencies.
.env.example Template for local environment variables.
REVIEW.md Quick-reference for returning to this project.

Local development

cd /home/jess/workspace/theme-song-booth
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env
# Edit .env and set APP_SECRET_KEY, ADMIN_PASSWORD, SMTP_PASS, PUBLIC_BASE_URL
.venv/bin/python init_db.py
.venv/bin/python -m flask --app app run --host=0.0.0.0

Visit:

Deployment with Portainer

  1. Log in to Portainer.
  2. Go to StacksAdd stack.
  3. Choose Repository:
    • URL: https://gitlab.hallsworth.ca/yrtria/theme-song-booth.git
    • Branch: main
    • Compose path: docker-compose.yml
  4. Add environment variables:
Variable Required Purpose
APP_SECRET_KEY Yes Long random string for Flask sessions and to encrypt stored SMTP password. Generate with python3 -c "import secrets; print(secrets.token_hex(32))".
ADMIN_PASSWORD Yes Password for /admin.
SMTP_PASS Yes Password for the SMTP account.
PUBLIC_BASE_URL Yes Public HTTPS URL, e.g. https://booth.dionysismedia.ca.
HOST_PORT No Host-side port mapping, default 127.0.0.1:8000.
INTERNAL_PORT No Port gunicorn binds inside container, default 8000.
BOOTH_NAME No Name used in emails, default Trollgorithm Theme Songs.
PRICE_PER_VERSION No Shown to the operator/customer, default 10.00.
CURRENCY No Currency label, default CAD.
MAX_REVISIONS No Default customer revision limit if not changed in settings, default 2.
HERMES_API_KEY No API key for the /api/prompt callback. If omitted, generate one from /admin/settings.
  1. Deploy the stack.
  2. Open a console in the theme-song-booth container and run once:
python init_db.py
  1. Point your reverse proxy at the HOST_PORT you chose.
  2. Visit /admin/settings and click Regenerate API Key to create the Hermes callback key.
  3. Update your Hermes skill or config with the new key and the booth public URL.
  4. Print or display a QR code pointing to https://your-domain/request.

Updating the deployment

After each push to GitLab, go to Portainer → Stackstheme-song-boothPull and redeploy to rebuild from the repo.

Important notes

  • No .env file in production. docker-compose.yml passes variables directly from Portainer. This avoids Portainer's env_file not found error.
  • Runtime settings persist. SMTP config, revision limit, auto-refresh interval, booth open/closed state, Hermes API key, MP3 metadata defaults, pricing, and kiosk cycle mode are stored in booth_settings.json inside the persistent uploads volume. They survive redeploys.
  • Booth open/closed switch. Operators can flip the booth status from /admin/settings. When closed, /request and /kiosk show the closed banner.
  • Payments are manual. The app records a Square payment reference but does not integrate with Square's API. Use a Square Terminal/Reader at the booth.
  • Operator queue is the dashboard. No operator email alerts are sent; approvals and revision notes appear as status changes in /admin.
  • Hermes callback workflow. Operators copy request details + a signed callback URL from /admin/request/<id>. Hermes POSTs back Title/Style/Lyrics; the record becomes prompt_ready.
  • MP3 metadata. Uploaded files are tagged with title (from the saved prompt), plus configured artist/album/year/comment values.
  • Email logo. static/DM-Logo_email.png is attached inline to all customer emails as the Dionysis Media signature.
  • Stems / Extras delivery. Operators paste a file-share link from Pingvin Share (or similar) into the request page. The link appears as a download button on the customer player page after delivery.
  • Kiosk page. Public, no login. Shows the open/closed banner, cycles between the request-form QR code and the configured price list, and auto-refreshes so updates to pricing or booth state appear.
  • Security: the repo is public on GitLab. No secrets are committed. Admin password is plain text in the Portainer environment. The Hermes API key is stored in booth_settings.json and masked in the admin UI.

Common troubleshooting

Problem Cause Fix
"Send Preview Link" does nothing Form tags were unbalanced (now fixed). Redeploy the latest commit.
Emails not arriving SMTP settings wrong or messages in spam. Use Send Test Email on /admin/settings; verify host/port/password.
Can't reach app through domain Reverse proxy points to wrong host port. Match HOST_PORT to your proxy upstream.
Static banner not showing Browser cached old image. Hard-refresh or redeploy stack.
Logo missing from email Logo file missing from static/. Ensure static/DM-Logo_email.png is in the container.
Database schema mismatch New column/table added but old DB not migrated. Go to /admin/settings and click Fix Database Schema, or run python init_db.py.
Kiosk shows old prices Page auto-refreshes every 30s; check /admin/pricing. Verify pricing values and redeploy if templates changed.

License / ownership

Built for Jess's Trollgorithm theme-song booth. All code and assets are private to that project.