MomentumOS

Challenge 3 · Team USA × Google Cloud Hackathon — The Road to LA28 Games Bracket

A multi-agent momentum engine that ranks every LA28 Olympic and Paralympic sport on a National Momentum Index, using Gemini with Google Search grounding plus structured scoring and conditional fan narratives. Ships as a live full-stack app on Google Cloud Run.

Judges: open the frontend Live app →

Elevator pitch

Fans cannot manually digest momentum across twenty-five sports while drowning in headlines. MomentumOS runs three coordinated AI agents—Scout (grounded web search), Scorer (transparent index), Narrator (conditional storytelling)—so Olympic and Paralympic programs get equal analytical depth, explainable scores, and a ranked bracket judges can test at a real URL.


Live deployment

Role URL
Frontend (share this) https://momentumos-frontend-76wlhnioma-uc.a.run.app
Backend API https://momentumos-backend-76wlhnioma-uc.a.run.app
Smoke test Link
Health GET /health
API map GET /
OpenAPI /docs

Redeployed? Replace URLs from gcloud run services describe SERVICE --region REGION --format='value(status.url)'.


Problem → solution

Problem How MomentumOS addresses it
Fragmented signals Scout pulls live web context via Gemini + Google Search grounding, focused on Team USA per sport.
“Momentum” is vague Scorer outputs an explicit 0–100 National Momentum Index plus Recency (0–33), Trajectory (0–33), News volume (0–34)—shown in the UI tooltip for technical depth.
Paralympic coverage gap Same pipeline and prompts for Olympic and Paralympic sports; UI renders two equal columns in “All” view.
Demo must survive judging FastAPI + Next.js containers on Cloud Run; 300s backend timeout for long pipelines; 30‑minute in-memory cache for instant repeat demos; /momentum/cached for cache-only reads.

Technical architecture

System context

flowchart TB
  subgraph users [Judges and fans]
    Browser[Browser]
  end

  subgraph gcp [Google Cloud Run — us-central1]
    FE[momentumos-frontend<br/>Next.js 14 standalone]
    BE[momentumos-backend<br/>FastAPI + Uvicorn]
  end

  subgraph googleai [Google AI — Gemini API]
    GS[Google Search grounding]
    Flash[Gemini 2.5 Flash]
    Pro[Gemini 2.5 Pro]
  end

  Browser <-->|HTTPS| FE
  FE <-->|REST JSON CORS| BE
  BE -->|generate_content + Search tool| Flash
  BE --> GS
  BE -->|batch narration| Pro

Request flow (one pipeline run)

sequenceDiagram
  actor User
  participant Next as Next.js
  participant API as FastAPI
  participant Scout as Agent Scout
  participant Score as Agent Scorer
  participant Narr as Agent Narrator

  User->>Next: Run MomentumOS Pipeline
  Next->>API: GET /momentum?sport_type=all
  Note over API: Cache hit? return stored PipelineResult

  API->>Scout: 25 sports batched parallel threads
  Scout->>Scout: Flash + Google Search per sport
  Scout-->>API: ScoutResult[]

  API->>Score: Flash refines heuristics → MomentumScore[]
  Score-->>API: sorted by momentum_score

  API->>Narr: Pro generates 2-sentence blurbs
  Narr-->>API: NarratorResult[]

  API->>API: Split Olympic / Paralympic rerank
  API-->>Next: PipelineResult + agent_steps
  Next-->>User: Bracket + optional trace

Agent responsibilities

Agent Model Responsibility
Scout Gemini 2.5 Flash + Google Search tool For each LA28 sport: synthesize recent news + major competition narrative; signal count + snippets for downstream math.
Scorer Gemini 2.5 Flash Combine keyword heuristics with LLM refinement into final sub-scores and one-line reasoning; global sort.
Narrator Gemini 2.5 Pro Fan-facing two-sentence blurbs with mandatory conditional phrasing (no “will win”).

Concurrency: Scout and Scorer run blocking generate_content inside asyncio.to_thread with thread-local Gemini clients so parallel batches do not share one HTTP client across threads.

Data provenance

Layer Source
Sport universe Static seed backend/data/sports_seed.py (LA28 Olympic + Paralympic list).
Live substance No BigQueryGemini grounded search at request time; summaries are model + search, not a scraped warehouse.
Scores & copy Derived in-process from Scout text through Scorer and Narrator.

API surface (backend)

Method Path Behavior
GET / API discovery JSON
GET /health Liveness
GET /momentum Full pipeline; refresh=true bypasses cache; sport_type filters analysis
GET /momentum/cached { cached, result?, message? } — always 200

Repository layout

Path Purpose
frontend/ Next.js 14 App Router, Tailwind, bracket UI, agent trace
backend/ FastAPI, agents (scout, scorer, narrator, gemini_client), models, data
frontend/cloudbuild.yaml Cloud Build Docker build with NEXT_PUBLIC_BACKEND_URL
infra/deploy.sh Bash deploy (LF only — see .gitattributes)
infra/deploy.ps1 PowerShell deploy for Windows
DEMO_SCRIPT.md 3-minute narration for your recorded demo

Local development

Backend

cd backend
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
python -m pip install -r requirements.txt
cp .env.example .env   # set GOOGLE_API_KEY
uvicorn main:app --reload --port 8080

Frontend

cd frontend
npm ci
export NEXT_PUBLIC_BACKEND_URL=http://localhost:8080   # PowerShell: $env:NEXT_PUBLIC_BACKEND_URL=...
npm run dev

Open http://localhost:3000.

Environment

Variable Service Purpose
GOOGLE_API_KEY Backend Gemini + Search grounding
NEXT_PUBLIC_BACKEND_URL Frontend build Browser → API base URL

Optional tuning (backend): SCOUT_BATCH_SIZE, SCOUT_SPORT_TIMEOUT_SEC, SCORER_CONCURRENCY (see code comments).


Deploy to Cloud Run

See infra/deploy.sh or infra/deploy.ps1.

$env:PROJECT_ID = "your-project"
$env:GOOGLE_API_KEY = "your-key"
.\infra\deploy.ps1

Prerequisites: gcloud auth login, APIs enabled (run, cloudbuild, containerregistry). Frontend image uses frontend/cloudbuild.yaml because gcloud builds submit does not accept raw --build-arg.

Troubleshooting (Windows): WinError 32 during upload — reduce context via .gcloudignore, pause OneDrive/antivirus on the repo, retry.


Why this stack (for judges asking “why?”)

  • Gemini Flash for high-throughput Scout + Scorer; Google Search grounding so outputs track current public signal, not static training cutoffs alone.
  • Gemini Pro for Narrator — richer conditional copy across all sports in one batched call.
  • Cloud Run — serverless containers, scale to zero, 300s timeout for multi-minute pipelines, separate frontend and backend services with IAM-friendly URLs.
  • Next.js standalone — minimal Node image; NEXT_PUBLIC_BACKEND_URL baked at build time for correct browser→API routing on Cloud Run.

Submission checklist

  • [ ] Live frontend URL works end-to-end (run pipeline once before recording).
  • [ ] /health returns 200 on backend.
  • [ ] Olympic and Paralympic rankings visible with equal UI weight (All view).
  • [ ] Agent trace toggle demonstrates Scout → Scorer → Narrator.
  • [ ] README / Devpost mention Gemini + Google Search grounding explicitly.
  • [ ] Demo video (~3 min) shows Cloud Console or Cloud Run + agent trace — script in DEMO_SCRIPT.md.

License

Apache License 2.0 — see LICENSE.


MomentumOS — National Momentum Index for Team USA · LA28 · Built with Next.js, FastAPI, Gemini 2.5 Flash/Pro, Google Search grounding, Google Cloud Run.

Built With

  • docker
  • fastapi
  • gemini-2.5-flash
  • gemini-2.5-pro
  • google-cloud-run
  • google-search-grounding
  • next.js-14
  • python
  • server-sent
  • tailwind-css
  • typescript
  • uvicorn
Share this project:

Updates