Spaces:
Sleeping
Vivek: Adaptive Presentation Engine β Complete Reference
A professional, modular backend demonstrating Bayesian strategy selection and real-time posterior updating. This app learns user preferences and adapts its response format (bullet points, prose, questions, etc.) based on observed rewards.
Table of Contents
- Project Structure
- File Manifest
- System Architecture
- How the App Works
- Setup & Running
- Configuration
- API Reference
Project Structure
backend/
βββ __init__.py # Package entrypoint
βββ config.py # Environment + constants
βββ utils.py # Math, heuristics, post-processing
βββ llm.py # LLM backends (Anthropic, OpenAI-compatible)
βββ engine.py # Bayesian learner
βββ server.py # HTTP handlers + runner
Root folder
βββ app.py # Launcher (imports backend.server.run_server)
βββ frontend/
β βββ index.html # Frontend demo UI
βββ Dockerfile # Container image
βββ requirements.txt # Python dependencies
βββ README.md # Original readme (kept for reference)
βββ UpdatedReadme.md # This file
File Manifest
backend/__init__.py
Purpose: Package initialization and public API.
Exposes run_server() so callers only need:
from backend import run_server
run_server()
backend/config.py
Purpose: Centralized configuration and constants.
Key variables:
LLM_MODEβ selects backend:"openai_compat"or"anthropic"OPENAI_BASE_URL,OPENAI_API_KEY,OPENAI_MODELβ remote OpenAI-compatible API (Groq)ANTHROPIC_API_KEY,ANTHROPIC_MODELβ Anthropic Claude API configurationD=10β feature vector dimensionalityLAMBDA,GAMMA,ALPHA_G,TS_TEMPERATUREβ Bayesian hyperparametersSTRATEGIESβ dict of 5 response primitives (bulleted, narrative, concise, Socratic, step-by-step)HERE,INDEX_HTMLβ paths for serving the frontend
Usage: Other modules import from this single source of truth.
backend/utils.py
Purpose: Small, reusable utilities.
Functions:
sigmoid(x)β numerically stable logistic functionmean_uncertainty(sigma_inv)β summarize posterior variance from precision matrixfast_valence(message, prev_response)β lightweight regex-based sentiment heuristic; returns{"pos", "neg", "reason"}enforce_response(strategy, text)β post-process LLM output to match the chosen format (strips questions, forces bullets/numbers, caps sentence counts)
Helpers (module-level):
_POS,_NEG,_REPHRASEβ regex patterns for auto-reward detection
Usage: Called by server during chat turns and posterior updates.
backend/llm.py
Purpose: LLM API wrappers for Anthropic and OpenAI-compatible endpoints.
Public functions:
call_openai_compat(prompt, system, timeout=120)β POST to OpenAI-compatible endpoint; returns(text, elapsed_sec, mode)call_anthropic(prompt, system, timeout=120)β call Anthropic Messages API; returns(text, elapsed_sec, mode)openai_health(timeout=10)β check OpenAI-compatible endpoint and available modelsanthropic_health()β lightweight Anthropic config health summary
Internal helpers:
_post_json_url(),_get_json_url()β raw HTTP wrappers
Usage: Server calls these during /api/chat to fetch responses from the LLM.
backend/engine.py
Purpose: The core Bayesian learner for strategy selection and posterior updating.
Class: BayesianEngine
__init__()β initialize global and per-user posterior means (mu) and precision matrices (sigma_inv)get_user(uid)β fetch or create user statefeaturize(message, user)β convert message + history into a fixed-length feature vector (10-dim)select(uid, message)β use Thompson Sampling to pick a strategy; return(strategy, scores, x)update(uid, strategy, x, reward)β Bayesian update for user and global posteriorapply_preferences(uid, strategy_names)β apply soft bias or hard-lock if user selects one strategyposterior_summary(),user_posterior(),global_posterior()β compute compact summaries of expected reward + uncertainty
Singletons:
engineβ global instance used by the serverUSERB_IDβ reserved user ID for a secondary reference posterior (demo artifact)
Bayesian model: Online logistic regression with exponential decay (Ξ³=0.99) and per-strategy Gaussian posteriors.
Usage: Server calls during /api/chat, /api/reward, /api/preference endpoints.
backend/server.py
Purpose: HTTP server and request handlers.
Class: Handler(BaseHTTPRequestHandler)
Handles:
GET /β serveindex.htmlfrontendGET /api/healthβ return LLM backend statusGET /api/stateβ return user's current posterior and global statsPOST /api/chatβ accept user message, auto-reward previous turn, select strategy, call LLM, enforce format, persist statePOST /api/rewardβ accept explicit user rewardPOST /api/preferenceβ set user strategy preferencesPOST /api/resetβ reset user stateOPTIONS *β handle CORS preflight
Private helpers:
_json()β JSON response with CORS headers_html()β serve frontend file_body()β parse JSON request body_cors()β set CORS headerslog_message()β suppress access logs for cleanliness
Function: run_server()
- Prints startup banner
- Performs lightweight health checks on Anthropic/OpenAI endpoint
- Starts
ThreadedServeron port 5051 (configurable viaPORTenv var)
Class: ThreadedServer(ThreadingMixIn, HTTPServer)
- Allows concurrent request handling
Usage: Imported and called by app.py.
app.py (Root)
Purpose: Lightweight launcher script.
Simply imports and calls:
from backend.server import run_server
if __name__ == "__main__":
run_server()
This keeps a familiar entrypoint (python app.py) while the implementation lives in the package.
index.html
Purpose: Frontend React/Preact demo.
Communicates with backend via:
GET /api/healthβ check LLM status on loadGET /api/stateβ fetch user posteriorsPOST /api/chatβ send message, receive response + Bayesian statePOST /api/rewardβ send user feedbackPOST /api/preferenceβ set strategy lockPOST /api/resetβ reset session
Displays:
- Strategy label and instruction
- Expected reward scores per strategy
- Feature vector (x β βΒΉβ°)
- Posterior bar charts (mean + uncertainty)
- Auto-detected valence reason
Dockerfile
Purpose: Container build for deployment.
Installs Python, dependencies, and runs python app.py.
requirements.txt
Purpose: Python package dependencies.
Currently:
numpyβ linear algebra for Bayesian updatespython-dotenvβ load.envfor API keys
System Architecture
High-Level Component Diagram
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend (index.html) β
β Browser UI β POST /api/chat, GET /api/state, etc. β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β app.py (Launcher) β
β from backend.server import run_server() β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HTTP Server + Handler (backend/server.py) β
β ββ GET /api/health β check LLM backend β
β ββ GET /api/state β fetch posteriors β
β ββ POST /api/chat β process user message β
β ββ POST /api/reward β apply explicit reward β
β ββ POST /api/preferenceβ lock strategy β
β ββ POST /api/reset β clear user data β
ββββββββββββββββββββββββββ¬ββββββββββ¬βββββββββββββββ¬βββββββββββββββββββ
β β β
βββββββββββββββββ β ββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββ βββββββββββββββ ββββββββββββββββββ
β Bayesian β β LLM Backendsβ β Utils (Heuristics
β Engine β β (backend/llm) β β & Post-process)
β (backend/ β β ββ Anthropic β β ββ sigmoid()
β engine.py) β β ββ OpenAI β β ββ fast_valence()
β β β β β ββ enforce_response()
β β’ select() ββββββββββββ€ β’ call_*() β ββββββββββββββββββ
β β’ update() β β β’ health() β
β β’ featurize()β β β’ format_*()β
β β’ apply_prefβ β β
ββββββββββββββββ βββββββββββββββ
β²
β (reads hyperparams + strategy list)
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββ
β Config (backend/config.py) β
β ββ LLM_MODE, OPENAI_*, ANTHROPIC_* β
β ββ D, LAMBDA, GAMMA, ALPHA_G, TS_TEMP β
β ββ STRATEGIES dict + STRATEGY_NAMES β
β ββ HERE, INDEX_HTML paths β
ββββββββββββββββββββββββββββββββββββββββββββ
How the App Works
1. Initialization
- User loads
http://localhost:5051β frontend fetches/api/healthand/api/state - Server initializes or fetches user state (in-memory dict keyed by
uid) - User inherits global posterior (hierarchical Bayesian prior)
2. User Sends a Message
User message
β
POST /api/chat {uid, message}
β
[Server] fast_valence(message, prev_response)
ββ Auto-reward previous turn (if exists)
ββ Call engine.update(uid, strategy, x, reward)
β
[Server] engine.select(uid, message)
ββ featurize(message, user) β x β βΒΉβ°
ββ Thompson Sampling per strategy
ββ Return best strategy + scores
β
[Server] Build system prompt with FORMAT RULE
ββ Include selected strategy instruction
ββ Add recent conversation history
ββ Send to LLM
β
[LLM] Generate response (single-call)
ββ Return text + optional widget HTML
β
[Server] enforce_response(strategy, text)
ββ Strip unwanted questions
ββ Force format (bullets, numbers, etc.)
ββ Return polished response
β
[Server] Persist conversation + state
ββ Update user["history"], ["last_response"], ["last_x"]
β
[Server] Return JSON response
ββ response text + strategy label
ββ instruction (what the system told the LLM)
ββ scores (expected reward per strategy)
ββ x_vec (feature vector used)
ββ posteriors (updated beliefs)
ββ auto_detected + auto_r (heuristic reward)
ββ auto_reason (why the heuristic fired)
β
[Frontend] Display response
ββ Show strategy + instruction
ββ Show bar charts for expected reward
ββ Show feature vector
ββ Display π/π buttons
3. User Rates Response
User clicks π or π
β
POST /api/reward {uid, strategy, x_vec, reward}
β
[Server] engine.update(uid, strategy, x, reward)
ββ Update user["mu"][strategy] via logistic regression
ββ Update user["sigma_inv"][strategy] (precision matrix)
ββ Also update global posterior (with weight Ξ±=0.05)
ββ Append to user["reward_log"]
β
[Server] Recompute posteriors
ββ Return new bar chart data
β
[Frontend] Animate bar chart updates
ββ Show how beliefs changed
4. Posterior Update (Bayesian Mechanics)
The engine maintains per-user Gaussian posteriors Ξ² ~ N(ΞΌ, Ξ£) for each strategy.
Model: Logistic regression where reward rΜ = sigmoid(x^T Ξ²)
Update rule:
- rΜ_old = sigmoid(x^T ΞΌ_old)
- Ξ£_new = Ξ£_old^{-1} + x x^T Β· w + Ξ» I (w = rΜ(1 - rΜ))
- ΞΌ_new = ΞΌ_old + Ξ£_new^{-1} x (r - rΜ_old)
Global posterior gets a small, weighted update (Ξ±=0.05) so all users benefit from collective learning.
Exponential decay (Ξ³=0.99) biases the engine toward recent history.
Setup & Running
1. Install Python 3.8+
python3 --version
2. Clone/download the repo
cd backend
3. Create a virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
4. Install dependencies
pip install -r requirements.txt
5. LLM backend
This repository supports OpenAI-compatible providers and Anthropic Claude.
6. Run the app
python app.py
You should see a startup banner and then the server will be live at http://localhost:5051.
7. Open browser
http://localhost:5051
Configuration
Environment Variables
Create a .env file in the root folder:
# Backend selection
LLM_MODE=openai_compat # or "anthropic"
# OpenAI-compatible (Groq, etc.)
OPENAI_BASE_URL=https://api.groq.com/openai/v1
OPENAI_API_KEY=your_groq_api_key_here
OPENAI_MODEL=llama-3.1-8b-instant
# Anthropic (Claude)
ANTHROPIC_API_KEY=your_anthropic_key_here
ANTHROPIC_MODEL=claude-opus-4-6
# Port
PORT=5051
Bayesian Hyperparameters
Edit backend/config.py:
D = 10 # Feature vector dimension
LAMBDA = 0.01 # L2 regularization on posteriors
GAMMA = 0.99 # Exponential decay (prefer recent history)
ALPHA_G = 0.05 # Global posterior update weight
TS_TEMPERATURE = 2.0 # Thompson Sampling variance scale (exploration)
API Reference
GET /api/health
Returns: LLM backend status.
Response:
{
"server": "ok",
"mode": "openai_compat",
"openai_base_url": "https://api.groq.com/openai/v1",
"model": "llama-3.1-8b-instant",
"ok": true,
"reachable": true,
"models": ["llama-3.1-8b-instant", "mixtral-8x7b-32768"]
}
GET /api/state?uid=demo
Returns: Current user state and posteriors.
Response:
{
"posterior": {
"structured_bullets": {"r": 0.52, "u": 0.34},
"narrative_prose": {"r": 0.48, "u": 0.35},
...
},
"global": {...},
"userb": {...},
"global_n": 42,
"n_users": 3,
"msg_count": 5
}
POST /api/chat
Body:
{
"uid": "demo",
"message": "How do I make pasta?"
}
Response:
{
"response": "- Cook 1 liter of water\n- Add salt\n- ...",
"strategy": "step_by_step",
"instruction": "Numbered list of 3-6 steps only.",
"elapsed": 2.3,
"llm_mode": "anthropic",
"scores": {
"structured_bullets": 0.54,
"narrative_prose": 0.48,
...
},
"x_vec": [0.12, 0.34, ...],
"posterior": {...},
"global": {...},
"auto_detected": true,
"auto_r": 0.75,
"auto_reason": "positive signal(s)"
}
POST /api/reward
Body:
{
"uid": "demo",
"strategy": "step_by_step",
"x_vec": [0.12, 0.34, ...],
"reward": 0.9
}
Response:
{
"posterior": {...},
"global": {...},
"global_n": 43
}
POST /api/preference
Body:
{
"uid": "demo",
"strategies": ["structured_bullets"]
}
Response:
{
"posterior": {...}
}
POST /api/reset
Body:
{
"uid": "demo"
}
Response:
{
"ok": true
}
Troubleshooting
Server won't start
- Ensure port 5051 is available:
lsof -i :5051 - Check Python version:
python --version(need 3.8+) - Verify dependencies:
pip install -r requirements.txt
LLM returns empty responses
- If using OpenAI-compatible: verify API key in
.env - If using Anthropic: verify
ANTHROPIC_API_KEYandANTHROPIC_MODEL - Check model name matches
OPENAI_MODEL/ANTHROPIC_MODEL
Feature vector or posterior looks weird
- This is expected! Bayesian posteriors start with high uncertainty.
- Send a few more messages and rate them β posteriors will stabilize.
Valence heuristic seems wrong
- The regex patterns in
utils.pyare intentionally simple. - For production, replace with a small classifier model.
License & Attribution
Built as a demonstration of hierarchical Bayesian architecture. Feel free to adapt for your use case.
For questions or contributions, reach out to the team.