An implementation of Google Deep Search with support for 1000+ references, local inference, chatting with your scraping session using RAPTOR, and report generation.
Python
186
21 commits
updated Aug 14, 2026
A local research assistant: you give it a topic, it searches Semantic Scholar, filters papers, builds a RAPTOR summary tree, and answers questions from that corpus. Chat, summarization, and embeddings all go through a llama.cpp llama-server over its OpenAI-compatible /v1 API.
The algorithms live in an installable Python package, academic_deepsearch. Streamlit is only the UI.
academic_deepsearch (LangGraph pipeline, RAPTOR, filters, reports)llama-server (/v1/chat/completions, /v1/embeddings, /v1/models, /health)langchain-openai pointed at the local serverllama-server
8080)--embeddings), often on a second server (default 8081)git clone https://github.com/iblameandrew/local-deepsearch-academic.git
cd local-deepsearch-academic
python -m venv .venv
# Windows: .venv\Scripts\activate
source .venv/bin/activate
pip install -e ".[app]"
For tests and lint: pip install -e ".[dev]".
requirements.txt pins the same runtime stack if you prefer a flat install.
Two processes are the usual setup, because one llama-server is typically either a chat model or an embedding model:
llama-server -m /path/to/chat.gguf --host 127.0.0.1 --port 8080
llama-server -m /path/to/embed.gguf --host 127.0.0.1 --port 8081 --embeddings
Environment variables (also used by Docker):
| Variable | Default | Purpose |
|---|---|---|
LLAMA_CPP_BASE_URL | http://127.0.0.1:8080/v1 | Chat, relevance, summaries, report rewrite |
LLAMA_CPP_EMBED_BASE_URL | same as chat URL | Embeddings |
LLAMA_CPP_API_KEY | sk-no-key | Dummy key for the OpenAI client; set this if you started the server with --api-key |
The sidebar talks to GET /health and GET /v1/models. If the server is down you can still type a model id by hand.
streamlit run app.py
Configure the topic, publishers, and llama.cpp URLs in the sidebar, then start the pipeline. Enable Debug Mode to run search against the built-in mock papers (the LLM still comes from llama.cpp).
from academic_deepsearch import (
ResearchConfig,
ResearchPipeline,
MockSearcher,
)
config = ResearchConfig(
query="indoor air quality monitoring using machine learning",
publishers=["IEEE", "ACM", "Springer", "Elsevier", "Arxiv", "Scholar"],
max_results=100,
llm_base_url="http://127.0.0.1:8080/v1",
embed_base_url="http://127.0.0.1:8081/v1",
chat_model="local",
embedding_model="local",
)
# Offline / tests: inject search + model fakes.
# Live: omit searcher/llm/embeddings and the pipeline will call Semantic Scholar
# and llama.cpp using the URLs above.
result = ResearchPipeline(config, searcher=MockSearcher()).run()
docs = result.retrieve("What clustering method is used?")
Lower-level helpers (filter_by_publisher, filter_by_relevance, RAPTORIndex, PDF/Mermaid/report builders) are exported from academic_deepsearch.
The package does not import Streamlit. Pass a ProgressReporter if you want logs; tests use NullReporter.
# App container; llama-server stays on the host
docker compose up app --build
# Offline test image (no llama.cpp, no Semantic Scholar)
docker compose run --rm test
The app container defaults LLAMA_CPP_BASE_URL to http://host.docker.internal:8080/v1.
Optional compose profile llm starts ghcr.io/ggml-org/llama.cpp:server and expects ./models/chat.gguf and ./models/embed.gguf. It is not used in CI.
docker compose --profile llm up
pytest
pytest --cov --cov-report=term-missing
ruff check academic_deepsearch tests app.py
The default suite is offline. Tests marked @pytest.mark.live (network / llama.cpp) are excluded unless you pass -m live.
GitHub Actions (.github/workflows/ci.yml) runs Ruff, pytest on Python 3.11 and 3.12, and builds both the test and runtime Docker stages.
Issues and pull requests are welcome: iblameandrew/local-deepsearch-academic.
21 commits
Python
99.2%
An implementation of Google Deep Search with support for 1000+ references, local inference, chatting with your scraping session using RAPTOR, and report generation.
Python
186
21 commits
updated Aug 14, 2026
A local research assistant: you give it a topic, it searches Semantic Scholar, filters papers, builds a RAPTOR summary tree, and answers questions from that corpus. Chat, summarization, and embeddings all go through a llama.cpp llama-server over its OpenAI-compatible /v1 API.
The algorithms live in an installable Python package, academic_deepsearch. Streamlit is only the UI.
academic_deepsearch (LangGraph pipeline, RAPTOR, filters, reports)llama-server (/v1/chat/completions, /v1/embeddings, /v1/models, /health)langchain-openai pointed at the local serverllama-server
8080)--embeddings), often on a second server (default 8081)git clone https://github.com/iblameandrew/local-deepsearch-academic.git
cd local-deepsearch-academic
python -m venv .venv
# Windows: .venv\Scripts\activate
source .venv/bin/activate
pip install -e ".[app]"
For tests and lint: pip install -e ".[dev]".
requirements.txt pins the same runtime stack if you prefer a flat install.
Two processes are the usual setup, because one llama-server is typically either a chat model or an embedding model:
llama-server -m /path/to/chat.gguf --host 127.0.0.1 --port 8080
llama-server -m /path/to/embed.gguf --host 127.0.0.1 --port 8081 --embeddings
Environment variables (also used by Docker):
| Variable | Default | Purpose |
|---|---|---|
LLAMA_CPP_BASE_URL | http://127.0.0.1:8080/v1 | Chat, relevance, summaries, report rewrite |
LLAMA_CPP_EMBED_BASE_URL | same as chat URL | Embeddings |
LLAMA_CPP_API_KEY | sk-no-key | Dummy key for the OpenAI client; set this if you started the server with --api-key |
The sidebar talks to GET /health and GET /v1/models. If the server is down you can still type a model id by hand.
streamlit run app.py
Configure the topic, publishers, and llama.cpp URLs in the sidebar, then start the pipeline. Enable Debug Mode to run search against the built-in mock papers (the LLM still comes from llama.cpp).
from academic_deepsearch import (
ResearchConfig,
ResearchPipeline,
MockSearcher,
)
config = ResearchConfig(
query="indoor air quality monitoring using machine learning",
publishers=["IEEE", "ACM", "Springer", "Elsevier", "Arxiv", "Scholar"],
max_results=100,
llm_base_url="http://127.0.0.1:8080/v1",
embed_base_url="http://127.0.0.1:8081/v1",
chat_model="local",
embedding_model="local",
)
# Offline / tests: inject search + model fakes.
# Live: omit searcher/llm/embeddings and the pipeline will call Semantic Scholar
# and llama.cpp using the URLs above.
result = ResearchPipeline(config, searcher=MockSearcher()).run()
docs = result.retrieve("What clustering method is used?")
Lower-level helpers (filter_by_publisher, filter_by_relevance, RAPTORIndex, PDF/Mermaid/report builders) are exported from academic_deepsearch.
The package does not import Streamlit. Pass a ProgressReporter if you want logs; tests use NullReporter.
# App container; llama-server stays on the host
docker compose up app --build
# Offline test image (no llama.cpp, no Semantic Scholar)
docker compose run --rm test
The app container defaults LLAMA_CPP_BASE_URL to http://host.docker.internal:8080/v1.
Optional compose profile llm starts ghcr.io/ggml-org/llama.cpp:server and expects ./models/chat.gguf and ./models/embed.gguf. It is not used in CI.
docker compose --profile llm up
pytest
pytest --cov --cov-report=term-missing
ruff check academic_deepsearch tests app.py
The default suite is offline. Tests marked @pytest.mark.live (network / llama.cpp) are excluded unless you pass -m live.
GitHub Actions (.github/workflows/ci.yml) runs Ruff, pytest on Python 3.11 and 3.12, and builds both the test and runtime Docker stages.
Issues and pull requests are welcome: iblameandrew/local-deepsearch-academic.
21 commits
Python
99.2%