Use as a starter for a Flutter chat app with token-by-token streaming
Learn how to bridge Server-Sent Events from FastAPI into Flutter via the Dio HTTP client
Front a Claude-on-OpenRouter chatbot with a FastAPI proxy so the API key stays off the device
Swap the empathetic persona system prompt for your own character and ship a different chatbot
Need an OpenRouter API key plus a Python venv for the back end and the correct localhost host depending on emulator or web target.
CheerUp is a small AI chat app that pairs a mobile front end with a Python back end. The mobile app is built in Flutter, the back end is a FastAPI service in Python, and the AI itself is a Claude model accessed through OpenRouter. The character of the chatbot is called CheerUp, an empathetic comfort buddy that listens, validates feelings, and gently encourages the user. That persona is set by a system prompt held on the back end. The main thing the README focuses on is how replies stream into the screen one word at a time, the way ChatGPT does. Without streaming, the user would wait five to ten seconds for the AI to finish before seeing anything. The author chose Server-Sent Events, a one-way HTTP push protocol, so each token can appear as soon as it is generated. The README contrasts this with WebSockets, which allow two-way traffic but are heavier to set up, and notes that one-way streaming is enough here. The data flow is laid out step by step. The user types a message, the Flutter ChatProvider calls a ChatService that uses the Dio HTTP library to POST to the FastAPI endpoint at /chat/stream. FastAPI calls OpenRouter with streaming enabled, forwards each token as an SSE event back to Flutter, and the Flutter side appends every token to a buffer that the UI rebuilds in real time. When a final [DONE] event arrives, the assembled text is saved as a Message object in the chat history. The rest of the README is a tour of design choices presented in interview-style notes. FastAPI sits in the middle so the OpenRouter API key never lives inside the mobile app, and so future server-side logic such as rate limiting or auth can be added without touching the client. State uses the Provider package rather than BLoC or Riverpod, the back end retries calls with exponential backoff and jitter, the full conversation history is resent on each request, and Pydantic schemas validate request and response bodies. The README also lists how to run both pieces. The back end is a Python virtual environment with requirements installed from pip, then started with run.py on port 8000. The Flutter app uses different localhost addresses depending on whether it runs on an Android emulator, iOS, or web.
Generated 2026-05-22 · Model: sonnet-4-6 · Verify against the repo before relying on details.