API Service¶
ai-engine-api is a FastAPI app (Python 3.12+) that wraps the ai-engine library and
serves the demo frontend. It is the single network boundary of the system.
flowchart TB
subgraph client["Clients"]
web["Demo frontend<br/>(Leaflet map + quiz)"]
rsk["RudderStack webhook"]
end
subgraph api["ai-engine-api (FastAPI)"]
mw["log_requests middleware<br/>+ CORS (allow all)"]
static["/demo/* static pages"]
search["/api/search*"]
narr["/api/narrative"]
dbg["/debug/*"]
dbw["/db/*"]
rsr["/api/* (conditional)"]
end
subgraph lib["ai-engine library"]
gs["GlobalSearch"]
ng["NarrativeGenerator"]
pbi["ProjectionBuilder"]
dbi["DB_Interface"]
comps["recsys components"]
end
qd[("Qdrant")]
pg[("PostgreSQL")]
llm["Ollama / OpenRouter"]
web --> static & search & narr
rsk --> rsr
search --> gs --> qd
narr --> ng --> llm
dbg --> pbi --> pg
dbw --> dbi --> pg
rsr --> comps
classDef store fill:#EFEAE0,stroke:#A8895B,color:#423D34;
class qd,pg store;
Route groups¶
| Prefix | Purpose | Backed by |
|---|---|---|
GET /, /demo/* |
Health + static demo pages | FileResponse |
GET /api/search* |
Semantic / geo / preference / profile search | GlobalSearch, ProjectionBuilder |
POST /api/narrative |
LLM narrative from items | NarrativeGenerator |
GET /debug/* |
User & item introspection | ProjectionBuilder, DB_Interface, GlobalSearch |
POST /db/* |
Register users / log events | DB_Interface |
/api/* |
Ingest webhook + recommend (when module present) | recsys.api.make_router |
Full endpoint detail with params, schemas, and a try-it console: the interactive REST API reference (Scalar, from the OpenAPI spec).
Cross-cutting¶
- Middleware
log_requestslogs duration (ms), status, client IP, user-agent (Loguru). - CORS is wide open (
allow_origins=["*"]): demo posture, tighten for prod. searcher: GlobalSearchis a module-level singleton built withCOLLECTION_NAME.- The recsys router is mounted only if
ai_engine.recsysimports successfully andbuild_components()succeeds, graceful degradation when Redis/Qdrant are absent.
Persistence¶
PostgreSQL schema (schema.sql):
erDiagram
visitor ||--o{ device : has
visitor ||--o{ session : has
device ||--o{ session : on
visitor ||--o{ visitor_event : logs
visitor {
bigint id PK
text license_plate UK
text email UK
int age
text gender
text nationality
bool personal_connection
text payload
}
device {
uuid id PK
bigint user_id FK
text device_id_token UK
inet last_ip
}
session {
uuid id PK
bigint user_id FK
uuid device_id FK
text session_token UK
timestamptz expires_at
bool is_revoked
}
visitor_event {
bigint id PK
bigint user_id FK
uuid session_id
text item_id
text event_type
jsonb event_payload
timestamptz ts
}
DB_Interface.fetch_events pairs start/end rows into dwell_seconds; user registration
auto-generates a unique license_plate (XX-XXXX, retry on collision).
Frontend (static demo)¶
| Page | Route | Role |
|---|---|---|
intent.html |
/demo |
Landing: search bar + mode cards (Explore / Guided learning / Story builder) |
index.html |
/demo/app |
Explore: Leaflet map, geo radius, text search, 2D topic scatter, item detail modal |
newQuiz.html |
/demo/newQuiz |
Step-by-step guided learning quiz |
newQuizResults.html |
/demo/newQuiz/myResults |
Quiz results summary |
app.js drives the Explore page: Leaflet + Nominatim location autocomplete (250 ms
debounce), text search → /api/search, geo search → /api/search/geo, results cache for
narrative generation, item detail overlay. ACTIVE_USER_ID defaults to 1110
(override via ?user_id=).
Deployment¶
docker-compose.yml ships the API plus a Jitsu analytics stack (Jitsu + Postgres + Redis +
ClickHouse). API container exposes :8000. Runtime deps are lean, fastapi, uvicorn,
and the ai-engine git dependency, all heavy ML deps come transitively from the library.