|
|
2 months ago | |
|---|---|---|
| .github/instructions | 2 months ago | |
| _chromadb | 2 months ago | |
| backend | 2 months ago | |
| frontend | 2 months ago | |
| scripts | 2 months ago | |
| templates | 2 months ago | |
| var/chroma_repair | 2 months ago | |
| .gitignore | 2 months ago | |
| Makefile | 2 months ago | |
| README.md | 2 months ago | |
| __init__.py | 2 months ago | |
| admin.py | 2 months ago | |
| all_talks_to_db.py | 2 months ago | |
| arango_client.py | 2 months ago | |
| bootstrap.py | 2 months ago | |
| chat_design.excalidraw | 2 months ago | |
| config.py | 2 months ago | |
| documents2db.py | 2 months ago | |
| download_documents.py | 2 months ago | |
| favicon.png | 2 months ago | |
| info.py | 2 months ago | |
| prompts.md | 2 months ago | |
| requirements.txt | 2 months ago | |
| talks2db.py | 2 months ago | |
| utils.py | 2 months ago | |
README.md
Riksdagen Sökplattform – Teknisk Översikt
En plattform för att utforska riksdagsdebatter och metadata. Backenden bygger på FastAPI, ArangoDB (med ArangoSearch), samt ChromaDB för vektorsök i chatten. Frontenden är en React/Vite-applikation skriven i TypeScript. LLM-funktionalitet kopplas in via _llm-paketet.
📋 Innehållsförteckning
- Systemöversikt
- Projektstruktur
- Backend-arkitektur
- Frontend-arkitektur
- Dataflöden
- Viktiga Python- och TypeScript-komponenter
- ArangoDB och ArangoSearch
- ChromaDB för vektorsök
- LLM-integration
- Utvecklingsflöde
- Felsökning och tips
🏗️ Systemöversikt
┌─────────────┐ HTTP ┌──────────────┐ Python ┌───────────────┐
│ Browser │ ─────────▶ │ FastAPI │ ───────────▶ │ ArangoDB │
│ (React) │ ◀───────── │ backend │ ◀─────────── │ (ArangoSearch) │
└─────────────┘ └──────┬───────┘ └───────────────┘
│
│ embeddings / metadata
▼
┌──────────────┐
│ ChromaDB │
└──────┬───────┘
│
▼
┌──────────────┐
│ _llm │ (OpenAI API-kompatibel klient)
└──────────────┘
- ArangoDB: primär databas. Sök görs via ArangoSearch-vyer och AQL; inga relationsfrågor används.
- ChromaDB: håller embeddings för chatten och mer avancerad semantisk sökning.
- LLM: genererar chattsvar med hjälp av
_llm.LLM(kopplad till t.ex. vLLM/OpenAI API).
📁 Projektstruktur
riksdagen/
├── arango_client.py # Initierar Arango-klienten (används av backend & scripts)
├── backend/
│ ├── app.py # FastAPI-app, routerregistrering
│ ├── search.py # SearchService med ArangoSearch-frågor
│ ├── chat.py # Chat-endpoints (LLM + Chroma)
│ ├── vector.py # Hjälpfunktioner för vektorsök (omfattar Chroma-anrop)
│ └── ... # Övriga routrar, scheman och konfigurationer
├── frontend/
│ ├── src/
│ │ ├── App.tsx # Inträde, växlar mellan sök/chat-lägen
│ │ ├── api.ts # Axios-klient mot `/api/*`
│ │ ├── types.ts # TypeScript-typer för API-svar
│ │ ├── components/ # UI-komponenter (SearchPanel, ChatPanel m.fl.)
│ │ └── styles.css # Globala stilar
│ └── vite.config.ts
├── scripts/
│ ├── ingest_arguments.py # Exempel: läser in data till ArangoDB
│ └── build_embeddings.py # Skapar embeddings och för in i Chroma
├── _arango/
│ ├── _arango.py # Wrapper kring python-arango (förbättrad initiering)
│ ├── queries/ # Samling av AQL/ArangoSearch-frågor
│ └── helpers.py # Hjälpfunktioner för AQL-byggande
├── _chromadb/
│ ├── client.py # Instansierar ChromaDB-klient
│ ├── collections.py # Hanterar samlingar (persistens, insättning, sök)
│ └── embeddings.py # Hjälp för integrering mot embeddingsgenerator
├── _llm/
│ └── llm.py # LLM-wrapper (OpenAI API-kompatibelt gränssnitt)
└── README.md
Tips: Utforska
_arango,_chromadboch_llmför att förstå hur databaskopplingar och LLM-anrop är kapslade.
🔧 Backend-arkitektur
backend/app.py
- Skapar FastAPI-instansen och exponerar endpoints under
/api. - Registrerar t.ex.
search_router,chat_router,meta_router. - Konfigurerar CORS så att frontenden kan nå backenden under utveckling och produktion.
backend/search.py
- Innehåller klassen
SearchService. SearchServiceanvänderarango_clientoch_arango-hjälpare för att köra ArangoSearch-frågor.- Vanliga metoder (namn kan skilja något, läs filen för exakt signatur):
search(...): bygger en ArangoSearch AQL-query med filter (parti, år, talare) samt scoring viaBM25()ellerTFIDF().get_metadata(...): hämtar distinkta värden till frontendens filter.get_document_by_id(...): används för detaljerad visning/snippets.
backend/chat.py
- Hanterar endpointen
POST /api/chat. - Steg i chatthanteringen:
- Plockar senaste användarfrågan.
- Anropar ChromaDB (via
_chromadb) för semantisk återhämtning. - Kompletterar kontext med Arango-sökresultat om relevant.
- Bygger prompt och anropar
_llm.LLM. - Returnerar AI-svaret plus metadata (t.ex. vilka dokument som användes).
- Har ofta även
POST /api/vector-searchsom låter frontenden testa Chroma-resultat separat.
backend/vector.py (eller motsvarande modul)
- Innehåller hjälpfunktioner för att:
- Normalisera text.
- Skicka query till ChromaDB och hämta top-k embeddings-matchningar.
- Eventuellt uppdatera/återskapa Chroma-samlingar.
⚛️ Frontend-arkitektur
App.tsx: växlar mellan sök- och chat-läge (t.ex. viaconst [mode, setMode] = useState<'search' | 'chat'>('search')).api.ts: axios-klient som exporterar:searchTalks(params)→POST /api/search.chat(messages, strategy)→POST /api/chat.vectorSearch(query)→POST /api/vector-search.getMeta()→GET /api/meta.
components/SearchPanel.tsx:- Kontrollerade inputs för fritext, år, parti m.m.
- Använder
react-query(useMutation/useQuery) för att trigga backend-anrop. - Visar resultat i
ResultsTable.tsx.
components/ChatPanel.tsx:- Håller konversation i state (lista av
{ role, content }). - Skickar hela historiken till chat-endpointen.
- Renderar streamen av svar.
- Håller konversation i state (lista av
types.ts:- Speglar backendens Pydantic-scheman med TypeScript-interfaces (
SearchRequest,SearchResponse,TalkResult,ChatRequest, etc.). - Bra översättning mellan Python-modeller och TypeScript.
- Speglar backendens Pydantic-scheman med TypeScript-interfaces (
🔄 Dataflöden
Sökning via ArangoSearch
- Frontend (
SearchPanel.tsx) samlar användarens filter och anroparsearchTalksifrontend/src/api.ts. - FastAPI (
backend/search.py) tar emot POST/api/search, instansierarSearchServiceoch skickar vidare parametrar. SearchService.searchbygger en AQL-fråga mot ArangoSearch-vyn (t.ex.talks_view) där filter och scoring läggs till. Se_arango/queries/search_view.pyför den faktiska queryn.FOR doc IN talks_view SEARCH ANALYZER(doc.anforande_text, "text_sv") %PHRASE(@query)% FILTER (@party == null OR doc.party == @party) FILTER (@year == null OR doc.year == @year) SORT BM25(doc) DESC LIMIT @offset, @limit RETURN MERGE(doc, { snippet: doc.preview })- ArangoDB returnerar matchande dokument. Backend formaterar svaren (färger, snippet) och skickar JSON tillbaka.
- Frontend renderar resultatet i
ResultsTable.tsx, uppdaterar statistikpaneler och hanterar paginering.
Chattflöde med LLM och Chroma
- Frontend (
ChatPanel.tsx) skickar konversationen tillPOST /api/chat. backend/chat.py:- Extraherar senaste användarfrågan.
- Hämtar relevanta chunkar via Chroma (
_chromadb.collections.get_collection(...).query(...)). - Optionellt kompletterar kontexten med
SearchService.searchför ArangoSearch-träffar. - Bygger prompten, anropar
_llm.LLM(model="vllm")och returnerar svaret.
- Frontend lägger till AI-svaret i konversationen och visar källor/metadata för transparens.
🧩 Viktiga Python- och TypeScript-komponenter
| Fil | Funktion |
|---|---|
arango_client.py |
Initierar Arango-klienten med anslutningsuppgifter från miljön. |
_arango/_arango.py |
Wrapper som kapslar uppkoppling och hjälpfunktioner mot ArangoDB och views. |
_arango/queries/* |
Samling återskapbara AQL-snippets för sök, metadata och detaljhämtning. |
_chromadb/client.py |
Skapar ChromaDB-klienten (lokal DuckDB + Parquet som standard). |
_chromadb/collections.py |
Hjälper till att skapa/hämta Chroma-samlingar, lägga in chunkar och göra query. |
_llm/llm.py |
OpenAI-kompatibel klient. Använd LLM(model='vllm') och chat(...) för generering. |
backend/search.py |
Innehåller SearchService och API-routes för sök, bygger AQL mot ArangoSearch. |
backend/chat.py |
Chat- och vector-endpoints. Kopplar ihop Chroma-resultat med LLM-svar. |
frontend/src/api.ts |
Axios-klient för att prata med backenden (searchTalks, chat, vectorSearch, getMeta). |
frontend/src/components/* |
UI-komponenter i React/TypeScript för sök, resultat, chat, statistik. |
🗄️ ArangoDB och ArangoSearch
- Kollektioner: rådata om tal, talare och debatter lagras i Arango-kollektioner.
- Views: exempelvis
talks_viewindexerar textfält med analysatorntext_sv. Alla fritextfrågor går via vyn. - AQL-byggstenar:
FOR doc IN talks_viewSEARCHmedANALYZER,PHRASEeller token-matchning.FILTERför parti, år, kategori och talare.SORT BM25(doc)ellerSORT doc.datumberoende på begärd sortering.LIMIT @offset, @limitför paginering.
- Metadata: hämtas via dedikerade queries i
_arango/queries/meta.py(t.ex.COLLECT party = doc.party RETURN DISTINCT party).
🧠 ChromaDB för vektorsök
- Embeddings genereras via
scripts/build_embeddings.pysom:- Läser dokument från Arango via
arango_client. - Delar text i chunkar (
_chromadb/embeddings.py). - Beräknar embeddings (vanligen med
_llmeller annan embeddingsgenerator). - Sparar chunkar + metadata i en Chroma-samling.
- Läser dokument från Arango via
- Chatten hämtar liknande chunkar med
collection.query(query_texts=[...], n_results=top_k)och använder resultaten i prompten.
🔧 Utvecklingsflöde
| Steg | Befallning | Kommentar |
|---|---|---|
| Starta backend i utvecklingsläge | uvicorn backend.app:app --reload --port 8000 |
Kör i projektroten. |
| Starta frontend i dev-läge | cd frontend && npm run dev |
Öppna http://localhost:5173. |
| Bygg frontend för produktion | make frontend |
Skapar frontend/dist. |
| Ladda om nginx (om du serverar statiskt) | sudo systemctl reload nginx |
Efter ny frontend-build. |
| Kör embeddings-script | python -m scripts.build_embeddings --limit 500 |
Uppdaterar Chroma-samlingen. |
| Kör Arango-inmatning | python -m scripts.ingest_arguments |
Läser in tal/metadata i Arango. |
🧪 Felsökning och tips
- Arango-anslutning: kör
python arango_client.pyellerarangosh --server.endpoint tcp://127.0.0.1:8529. - Kontrollera AQL: använd ArangoDB Web UI eller
arangoshför att testa samma query somSearchServicebyggde. - Chroma-status: kontrollera
persist_directoryi_chromadb/client.py; ta bort katalogen om du behöver återskapa samlingen. - Embeddings: kör
python -m scripts.build_embeddings --limit 20för att uppdatera Chroma när nytt material importeras. - LLM-svar: logga prompt och kontext i
backend/chat.pyom svaren känns irrelevanta. - React/TypeScript: använd
useQueryför GET,useMutationför POST och typsätt API-kontrakt viafrontend/src/types.ts.
🤖 LLM-integration
-
_llm/llm.pyär huvudgränssnittet. Grundmönster:from _llm import LLM def generate_answer(prompt: str) -> str: llm = LLM(model="vllm") messages = [ {"role": "system", "content": "Du är en assistent som förklarar riksdagsdebatter sakligt."}, {"role": "user", "content": prompt}, ] response = llm.chat(messages=messages) return response -
Miljövariabler (
CHAT_MODEL,LLM_BASE_URL,LLM_API_KEY) styr målmodell och endpoint. -
Chat-endpointen täcker redan vanlig användning. För experiment: återanvänd samma mönster men bygg tydlig prompt av kontexten du hämtar.
Undvik onödiga
try/except. Fel bubbla upp så att du ser den faktiska orsaken (t.ex. nätverksproblem, fel API-nyckel).