Spaces:
Sleeping
Sleeping
[deploy] HF Space packaging: README frontmatter, packages.txt, DEPLOY.md
Browse filesMake the repo a valid Gradio Space and document the two-piece deploy:
- README.md: HF Space YAML frontmatter (sdk: gradio, app_file: app/app.py) +
a 'Live demo: HF Space + Modal' section and NUM_CTX/MODAL_* in the config table.
- packages.txt: WeasyPrint's system libs (Pango/HarfBuzz) + Noto fonts so PDF
generation works on the Space's base image (and non-Latin docs render).
- deploy/DEPLOY.md: copy-pasteable steps β HF login, create Space in
build-small-hackathon, push code, upload the gitignored RAG index via hf upload
(auto-LFS), set Space secrets, verify, submit, and stop the Modal meter after.
Co-authored-by: Codex <noreply@openai.com>
- README.md +46 -2
- deploy/DEPLOY.md +146 -0
- packages.txt +6 -0
README.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
<div align="center">
|
| 2 |
|
| 3 |
# π Fugee
|
|
@@ -20,9 +36,14 @@ countries, and generates a personalised documentation package they can download
|
|
| 20 |
and edit.
|
| 21 |
|
| 22 |
It is a **single-process Gradio web app** backed by a **pure-Python agent loop**
|
| 23 |
-
(`agent/loop.py`, ported from pi-agent-core's patterns) and a **small
|
| 24 |
served by Ollama. No Node.js, no microservices, no external database.
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
The design point: *a genuinely useful agentic product running on a small model.*
|
| 27 |
The interview is fully **deterministic** (fixed questions and controls,
|
| 28 |
hand-translated into 10 languages) and the LLM is used only where it adds real
|
|
@@ -94,9 +115,11 @@ Read at startup by `app/config.py` (no `python-dotenv` dependency):
|
|
| 94 |
|
| 95 |
| Variable | Meaning | Example |
|
| 96 |
|-----------------|----------------------------------------------------------------|---------|
|
| 97 |
-
| `OLLAMA_HOST` | Base URL of
|
| 98 |
| `MODEL_ID` | The single β€32B tool-calling instruct model for the whole app | `lfm2.5:8b` |
|
| 99 |
| `MODEL_PROVIDER`| `ollama` (default) or a litellm provider name | `ollama` |
|
|
|
|
|
|
|
| 100 |
|
| 101 |
> **One model, no fallback.** The hackathon build deliberately uses a single
|
| 102 |
> small model end to end. `web_search` is **disabled** β the assessment is
|
|
@@ -105,6 +128,27 @@ Read at startup by `app/config.py` (no `python-dotenv` dependency):
|
|
| 105 |
|
| 106 |
---
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
## Project layout
|
| 109 |
|
| 110 |
```
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Fugee
|
| 3 |
+
emoji: π
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: yellow
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 6.15.2
|
| 8 |
+
app_file: app/app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
+
short_description: Agentic AI guidance for displaced people, on a small (β€32B) LLM
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
<!-- The block above is Hugging Face Space metadata (required for the Space to
|
| 15 |
+
build). The hackathon submission tool appends track/badge tags to it. -->
|
| 16 |
+
|
| 17 |
<div align="center">
|
| 18 |
|
| 19 |
# π Fugee
|
|
|
|
| 36 |
and edit.
|
| 37 |
|
| 38 |
It is a **single-process Gradio web app** backed by a **pure-Python agent loop**
|
| 39 |
+
(`agent/loop.py`, ported from pi-agent-core's patterns) and a **small (β€32B) LLM**
|
| 40 |
served by Ollama. No Node.js, no microservices, no external database.
|
| 41 |
|
| 42 |
+
> **This Space** runs the Gradio UI on free CPU and calls the LLM (`lfm2.5:8b`)
|
| 43 |
+
> and embeddings (`nomic-embed-text`) on a GPU **Ollama** endpoint hosted on
|
| 44 |
+
> [Modal](https://modal.com) β so the same code and the same small model run
|
| 45 |
+
> unchanged, just on rented GPU. See [`deploy/DEPLOY.md`](deploy/DEPLOY.md).
|
| 46 |
+
|
| 47 |
The design point: *a genuinely useful agentic product running on a small model.*
|
| 48 |
The interview is fully **deterministic** (fixed questions and controls,
|
| 49 |
hand-translated into 10 languages) and the LLM is used only where it adds real
|
|
|
|
| 115 |
|
| 116 |
| Variable | Meaning | Example |
|
| 117 |
|-----------------|----------------------------------------------------------------|---------|
|
| 118 |
+
| `OLLAMA_HOST` | Base URL of the Ollama server (local, LAN, or Modal endpoint) | `http://127.0.0.1:11434` |
|
| 119 |
| `MODEL_ID` | The single β€32B tool-calling instruct model for the whole app | `lfm2.5:8b` |
|
| 120 |
| `MODEL_PROVIDER`| `ollama` (default) or a litellm provider name | `ollama` |
|
| 121 |
+
| `NUM_CTX` | Ollama context window β keep large; the small default truncates the assessment prompt | `16384` |
|
| 122 |
+
| `MODAL_KEY` / `MODAL_SECRET` | Proxy-auth headers when `OLLAMA_HOST` is a protected Modal endpoint (hosted demo only) | β |
|
| 123 |
|
| 124 |
> **One model, no fallback.** The hackathon build deliberately uses a single
|
| 125 |
> small model end to end. `web_search` is **disabled** β the assessment is
|
|
|
|
| 128 |
|
| 129 |
---
|
| 130 |
|
| 131 |
+
## Live demo: Hugging Face Space + Modal
|
| 132 |
+
|
| 133 |
+
The deployed demo splits into two pieces so it runs **free** and **fast** without
|
| 134 |
+
changing the app or the model:
|
| 135 |
+
|
| 136 |
+
```
|
| 137 |
+
HF Space (free CPU, Gradio) Modal (GPU, Ollama)
|
| 138 |
+
ββββββββββββββββββββββββββββ HTTPS ββββββββββββββββββββββββββββββββ
|
| 139 |
+
β app/app.py + curated data β ββββββββΆ β ollama serve β
|
| 140 |
+
β + guidelines RAG (cosine) β proxy β β’ lfm2.5:8b (assessment) β
|
| 141 |
+
β OLLAMA_HOST β Modal URL β auth β β’ nomic-embed-text (RAG) β
|
| 142 |
+
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
The Space sets `OLLAMA_HOST` to the Modal endpoint and sends the proxy-auth
|
| 146 |
+
headers (`agent/ollama_auth.py`); everything else is identical to local. Full,
|
| 147 |
+
copy-pasteable steps β create the Space, deploy Modal, set secrets, upload the
|
| 148 |
+
RAG index β are in **[`deploy/DEPLOY.md`](deploy/DEPLOY.md)**.
|
| 149 |
+
|
| 150 |
+
---
|
| 151 |
+
|
| 152 |
## Project layout
|
| 153 |
|
| 154 |
```
|
deploy/DEPLOY.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Deploying Fugee β Hugging Face Space + Modal
|
| 2 |
+
|
| 3 |
+
The demo runs in two pieces: the **Gradio UI on a free HF CPU Space**, calling the
|
| 4 |
+
**LLM + embeddings on a GPU Ollama endpoint on Modal**. Same code, same model
|
| 5 |
+
(`lfm2.5:8b`), just on rented GPU.
|
| 6 |
+
|
| 7 |
+
```
|
| 8 |
+
HF Space (free CPU) ββHTTPS, proxy-authβββΆ Modal (L4 GPU, ollama serve)
|
| 9 |
+
app/app.py lfm2.5:8b + nomic-embed-text
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
Run the steps in order. Steps that only the maintainer can do (auth, secrets) are
|
| 13 |
+
marked **[you]**.
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## 0. Prerequisites (already done in this repo)
|
| 18 |
+
|
| 19 |
+
- `deploy/modal_app.py` is deployed and **kept warm**
|
| 20 |
+
(`MODAL_MIN_CONTAINERS=1`) β endpoint `https://hf-labs--fugee-ollama-serve.modal.run`.
|
| 21 |
+
- A Modal **Proxy Auth Token** exists; its id/secret are in `.env.modal`
|
| 22 |
+
(gitignored) as `MODAL_KEY` / `MODAL_SECRET`.
|
| 23 |
+
- Models cached in the Modal Volume (`modal run deploy/modal_app.py::download_models`).
|
| 24 |
+
|
| 25 |
+
Re-check the endpoint is warm before a demo:
|
| 26 |
+
|
| 27 |
+
```bash
|
| 28 |
+
set -a; . ./.env.modal; set +a
|
| 29 |
+
curl -s -o /dev/null -w "%{http_code}\n" \
|
| 30 |
+
https://hf-labs--fugee-ollama-serve.modal.run/api/version \
|
| 31 |
+
-H "Modal-Key: $MODAL_KEY" -H "Modal-Secret: $MODAL_SECRET" # expect 200
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
## 1. **[you]** Authenticate the HF CLI
|
| 37 |
+
|
| 38 |
+
Create a token with **write** access at <https://huggingface.co/settings/tokens>,
|
| 39 |
+
then:
|
| 40 |
+
|
| 41 |
+
```bash
|
| 42 |
+
hf auth login # paste the write token
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
---
|
| 46 |
+
|
| 47 |
+
## 2. **[you]** Create the Space in the hackathon org
|
| 48 |
+
|
| 49 |
+
Web: **New Space** β Owner `build-small-hackathon`, name `fugee`, SDK **Gradio**,
|
| 50 |
+
hardware **CPU basic (free)**, **Public**. Or CLI:
|
| 51 |
+
|
| 52 |
+
```bash
|
| 53 |
+
hf repo create build-small-hackathon/fugee --repo-type space --space-sdk gradio
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
(If the flag name differs on your CLI version, run `hf repo create --help`.)
|
| 57 |
+
|
| 58 |
+
---
|
| 59 |
+
|
| 60 |
+
## 3. Push the code to the Space
|
| 61 |
+
|
| 62 |
+
The Space is its own git repo. Add it as a remote and push the current branch to
|
| 63 |
+
its `main` (force, to replace the starter README on first deploy):
|
| 64 |
+
|
| 65 |
+
```bash
|
| 66 |
+
git remote add space https://huggingface.co/spaces/build-small-hackathon/fugee
|
| 67 |
+
git push space HEAD:main --force
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
This pushes everything except gitignored files β so **not** the 23 MB RAG index
|
| 71 |
+
(next step). The Space starts building on push.
|
| 72 |
+
|
| 73 |
+
---
|
| 74 |
+
|
| 75 |
+
## 4. Upload the RAG index (gitignored β uploaded directly)
|
| 76 |
+
|
| 77 |
+
`specs/data/guidelines_index.json` is needed at runtime for `guideline_search`.
|
| 78 |
+
`hf upload` stores it via LFS automatically (no local git-lfs required):
|
| 79 |
+
|
| 80 |
+
```bash
|
| 81 |
+
hf upload build-small-hackathon/fugee \
|
| 82 |
+
specs/data/guidelines_index.json specs/data/guidelines_index.json \
|
| 83 |
+
--repo-type space
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
## 5. **[you]** Set the Space secrets & variables
|
| 89 |
+
|
| 90 |
+
Space β **Settings β Variables and secrets**. The app reads these from the
|
| 91 |
+
environment (its `.env` loader never overrides real env vars).
|
| 92 |
+
|
| 93 |
+
**Secrets** (encrypted):
|
| 94 |
+
|
| 95 |
+
| Name | Value |
|
| 96 |
+
|------|-------|
|
| 97 |
+
| `OLLAMA_HOST` | `https://hf-labs--fugee-ollama-serve.modal.run` |
|
| 98 |
+
| `MODAL_KEY` | your Modal Proxy Auth Token id (`wk-β¦`) |
|
| 99 |
+
| `MODAL_SECRET` | your Modal Proxy Auth Token secret (`ws-β¦`) |
|
| 100 |
+
|
| 101 |
+
**Variables** (public):
|
| 102 |
+
|
| 103 |
+
| Name | Value |
|
| 104 |
+
|------|-------|
|
| 105 |
+
| `MODEL_ID` | `lfm2.5:8b` |
|
| 106 |
+
| `MODEL_PROVIDER` | `ollama` |
|
| 107 |
+
| `NUM_CTX` | `16384` |
|
| 108 |
+
|
| 109 |
+
> `MODEL_ID` **must** be set β the code default is `qwen2.5:7b`, which isn't on
|
| 110 |
+
> the Modal endpoint. `OLLAMA_HOST` + `MODAL_KEY` + `MODAL_SECRET` are required for
|
| 111 |
+
> the Space to reach the model. The Modal **account** token never goes here β it
|
| 112 |
+
> stays in `~/.modal.toml` on your machine.
|
| 113 |
+
|
| 114 |
+
Setting a secret restarts the Space.
|
| 115 |
+
|
| 116 |
+
---
|
| 117 |
+
|
| 118 |
+
## 6. Verify the live Space
|
| 119 |
+
|
| 120 |
+
Open `https://huggingface.co/spaces/build-small-hackathon/fugee`, wait for the
|
| 121 |
+
build (watch the **Logs** tab), then walk a full flow: language β interview β
|
| 122 |
+
assessment β recommendations β documents. First model call may take a few seconds
|
| 123 |
+
even though Modal is warm.
|
| 124 |
+
|
| 125 |
+
If PDF generation errors in the logs, it's a missing system lib β confirm
|
| 126 |
+
`packages.txt` installed (Pango/HarfBuzz/Noto fonts).
|
| 127 |
+
|
| 128 |
+
---
|
| 129 |
+
|
| 130 |
+
## 7. Submit & costs
|
| 131 |
+
|
| 132 |
+
- **Submission:** on the hackathon *submit* page, enter `fugee` under
|
| 133 |
+
`build-small-hackathon/` β it loads the README and writes track/badge tags into
|
| 134 |
+
the frontmatter β commit that back (`git pull space main` then push, or edit on HF).
|
| 135 |
+
- **GPU limit:** the "10 ZeroGPU apps per user" rule does **not** apply β we use
|
| 136 |
+
Modal, not ZeroGPU.
|
| 137 |
+
- **After the demo window**, stop the Modal meter:
|
| 138 |
+
|
| 139 |
+
```bash
|
| 140 |
+
MODAL_MIN_CONTAINERS=0 modal deploy deploy/modal_app.py # scale to zero
|
| 141 |
+
# or fully stop:
|
| 142 |
+
modal app stop fugee-ollama
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
Scale-to-zero keeps the deployment but costs nothing while idle (cold start
|
| 146 |
+
~40 s on the next request).
|
packages.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
libpango-1.0-0
|
| 2 |
+
libpangocairo-1.0-0
|
| 3 |
+
libpangoft2-1.0-0
|
| 4 |
+
libharfbuzz0b
|
| 5 |
+
fonts-noto-core
|
| 6 |
+
fonts-noto-cjk
|