A localhost research workspace for NASA and space-biology literature. Search the imported collection, inspect source evidence, compare papers, save a reading list, explore research trends and investigate candidate knowledge gaps.
The interface includes a textured Three.js Earth with independently moving clouds, night lights, surface normals, ocean reflections, an atmosphere and a layered round starfield. All visual assets, fonts and browser dependencies are served locally.
Use Node.js 22 or newer. From this project directory:
npm install
npm startOpen http://localhost:3000. The server binds to 127.0.0.1; no deployment or cloud database is needed. npm run dev restarts the server after code edits.
Your existing data/papers.db is preserved. Do not seed an existing installation just to launch the app. On a fresh checkout with no database, use npm run seed for five clearly marked demo records, then start the app. These examples are not verified publications.
- Discover: BM25-style keyword ranking, optional compatible local semantic vectors, organism/environment/platform/domain filters, year range, source-only results, sorting, grid/list layouts and pagination.
- Evidence details: stored results-first summary, source abstract, extracted implications, candidate gaps, original URL, enrichment provenance, metadata-coverage rubric and related research.
- Saved library: browser-local reading list. No account or cloud synchronization. Bookmarks persist in the same browser and origin.
- Compare: choose two or three papers to inspect research conditions, findings and gaps side by side.
- Research insights: domain distribution, publication-year trends, taxonomy-based topic groups and metadata coverage, calculated from SQLite.
- Knowledge gaps: imported limitations ranked by average metadata coverage plus recurrence. Open the supporting record to verify each point.
- Evidence assistant: answers from retrieved research. Without a model it selects relevant excerpts and supplies record citations. With a configured model it generates a cited synthesis from retrieved context.
- CSV export: exports the current page of results; spreadsheet formula prefixes are escaped.
Press Ctrl/Cmd K to focus search. Pause the Earth and starfield with the header motion button. The app respects reduced-motion preferences, pauses rendering while hidden, and provides a textured fallback if WebGL is unavailable.
The app works without an API key. Install Ollama separately if you want local generated answers and semantic embeddings. Model downloads are intentionally not automatic.
ollama pull llama3.2:3b
ollama pull nomic-embed-text
ollama serveIf Ollama is already running, another ollama serve is unnecessary. Available memory and hardware determine which models run comfortably. Choose models appropriate to your computer and update .env.local if you use different names.
Copy .env.example to .env.local only if you do not already have that file. Existing environment files are loaded without overwriting shell environment variables.
AI_PROVIDER=local
OLLAMA_URL=http://127.0.0.1:11434
OLLAMA_CHAT_MODEL=llama3.2:3b
OLLAMA_EMBED_MODEL=nomic-embed-textCreate embeddings once, then restart the app:
npm run reindex -- --limit 20 # small initial check
npm run reindex # index remaining records
npm startIndexing the whole collection can take time. Completed vectors are persisted and the command resumes missing vectors. Each vector is keyed by provider and model. Legacy Gemini embeddings remain preserved in the old column but are not mixed with local vectors. Until a compatible index exists, the app reports keyword search. The model-status dialog shows connectivity and indexed counts.
Set AI_PROVIDER=offline to disable model calls. Optional Gemini support requires both AI_PROVIDER=gemini and GEMINI_API_KEY. Selecting that provider sends research context and questions to Gemini. A key alone never enables cloud requests.
The local provider uses Ollama's documented embedding, chat and model-list endpoints. Real Ollama generation and embedding require the service and models to be installed. The contract is tested with a local HTTP fixture, separately from the working offline mode.
Supported CSV fields include title/Title, abstract/Abstract, url/URL/Link, year/Year/PubYear, DOI, PMCID, PMID and optional facet arrays. Source URLs can be constructed from supplied publication identifiers. No identifier is invented.
npm run ingest:file -- data/my_papers.csv --offline
npm run ingest:file -- data/my_papers.csv --limit 20
node scripts/pmc_to_ingest_csv.mjs data/SB_publication_PMC.csv data/pmc_ingest.csv
node scripts/osdr_to_csv.mjs "microgravity" 20 data/osdr_import.csvOffline imports use conservative explicit-text facet rules and extract sentences from the supplied abstract. Unsupported mission implications and gaps remain empty. With a model configured, enrichment attempts model extraction and falls back to extracts on failure. Reimporting the same normalized title + URL updates the record instead of inserting it again. Existing duplicates from historical imports are preserved. Citation retrieval and related-paper mapping avoid repeated normalized titles.
PMC enrichment excludes XML attributes from text. OSDR publication rows use study descriptions when no publication abstract is available and leave unknown publication years empty. Inspect the metadata_note column before ingesting an OSDR export. These scripts fetch public source metadata; they do not upload your database. Restart the server after CLI changes so the in-memory catalog refreshes.
A safe recovery tool can restore missing URLs and years from your existing bibliography CSV using exact normalized titles:
npm run repair:metadata # dry run
npm run repair:metadata -- --apply # create backup, then applyRecovery skips conflicting matches and preserves populated fields. Backups are in data/backups/ and are Git-ignored. To restore, stop the app and replace data/papers.db with the selected backup; keep the current database separately until recovery is checked. SQLite WAL files should be handled with the database closed.
The local collection contains 6,020 imported records. The October 2026 repair recovered 4,734 source URLs and 5,377 years, while skipping 28 conflicting title matches. There are now 5,344 usable non-demo source links; five example.com links are treated as demo placeholders. Source URLs have not been checked individually for availability.
The collection includes legacy records, historical papers, duplicate source records, incomplete facets, and some text extraction artifacts. A source link does not prove NASA relevance or validate a claim. Existing summaries, implications and gaps are imported and unreviewed. No real-time ingestion status or scientific-confidence score is claimed.
Metadata coverage is a transparent completeness rubric: source URL 35, abstract 25, year 10, summary 10, organism 10, domain 10. It does not measure study quality, causal support or model accuracy. Gap ranking is a navigation heuristic. Topic groups use stored labels, not unsupervised ML clustering. AI citations reference retrieved records but do not guarantee that every claim is entailed by the source.
Human source validation, retrieval evaluation, measured summary quality, licensed full-text ingestion and evaluated topic clustering remain future work. Supabase, Vercel and deployment are outside the current scope.
server.mjs Express app and localhost entry point
lib/config.mjs Environment and model configuration
lib/db.mjs Non-destructive schema setup and serialization
lib/catalog.mjs Search, facets, related papers, analytics and retrieval
lib/ai.mjs Ollama and optional Gemini providers
lib/enrichment.mjs CSV normalization and conservative enrichment
lib/pmc.mjs PMC metadata parsing
public/ UI modules, styles, local Earth textures
scripts/ Import, metadata repair and embedding tools
tests/research.test.mjs Isolated SQLite/API/provider regression tests
docs/IMPLEMENTATION_PLAN.md Proposal mapping and implementation decisions
docs/VERIFICATION.md Verification evidence and remaining requirements
npm test
npm run check
npm auditTests use an isolated in-memory database, temporary CSV files and a local mock model service. They do not change your research database or call cloud AI. See docs/VERIFICATION.md and docs/screenshots/ for browser checks. The interface is an independent project and does not claim NASA endorsement. Texture and package attribution: public/assets/README.md.
Read the illustrated project explanation (PDF) for architecture, data flow, search, AI modes, user workflows, local setup and verification limits. The source generator is scripts/build_explanation_pdf.py (Python, ReportLab and Pillow; Arial fonts on Windows).
The complete published research collection is at https://nasa-bioscience-xplorer.vercel.app.
The deployment uses a bundled, read-only SQLite snapshot with all 6,020 local research records. data/deployment-manifest.json records the row count and SHA-256 of every research field. The snapshot omits only the unused, unlabelled legacy embedding column; model-tagged vectors are preserved. api/index.mjs opens it read-only, without migrations or WAL writes on Vercel. The raw database is not served as a public file.
Production currently matches localhost's working keyword retrieval and cited-excerpt assistant. It does not connect to your computer's Ollama service or claim generated AI/semantic retrieval. These require an explicitly configured hosted model provider and a compatible index. Bookmarks are stored separately in each browser/origin, as on localhost.
After changing your local corpus, publish a fresh snapshot:
npm run export:deployment
node scripts/verify-deployment.mjs
npx vercel@latest deploy --prodCommit the new snapshot and manifest together if deploying from GitHub. The production build verifies corpus integrity and refuses a missing or mismatched snapshot rather than silently seeding demo records. Local .env files, backups, the editable original database and large source CSVs remain excluded from deployments.