helmo Codex commited on
Commit
3010c3f
Β·
unverified Β·
1 Parent(s): 407af0d

[deploy] HF Space packaging: README frontmatter, packages.txt, DEPLOY.md

Browse files

Make 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>

Files changed (3) hide show
  1. README.md +46 -2
  2. deploy/DEPLOY.md +146 -0
  3. 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 local LLM**
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 your Ollama server | `http://192.168.0.233:11434` |
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