Multi‑room real‑time chat with optional AI answers. Start locally in a minute. Move to Azure when you're ready—no code changes.
Want architecture diagrams, CloudEvents/tunnel details, RBAC & env matrix? See docs/ADVANCED.md. Release history: RELEASE_NOTES.md
- Real‑time rooms (create / join instantly)
- AI bot responses (GitHub Models via your PAT)
- Persistence + scale when on Azure Web PubSub
- Same React UI + Python backend in all modes
Prereqs:
- Python 3.12+
- Node 18+
- Create a PAT with Models – Read: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
- (Recommended) Create and activate a virtual environment:
- macOS/Linux (bash/zsh):
python3 -m venv .venv source .venv/bin/activate python -m pip install --upgrade pip - Windows (PowerShell):
python -m venv .venv .venv\Scripts\Activate.ps1 python -m pip install --upgrade pip
deactivate
- macOS/Linux (bash/zsh):
- Install backend + frontend deps (inside the venv):
pip install -r requirements.txt # optional (tests, typing): pip install -r requirements-dev.txt - (Set token if you want AI answers)
Alternatively, you can update GITHUB_TOKEN in ./python_server/.env
export GITHUB_TOKEN=<your_pat> # bash/zsh # PowerShell $env:GITHUB_TOKEN="<your_pat>"
- Start everything (serves React build automatically):
python start_dev.py
- Open http://localhost:5173
Running services:
- HTTP API :5000
- Local WebSocket :5001 (self transport)
- Browse to http://localhost:5173
- You're placed in room
public - Create / join a room: type a name → Enter
- Ask something; the AI bot replies (uses your GitHub token)
- Open a second window to watch live streaming & room isolation
Install dev extras first:
pip install -r requirements-dev.txtBackend (pytest):
python -m pytest python_server/tests -qSingle file:
python -m pytest python_server/tests/test_runtime_config.py -qVerbose / timing:
python -m pytest -vvFrontend (Vitest + RTL):
npm --prefix client testSelected coverage areas (backend): config merge, room store limits, transport factory, room lifecycle, streaming send path.
Install the Azure Developer CLI if you haven't: https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd
azd env new chatenv
azd env set githubModelsToken ghp_your_token_here # store token for this env
azd upSecurity note: azd env set persists the value in the environment state on disk; avoid committing the .azure folder.
That single azd up command:
- Provisions Azure Web PubSub + Storage + App Service (with Managed Identity)
- Builds the React client
- Deploys the Python backend
- Applies app settings sourced from previously persisted environment values (e.g.
githubModelsTokenset viaazd env set) - Prints your site URL + negotiate endpoint
Recommended Default: Pass the token via secure Bicep parameter at provision time (Option A). This avoids surprise hooks and keeps behavior explicit. For production, prefer Key Vault (Option D).
Option A (Secure Bicep Parameter – default)
azd env set githubModelsToken ghp_your_token_here
azd upRotate: azd env set githubModelsToken <new> then azd provision.
Remove: azd env unset githubModelsToken then azd provision.
Option B (Manual CLI – update anytime)
az webapp config appsettings set \
--resource-group <your-resource-group> \
--name <your-web-app-name> \
--settings GITHUB_TOKEN="ghp_your_github_token_here"
az webapp restart \
--resource-group <your-resource-group> \
--name <your-web-app-name>Option C (Portal) Azure Portal → App Service → Configuration → Application settings → New application setting: Name=GITHUB_TOKEN, Value=your-token
Option D (Key Vault Reference – production / rotation)
- Store the PAT as a secret in a Key Vault you control.
- Grant the web app’s managed identity
getpermissions. - Add an app setting:
GITHUB_TOKEN=@Microsoft.KeyVault(SecretUri=https://<vault>.vault.azure.net/secrets/<secret-name>/<version>) - Restart the web app.
azd deploy # code only (frontend or backend)Infra template changes:
azd provision && azd deploy| Variable | Purpose |
|---|---|
GITHUB_TOKEN |
Enables AI responses (GitHub Models) |
TRANSPORT_MODE |
self (default) or webpubsub to use Azure Web PubSub service |
STORAGE_MODE |
memory (default) or table for Azure Table / Azurite persistence |
WEBPUBSUB_ENDPOINT or WEBPUBSUB_CONNECTION_STRING |
The Azure Web PubSub endpoint when transport_mode is webpubsub |
AZURE_STORAGE_ACCOUNT or AZURE_STORAGE_CONNECTION_STRING |
The Azure Storage endpoint when storage_mode is table |
WEBPUBSUB_HUB |
(Optional) Override the hub name used for the chat app when using Web PubSub (default: demo_ai_chat) |
CHAT_TABLE_NAME |
(Optional) Override Azure Table name (default: chatmessages) |
Notes:
- In Azure deployment the Bicep sets
TRANSPORT_MODE=webpubsubandSTORAGE_MODE=table. - Locally you can mix and match (e.g.
self+tablewith Azurite orwebpubsub+memory).
Want predictable names? Provide overrides (must be globally unique where required):
azd env set webPubSubNameOverride mywps1234
azd env set webAppNameOverride mychatweb1234
azd provision| Change | Command |
|---|---|
| Backend / frontend code | azd deploy |
| Infra (Bicep) changes | azd provision && azd deploy |
| New environment | azd env new <name> --location <region> then azd up |
Run the backend locally while using a real Web PubSub instance (and optionally Table storage) in Azure:
azd up(once) provisions resources.- Create a local
.envwith:TRANSPORT_MODE=webpubsub WEBPUBSUB_ENDPOINT=https://<name>.webpubsub.azure.com # optional persistence STORAGE_MODE=table python start_dev.py- (Optional) Tunnel for CloudEvents (see ADVANCED.md §2.3)
More: ADVANCED.md
Do I need Azure to try it? No—local mode works offline.
Why Web PubSub? Managed scale, groups, CloudEvents, secure client negotiation.
Where are advanced knobs? All in docs/ADVANCED.md (RBAC, credential chain, persistence, CloudEvents, tunnels).
- Explore advanced capabilities: docs/ADVANCED.md
- Try hybrid tunnel mode for full lifecycle locally
- Customize AI logic in
python_server/chat_model_client.py - Review how scalable history works now (Table storage) in the persistence section of the advanced doc.
Control runtime log level
- Set
LOG_LEVELto adjust all server logs (DEBUG,INFO,WARNING,ERROR). Defaults toINFO. - Optional: customize the format with
LOG_FORMAT(defaults to"%(asctime)s %(levelname)s %(name)s: %(message)s").
Example (PowerShell):
$env:LOG_LEVEL="DEBUG"
python start_dev.pyDEBUGenables verbose traces from Flask, OpenAI SDK, and httpx transport.
Azure App Service
- Portal → App Service → Configuration → Application settings → add
LOG_LEVEL, then restart. - Stream logs:
az webapp log tail --resource-group <rg> --name <app-name>.
App Service setting GITHUB_TOKEN missing after azd up
- Make sure you set the value before the first
azd provision:azd env set githubModelsToken <token>. - If you added the token after the first deployment, run
azd provision(you don't needazd deployfor an app setting change). Useazd provision --no-stateif it claims no changes.
Changed token but app setting didn’t update
- Confirm the parameter file or environment value is non-empty.
- Run
azd env get githubModelsTokento verify what azd stored. - Re-run
azd provision. (Only a code change needsazd deploy.)
Early ECONNREFUSED errors in the browser during local dev
- The React dev server starts first and immediately proxies
/api/*to Flask while it’s still binding. - These transient errors vanish once
Flask app runningappears in the terminal. Safe to ignore.
Web PubSub negotiate failing (401/403 or missing access)
- Ensure the web app’s Managed Identity has necessary roles (e.g. Web PubSub Service Owner / Contributor) on the Web PubSub resource.
- If using the
createRoleAssignmentsparameter and you turned it off after first provision, assign roles manually.
Unauthorized error when calling openai
- Check if the GitHub PAT has model read permission
General diagnostic tips
- Show current environment values:
azd env get. - List effective app settings (Azure):
az webapp config appsettings list --name <app-name> --resource-group <rg>.
Happy hacking! Open an issue or PR in our GitHub repo with feedback.