Sinai is a local-first multi-device assistant platform for live demos.
It is designed for hackathon judging:
- one shared monitor view for the room
- many phone clients with clear device identity
- a dedicated Data Mode fed by live Arduino/sensor readings
- realtime sync across monitor, phones, and sensor updates
- global FIFO prompt queue so responses follow ask order across devices
- local execution on laptop or Raspberry Pi (no cloud dependency required)
- Assistant Mode: shared feed of prompts + assistant responses
- Data Mode: live sensor dashboard with readable metrics and update feed
- connected devices list and recent activity
- clear per-device names and accents
- first-join device naming
- persisted identity in local storage
- prompt input and response history
- touch-friendly composer and fast send flow
- ingest endpoint:
POST /api/data/ingest - serial bridge script:
arduino/serial_to_sinai.py - merged into Data Mode in near realtime
Sinai/
app/
local_web/
server.py # FastAPI app + websockets + data ingest
services/
context_provider.py # Context construction (live/mock)
fallback_assistant.py # Fallback response path
ollama_client.py # Local Ollama client
prompting.py # System prompt + message assembly
session_store.py # Device identity + session/feed state
static/
index.html # Monitor + client surfaces
app.js # Realtime UI logic and rendering
styles.css # Production-ready demo styling
services/
sensor_ingestion.py # Hardware/mock sensor acquisition
normalization.py # Sensor label classification
models/
environmental.py # Sensor domain models
arduino/
grove_light_serial.ino # Example Arduino sketch (JSON serial lines)
serial_to_sinai.py # Serial -> Sinai ingest bridge
docs/
install_sinai_web_pi.sh # One-command Pi setup
setup_pi_hotspot_portal.sh # Pi hotspot + captive redirect
install_ollama_mini_pi.sh
pi_ollama_deployment.md
requirements.txt
requirements-hardware.txt
- FastAPI server (
app/local_web/server.py)- REST API for chat, context, history, devices, and data ingest
- WebSocket endpoint for low-latency monitor/client updates
- background sensor polling loop for dashboard freshness
- SessionStore
- per-device identity (name, color, message count, connection state)
- per-session chat history
- shared monitor feed
- SensorFeedState
- baseline sensor frames from live/mock provider
- optional Arduino bridge overlay with stale-time handling
- rolling history + trend series for Data Mode
- Ollama path + fallback path
- local LLM via Ollama when available
- deterministic fallback response when unavailable
- Phone opens
/client, joins with device name. - Device identity is registered and persisted.
- Prompt is sent to
POST /api/chat. - Prompt + reply events are broadcast to monitor through websocket.
- Phone receives updated history/reply and keeps identity attached.
- Arduino emits JSON lines over serial (USB).
arduino/serial_to_sinai.pyparses and posts readings toPOST /api/data/ingest.- Server merges readings into current sensor frame.
- Data Mode updates instantly on monitor via websocket broadcasts.
python -m venv .venv
source .venv/bin/activate # Windows PowerShell: .\.venv\Scripts\Activate.ps1
pip install --upgrade pip
pip install -r requirements.txtollama serve
ollama pull llama3.2:1buvicorn app.local_web.server:app --host 0.0.0.0 --port 8501Open:
- monitor:
http://<host-ip>:8501/monitor - phone:
http://<host-ip>:8501/client
If you open / directly, default surface is the phone/client flow.
python arduino/serial_to_sinai.py --port /dev/ttyACM0 --server http://127.0.0.1:8501Windows example:
python arduino/serial_to_sinai.py --port COM5 --server http://127.0.0.1:8501POST /api/chat- body:
{
"message": "What should we prioritize next 24h?",
"mode": "live",
"site_name": "Sinai Local Node",
"region": "Coastal Recovery Zone"
}POST /api/device/register- body:
{
"device_name": "Judge Phone 1"
}POST /api/data/ingest- body:
{
"source": "arduino-serial",
"device_name": "Arduino Uno",
"readings": {
"temperature_c": 27.3,
"humidity_percent": 56,
"soil_moisture_pct": 41,
"light_lux": 9120,
"uv_index": 4.2,
"air_quality_eco2_ppm": 742,
"air_quality_tvoc_ppb": 182,
"pressure_hpa": 1008.2
}
}OLLAMA_HOST(defaulthttp://127.0.0.1:11434)OLLAMA_MODEL(default from app config)SINAI_SESSION_SECRET
SINAI_SITE_NAME(defaultSinai Local Node A-17)SINAI_MONITOR_DATA_MODE(liveormock, defaultlive)SINAI_DATA_POLL_INTERVAL(seconds, default1.2)SINAI_ARDUINO_STALE_SECONDS(seconds, default25)
cd /home/pi/Sinai
bash docs/install_sinai_web_pi.sh llama3.2:1b /home/pi/SinaiThis installs dependencies, pulls model, and creates sinai-web systemd service.
systemctl status sinai-web --no-pager
systemctl status ollama --no-pagersudo bash docs/setup_pi_hotspot_portal.sh Sinai-AI-Test OPEN 192.168.50.1Then phones join Pi Wi-Fi and open:
http://192.168.50.1/client
Use monitor/HDMI:
http://127.0.0.1/monitor(orhttp://127.0.0.1:8501/monitor)
OPEN means no password. If you want a password later, pass one as the second argument.
- reduced assistant response target length for faster generation
- reduced Ollama token ceiling for faster turnaround
- websocket-first realtime updates for monitor/client
- fallback polling only when websocket is disconnected
- lightweight DOM updates and bounded feed/history windows
- rolling sensor history for sparkline rendering (small in-memory footprint)
- reconnect handling for phones that refresh or temporarily drop Wi-Fi
- Open monitor on HDMI (
/monitor). - Connect two phones to
/client, set different device names. - Send prompts from both phones; monitor shows identity per prompt/reply.
- Switch monitor to Data Mode.
- Start Arduino bridge and show live metric changes.
- Emphasize that everything runs locally on one node.