Spaces:
Running on Zero
A newer version of the Gradio SDK is available: 6.19.0
title: smolnalysis
emoji: 📊
colorFrom: green
colorTo: indigo
sdk: gradio
sdk_version: 6.18.0
python_version: '3.12'
app_file: app.py
pinned: false
license: mit
short_description: Interactive open data analysis app for CKAN datasets.
tags:
- track:backyard
- sponsor:openbmb
- sponsor:modal
- achievement:offgrid
- achievement:welltuned
- achievement:offbrand
- achievement:fieldnotes
📊 smolnalysis
Ask a question about open data. Get UI generated on the fly. All powered by small expert models.
smolnalysis is an interactive open data agent built for the Build Small Hackathon. It combines MiniCPM5-1B, specialist LoRA adapters, and a learned router to create dynamic, data-driven interfaces directly from natural language questions about CKAN-style datasets.
The app runs on gr.Server. Gradio provides the Python API server and Space-friendly runtime, while a custom lightweight HTML chat frontend calls /api/chat. OpenUI-Lang output is cleaned and rendered server-side before it is inserted into the chat.
Submission Links
- Live app: smolnalysis on Hugging Face Spaces
- Source code: Meteord/smolnalysis on GitHub
- Demo video: In github
- Field notes (German): Build Small Hackathon Blog Post
- Models (all below 2B and 4Bit quantized and we therefore want to participate in the Tiny Titan challenge)
- Base model: MiniCPM5-1B
- Fine-tuned LoRA adapters:
- Contributors:
illuminate25andMeteord - Social Media Post
- Modal-Challenge: Our Documentation, how we used modal (German)
How It Works
smolnalysis combines two key ideas:
1. OpenUI-Lang for Token-Efficient UI Generation
Instead of generating full HTML or JSON UI specifications, the app uses OpenUI-Lang, a lightweight declarative language for component-based interfaces.
root = Stack([header, cards, footer])
header = CardHeader("Weather in Munich", "Current Forecast")
cards = Stack([tempCard, windCard, humCard], "row", "m", "stretch", "start", true)
tempCard = Card([CardHeader("Temperature", "Partly Cloudy"), TextContent("14 C", "large-heavy")], "card")
windCard = Card([CardHeader("Wind", "From Northwest"), TextContent("18 km/h", "large-heavy")], "card")
humCard = Card([CardHeader("Humidity", "Moderate"), TextContent("62%", "large-heavy")], "card")
footer = Card([CardHeader("5-Day Forecast", ""), forecastChart], "sunk")
2. CKAN Integration with Specialist Adapters
The app connects to CKAN portals such as opendata.muenchen.de, discovers relevant datasets, and uses role-specific adapters to:
- Parse natural language questions about datasets
- Produce validated CKAN retrieval actions
- Generate OpenUI-Lang from retrieved context
3. Learned Adapter Routing
Incoming requests are routed by a small classifier trained on the same chat-template prompts used by the adapters. The router uses a frozen MiniCPM encoder and a lightweight MLP head, then selects one of:
general_agent: base model, no adapterckan_retrieval: initial data/retrieval promptopenui_translator: prompt that already contains aTool result
Architecture
The system uses a role-based routing pattern:
- The router selects the most suitable role for the latest user message.
- MiniCPM-1B is used as the shared base model.
- Task-specific LoRA adapters specialize behavior without full model retraining.
- CKAN-style requests run retrieval first, then pass
user question + Tool resultto the OpenUI adapter. - OpenUI-Lang output is rendered inline in the custom chat frontend.
Models Used
| Component | Model | Parameters | Purpose |
|---|---|---|---|
| Base LLM | openbmb/MiniCPM5-1B | 1B | Core language understanding and generation |
| CKAN adapter | LoRA adapter | ~11M | CKAN retrieval actions |
| OpenUI adapter | LoRA adapter | ~11M | OpenUI-Lang generation |
| Router | Frozen MiniCPM encoder + MLP head | <1M trainable head | Role selection |
Local Setup
uv venv
uv sync
uv run python app/app.py
Open http://127.0.0.1:7860/.
Runtime Configuration
Common settings:
SMOLNALYSIS_MINICPM_TRANSFORMERS_MODEL_ID=openbmb/MiniCPM5-1B
SMOLNALYSIS_MINICPM_MAX_NEW_TOKENS=512
SMOLNALYSIS_MINICPM_TEMPERATURE=0.7
Adapter defaults are configured in app/backend/adapter_registry.py.
The router is enabled by default. If local router artifacts are missing, the runtime downloads them from build-small-hackathon/smolnalysis-adapter-router. Override with SMOLNALYSIS_ROUTER_REPO_ID only if you publish a different router repo.
Useful Commands
uv run python app/app.py
uv run python -m unittest tests.test_smolnalysis_model_wrapper
uv run python -m unittest tests.test_openui_adapter_demo
npm run build:openui-renderer
HF_TOKEN=... python train/router/upload_router_to_hf.py --router-dir train/router/outputs/router-mlp --repo-id build-small-hackathon/smolnalysis-adapter-router
Planning
- Project vision and idea: tasks/vision.md
- Task tracker: tasks/task_list.md
Acknowledgements
Special thanks to:
- Hugging Face for Gradio, Spaces, and the hackathon
- OpenBMB for MiniCPM and sponsorship
- Modal for providing training credits
- The Build Small Hackathon organizers and community