Skip to content

ash23x/AxOntos

Repository files navigation

AxOntos — sovereign research intelligence

AxOntos

Your research corpus. Your infrastructure. Your intelligence.

A sovereign research intelligence system that transforms a collection of PDFs into an interrogable knowledge engine. Drop your papers in, run the embedder, ask questions. Everything runs on your hardware — no cloud dependency, no subscription, no data leaving your box.

This is not a toy RAG demo. It is a production-grade research tool with hybrid search (vector + keyword), dual-tier synthesis (local GPU + optional cloud), a React frontend with in-browser PDF viewing, and Docker deployment. Built and battle-tested on a corpus of 6,500+ scientific papers.


What Makes This More Than a Basic RAG

Feature Basic RAG AxOntos
Search Vector only Hybrid vector + keyword with acronym expansion
Models Single Dual-tier: local Ollama + optional Anthropic cloud
Retrieval Fixed chunk count Model-aware: auto-tunes chunks to context window size
Chunking Naive character split Sentence-boundary aware with hard ceiling
Embedding Cloud API Sovereign: Nomic v1.5 via local Ollama
Pipeline Fragile Checkpointed: crash-safe, resumes from failure
Frontend Terminal React SPA with search, chat, PDF viewer, cost display
Deployment Script Docker Compose (one command)

Quick Start (5 minutes)

Prerequisites

  • Python 3.10+
  • Node.js 18+ (for frontend)
  • Ollama installed and running (ollama.ai)
  • GPU recommended (embedding is ~10x faster with CUDA)

1. Clone and install

git clone https://github.com/ash23x/axontos.git
cd axontos
pip install -r requirements.txt
cp .env.example .env

2. Pull the models

# Embedding model (required — 139 MB)
ollama pull nomic-embed-text

# Chat model (pick one)
ollama pull llama3.1:8b        # 4.7 GB — good default
ollama pull qwen3:14b          # 8.6 GB — better quality
ollama pull gemma2:9b          # 7.2 GB — alternative

3. Add your PDFs

mkdir corpus
# Copy or symlink your PDF library into the corpus/ folder
# Subdirectories are fine — the crawler searches recursively

4. Build the index

# Step 1: Crawl your corpus and build the manifest
python -m jarvis.crawler

# Step 2: Embed everything (this takes a while — ~2 mins per 100 PDFs on GPU)
python embed_v3_streaming.py

The embedder checkpoints per document. If it crashes, restart it — it picks up exactly where it left off.

5. Launch

# Start the API backend
python -m uvicorn jarvis.api:app --host 0.0.0.0 --port 8500

# In another terminal: start the frontend
cd frontend
npm install
npm run dev

Open http://localhost:5503 in your browser. Green dot = connected. Search your corpus.


Architecture

Browser (:5503)  →  Vite dev server  →  proxy /api/*  →  FastAPI (:8500)
                                                              │
                                                    ┌────────┼────────┐
                                                    ▼        ▼        ▼
                                                ChromaDB   Ollama   Anthropic
                                               (vectors)  (local)   (cloud)
                                                              │        │
                                                         ┌────┘    optional
                                                         ▼
                                                    nomic-embed-text
                                                    llama3.1 / qwen3

Two Ports — By Design

Port Service Purpose
8500 FastAPI backend REST API: search, chat, stats, PDF serving
5503 Vite dev server React frontend with hot-reload (development)
8080 nginx Production frontend (Docker only — single port)

In development, Vite runs on :5503 and proxies /api/* requests to the backend on :8500. The browser only talks to :5503.

In Docker production mode, nginx serves the static React build and proxies API calls — everything through a single port (:8080).


Configuration

All configuration is via environment variables. Copy .env.example to .env and edit:

# Path to your PDF corpus
SRAG_CORPUS=./corpus

# Ollama connection
SRAG_OLLAMA_URL=http://localhost:11434

# Embedding model (must be pulled in Ollama)
SRAG_EMBED_MODEL=nomic-embed-text:latest

# Chat model (must be pulled in Ollama)
SRAG_CHAT_MODEL=llama3.1:8b

# Optional: Anthropic API key for cloud synthesis
# SRAG_ANTHROPIC_KEY=sk-ant-...

Cloud Models (Optional)

If you set SRAG_ANTHROPIC_KEY, the frontend unlocks Claude Sonnet 4.6 ($0.02/query) and Claude Opus 4.6 ($0.08/query) as synthesis options. These provide dramatically better cross-domain reasoning than local models but cost money per query. The cost is displayed in the interface.

Local models work perfectly without any API key. Cloud is a nice-to-have, not a requirement.


API Reference

All endpoints served from the FastAPI backend on port 8500.

Method Endpoint Description
GET / Health check
GET /stats Corpus statistics: paper count, chunk count, model info
GET /models Available models (local + cloud) with sizes and costs
POST /search Hybrid search. Body: {query, n, mode}
POST /chat RAG synthesis. Body: {question, model, n_chunks}
GET /pdf?path=... Serve PDF from corpus (path-validated)
POST /add Ingest a new paper into the corpus

Search Modes

  • both (default) — Vector similarity + keyword matching, blended and ranked
  • vector — Pure embedding cosine similarity
  • keyword — Manifest keyword search only

Acronym Expansion

Embedding models don't understand domain acronyms. "NLP" embeds as three characters, not as "Natural Language Processing." AxOntos maintains an acronym dictionary that transparently expands queries before embedding.

Edit jarvis/search.py to add your domain-specific acronyms:

ACRONYMS = {
    "llm": "Large Language Model LLM",
    "rag": "Retrieval Augmented Generation RAG",
    # Add your domain acronyms here:
    # "xyz": "Full Name Of XYZ Concept XYZ",
}

This is the single highest-impact customisation you can make. If your corpus uses domain-specific abbreviations, add them here.


Docker Deployment

For production or sharing with collaborators:

docker-compose up --build

This starts two containers:

  • axontos-api on port 8500 (FastAPI + ChromaDB)
  • axontos-frontend on port 8080 (nginx + React build)

Open http://localhost:8080 — single port, no proxy config needed.

Volume Mounts

volumes:
  - ./corpus:/data/pdfs:ro          # Your PDF library (read-only)
  - rag-chroma:/data/chromadb       # Persistent vector database
  - ./manifest.json:/data/manifest.json:ro

Connecting to Ollama

Docker containers reach Ollama on the host via host.docker.internal:11434. This works out of the box on Docker Desktop (Windows/Mac). On Linux, add --add-host=host.docker.internal:host-gateway to your Docker run command or use network_mode: host.


The Embedding Pipeline

How It Works

  1. Crawljarvis/crawler.py discovers all PDFs, extracts metadata, builds manifest.json
  2. Chunkembed_v3_streaming.py extracts text via PyMuPDF, splits into sentence-boundary-aware chunks (target 500 chars, hard max 1000 chars, 50 char overlap)
  3. Embed — Chunks are batched (100 per GPU call) and embedded via Nomic (768 dimensions)
  4. Store — Vectors are upserted into ChromaDB in two collections: paper-level and chunk-level

Crash Safety

The embedder writes a checkpoint (done_docs.txt) after each document. If the process dies — power cut, OOM, VRAM exhaustion — restart it and it resumes from the exact point of failure. No re-embedding of completed documents.

Performance

On an NVIDIA RTX 4070 (12 GB VRAM):

  • ~2 minutes per 100 PDFs
  • ~12 hours for 6,500 papers
  • Query latency: ~1.8s cold, ~0.1s warm

CPU-only embedding works but is ~10x slower.


Frontend

The web interface features:

  • Search tab — Free-text query with mode selector (All/Papers/Chunks), similarity percentage bars, clickable PDF links
  • Chat tab — Conversational RAG with model dropdown (local/cloud), inline source citations, cost display for cloud models
  • PDF viewer — Click any source to view the original PDF in-browser
  • Model selector — Switch between local Ollama models and cloud Claude models
  • KaTeX — Mathematical notation rendering in scientific answers

The design is a dark theme with gold accent instrumentation. It looks like a research tool, not a toy.


Project Structure

axontos/
├── jarvis/                     # Core Python package
│   ├── config.py               # Environment-driven configuration
│   ├── search.py               # Hybrid search + acronym expansion
│   ├── chat.py                 # RAG synthesis (local + cloud)
│   ├── cloud_chat.py           # Anthropic API bridge
│   ├── api.py                  # FastAPI REST endpoints
│   ├── embedder.py             # Paper-level embedding
│   ├── crawler.py              # PDF discovery + manifest
│   └── add.py                  # Single-paper ingestion
├── frontend/                   # React + Vite SPA
│   ├── src/App.jsx             # Main application (598 lines)
│   ├── Dockerfile              # Multi-stage: build + nginx
│   ├── nginx.conf              # Production reverse proxy
│   └── package.json            # React 18 + Vite 6 + KaTeX
├── embed_v3_streaming.py       # V3 chunk embedder (crash-safe)
├── docker-compose.yml          # Two-service deployment
├── Dockerfile                  # Backend container
├── requirements.txt            # Python dependencies
├── .env.example                # Configuration template
└── corpus/                     # Your PDFs go here

Customisation

System Prompt

Edit jarvis/chat.py — the SYSTEM_PROMPT variable. Tell the model what kind of researcher it is, what domains the corpus covers, and how you want it to synthesise across disciplines.

Similarity Threshold

In jarvis/config.py, MIN_SIMILARITY controls the cutoff. Default is 0.55. Raise it for precision (fewer but better results), lower it for recall (more results, more noise).

Model-Aware Retrieval

In jarvis/chat.py, the _retrieval_config() function tunes how many chunks and papers are retrieved based on the model's context window. Cloud models with 200K context get 15 chunks; local 8B models with 4K context get 5. Add your own models here.


Requirements

Python

  • chromadb >= 0.4.0
  • pymupdf >= 1.23.0
  • requests >= 2.28.0
  • fastapi >= 0.100.0
  • uvicorn >= 0.22.0
  • python-dotenv >= 1.0.0
  • psutil >= 5.9.0

Frontend

  • react 18
  • react-dom 18
  • katex >= 0.16
  • vite 6

Infrastructure

  • Ollama (local LLM server)
  • GPU with CUDA (recommended, not required)

License

MIT License — see LICENSE.


Credits

Built by Ontos Labs Ltd.

If you use this for research, we'd love to hear about it.

About

AxOntos — sovereign research intelligence. Drop your PDFs, ask questions. Hybrid search, dual-tier synthesis, React frontend. No cloud dependency.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors