Ask questions about a PDF and get answers grounded in it, with the page they came from and what they cost.
Upload a document — a research paper, a car manual, a contract — and Paper-AI indexes it, works out what kind of document it is, and answers questions from its contents. You can also attach a photo (a dashboard warning light, a diagram) and ask about that.
Built with Streamlit and the Gemini API.
Answers come from the document, not the model. Every answer is built from passages retrieved out of your PDF, and cites the page each one came from. When the document does not cover the question, it says so instead of guessing.
The prompt adapts to the document. On upload, the document is profiled — type, domain, audience, terminology — and that profile writes the system prompt. A legal contract and a workshop manual get different personas. The generated prompt is editable in the sidebar.
Retrieval adapts to the question. "What is X?" and "Summarise the whole paper" need different amounts of context, so intent decides how many chunks to pull and how strict the similarity cut-off is. Questions that can be classified by pattern skip the planning call entirely.
PDFs with no text still work. Scans, and files distilled with their lettering converted to vector outlines, carry no text for a parser to read. Those pages are rendered to images and transcribed by the model before indexing.
Photos can be the question. Attach a picture of a warning light; it is turned into search terms in the document's own vocabulary, and the answer comes back from the manual.
Everything is costed. Each answer and the session total are shown in tokens and in your local currency, at live exchange rates.
Requires Python 3.12+ and a Gemini API key (aistudio.google.com).
git clone https://github.com/amalskr/Paper-AI.git
cd Paper-AI
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtPut your key in a .env file in the project root:
GEMINI_API_KEY=your-key-here
.env is git-ignored. Keep it that way — never commit a key.
Then:
streamlit run src/app.pyThe app opens at http://localhost:8501.
If
streamlitis "command not found", the virtualenv is not active. Eithersource .venv/bin/activatefirst, or run.venv/bin/streamlit run src/app.py.
PDF ──► text ──► chunks ──► embeddings ──► FAISS index
│
question ──► intent ──► query embedding ──► search ──► passages
│
system prompt + passages
│
answer + pages
Indexing is keyed by a SHA-256 of the file's bytes, so re-uploading the same PDF loads the saved index instead of paying to build it again.
| Module | Does |
|---|---|
pdf_loader.py |
Pulls the text layer out of a PDF, page by page |
ocr.py |
Reads pages as images when there is no text layer |
text_splitter.py |
Chooses chunk size from the document's own shape |
embedding.py |
Batched, parallel embeddings for chunks and queries |
vector_store.py |
FAISS index plus chunks, saved per document |
ingest.py |
Upload → searchable document, in one call |
doc_profile.py |
Profiles the document and writes its system prompt |
retrieval.py |
Plans the query, then searches and compacts passages |
answer.py |
Builds the grounded prompt and streams the answer |
vision.py |
Turns an attached photo into something searchable |
llm.py |
The only place that talks to Gemini; meters every call |
pricing.py |
Token counts → money, in local currency |
config.py |
Every model, threshold and limit, with the reason why |
app.py |
The Streamlit interface |
config.py is worth reading before changing anything — the defaults
carry the measurements that produced them.
The choices that matter most are written down in config.py next to the
values they justify. In short:
- Thinking tokens bill at the output rate, so they are capped low wherever the job is not really reasoning. On grounded answers that cut latency ~45% without changing the answers; on page transcription it was the difference between 3,556 thinking tokens per page and none.
- Query planning and profiling run on a cheaper model than the one that writes answers.
- Repeated questions, and re-uploads of the same file, are served from cache rather than paid for twice.
Reading a PDF that has no text layer is the one genuinely expensive operation: it costs a model call per page. A 264-page manual came to roughly $0.84 and four minutes — paid once, then cached.
src/ the app
papers/ sample PDFs
vector_store/ saved indexes, one folder per document (git-ignored)
.streamlit/ theme
rag.py, evaluation*.py and failure_testing.py are the earlier
standalone scripts the pipeline grew out of. They are kept as a record of
the steps, and are not part of the app.
© 2026 Amal · Powered by CeylonAPZ