π§ AI Engine¶
This describes the design, invocation flow, contracts, and deployment notes for the ai-engine.
Purpose¶
The ai-engine is a small Python Flask service that orchestrates a set of AI "agents" to generate structured mindmap (a.k.a. Visualli) JSON from long-form text. It is intended to be invoked by the backend (backend/server) after a user uploads any content from the frontend (PDF, text, ..).
Design¶
Components Overview¶
- HTTP Ingress (Node server) β
backend/server/server.jsaccepts uploads and text, extracts plain text, and calls the ai-engine. - Python Flask Service β
ai-engineexposes/generate_mindmapthat accepts{ text: string }and returns validated mindmap JSON. - Agent Layer β
agents.pyinitializes AI agents (MindMapAgent, ComplianceAgent) via the autogen library to generate and gate outputs. - Position Optimizer β
position_optimizer.pylays out nodes in radial coordinates and writesposition.xandposition.y. - Persistence β The Node server receives the returned mindmap JSON and stores it in MongoDB (collection
visuallis).
Sequence Diagram¶
sequenceDiagram
autonumber
participant User
participant Node as Node Backend
participant Flask as Flask ai-engine
participant Agents
participant Mongo as MongoDB
User->>Node: Upload PDF/text\nPOST /api/upload or /api/upload/text
Node->>Node: Extract text\npdf-parse (PDF) or direct blob
Node->>Flask: POST /generate_mindmap
Note over Node,Flask: Alternatively via proxy\nNode /api/generate_mindmap
Flask->>Agents: agents.main(task)
Agents->>Agents: initialize_agents()\nMindmapAgent + ComplianceAgent
Agents->>Agents: MindmapAgent.run(task)\nproduce initial JSON
Agents->>Agents: ComplianceAgent.run(task)\nvalidate to MindmapData
Agents->>Agents: position_optimizer.tidy_radial(...)\ncompute x,y positions
Agents-->>Flask: Return final JSON
Flask-->>Node: JSON response
Node->>Mongo: Persist JSON to collection "visuallis"
Node-->>User: Success payload
I/O Contracts¶
Endpoint: POST /generate_mindmap
- Request JSON body:
- { "text": "
- Success response: JSON matching
MindmapData(seesrc/schemas/mindmap.py). Key fields: metadata(title, description, version, created, lastModified)nodes(list of nodes with at least:id,title,level,position{x,y},color, optionalparent, optionalrelationshipLabel, optional nestedchildren)topLevelConnections(list of{ from, to, label })
Notes on shape: The code expects the returned JSON to be convertible to Python dicts and ultimately to be inserted into MongoDB. The Node server adds some top-level fields (created, lastModified, version, title) if missing.
Key Files¶
src/main.pyβ Flask app and the/generate_mindmapendpoint. Runs the async agent pipeline in a background thread.src/agents/agents.pyβ AI Agent definitions and the asyncmain(task)orchestration.src/agents/position_optimizer.pyβ Radial layout algorithm used to assignx,ypositions to nodes (tidy_radialfunction). Algorithm to ensure nodes in the visual don't overlap and diverge outwards radially.src/schemas/mindmap.pyβpydanticschema for the expected mindmap JSON shape (MindmapData).src/wsgi/handler.pyβ WSGI Lambda handler (wraps the Flask app withserverless_wsgi.handle_request) for Serverless/AWS Lambda deployments.src/wsgi/app.pyβ tiny module that imports and runs the Flask app for local execution under a module.
Error Handling & Edge Cases¶
- Timeouts: Node sets a 5-minute timeout when calling Flask. The agent pipeline may take time depending on model responses.
- Invalid/empty text: Node and Flask both check for empty extracted text and return 400.
- Invalid response from Python: Node checks that
response.datais an object; otherwise returns 500. - PDF parsing failures: Node has multiple fallbacks and returns 400 with helpful messages if parsing fails.
- Model keys missing:
agents/agents.pywarns whenOPENAI_API_KEYis not set and logs via Logtail; agent clients will fail if keys are missing.
Environment Vars Used¶
OPENAI_API_KEYβ required for the OpenAI client used by agents.
Set these vars locally (example .env) in backend/ai-engine/.env or export them in your shell before starting.
Deployment Notes¶
- Local development:
- Start the ai-engine Flask app (it listens on port 5000 by default).
cd backend/ai-engine
python3 -m src.wsgi.app
- Start the Node backend:
cd backend/server
node server.js
-
The Node backend calls
http://127.0.0.1:5000/generate_mindmapby default, or uses the proxy route/api/generate_mindmap. -
Serverless / Lambda:
src/wsgi/handler.pyis prepared for Lambda viaserverless_wsgi.handle_request(app, event, context).serverless.ymlis present in the ai-engine directory and can be configured to deploy the Flask app behind API Gateway.
Observability & Logging¶
- The agents module configures
logtail(BetterStack) as a handler. Make sureBETTERSTACK_SOURCE_TOKENandBETTERSTACK_INGESTING_HOSTare set to collect logs. stdoutis redirected to the logger viaStdOutToLoggerso agent library prints are captured.
Performance / cost considerations¶
- Model usage: Agents instantiate multiple clients (
gpt-4o,gpt-4o-mini, etc.) β these can be expensive. Consider rate limits and batch sizes. - Concurrency: Flask endpoint runs the full pipeline inside a background thread using a fresh event loop. If the server receives many concurrent requests, the ThreadPoolExecutor default size may need tuning.
Security considerations¶
- Validate inputs: The Node server and Flask endpoint expect plain text; be careful to limit upload sizes (Node uses a 5MB limit) and sanitize any filename inputs.
- Secrets: Keep
OPENAI_API_KEYand BetterStack tokens out of source control (use.envand secrets manager in production).
Next steps / Improvements¶
- Add unit tests around
agents.main(mock model clients) andposition_optimizer.tidy_radial. - Provide a health endpoint in the Flask service for readiness checks (used by load balancers).
- Add request tracing (e.g., a request ID passed from Node to Flask) for easier debugging.
- Limit the ThreadPoolExecutor size and implement an in-queue to avoid overload during spikes.