sam / README.md
notmartin's picture
Position Sam as health companion
e78cdf7 unverified
|
Raw
History Blame Contribute Delete
8.75 kB
---
title: Sam
emoji: 🤖
colorFrom: indigo
colorTo: purple
sdk: gradio
app_file: app.py
pinned: false
tags:
- 0g-hackathon
- reachy_mini
- reachy_mini_python_app
---
# Sam
Sam is a **Reachy Mini AI health companion** powered by **0G intelligence** and
durable memory on **0G Storage**. Medication support is the first real workflow:
Sam listens to pharmacy instructions, reasons over them with 0G Compute, keeps a
local memory for fast retrieval, syncs that memory to 0G Storage, and acts on it
through voice, movement, and reminders. One control loop:
> **listen** (0G Whisper STT) → *optionally* **see** (0G Qwen3-VL) → **think**
> (0G GLM-5 chat) → **speak** (local TTS) → **express** with head + antennas.
The chat model returns both *what to say* and *how it feels*, so Sam nods,
tilts, perks its antennas and bobs while talking.
Runs identically in **MuJoCo simulation** and on physical hardware.
## What's wired up
| Capability | 0G model | Status |
|---|---|---|
| 🧠 Chat / reasoning | `zai-org/GLM-5-FP8` | ✅ enabled |
| 👂 Speech-to-text | `openai/whisper-large-v3` | ✅ enabled |
| 👁️ Vision | `qwen/qwen3-vl-30b-a3b-instruct` | ⚙️ code ready, **fund a sub-account to enable** |
| 🗣️ Text-to-speech | local (`say` / `espeak`) | no 0G TTS provider yet |
| 💊 Health plan + medication support | local JSON + 0G Storage sync | ✅ enabled |
## Medication safety
Sam is a health companion, not a doctor. It records medication instructions that
the user says came from a pharmacist or doctor, then uses 0G intelligence to add
short, non-prescriptive safety context and uses 0G Storage as durable memory.
Sam does **not** prescribe, change dosage, validate medication instructions,
identify pills as medical truth, or claim that someone swallowed a medicine.
Sam may add a short non-prescriptive caveat when 0G intelligence or local safety
rules detect a well-known concern. For example, if a user mentions ulcer history
with naproxen, Sam can save the reminder while advising them to cross-check with
a doctor or pharmacist.
## Setup
Requires Python 3.10–3.13 (the mujoco deps don't support 3.14). We use [`uv`](https://docs.astral.sh/uv/).
```bash
uv venv --python 3.12
source .venv/bin/activate
uv pip install -e ".[mujoco]"
cp .env.example .env # then fill in your 0G keys (see below)
```
### 0G keys
Each provider needs its **own** host + key (a key is bound to one provider):
```bash
0g-compute-cli inference list-providers # find provider addresses + models
0g-compute-cli inference get-secret --provider <ADDR> --duration 0
```
Copy the printed `app-sk-…` token and the `curl` host into the matching
`OG_CHAT_* / OG_STT_* / OG_VISION_*` block in `.env`.
**Mainnet = real funds** — each call spends a tiny amount of 0G.
### Hugging Face Space
This repo is a **Gradio Space** so 0G calls run server-side and API keys stay
private. In the Space settings, add these as **Secrets**:
```text
OG_CHAT_BASE_URL
OG_CHAT_MODEL
OG_CHAT_PROVIDER
OG_CHAT_API_KEY
OG_STT_BASE_URL
OG_STT_MODEL
OG_STT_PROVIDER
OG_STT_API_KEY
```
Add `OG_VISION_*` too once the vision provider is funded. Rebuild the Space after
changing secrets.
### Sam medication memory
Sam reads and writes medication memory locally first so reminders are fast and
reliable. When 0G Storage is configured, every local change is marked for sync
and a background sync keeps retrying until 0G Storage has the latest memory.
```text
SAM_MEMORY_PATH=/path/to/sam_memory.json
OG_STORAGE_ENABLED=true
OG_STORAGE_INDEXER_URL=...
OG_STORAGE_RPC_URL=...
OG_STORAGE_PRIVATE_KEY=...
OG_STORAGE_MEMORY_ROOT=...
```
`OG_STORAGE_PRIVATE_KEY` must be a secret. If 0G Storage is unavailable, Sam
continues from local JSON and keeps the memory marked as pending sync.
## Run
**1. Start the sim daemon** (separate terminal). On macOS use `--no-media`
(the daemon's media server stalls headless on a camera/mic permission prompt):
```bash
source .venv/bin/activate
reachy-mini-daemon --sim --no-media # add --headless to skip the 3D viewer
```
**2. Talk to Sam:**
```bash
# Check real 0G config without needing the robot/sim daemon:
python -m mr_reachy --health-check --no-robot
# Single real 0G exchange without needing the robot/sim daemon:
python -m mr_reachy --once "Tell me a robot joke" --no-robot --no-speak
# Single real 0G exchange with robot/sim motion:
python -m mr_reachy --once "Tell me a robot joke"
# Type at it with robot/sim motion + local speech:
python -m mr_reachy --text
# Full voice conversation (needs a mic):
python -m mr_reachy
```
Say "what do you see?" to trigger the vision path (once a vision sub-account is funded).
Say "bye" / type `quit` to exit.
Medication demo phrases:
```text
Sam, I need to take metformin three times a day for five days.
I took it.
```
If the user does not provide exact times, Sam uses safe default reminder slots:
`09:00`, `14:00`, and `20:00` for three-times-per-day schedules.
## On the robot (demo station — Reachy Mini Wireless)
At the demo station the app runs **on the robot's Pi**, started from the dashboard
for a short slot. On hardware Sam uses the robot's **onboard mic, speaker
and camera** (via the daemon media manager) and **antenna push-to-talk** instead
of the laptop mic. In the desktop simulator, the dashboard app uses the laptop
mic/speaker path automatically. Override with `MR_REACHY_BACKEND=robot` or
`MR_REACHY_BACKEND=local` if the SDK guesses wrong.
> ⚠️ The on-robot I/O path is built against the SDK API but has **not been tested
> on a physical robot yet**. Rehearse before the slot and tune the two values below.
**1. 0G keys on the robot** — your `.env` is gitignored and does **not** travel with
the published app, and the framework injects no secrets. So the app would run but
never reach 0G. SSH into the robot and drop your keys where `config.py` looks for them:
```bash
# on the robot (over SSH):
mkdir -p ~/.config/mr_reachy
nano ~/.config/mr_reachy/.env # paste the OG_CHAT_* / OG_STT_* lines from your local .env
```
(Alternatively point `MR_REACHY_ENV` at a keys file.) Keep keys off the public Space —
publish with `--private` if you ever bake config in.
**2. Speech — install Piper on the robot** (0G has no TTS provider):
```bash
pip install "mr-reachy[robot]" # piper-tts + pillow
# download a voice once, then point the app at it:
export PIPER_MODEL=/path/to/en_US-amy-medium.onnx # (+ matching .onnx.json)
```
**2. Internet** — the robot must reach the 0G endpoints
(`compute-network-*.integratenetwork.work`). Venue Wi-Fi may block this; test early.
**3. Antenna push-to-talk** — press an antenna to talk, release to send. Tune the
sensitivity if needed:
```bash
export MR_ANTENNA_THRESHOLD=0.5 # radians of deflection that counts as a press
```
**4. Publish & install:**
```bash
# Run the checker DEACTIVATED — an active venv's $VIRTUAL_ENV breaks its nested temp venv:
env -u VIRTUAL_ENV .venv/bin/reachy-mini-app-assistant check .
reachy-mini-app-assistant publish # requires `hf auth login`
```
Then **Install to Robot** from your Hugging Face Space (dashboard URL
`http://reachy-mini.local:8000`) and start it from the dashboard. The robot
auto-returns to its rest pose when the app stops.
The app is registered via the `reachy_mini_apps` entry point
(`mr_reachy.main:MrReachy`) in `pyproject.toml`.
### Driving a robot from your machine (Lite, or testing Wireless over the network)
```bash
python -m mr_reachy --on-robot # uses robot media + antenna push-to-talk
```
`ReachyMini()` auto-connects to a local daemon, falling back to `reachy-mini.local`.
For an explicit network connection use `connection_mode="network"`.
## Layout
```
mr_reachy/
main.py # ReachyMiniApp + conversation loop + CLI
og_client.py # 0G Compute: chat / STT / vision (OpenAI-compatible)
medication.py # medication plans, doses, parser, confirmation intent
storage.py # local JSON cache + background 0G Storage sync
reminders.py # due-dose reminder loop + confirmation/missed-dose handling
io_backends.py # Local (laptop) vs Robot (onboard media + antenna push-to-talk)
tts.py # on-device speech synthesis (Piper / say / espeak)
expressions.py # emotion -> head pose + antenna gestures
audio.py # laptop mic VAD capture + local TTS
config.py # loads .env into typed settings
```
See `plan.md` for the design and `agents.local.md` for environment notes.
## Validation
```bash
python -m unittest tests.test_medication tests.test_storage tests.test_reminders
python -m py_compile app.py mr_reachy/main.py mr_reachy/medication.py mr_reachy/storage.py mr_reachy/reminders.py
```