standpoint.api module

FastAPI backend for the Standpoint browser GUI.

This is the thin server behind the single-page GUI: it turns an edited table into a positioning result the browser can render. The heavy lifting stays in the library: positioning() runs the PCA, orientation, colouring, LLM pole naming, and analysis; this module only exposes it over HTTP and serves the static page.

Endpoints

GET / redirect to the GUI. GET /gui the single-page editor + viewer (see webgui.GUI_HTML). GET /api/example a starter table (CSV text) to populate the grid. POST /api/position from an edited table, return the Vega-Lite spec + Markdown + YAML.

Run it with standpoint-gui (installed by the gui extra) or uvicorn standpoint.api:app. It is intentionally not imported by the core package, so the library and CLIs carry no web dependency.

class standpoint.api.AutofillRequest(*, noun='Option', options, criteria, model='qwen2.5vl:7b', lang='')[source]

Bases: BaseModel

Body of POST /api/autofill: the names to score, plus model and language.

Parameters:
noun

The first-column word (what a row is, e.g. “Programming Language”).

Type:

str

options

Option (row) names to rate.

Type:

list[str]

criteria

Criterion (column) names to rate each option on.

Type:

list[str]

model

Ollama model that produces the ratings.

Type:

str

lang

Force the prompt language; “” detects it from the names.

Type:

str

criteria: list[str]
lang: str
model: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

noun: str
options: list[str]
class standpoint.api.PositionRequest(*, table, reference='0', lower='', model='qwen2.5vl:7b', lang='')[source]

Bases: BaseModel

Body of POST /api/position: one edited table plus a few options.

Parameters:
table

The edited comparison table as CSV text (first column = option names).

Type:

str

reference

Row index (as a string) or exact option name to place top-right.

Type:

str

lower

Comma-separated criteria where lower is better (e.g. "Price,Weight").

Type:

str

model

Ollama model used to name the axes and write the analysis.

Type:

str

lang: str
lower: str
model: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

reference: str
table: str
class standpoint.api.PositionResponse(*, vega, markdown, yaml, axes, poles, reference, roles, slug)[source]

Bases: BaseModel

What the browser needs to draw the quadrant and show the write-up.

Parameters:
axes: dict[str, str]
markdown: str
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

poles: list[str]
reference: str
roles: dict[str, str]
slug: str
vega: dict
yaml: str
class standpoint.api.TableText(*, table)[source]

Bases: BaseModel

A table as CSV text: the body of the XLSX download request.

Parameters:

table (str)

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

table: str
standpoint.api.autofill(req)

“Flemme” (lazy) auto-fill: score every option on every criterion via the model.

The user typed only the row and column names (common for a freshly uploaded CSV that carries headers but no values); this asks the local model to fill the whole ratings matrix from its own knowledge, offline.

Returns:

{"ratings": {option: {criterion: int}}} for the front-end to load into the grid.

Return type:

dict

Raises:

HTTPException – 400 if no option / criterion was named; 503 if the model is unavailable.

Parameters:

req (AutofillRequest)

standpoint.api.download_xlsx(req)

Convert the edited table (CSV text) to an .xlsx file for download.

Parameters:

req (TableText) – The current grid serialized to CSV.

Returns:

The workbook bytes with an attachment disposition so the browser saves standpoint.xlsx.

Return type:

Response

Raises:

HTTPException – 400 if the CSV can’t be parsed into a table.

standpoint.api.example()

Return a starter table (CSV text) to populate an empty grid.

Prefer the tracked examples/programming_languages.csv so the GUI stays in sync with it; fall back to the small built-in table when the file isn’t present.

Return type:

str

standpoint.api.favicon()

Serve the multi-size favicon browsers request from the site root by default.

Return type:

fastapi.responses.FileResponse

standpoint.api.gui()

Serve the single-page table editor + quadrant viewer.

Return type:

str

standpoint.api.i18n_strings(lang='en')

Return the GUI’s localized strings for lang (falls back to English).

The single-page app fetches this to render every label, button, and message in the language chosen by the header toggle, so the UI text lives in i18n.yaml next to the LLM prompts rather than being hard-coded in the HTML.

Parameters:

lang (str)

Return type:

dict

standpoint.api.index()

Redirect the site root to the GUI page.

Return type:

fastapi.responses.RedirectResponse

standpoint.api.main_gui()[source]

Console entry point (standpoint-gui): serve the GUI on localhost:8000.

Return type:

None

standpoint.api.position(req)

Run the full positioning on an edited table and return everything to draw it.

Parameters:

req (PositionRequest) – The edited table and options from the browser.

Returns:

The Vega-Lite spec (rendered client-side by vega-embed), the Markdown interpretation, the YAML dump, and the axis names / poles / roles.

Return type:

PositionResponse

Raises:

HTTPException – 400 if the table is empty or degenerate, or the reference is unknown; the library’s ValueError message is passed straight through to the UI.

async standpoint.api.upload(file=fastapi.File)

Load an uploaded CSV or XLSX table and return it as CSV for the grid.

Parameters:

file (UploadFile) – The uploaded file; .xlsx / .xls are read with pandas (openpyxl), anything else is treated as CSV or Markdown via parse_table.

Returns:

The table as CSV text, ready to populate the editor grid.

Return type:

str

Raises:

HTTPException – 400 if the file can’t be read as a table.

standpoint.api.webmanifest()

Serve the PWA manifest (name, theme colours, install icons).

Return type:

fastapi.responses.FileResponse