A Perplexity-style Q&A app built with Flutter (frontend) and FastAPI (backend).
This project was created to sharpen skills in Streams & WebSockets β the frontend streams answers from the backend WebSocket and renders them live as Markdown.
- Perplexity Clone π
This repository demonstrates a live Q&A streaming flow: a Flutter client connects to a FastAPI backend over WebSockets and displays streaming text chunks as Markdown. The app is optimized for local development across Android, iOS, Web and Desktop using simple networking patterns for connecting emulators and physical devices.
perplexity_clone/
β
βββ lib/ # Flutter source code
β βββ main.dart
β βββ core/
β βββ presentation/
β βββ services/
β
βββ assets/
β βββ images/
β βββ ...
β
βββ server/ # Backend (FastAPI)
β βββ main.py # FastAPI app (contains http & ws endpoints)
β βββ requirements.txt # pip dependencies
β βββ README.md # backend-specific docs (optional)
β βββ venv/ # virtualenv (should be in .gitignore)
β
βββ pubspec.yaml # Flutter metadata & deps
βββ README.md # This file
βββ .gitignore
- Python 3.9+
- pip
- (recommended) virtualenv or
python -m venv adbif you plan to connect a physical Android device via USB
cd server
python3 -m venv venvWindows (PowerShell)
# If PowerShell prevents script execution, run once as admin or for current user
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Activate venv
.\venv\Scripts\activatemacOS / Linux
source ./venv/bin/activate
β οΈ Make sure Python is installed and accessible from your PATH.
pip install -r requirements.txtExample server/requirements.txt
fastapi
uvicorn[standard]
websockets
python-dotenv # optional, if you use .env
(You can pin versions for reproducible environments.)
Recommended (explicit uvicorn command β binds to all interfaces so mobile devices can reach it):
uvicorn main:app --reload --host 0.0.0.0 --port 8000If you prefer the FastAPI CLI and it's available:
fastapi dev main.pyAPI keys setup (Tavily & Google Gemini)
This project requires external API keys for Tavily (search) and Google Gemini (LLM) integrations.
- Go to
Tavilyand sign up. - Create a new project and generate an API key.
- Copy the key (e.g., tvly-dev-...).
- Go to Google AI Studio or the
Google Cloud Console. - Enable
Generative Language API. - Create credentials β API key.
- Copy the key (starts with AIza...).
What to expect
- HTTP API (example):
http://127.0.0.1:8000/chat - WebSocket:
ws://127.0.0.1:8000/ws/chat
Tip: use --host 0.0.0.0 when you want other devices on the LAN to access the server (e.g., http://192.168.x.y:8000).
Use adb reverse to map device port β PC port so the device can use localhost on your PC.
adb devices # ensure device is connected & authorized
adb reverse tcp:8000 tcp:8000Then in your Flutter app you can point to:
http://127.0.0.1:8000
ws://127.0.0.1:8000/ws/chat
If using adb connect <DEVICE_IP> (device over WiβFi):
adb -s <device-ip-or-id> reverse tcp:8000 tcp:8000- Android Emulator (AVD): use
10.0.2.2:8000to reach your machine's localhost. - Genymotion: use
10.0.3.2:8000.
Run the backend listening on 0.0.0.0:
uvicorn main:app --reload --host 0.0.0.0 --port 8000
Find your PCβs LAN IP (e.g. 192.168.1.42) and connect from the device to:
http://192.168.1.42:8000
ws://192.168.1.42:8000/ws/chat
Make sure firewall rules allow incoming connections on port 8000.
flutter pub getflutter gen-l10nAdd the following to pubspec.yaml:
flutter_launcher_icons:
android: true
ios: true
image_path: "assets/images/app_icon.png"Then run:
flutter pub run flutter_launcher_iconsAdd to pubspec.yaml:
flutter_native_splash:
color: "#51B848"
image: assets/images/logo_large.png
android: true
ios: true
fullscreen: trueThen run:
flutter pub run flutter_native_splash:createflutter runUse http://10.0.2.2:8000 on AVD emulator, or http://127.0.0.1:8000 if you used adb reverse with a physical device.
If you used your PC LAN IP, point the app to http://<PC_IP>:8000 and ws://<PC_IP>:8000/ws/chat.
If you want configurable endpoints, use a .env in server/ or a constants file in Flutter.
server/.env
HOST=0.0.0.0
PORT=8000
Flutter example
// lib/core/constants.dart
const backendHost = 'http://10.0.2.2:8000';
const websocketUrl = 'ws://10.0.2.2:8000/ws/chat';adb reverse not working
- Confirm
adb devicesshows your device and it isdevice(notunauthorized). - Reconnect USB, accept the RSA prompt on the device.
- Use
adb -s <id> reverse ...if multiple devices are attached. - Alternative: host on
0.0.0.0and use PC LAN IP.
WebSocket connection refused
- Ensure backend is running and listening on the port you expect.
- If using
127.0.0.1on backend, mobile device may not reach it β useadb reverseor0.0.0.0+ PC IP. - Check firewall/antivirus blocking the port.
CORS / security
- WebSocket from Flutter mobile clients generally does not require CORS.
- For web builds, ensure your server adds appropriate CORS headers (e.g., using
fastapi.middleware.cors.CORSMiddleware).
Large streamed messages / chunking
- If streaming text in chunks, ensure the client correctly appends chunks and updates UI on the main thread (use
setStateor state management callbacks). - Consider a small
backpressureor rate-limiting in the backend if your client cannot keep up.
Slow scroll-to-bottom / UI not updating
- Ensure you call scroll after the frame is rendered:
WidgetsBinding.instance.addPostFrameCallback. - Use
ListViewwithcontroller.jumpTooranimateToafter new chunks arrive.
Tokenization / encoding issues
- Make sure you agree on encoding (usually UTF-8) and avoid sending binary chunks as text unless both sides expect it.
- Streaming answers from FastAPI WebSocket to Flutter via a
Stream. - Live Markdown rendering for richly formatted answers.
- Skeleton loaders while waiting for content.
- Clear separation between backend and frontend for local development.
- Designed to work on Web, Android, iOS and Desktop.
perplexiy_clone_demo.mp4
- Fork the repo.
- Create a feature branch:
git checkout -b feat/your-feature. - Commit and push:
git commit -am "Add feature" && git push origin feat/your-feature. - Open a Pull Request with a clear description and testing steps.
Open issues for bugs or feature requests and keep backend/frontend changes split with documented env variables.
If you want help setting this up, want features added, or want to collaborate:
- Email: tushkwork@gmail.com
- Mobile: 9673072109
Happy hacking β stream safely and render beautifully!