An AI application that helps maintain healthy habit streaks through smart negotiation, not force.
cd backend
pip install -r requirements.txt
# copy and fill your keys
copy .env.example .env
# run (Windows/macOS/Linux)
python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000Backend will run at http://localhost:8000.
More details: see backend/README.md.
cd frontend/flexifit_app
flutter pub getflutter devices
flutter run -d chrome
# or
flutter run -d edgeflutter devices
flutter run -d <device-id>If you want to use an Android emulator:
flutter emulators
flutter emulators --launch <emulator-id>
flutter run -d <device-id>Set the backend URL at runtime using --dart-define:
# Local backend
flutter run -d <device-id> --dart-define=API_BASE_URL=http://localhost:8000
# Deployed backend
flutter run -d <device-id> --dart-define=API_BASE_URL=<your-backend-url>If you prefer a boolean flag for local dev (if supported in your build):
flutter run -d <device-id> --dart-define=USE_LOCAL_API=true- Open app → Dialog appears
- Input: "Run 5km every day"
- Expected: Goal saved, chat starts
- Chat: "I'm really tired today"
- Expected: AI validates feelings + offers micro-habit
- Example response: "I understand you're tired. How about just a 10-minute walk?"
- Chat: "Ready for action!"
- Expected: AI provides encouragement + actionable steps
- Check API key in
.env - Test endpoint:
http://localhost:8000/docs
- Ensure
baseUrlmatches environment - Check Flutter console for HTTP errors
- Android 13+: user must allow notification permission.
- Android 12+: exact alarm permission may be required for precise scheduling.
- Some devices (Doze/OEM battery optimization) may delay scheduled notifications; set the app battery mode to “Unrestricted” if needed.
- Push to GitHub
- Connect Railway → Deploy from GitHub
- Set Railway Variables (
GOOGLE_API_KEY,OPIK_API_KEY) - Deploy using the monorepo Dockerfile setup (details in backend/README.md)
- Update Flutter
baseUrlwith the Railway public URL
Backend Swagger docs (Railway): https://flexifit-production.up.railway.app/docs
flutter build apk --releaseThis option builds Flutter Web in GitHub Actions and deploys the generated static site to Vercel. You do not need Flutter installed on Vercel.
- Create a new project in Vercel (Dashboard).
- The deployment will be done by GitHub Actions using the Vercel CLI.
In GitHub: Settings → Secrets and variables → Actions → Secrets, add:
VERCEL_TOKEN(Vercel access token for GitHub Actions)VERCEL_PROJECT_NAME(your Vercel project name/slug, e.g.flexifit)VERCEL_SCOPE(optional: team slug/username, e.g.psianturis-projects)
Important: these are NOT the same as app/runtime environment variables.
VERCEL_*secrets are only for GitHub Actions → Vercel deployment authentication + selecting the target Vercel project.- Things like Gemini API key belong to the backend (Railway) and are set in Railway variables.
- Things like API base URL for the Flutter app are set as GitHub Actions Variables and baked into the web build via
--dart-define.
So: you do not put VERCEL_TOKEN etc into Vercel “Environment Variables” for the app. They live in GitHub Secrets so CI can deploy.
How to get VERCEL_TOKEN:
- Vercel Dashboard → your Avatar/Profile → Settings → Tokens → create a token.
How to pick VERCEL_PROJECT_NAME:
- This is the Vercel project name/slug (example:
flexifit). - Your public domain can be changed in Vercel → Domains (example:
flexifit-encode.vercel.app).
If you deploy under a Team, set VERCEL_SCOPE to the team slug (example: psianturis-projects).
Tip: do not commit the .vercel/ folder to git.
In GitHub: Settings → Secrets and variables → Actions → Variables, add:
API_BASE_URL(example:https://flexifit-production.up.railway.app)SHOW_DEBUG_EVALS(falserecommended for prod)
These are injected into flutter build web using --dart-define.
Note: --dart-define is build-time for Flutter Web. Changing Vercel environment variables after deploy will not change the already-built web bundle.
- Push to
main. - Workflow:
.github/workflows/deploy_flutter_web_vercel.ymlbuilds and deploys.
Notes:
- Flutter Web is a single-page app; we include a
vercel.jsonroute rule to rewrite unknown routes toindex.html. - If your backend restricts CORS origins, add your Vercel domain to backend
CORS_ORIGINS. - In Vercel project settings, keep Root Directory empty when using GitHub Actions + Vercel CLI to deploy prebuilt static files.
Common gotchas on web:
- Make sure backend CORS allows your Vercel domain.
- Microphone / speech-to-text depends on browser support + HTTPS permissions.
✅ Core MVP: AI Negotiator with BJ Fogg methodology
✅ Stateless Architecture: Fast deploy, no database complexity
✅ Context Injection: AI "remembers" goal without server storage
✅ Advanced Prompting: Few-shot examples + structured negotiation protocol
✅ Opik Integration: End-to-end observability (traces + metrics)
✅ Smart Demo UI: Quick reply buttons for consistent demo experience
Context Injection Technique: Every user message is wrapped with goal context, making AI appear "smart" without needing complex database server.
context_prompt = f"USER'S GOAL: {goal}\nUSER SAYS: {message}"We implemented a closed-loop, self-improving AI system using Opik tracing + online LLM-based evaluations:
- Real-time evaluation: Every AI response is scored on Empathy (1-5) with a human-readable rationale.
- Automated self-correction: If the score falls below a threshold, the backend automatically rewrites the response once before returning it to the user.
- Scientific Experiments: A golden-dataset experiment runner (backend/evals/run_experiment.py) runs fixed scenarios across prompt/model versions and logs results to Opik for comparison.
- Client-Side Debugging: A Flutter debug overlay (enabled via
--dart-define=SHOW_DEBUG_EVALS=true) shows empathy score + rationale in real time without affecting production UX.