Stateless Python API that powers Granuler's Technology Maturity Assessment workflow. Accepts a JSON payload from a Bubble form, calls an LLM for narrative content, and returns a branded 54-slide PPTX report — all in one request.
Bubble (client form) ──POST JSON──► Railway (this API)
│
┌────────┴────────┐
LiteLLM python-pptx
(AI narrative) (fills template)
│
assets/granuler_template.pptx
- Bubble sends
POST /generate-reportwith intake fields + 10 pillar assessments (40 subtopics) - API calculates pillar scores and overall maturity score
- LiteLLM generates narrative content (observations, risks, roadmap, etc.)
- python-pptx fills the branded 54-slide master template
- API returns the
.pptxfile as a direct download
The template is never modified on disk — it's opened fresh per request, filled in memory, and returned as bytes.
| Level | Formula |
|---|---|
| Subtopic | 1–5 raw score |
| Pillar (out of 10) | (sum of subtopic scores / (subtopics × 5)) × 10 |
| Overall (out of 100) | average of pillar scores × 10 |
Maturity bands: At Risk (<40) → Developing (<60) → Managed (<76) → Advanced (<90) → Leading (≥90)
- IT Strategy Alignment
- Systems & Application Landscape
- Process Automation
- Data Quality & Reporting
- Compliance & Governance
- Cybersecurity & Risk
- Infrastructure & Reliability
- User Adoption & Training
- Vendor & IT Spend Control
- Scalability & Future Readiness
| Layer | Technology |
|---|---|
| API | FastAPI + Uvicorn |
| AI | LiteLLM (Gemini 2.5 Flash by default) |
| Slides | python-pptx |
| Deploy | Railway |
| Frontend | Bubble (external) |
python -m venv .venv
.venv\Scripts\activate # Windows
pip install -r requirements.txtCopy .env.example to .env and add your API key:
GEMINI_API_KEY=your-key-here
.venv\Scripts\python -m uvicorn api.main:app --reloadGET http://localhost:8000/health— liveness checkPOST http://localhost:8000/generate-report— generate report (seedemo.html)
Open demo.html in a browser to test the full flow without Bubble.
api/config.yaml controls the LLM model and assessment structure:
model: "gemini/gemini-2.5-flash" # swap to gpt-4o, claude-3-5-sonnet, etc.
max_tokens: 2048
temperature: 0.3
pillar_count: 10
subtopics_per_pillar: 4Model swaps require zero code changes — LiteLLM handles provider routing.
Deploys to Railway. Set GEMINI_API_KEY as a Railway environment variable. Railway auto-detects the Python project and runs Uvicorn.
POST /generate-report expects JSON matching the ReportRequest schema in api/main.py. Returns raw .pptx bytes with Content-Disposition: attachment.
Bubble owns the database, auth, and UI. This API is intentionally stateless.