# lovelypoet/paper-reader-agent architecture

> Architecture diagram of the GitHub repository lovelypoet/paper-reader-agent, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-15). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/lovelypoet/paper-reader-agent
- Repository: https://github.com/lovelypoet/paper-reader-agent

## Overview

This is a local document-ingestion and question-answering application. A user uploads a PDF or image through the Streamlit interface; the LangGraph ingestion workflow extracts text, validates and cleans it, then chunks and indexes it. The user can ask questions, which are answered from retrieved document passages with page and chunk citations. The README documents the processing stages, while the workflow, OCR, PDF, and validator implementations were not sampled; their detailed call relationships are therefore shown only where documentation supports them.

Main entry points: [`nodes/rag_node.py`](https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/rag_node.py) (Chunk and index), [`workflow.py`](https://github.com/lovelypoet/paper-reader-agent/blob/main/workflow.py) (Ingestion workflow), [`app.py`](https://github.com/lovelypoet/paper-reader-agent/blob/main/app.py) (Streamlit interface), [`nodes/validator_node.py`](https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/validator_node.py) (Text validation)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interface["User interface"]
  node_ui["Streamlit interface<br/>[app.py]"]
end

subgraph group_ingestion["Document ingestion"]
  node_workflow["Ingestion workflow<br/>[workflow.py]"]
  node_pdf["PDF extraction<br/>[pdf_node.py]"]
  node_ocr["Image OCR<br/>[ocr_node.py]"]
  node_validator["Text validation<br/>[validator_node.py]"]
end

subgraph group_retrieval["Retrieval and answers"]
  node_rag["Chunk and index<br/>[rag_node.py]"]
  node_chroma[("Chroma vector store")]
  node_ollama{{"Local Ollama"}}
end

subgraph group_runtime["Shared runtime"]
  node_state["Document state<br/>[state.py]"]
  node_config["Runtime settings<br/>[config.py]"]
end

node_user(("Document user"))

node_user -->|"uploads document"| node_ui
node_ui -->|"invokes ingestion"| node_workflow
node_workflow -->|"extracts PDF text"| node_pdf
node_workflow -->|"runs OCR"| node_ocr
node_pdf -->|"OCR fallback"| node_ocr
node_workflow -->|"validates text"| node_validator
node_validator -->|"retries weak text"| node_ocr
node_workflow -->|"indexes validated text"| node_rag
node_ui -->|"asks question"| node_rag
node_rag -->|"stores and retrieves"| node_chroma
node_rag -->|"embeds and answers"| node_ollama
node_rag -->|"cleans chunks"| node_validator
node_rag -->|"reads settings"| node_config
node_rag -->|"reads ingestion state"| node_state
node_ui -->|"saves uploads"| node_config

click node_ui "https://github.com/lovelypoet/paper-reader-agent/blob/main/app.py"
click node_workflow "https://github.com/lovelypoet/paper-reader-agent/blob/main/workflow.py"
click node_pdf "https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/pdf_node.py"
click node_ocr "https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/ocr_node.py"
click node_validator "https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/validator_node.py"
click node_state "https://github.com/lovelypoet/paper-reader-agent/blob/main/state.py"
click node_rag "https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/rag_node.py"
click node_config "https://github.com/lovelypoet/paper-reader-agent/blob/main/config.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_ui,node_user toneBlue
class node_workflow,node_pdf,node_ocr,node_validator toneAmber
class node_rag,node_chroma,node_ollama toneMint
class node_state,node_config toneRose
```

## Components

### User interface

- [Streamlit interface](https://github.com/lovelypoet/paper-reader-agent/blob/main/app.py): `app.py`

### Document ingestion

- [Ingestion workflow](https://github.com/lovelypoet/paper-reader-agent/blob/main/workflow.py): `workflow.py`
- [PDF extraction](https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/pdf_node.py): `nodes/pdf_node.py`
- [Image OCR](https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/ocr_node.py): `nodes/ocr_node.py`
- [Text validation](https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/validator_node.py): `nodes/validator_node.py`

### Retrieval and answers

- [Chunk and index](https://github.com/lovelypoet/paper-reader-agent/blob/main/nodes/rag_node.py): `nodes/rag_node.py`
- **Chroma vector store**
- **Local Ollama**

### Shared runtime

- [Document state](https://github.com/lovelypoet/paper-reader-agent/blob/main/state.py): `state.py`
- [Runtime settings](https://github.com/lovelypoet/paper-reader-agent/blob/main/config.py): `config.py`

### Other components

- **Document user**

## Connections

- Document user → Streamlit interface: uploads document (evidence: `README.md`)
- Streamlit interface → Ingestion workflow: invokes ingestion (evidence: `app.py`)
- Ingestion workflow → PDF extraction: extracts PDF text (evidence: `README.md`)
- Ingestion workflow → Image OCR: runs OCR (evidence: `README.md`)
- PDF extraction → Image OCR: OCR fallback (evidence: `README.md`)
- Ingestion workflow → Text validation: validates text (evidence: `README.md`)
- Text validation → Image OCR: retries weak text (evidence: `README.md`)
- Ingestion workflow → Chunk and index: indexes validated text (evidence: `README.md`)
- Streamlit interface → Chunk and index: asks question (evidence: `app.py`)
- Chunk and index → Chroma vector store: stores and retrieves (evidence: `nodes/rag_node.py`)
- Chunk and index → Local Ollama: embeds and answers (evidence: `nodes/rag_node.py`)
- Chunk and index → Text validation: cleans chunks (evidence: `nodes/rag_node.py`)
- Chunk and index → Runtime settings: reads settings (evidence: `nodes/rag_node.py`)
- Chunk and index → Document state: reads ingestion state (evidence: `nodes/rag_node.py`)
- Streamlit interface → Runtime settings: saves uploads (evidence: `app.py`)
