Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OffHand

Bet on yourself. Talk to the hand.

OffHand is a habit accountability app. You chat with The Challenger (a slightly cheeky hand persona), wager virtual "fingers" on a habit, and either follow through or lose them.

Chat‑only — no forms, no confirm buttons. Just talk.

OffHand landing page

OffHand chat with The Challenger


Features

  • Conversational betting — the LLM understands "bet 100 on the run tomorrow" and places it via tool calls.
  • Persistent chat memory keyed by session (MongoDB).
  • Per‑user identity + fingers balance, updated automatically as bets are created and completed.
  • Web app + PWA install (works offline shell, add to home screen).
  • Voice input (Web Speech API) + text‑to‑speech reply with system voice picker.
  • Markdown‑rendered replies, bullet lists for "show my bets".

Stack

Backend

  • FastAPI + Uvicorn
  • Beanie (async MongoDB ODM)
  • LangChain + Gemini (langchain-google-genai)
  • langchain-mongodb chat message history
  • uv for dependency management

Frontend

  • Plain HTML / CSS / vanilla JS in ui/ — no build step
  • Google Fonts (Space Grotesk + Inter), Ionicons, marked, DOMPurify
  • Service worker + web manifest for PWA install

Setup

Prereqs

  • Python 3.13
  • uv
  • MongoDB (local or Atlas)
  • Google AI Studio API key (Gemini)

Backend

  1. Clone and install:

    git clone https://github.com/<you>/OffHand
    cd OffHand
    uv sync
  2. Create a .env at the repo root:

    MODEL=gemini-2.5-flash
    API_KEY=your_google_ai_studio_key
    MONGODB_URL=mongodb://localhost:27017
  3. Run:

    make run

    Serves on http://localhost:8000.

Frontend

make ui

Serves ui/ on http://localhost:5173 via Python's built‑in http.server. Open it in a browser. First visit → sign up.

To point the UI at a deployed backend, edit const API at the top of ui/app.html.


Project layout

src/
  main.py                  FastAPI app + CORS + router mounts
  api/
    chatbot_router.py      POST /chatbot/
    user_router.py         POST /user/{signup,signin}, GET /user/{id}
  ai/
    llm.py                 tool loop
    prompts.py             SYSTEM_PROMPT
    context.py             current_user_id ContextVar
  service/
    bet_service.py         LangChain @tool functions
    user_service.py        auth + user helpers
  model/                   Beanie Documents
  config/                  settings + Mongo init

ui/
  index.html               landing page (install PWA)
  app.html                 chat UI
  manifest.webmanifest     PWA manifest — start_url = /app.html
  sw.js                    network-first for HTML, cache-first for assets
  hand.png, point.png      mascot + favicon

How it works

  • Frontend generates a user_id (on signup) and a session_id (per browser session), stores both in localStorage, and sends them as headers on every /chatbot/ call.
  • session_id keys the MongoDBChatMessageHistory collection → per‑session chat memory.
  • user_id is set into a Python ContextVar at the top of the chatbot route. Bet tools read it from there — the LLM never sees or handles user IDs, so it can't accidentally act on the wrong user.
  • The LLM is bound to four bet tools: create_bet, get_all_bets, get_bet, update_bet. User CRUD lives in a plain FastAPI router — deliberately not exposed as LLM tools.
  • Balances are updated automatically inside update_bet when a bet is completed or reopened.

Roadmap

  • Bet expiry (days) with auto‑forfeit on expires_at
  • The Challenger's own finger balance / counter‑bet tracking
  • Habit categories + streaks
  • Push notifications for expiring bets
  • Real password hashing (currently plaintext — hobby stage)

License

MIT (or whichever — add if needed).

About

Bet on yourself — talk to the hand. Chat-only habit tracker with a cheeky AI accountability persona and virtual "fingers" as stakes.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages