-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathconfig.example.yml
More file actions
481 lines (415 loc) · 18.2 KB
/
Copy pathconfig.example.yml
File metadata and controls
481 lines (415 loc) · 18.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
# Copy to config.yml and fill in. config.yml is git-ignored.
# Perspicacité v2 Configuration
version: "2.0.0"
config_name: "anthropic-default"
# =============================================================================
# Server Settings
# =============================================================================
server:
host: "0.0.0.0"
port: 8000
reload: false
# =============================================================================
# LLM Configuration — Anthropic default
# API keys are set via environment variables:
# ANTHROPIC_API_KEY, DEEPSEEK_API_KEY, OPENAI_API_KEY
# =============================================================================
llm:
default_provider: "anthropic"
default_model: "claude-sonnet-4-5"
default_timeout_s: 60 # applied to every LLM call that doesn't set its own timeout
# Ollama only: context window forwarded to the local model. Ollama defaults
# num_ctx to 2048, which truncates long RAG synthesis prompts and makes the
# model return nothing. Raise to fit your prompts (more RAM = larger value).
ollama_num_ctx: 8192
# ── Free-tier auto-rotation (zero-cost alternative) ──────────────────────
# Set free_auto_mode: true + add your OPENROUTER_API_KEY (free account at
# openrouter.ai — no credits needed) to rotate through free models instead.
# See config.example.openrouter-free.yml for a full zero-cost preset.
# free_auto_mode: false
# free_tier_fallback_models:
# - "deepseek/deepseek-v4-flash:free"
# - "qwen/qwen3-coder:free"
# - "nvidia/nemotron-3-super-120b-a12b:free"
# - "meta-llama/llama-3.3-70b-instruct:free"
# - "openrouter/free"
# ─────────────────────────────────────────────────────────────────────────
providers:
anthropic:
base_url: "https://api.anthropic.com"
timeout: 120
max_retries: 3
deepseek:
base_url: "https://api.deepseek.com"
timeout: 120
max_retries: 3
openai:
base_url: "https://api.openai.com/v1"
timeout: 60
max_retries: 3
context:
max_tokens: 8000
chat_history_turns: 10
summarize_threshold: 20
# =============================================================================
# Knowledge Base Configuration
# =============================================================================
knowledge_base:
# Open, local default: reproduces the published SciFact retrieval stack and needs
# no API key (routed to sentence-transformers). Swap for any HF or hosted embedder
# (e.g. SPECTER2, BGE-M3, S-PubMedBERT, or text-embedding-3-small).
embedding_model: "all-MiniLM-L6-v2"
chunk_size: 1000
chunk_overlap: 200
# Advanced: extract structured tables + figures with docling, IN ADDITION to
# the always-on fast fitz text extraction. Requires `uv sync --extra docling`.
# docling is CPU-only here and slow (~minutes/page), so this is off by default
# — turn it on for high-value PDFs where tables/figures matter.
docling_extract_tables_figures: false
docling_max_pages: 40 # skip docling extras for PDFs larger than this
docling_timeout_s: 600 # per-document docling wall-clock cap; on timeout, skip extras
chunking_method: "token"
default_top_k: 10
similarity_threshold: 0.7
use_two_pass: true
markdown_heading_aware: true # heading-aware markdown chunking for local-doc ingest
code_language_aware: true # language-aware code chunking for local-doc ingest
# Contextual retrieval tier — pick by cost / quality:
#
# none — structural prefix only (title + section), free.
# Already happens unconditionally for every chunk.
# abstract — also prepend the paper's abstract (or leading slice
# of full_text). Zero LLM calls, same prefix on every
# chunk of a paper. Recommended starting point.
# summary — one LLM call per paper produces a 50-100 word
# summary, cached, applied to every chunk. 1/N the
# cost of "chunk" for N chunks.
# chunk — Anthropic-style: one LLM call per chunk produces a
# chunk-specific contextual sentence. Most expensive,
# best recall (30-40% lift per Anthropic's benchmark).
#
# LLM contexts (summary, chunk) are cached on disk at
# data/contextual_cache/ keyed on (paper_id, chunk_index, doc_sha)
# so re-ingesting the same paper is free.
contextual_retrieval_tier: "none" # none | abstract | summary | chunk
contextual_retrieval_model: "claude-haiku-4-5"
contextual_retrieval_provider: "anthropic"
contextual_retrieval_max_chars: 400
# Content acquisition mode for KB ingestion:
# "auto" — try full text (structured → PDF), fall back to abstract
# "full_text" — require full text; fail papers that have none
# "abstract_only" — skip PDF steps entirely; use abstract from OpenAlex/Crossref
# ~80% faster for large corpora; shallower retrieval depth
ingest_mode: "auto"
# =============================================================================
# Database Configuration
# =============================================================================
database:
path: "~/.local/share/perspicacite/memory.db"
chroma_path: "./chroma_db"
# =============================================================================
# RAG Mode Settings
# =============================================================================
rag_modes:
# Cross-encoder model used for result reranking across all RAG modes.
# Any HuggingFace cross-encoder compatible with sentence-transformers works here.
# L-12 is the published default: paired with the local all-MiniLM-L6-v2 embedder a
# cross-encoder adds ~+10pp NDCG@10 on SciFact dev (docs/embedding_reranker_policy.md).
reranker_model: "cross-encoder/ms-marco-MiniLM-L-12-v2"
basic:
max_iterations: 1
use_hybrid: true
advanced:
max_iterations: 2
use_hybrid: true
use_wrrf: true
enable_reflection: false
query_expansion: true
deep_research: # renamed from "profound"
max_iterations: 3
use_hybrid: true
use_wrrf: true
enable_planning: true
enable_reflection: true
max_total_seconds: 540 # F-17: hard cycle budget; synthesis runs on top of this
synthesis_timeout_s: 90 # independent cap on final answer generation phase
agentic:
max_iterations: 5
use_hybrid: true
early_exit_confidence: 0.85
# Max papers processed by the map-reduce answer-synthesis step.
# Higher values improve coverage but increase latency and token cost.
# Range: 1–64; default is 8.
map_reduce_max_papers: 8
# Opt-in: write each agentic answer + an APA reference list to a .docx.
# Off by default; requires the optional [docx] extra (`uv sync --extra docx`).
export_apa_docx: false
export_apa_docx_dir: "output"
literature_survey:
seed_known_max: 5 # known papers to keep as survey anchors when all results are already in KB
# =============================================================================
# SciLEx Integration
# =============================================================================
scilex:
enabled: true
apis:
semantic_scholar:
enabled: true
rate_limit: 100
openalex:
enabled: true
rate_limit: 100
pubmed:
enabled: true
rate_limit: 10
arxiv:
enabled: true
rate_limit: 100
hal:
enabled: true
rate_limit: 100
dblp:
enabled: true
rate_limit: 100
istex:
enabled: true
rate_limit: 100
ieee:
enabled: false
springer:
enabled: false
elsevier:
enabled: false
# =============================================================================
# Web Search Configuration
# =============================================================================
web_search:
providers: ["google_scholar", "semantic_scholar"]
cache_ttl: 3600
# =============================================================================
# PDF Download Configuration
# =============================================================================
pdf_download:
# Email for Unpaywall API (required for querying open access PDFs)
# Get one at: https://unpaywall.org/products/api
unpaywall_email: "you@example.com"
# Alternative endpoint for PDF downloads — a private or institutional
# repository you maintain (campus proxy, internal aggregator of
# pre-cleared PDFs, on-prem PDF cache, etc.). User-provided; left
# empty by default. The endpoint receives ``<base>/<doi>`` and is
# expected to return the PDF bytes.
alternative_endpoint: ""
# Wiley TDM (Text and Data Mining) API Token
# Register at: https://developer.wiley.com/api/wiley-text-and-data-mining-tdm/
wiley_tdm_token: ""
# Elsevier ScienceDirect API Key
# Register at: https://dev.elsevier.com/
elsevier_api_key: ""
# Semantic Scholar API Key
# Register at: https://www.semanticscholar.org/product/api#api-key
semantic_scholar_api_key: ""
# AAAS (Science journals) API Key
# For institutional access to Science, Science Advances, etc
# aaas_api_key: ""
# Royal Society of Chemistry (RSC) API Key
# Register at: https://api.rsc.org/
# rsc_api_key: ""
# Springer Nature API Key
# Register at: https://dev.springernature.com/
# springer_api_key: ""
# Timeout for PDF downloads (seconds)
timeout: 30
# Maximum retries for failed downloads
max_retries: 3
# Optional cookie jar for institutional-access PDFs. Server-side
# equivalent of what the Zotero Connector browser extension does:
# the user logs into their library proxy / publisher SSO in their
# browser, exports cookies via a "Get cookies.txt"-style extension,
# and points Perspicacité at the file. PDF requests then carry the
# user's session cookies — paywalled PDFs the user is entitled to
# become reachable. Cookies expire; re-export as needed.
#
# cookies_path: "/Users/me/Library/perspicacite/proxy_cookies.txt"
# cookie_domains:
# - "sciencedirect.com"
# - "wiley.com"
# - "onlinelibrary.wiley.com"
# - "proxy.lib.example.edu"
cookies_path: ""
cookie_domains: []
# =============================================================================
# MCP Server Configuration
# =============================================================================
mcp:
enabled: true
host: "0.0.0.0"
port: 8000
transport: "streamable-http" # co-hosted with FastAPI at /mcp
# =============================================================================
# Authentication
# =============================================================================
auth:
enabled: true
# Token set via PERSPICACITE_AUTH_TOKEN environment variable
# =============================================================================
# UI Configuration
# =============================================================================
ui:
theme: "system"
citation_format: "nature"
# =============================================================================
# Logging
# =============================================================================
logging:
level: "INFO"
format: "json"
# =============================================================================
# Zotero Integration
# =============================================================================
zotero:
enabled: false # set true to enable both push (paper → Zotero) and ingest (Zotero → KBs)
api_key: ""
library_id: ""
library_type: "user" # or "group"
collection_key: "" # optional; used by PUSH only — empty = no default collection
# Note: ingest does NOT use collection_key. Instead, /api/zotero/plan
# generates one KB per top-level collection (with subcollections rolled up)
# plus an "Unfiled" KB for items not in any collection.
# =============================================================================
# Local Documents
# =============================================================================
# Paths server-side ingest will accept. If empty, POST /api/kb/{name}/local-paths
# returns 503 and the ingest_local_documents MCP tool refuses all calls.
# Web upload (POST /api/kb/{name}/local-files, multipart) is unaffected.
local_docs:
allowed_roots: []
# Example:
# allowed_roots:
# - "/Users/me/Documents/research"
# - "/data/lab-notes"
# =============================================================================
# Capsule (per-paper artifact: figures, structured text blocks, mined resources)
# =============================================================================
capsule:
enabled: true
auto_build_on_ingest: true
root: ./data/capsules
min_version: "0.1"
# =============================================================================
# Multimodal RAG (Cycle B): figures-in-prompt + inline thumbnails in answers
# =============================================================================
multimodal:
enabled: true # Pull figure_refs from retrieved chunks into the LLM call
max_images: 6 # Cap on images sent per LLM call
vision_allowlist: # Prefix-match against the model string (provider/model)
- "anthropic/claude-"
- "claude-"
- "openai/gpt-4o"
- "gpt-4o"
# =============================================================================
# External resources (Cycle C): V1 mining + V2 fetch-on-demand
# =============================================================================
# =============================================================================
# Copyright filter (defense-in-depth on synthesis output)
# =============================================================================
# Detects verbatim copying of source-paper text in the LLM's answer and
# applies the configured action. The system prompt already nudges the
# LLM toward paraphrasing; this is the runtime check.
#
# action options:
# log — warn only, answer unchanged (default, no cost)
# quote — wrap detected spans in “…” and append citation
# strip — replace spans with [content paraphrased]
# rewrite — one extra LLM call to paraphrase flagged spans
copyright_filter:
enabled: true
action: "log" # log | quote | strip | rewrite
min_ngram: 8 # min word-run length to flag (3..30)
rewrite_model: "claude-haiku-4-5"
rewrite_provider: "anthropic"
# =============================================================================
# External resources (Cycle C): V1 mining + V2 fetch-on-demand
# =============================================================================
external_resources:
mine: true # V1 — Cycle A, always-on
fetch_on_demand: true # V2 — gate for fetch helpers
cache_dir: ./data/cache
cache_ttl_days: 30
zenodo_max_bytes_per_file: 500000 # Skip Zenodo files larger than this
zenodo_max_bytes_per_record: 5000000 # Stop after cumulative bytes per record
text_file_extensions: # Allowlist for fetched text/code files
- .md
- .rst
- .txt
- .py
- .R
- .r
- .jl
- .ipynb
- .yml
- .yaml
- .toml
- .json
- .csv
# =============================================================================
# Search Provider Configuration
# =============================================================================
search:
# Timeout (seconds) for "reliable" tier providers.
# external tier = 1.5×, flaky tier = 2.25× this value.
provider_timeout_s: 20
# Max results fetched per provider before merge + dedup.
max_results_per_provider: 25
# Allowlist of provider names. Remove or comment out to disable a provider.
# Omit this key entirely to enable all registered providers.
enabled_providers:
- scilex # SciLEx aggregator (Semantic Scholar, OpenAlex, PubMed, arXiv, HAL, DBLP)
- europepmc # Europe PMC biomedical search (free, no key)
- pubchem # PubChem compound → literature search (free, no key)
- core # CORE open-access aggregator (free, optional key below)
- inspire # INSPIRE-HEP physics bibliography (free, no key)
- ads # NASA ADS astronomy (requires ads_api_key below)
# - google_scholar # Google Scholar via Playwright (requires [browser] dep + google_scholar.enabled: true below)
# - dblp_sparql # DBLP citation-ranked titles + SemOpenAlex abstracts (free, no key)
# CORE API key (optional — raises rate limit from 10 to unlimited req/min)
# Register at https://core.ac.uk/api-keys/register
core_api_key: ""
# NASA ADS token (required for ADS provider; register at https://ui.adsabs.harvard.edu)
# The ADS provider is silently skipped when this is empty.
ads_api_key: ""
# =============================================================================
# Google Scholar (Playwright/Chromium) — optional browser-based provider
# =============================================================================
#
# Requires: uv pip install -e "[browser]" && playwright install chromium
# Add "google_scholar" to search.enabled_providers above to activate.
#
google_scholar:
# Must be True AND "google_scholar" in search.enabled_providers for this to run.
enabled: false
# Run Chromium headless (true) or with a visible window (false, useful for debugging).
headless: true
# Seconds to wait between Scholar page requests. Keep >= 2.0 to avoid CAPTCHA.
delay_seconds: 2.0
# Hard cap on results per search call.
max_results: 20
# --- CAPTCHA fallback via OpenRouter web search ---
# When Scholar serves a CAPTCHA, fall back to an OpenRouter model with
# Exa web-search capability (academic domain allowlist). Costs ~$0.005/trigger.
# Set openrouter_api_key or OPENROUTER_API_KEY env var to activate.
openrouter_fallback_enabled: false
openrouter_api_key: "" # or set OPENROUTER_API_KEY env var
openrouter_fallback_model: "deepseek/deepseek-chat"
# For native-search models (Anthropic/OpenAI/xAI), use e.g. "anthropic/claude-haiku-4-5"
openrouter_fallback_domains:
- "arxiv.org"
- "biorxiv.org"
- "chemrxiv.org"
- "pubmed.ncbi.nlm.nih.gov"
- "europepmc.org"
- "semanticscholar.org"
- "crossref.org"
- "nature.com"
- "sciencedirect.com"
- "springer.com"
- "wiley.com"