Search, chat and research over parliamentary speeches and documents
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

7.3 KiB

Setting up plenum with an AI assistant

Most people setting this up will do it with an assistant rather than alone. This page is written for that: a prompt to start with, and the interview the assistant should run.


Give your assistant this

I want to set up plenum for the [your parliament]. The repository is at [path]. Read docs/ASSISTANT-SETUP.md and walk me through it — ask me the questions in the interview one section at a time, run the checks yourself, and tell me what you find before changing anything. I am not an expert on databases or git, so explain trade-offs in plain terms and tell me when a choice does not matter.


For the assistant

Your job is to end with a running deployment and a user who understands what was set up. Rules:

  1. Run python scripts/doctor.py first, before asking anything. It reports the machine's actual state — Python version, database, models, GPU, free ports. Several interview questions answer themselves from its output; do not ask what you can see.
  2. Ask one section at a time. Do not present all twenty questions at once.
  3. Recommend a default for every question and say why. Most users want to be told what is sensible, not handed a menu.
  4. Never invent a value. If you do not know the parliament's party colours or its open-data URL, say so and ask, or leave the default and flag it.
  5. Verify each stage before moving on. Every section below has a check. Report its real output; never infer success from an exit code.
  6. Prefer adding files to editing them. See YOUR-PARLIAMENT.md. Getting this wrong makes every future update painful.

Section 1 — What is this deployment?

Ask:

  • Which parliament? (country, and the body's name in its own language and in English)
  • What should the site be called?
  • Which language will the interface and the model's answers be in?
  • Is there an existing site whose look it should resemble, or should it look neutral?

Then write parliament.<code>.yaml — a new file, not an edit of parliament.yaml — and set PARLIAMENT_CONFIG=parliament.<code>.yaml in .env.

Quote short codes. YAML reads unquoted no, yes, on, off, y, n as booleans. country: NO becomes false. Write country: "NO".

Check: python -c "from parliament import PARLIAMENT; print(PARLIAMENT.meta)"

Section 2 — How should it look?

The shipped design is deliberately Nordic-institutional — warm paper, deep blue, a Garamond serif — and was drawn from riksdagen.se. It will look Swedish anywhere you deploy it unless changed.

Ask whether that is fine, or whether it should match their own parliament's visual language. If the latter, ask for a primary colour and whether they want a serif (traditional, institutional) or sans-serif (plainer, more like a tool) for headings.

Set the theme: block in their config. Every key maps to a CSS variable, so nothing in the stylesheet needs editing.

Check: curl -s localhost:8000/api/meta | python -m json.tool | grep -A8 theme

Section 3 — The database

Usually decided by the doctor output. If PostgreSQL is missing, offer the container:

docker run -d --name plenum-pg \
  -e POSTGRES_USER=plenum -e POSTGRES_PASSWORD=<generate one> -e POSTGRES_DB=plenum \
  -p 5432:5432 pgvector/pgvector:pg16

Ask only what you cannot detect: whether an existing server should be used, and whether they have rights to CREATE EXTENSION on it.

Set app.fts_config to a dictionary from SELECT cfgname FROM pg_ts_config; matching their language. If there is none, simple works without stemming — tell them the consequence: a search for a word will not match its inflected forms.

Check: python scripts/doctor.py — the PostgreSQL section should be all OK.

Section 4 — The chat model

Read the doctor's GPU line before asking.

What the doctor found Recommend
A GPU with 12 GB or more vLLM — fastest, handles concurrency
A GPU under 12 GB, or none Ollama — easy, slower, or a hosted provider
No GPU and no wish to run models OpenRouter, or Berget if EU data residency matters

Ask: are they willing to pay per request, or does this need to run on their own hardware? Does the data have to stay in a particular jurisdiction?

If local, offer to pull a model. It must support tool calling — without it, chat answers without searching, which is the one failure this project cannot tolerate. Qwen3 8B and above is a good default. Below ~7B, tool calling gets unreliable.

Check: python scripts/doctor.py — both "Chat model" and "Tool calling" must be OK. If tool calling fails, change the model. Do not proceed.

Section 5 — Embeddings

A separate endpoint from chat, and the most commonly confused step.

Ask whether to run embeddings locally (small model, ~2 GB VRAM, free) or via an API.

The dimension is load-bearing: it must match embeddings.dimension in their config and the vector(N) columns. Changing it later means re-embedding everything. Settle it before the schema is created.

Model Dimension
Qwen/Qwen3-Embedding-0.6B 384
nomic-embed-text (Ollama) 768
text-embedding-3-small (OpenAI) 1536

Check: the doctor's Embeddings section must say the dimension matches.

Section 6 — The data

Ask for their parliament's open-data URL and whether it publishes bulk archives or only a per-record API.

If it is not Sweden, an adapter has to be written: ingest/adapters/<name>.py. Read ingest/adapters/riksdagen.py first — it documents the traps that recur across sources: repeated elements arriving as an object when there is one and a list when there are several, null serialised as the string "None", HTML in text fields, party codes in mixed case.

Do not write an adapter from guesswork. Fetch one real record, show the user its actual fields, and map from that.

Check: load a small batch and inspect it — python -m ingest.cli load --source documents --limit 50, then query a few rows and show them to the user. Wrong-looking data here is far cheaper to fix than after a full load.

Section 7 — Serving it

Ask whether this is a personal machine or a public site.

Public means: nginx, TLS, systemd. Templates are in deploy/examples/, with __PROJECT_ROOT__ and __DOMAIN__ to substitute.

Two things to state plainly rather than assume they know:

  • database_query runs model-written SQL. It is restricted to reads by two layers, but it should still connect as a SELECT-only role. See SECURITY.md.
  • Do not add EnvironmentFile= to the systemd unit. systemd's parser rejects KEY = with a space, silently yielding empty values. The app loads .env itself.

Check: curl -s -o /dev/null -w '%{http_code}' https://<domain>/api/meta → 200.


Finish by telling them

  • Where their config lives and that it is theirs to edit
  • That python scripts/doctor.py diagnoses most later problems
  • That updates come via git fetch upstream && git merge upstream/main
  • Which parts are still Swedish: the interface strings are not translated unless they did it, and content/ holds site copy they will want to rewrite

If anything was left unfinished — no adapter yet, no data loaded, TLS not set up — say so explicitly rather than implying it is done.