Architecture¶
Chart-Generator is structured as a modular Python application with clearly separated layers. At its core is a three-stage service layer that translates a user request into executable visualisation code through successive steps. Data is held per session in memory; deployment can be local, behind a reverse proxy, or as a container.
At a glance¶
- Four layers: user interface, service layer, domain components (data, charts, LLM, sessions), and configuration.
- Three-stage agentic pipeline: intent recognition, plan creation, execution.
- State is held exclusively per session in memory (DataFrames serialised, charts stored as pickle).
- Generated code runs in a sandbox with restricted built-ins.
- External LLM endpoint (OpenAI-compatible protocol), one to five API calls per request.
- Configuration entirely via environment variables; reverse-proxy path configurable.
- Container-based operation supported via a slim Python image.
Architecture description¶
Layers and responsibilities¶
The user interface is built on Gradio and provides file upload, sheet selection, chat input, chart display, history list, theme switching, and export controls. It calls the service layer exclusively and contains no LLM logic.
The service layer is the central architectural element. It consists of three specialised services: the intent service classifies the request into one of four actions (create single, create multiple, modify, advisory only). The plan service uses the intent and available metadata to create an execution plan that specifies chart type, columns, aggregation, and modification steps. The execution service carries out the plan, validates the generated code, and handles retry and fallback.
The domain components encapsulate individual responsibilities: the DataFrame manager loads and optimises CSV and Excel files and extracts metadata. The LLM orchestrator manages the connection to the language-model endpoint and contains the prompts for code generation and error correction. The chart generator runs the code in a sandbox, drives the retry logic, and can fall back to a Seaborn variant. The interactivity enhancer enriches the Plotly figure with uniform layout, hover, and theme settings. The session manager holds DataFrames, metadata, the current chart, and the chart history per session.
The configuration layer loads all parameters from environment variables and validates them at startup; it is organised into five configuration classes covering LLM, data, charts, user interface, and export.
Workflow¶
flowchart TD
User([User]) -->|File upload| UI[Gradio UI]
User -->|Natural-language input| UI
UI -->|File| DM[DataFrame manager]
DM -->|Optimised DataFrames + metadata| SM[Session manager]
UI -->|Request + context| IS[Intent service]
IS -->|Intent + confidence| PS[Plan service]
PS -->|Execution plan| ES[Execution service]
IS -.->|Classification| LLM[(LLM endpoint)]
PS -.->|Planning| LLM
ES -.->|Code generation / error correction| LLM
ES -->|Code| CV[Code validator]
CV -->|Validated code| CG[Chart generator]
CG -->|Sandbox execution| FIG{Success?}
FIG -->|No, retries left| ES
FIG -->|No, max retries reached| SB[Seaborn fallback]
FIG -->|Yes| EN[Interactivity enhancer]
SB --> EN
EN -->|Final chart| SM
SM -->|Display + history| UI
UI -->|HTML / PNG| Export[(Export directory)]
The data flow proceeds in two phases. In the upload phase, the DataFrame manager loads the file, detects column types, optimises memory consumption, and stores the DataFrame and metadata in the session. If enabled, chart recommendations are then produced by the LLM and shown in the chat.
In the request phase, the input is first classified by the intent service. The plan service then derives an execution plan; for multi-create, the plan contains one step per sheet. The execution service generates Plotly Express code for each step, has it checked by the code validator, and hands it over for execution. If execution fails, the error is fed back to the LLM and the code is revised in up to three iterations. Only if that still fails does the Seaborn-based fallback take effect. The resulting figure is processed by the interactivity enhancer with uniform layout, theme, and mode bar, and is stored in the session as the current chart and in the history (up to ten entries).
Modification requests follow the same scheme but use the existing chart code as a basis and change only the aspect named by the user. Advisory requests do not produce a visualisation; they only return a recommendation text.
Role of the language model¶
The LLM is integrated at three points: in intent classification (low temperature, JSON output, trigger-word library in the prompt), in plan creation (with templates and anti-patterns from the pattern library), and in code generation and error correction. Communication uses an OpenAI-compatible protocol; in the classification and planning steps, JSON responses are expected and parsed tolerantly with respect to Markdown code fences. The system is designed for an externally provided, internally reachable endpoint; a public LLM provider is not required.
Robustness and security¶
Several mechanisms ensure robust processing: validation of the configuration at startup, limits for file size as well as row and column counts, a cap on API calls per request, timeouts for LLM calls, sandbox execution of generated code (restricted built-ins, no import, controlled globals), semantic validation of the code prior to execution, and a multi-stage fallback chain. Logging documents every pipeline step; failures on individual sheets during multi-create do not abort the overall request.
Configuration and deployment¶
All parameters are loaded from environment variables and validated at startup. Configurable items include the LLM endpoint and model name, maximum file size, row and column limits, retry and API-call counts, the default theme, chart dimensions, the export directory, and the server address, server port, and an optional reverse-proxy path. The application can be started directly with Python or run in a slim container; the export directory is created automatically at startup.
Technology overview¶
- Language and runtime: Python 3.10+.
- User interface: Gradio.
- Data processing: Pandas, NumPy, openpyxl, xlrd.
- Visualisation: Plotly Express and Plotly Graph Objects (primary), Matplotlib and Seaborn (fallback), Kaleido (PNG export).
- LLM integration: OpenAI Python library against an OpenAI-compatible endpoint.
- Configuration: python-dotenv, environment variables.
- Persistence: Session-based in memory (pickle plus base64 for DataFrames and figures).
- Deployment: Local, containerised (slim Python image), or behind a reverse proxy.