FastAPI + MySQL + Flutter/Vanilla HTML/JS group chat with LLM bot integration.
🚀 New here? Start with QUICKSTART.md for the fastest setup!
# Run the schema file to create database, user, and tables
mysql -u root -p < sql/schema.sql
# Or manually:
mysql -u root -p
# Then paste contents of sql/schema.sql
# Load GroceryDataset.csv (optional)
cd backend
python load_groceries.py
# 2) Backend
cd backend
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# Copy env and edit values
cp .env.example .env
# 3) Run app
python -m uvicorn app:app --host 0.0.0.0 --port 8000The application now supports multiple LLM models:
- OpenAI (gpt-4o-mini) - Cloud API
- Google Gemini (2.5-flash) - Cloud API
- TinyLlama - Local model via Ollama
Edit backend/.env with your API credentials:
# Database
DATABASE_URL=mysql+asyncmy://chatuser:chatpass@localhost:3306/groceryshopperai
JWT_SECRET=your-long-secret-key-here-minimum-32-characters
JWT_EXPIRE_MINUTES=43200
APP_HOST=0.0.0.0
APP_PORT=8000
# OpenAI (optional)
OPENAI_API_KEY=sk-your-openai-key-here
# Google Gemini (optional)
GEMINI_API_KEY=AIza_your-gemini-key-here
GEMINI_MODEL=models/gemini-2.5-flash
# Ollama (optional, for local TinyLlama)
# OLLAMA_API_BASE=http://localhost:11434GroceryShopperAI/
│
├── 📂 backend/ # FastAPI Backend (Python)
│ ├── app.py # Main FastAPI application with all API routes
│ ├── db.py # SQLAlchemy ORM models (User, Room, Message, RoomMember)
│ ├── auth.py # JWT authentication, password hashing
│ ├── llm.py # LLM integration (OpenAI, Gemini, TinyLlama)
│ ├── websocket_manager.py # WebSocket connection manager for real-time chat
│ ├── load_groceries.py # Script to load GroceryDataset.csv into database
│ ├── requirements.txt # Python dependencies (FastAPI, SQLAlchemy, Google Generative AI, etc.)
│ ├── .env.example # Environment variables template
│ ├── GroceryDataset.csv # Grocery items dataset
│ └── __pycache__/ # Python cache
│
├── 📂 flutter_frontend/ # Flutter Cross-Platform App (Dart)
│ ├── lib/
│ │ ├── main.dart # App entry point, theme setup
│ │ ├── 📂 pages/ # Screen pages
│ │ │ ├── login_page.dart # Login & Signup screen
│ │ │ ├── home_page.dart # Room list screen
│ │ │ ├── chat_detail_page.dart # Chat screen
│ │ │ └── profile_page.dart # User profile & model selection
│ │ ├── 📂 services/ # Business logic services
│ │ │ ├── api_client.dart # HTTP client for backend API
│ │ │ ├── auth_service.dart # Authentication logic
│ │ │ ├── storage_service.dart # Secure local token storage
│ │ │ └── image_service.dart # Image handling
│ │ ├── 📂 models/ # Data models
│ │ │ └── message.dart # Message model
│ │ ├── 📂 widgets/ # Reusable UI components
│ │ │ ├── frosted_glass_button.dart
│ │ │ └── ... other widgets
│ │ └── 📂 themes/ # Theme configuration
│ │ ├── colors.dart # Color palette
│ │ ├── light_mode.dart # Light theme
│ │ └── dark_mode.dart # Dark theme
│ ├── ios/ # iOS specific configuration
│ │ ├── Runner/ # Xcode project
│ │ ├── Pods/ # CocoaPods dependencies
│ │ └── Podfile # iOS dependency management
│ ├── android/ # Android specific configuration
│ │ ├── app/ # Android app module
│ │ ├── gradle/ # Gradle build system
│ │ └── build.gradle # Project-level build config
│ ├── web/ # Web specific configuration
│ │ ├── index.html # Web entry point
│ │ └── manifest.json # Web app manifest
│ ├── assets/ # App resources
│ │ ├── fonts/ # Custom fonts
│ │ └── ... images, etc
│ ├── pubspec.yaml # Flutter project config & dependencies
│ ├── pubspec.lock # Locked dependency versions
│ ├── analysis_options.yaml # Dart analyzer rules
│ └── README.md # Flutter app documentation
│
├── 📂 frontend/ # Optional: Vanilla HTML/JS Web Frontend
│ ├── index.html # Main HTML page
│ ├── app.js # JavaScript logic
│ └── styles.css # Styling
│
├── 📂 sql/ # Database Schema
│ └── schema.sql # MySQL database setup script
│ ├── CREATE DATABASE groceryshopperai
│ ├── CREATE USER chatuser
│ ├── CREATE TABLE users
│ ├── CREATE TABLE rooms
│ ├── CREATE TABLE room_members
│ ├── CREATE TABLE messages
│ └── CREATE INDEXES
│
├── 📂 twa_android_src/ # Trusted Web Activity (Android)
│ ├── app/
│ ├── build.gradle
│ └── settings.gradle
│
├── 📄 README.md # Main project documentation
├── 📄 QUICKSTART.md # Quick setup guide (5 min)
├── 📄 CHECKLIST.md # Setup verification checklist
├── 📄 requirements.txt # Reference copy of backend dependencies
└── 📄 .gitignore # Git ignore rules
POST /api/signup- Create new user accountPOST /api/login- User login, returns JWT token
GET /api/rooms- List all rooms user is member ofPOST /api/rooms- Create new roomGET /api/rooms/{room_id}/members- Get room membersPOST /api/rooms/{room_id}/invite- Invite user to room
GET /api/rooms/{room_id}/messages- Get chat history (limit: 50)POST /api/rooms/{room_id}/messages- Send message (triggers LLM if @gro mentioned)
GET /api/users/llm-model?platform=ios|android|web|desktop- Get available modelsPUT /api/users/llm-model- Change user's preferred modelPOST /api/models/download-tinyllama- Download TinyLlama locallyGET /api/models/download-progress- Check download progress
WS /ws?room_id={room_id}- Real-time chat connection
- id (PK)
- username (UNIQUE)
- password_hash
- preferred_llm_model (openai | gemini | tinyllama)
- created_at, updated_at
- id (PK)
- name (UNIQUE)
- owner_id (FK → users.id)
- created_at
- id (PK)
- room_id (FK → rooms.id)
- user_id (FK → users.id)
- joined_at
- id (PK)
- room_id (FK → rooms.id)
- user_id (FK → users.id, nullable)
- content (TEXT)
- is_bot (BOOLEAN)
- created_at
- User enters credentials on LoginPage
- ApiClient sends POST request to
/api/login - Backend returns JWT token
- StorageService stores token securely
- App navigates to HomePage
- HomePage displays list of rooms
- User selects room → ChatDetailPage
- WebSocket connects to
/ws?room_id={id} - Messages stream in real-time
- User types message → POST to
/api/rooms/{id}/messages - Message broadcast to all connected clients
- User types message with
@gromention - Message sent to backend
- Backend detects
@gromention - LLM called (based on user's preferred model)
- Bot response created as message with
is_bot=true - WebSocket broadcasts bot message to room
- User navigates to ProfilePage
- Clicks "AI Model" setting
- Dialog shows available models based on platform:
- iOS/Android: OpenAI, Gemini
- Web/Desktop: TinyLlama, OpenAI, Gemini
- Selection saved via PUT
/api/users/llm-model
| Model | Type | Provider | Setup | Platform Support |
|---|---|---|---|---|
| gpt-4o-mini | Cloud API | OpenAI | API Key | All |
| gemini-2.5-flash | Cloud API | API Key | All | |
| tinyllama | Local | Ollama | Local download | Desktop/Web only |
- User sends message with
@gro - Backend extracts user's preferred model
- Calls appropriate LLM provider:
- OpenAI: Uses
openailibrary, sends toapi.openai.com - Gemini: Uses
google-generativeaiSDK, sends to Google API - TinyLlama: Calls local
ollamaserver
- OpenAI: Uses
- Response streamed back
- Bot message inserted to database
- WebSocket broadcasts to room
- Framework: FastAPI (async Python web framework)
- Server: Uvicorn (ASGI server)
- Database ORM: SQLAlchemy 2.0 (async)
- Database Driver: asyncmy (async MySQL)
- Authentication: PyJWT + passlib (bcrypt)
- Real-time: WebSocket via Starlette
- LLM: google-generativeai, openai (via requests), ollama (HTTP)
- Framework: Flutter 3.x (Dart)
- HTTP: http package
- WebSocket: web_socket_channel
- Storage: flutter_secure_storage (encrypted)
- UI: Material Design
- Fonts: google_fonts
- Image Handling: image_picker
- MySQL 8.0+
- Character Set: utf8mb4 (supports emoji, multiple languages)
- Engine: InnoDB (transactions, foreign keys)
- Local Development: Uvicorn + MySQL + Ollama (optional)
- Deployment Ready: Docker compatible, scalable
✅ Real-time Chat - WebSocket for instant messaging
✅ LLM Integration - Multiple AI models support
✅ Cross-platform - iOS, Android, Web from single codebase
✅ Secure Auth - JWT + bcrypt password hashing
✅ User Management - Signup, login, profiles
✅ Room Management - Create rooms, invite members
✅ Message History - Persistent chat storage
✅ Model Selection - Per-user LLM preference
✅ Responsive UI - Works on all screen sizes
User (App)
↓
Flutter Frontend (api_client.dart)
↓
HTTP/WebSocket
↓
FastAPI Backend (app.py)
↓
SQLAlchemy ORM (db.py)
↓
MySQL Database (sql/schema.sql)
↓
LLM Services (llm.py)
├→ OpenAI API
├→ Google Generative AI
└→ Local Ollama Server
- fastapi, uvicorn, starlette
- sqlalchemy, asyncmy
- passlib, pyjwt, python-jose
- google-generativeai, google-api-core, google-auth
- python-dotenv, httpx, requests
- pydantic, jinja2
- http, web_socket_channel
- flutter_secure_storage
- google_fonts, intl
- image_picker
- Backend changes: Edit files in
backend/, restart Uvicorn - Frontend changes: Edit files in
flutter_frontend/lib/, hot reload in Flutter - Database changes: Modify
sql/schema.sql, run migration script - Configuration: Update
backend/.envfor API keys - Dependencies: Update
backend/requirements.txtorflutter_frontend/pubspec.yaml
-
Backend Development
- Edit
backend/app.py,db.py,llm.py - Restart Uvicorn to see changes
- Check logs in Terminal 1
- Edit
-
Frontend Development
- Edit files in
flutter_frontend/lib/ - Hot reload: Press
rin Flutter console - Check logs in Terminal 2
- Edit files in
-
Database Changes
- Edit
sql/schema.sql - Run:
mysql -u root -p < sql/schema.sql - Restart backend to reconnect
- Edit
-
Testing
- Use app UI to test features
- Check backend logs for API calls
- Use database client to verify data