Architecture

How ALMA works

Four stages, seven APIs, zero manual steps on weekday mornings.

The pipeline

1

Data — Events & Weather

Once a month, a GitHub Action scrapes Milan's cultural calendar and stores events in Supabase Postgres. Each morning it fetches the day's weather snapshot. Everything lives in a single speeches table.

Supabase Postgres GitHub Actions
2

Speech — ALMA writes her script

generate_speech.py feeds the day's events and weather to Claude Sonnet. The model writes a 60-second briefing in ALMA's voice — warm, local, specific. The text is saved back to Supabase.

Anthropic Claude Sonnet 4.6 Python
3

Video — Avatar + voice + subtitles

generate_video.py chains four AI services: ElevenLabs (TTS, voice Bianca) → Kling (talking-head avatar, SUMMER image) → Whisper (word-level timing) → ffmpeg (branded intro/outro + burned subtitles). Final MP4 is uploaded to Supabase Storage.

ElevenLabs TTS Kling Avatar Whisper ffmpeg
4

Email — Delivered to the team

send_email.py uses Resend to deliver a branded HTML email from alma@alma-milano.com. One CTA button links to the video. Done by 9 AM.

Resend HTML email

GitHub Actions workflows

  • 🗓
    monthly_dataset.yml
    Runs on the 25th of each month — scrapes Milan events, populates the DB for the next month.
  • ☀️
    daily_concierge.yml
    Mon–Fri 09:00 CEST — fetches weather, calls Claude, writes today's speech to Supabase.
  • 🎬
    generate_video.yml
    Manual trigger — runs the full TTS → Avatar → Whisper → ffmpeg pipeline (~20 min, ~$10).
  • 📬
    send_email.yml
    Manual trigger — sends today's video email to all recipients via Resend (~10 seconds).

Tech stack

Anthropic Claude
Script writing (Sonnet 4.6)
ElevenLabs
Text-to-speech, voice Bianca
Kling (fal.ai)
AI talking-head avatar
Whisper
Word-level subtitle timing
ffmpeg
Video assembly & subtitle burn
Supabase
Postgres DB + file storage
Resend
Transactional email delivery
GitHub Actions
Orchestration & scheduling