尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
Ask questions about public policy documents and get answers that cite the exact page they came from. This project rebuilds the retrieval-augmented generation (RAG) assistant from my class notebook and fixes its main weakness: duplicate chunks.
/): anyone can ask questions. Answers come only from the published documents, with numbered citations and the cited passage highlighted.Live demo: https://policy-knowledge-assistant.vercel.app
Demo video: link to be added
In the class notebook, uploading the same file twice indexed every chunk twice. A question would then retrieve the top 5 chunks, but several of those 5 were identical copies, so:
Admin upload ──► fingerprint check ──► parse ──► strip headers/footers ──► page-aware chunks
│ (SHA-256) │
└─ already indexed? block ▼
exact-duplicate check (normalized text hash)
│
near-duplicate check (shared vocabulary ≥ 0.9,
or embedding similarity ≥ 0.985 when embeddings are on)
│
▼
index: keywords (BM25) + optional embeddings
│
Public question ──► keyword ranking ─┬─► merged ranking ──► top 5 *distinct* passages ──► Groq answer with [n] citations
meaning ranking ─┘ (reciprocal rank fusion)
Duplicates are handled at four levels:
| Level | What it catches | How |
|---|---|---|
| File | The same file uploaded again, even under a new name | SHA-256 of the bytes, checked in the browser before upload and again on the server |
| Boilerplate | Running headers, footers, page numbers repeated on every page | Lines appearing on at least half the pages are removed before chunking |
| Passage | The same text arriving in a different file (re-saved copy, reprint) | SHA-256 of normalized text (case, spacing, punctuation ignored) |
| Retrieval | Anything that still slips through | Top-k selection skips results with the same hash, near-identical vocabulary, or embedding similarity ≥ 0.95 to a chosen result |
Other changes from the notebook:
The admin page builds and runs the test set:
Metrics reported:
| Metric | Meaning |
|---|---|
| Right page in top 5 | Share of questions where the source page was retrieved |
| Mean reciprocal rank | 1.0 = the right page was always ranked first |
| Duplicate results in top 5 | Share of result slots wasted on a copy of another result |
| Faithfulness | Answers fully supported by their cited passages |
| Correctness | Answers matching the reference |
Results can be downloaded from the admin page as CSV or JSON.
Run the evaluation on the deployed site and paste the table here.
| Metric | Improved | Baseline |
|---|---|---|
| Right page in top 5 | ||
| Mean reciprocal rank | ||
| Duplicate results in top 5 | ||
| Faithfulness | n/a | |
| Correctness | n/a |
Limits of this evaluation: questions are generated from single passages, so they favour fact-lookup questions over questions that need several passages; grading uses the same model family that produced the answers.
openai/gpt-oss-120b writes answers (falling back to openai/gpt-oss-20b if it hits its limit), and openai/gpt-oss-20b writes test questions and grades them, using strict JSON schemas. Groq's free limits are per model, so evaluation doesn't use up the chat budget. All models are configurable.gemini-embedding-2, 768 dimensions) for meaning-based search. Groq has no embedding models.src/
app/
page.tsx public chat
admin/page.tsx admin (login or dashboard)
api/chat streaming answers with sources
api/library public list of documents
api/admin/* login, upload, ingest, documents, evaluation
components/ chat, admin dashboard, answer rendering
lib/
ingest.ts upload pipeline and all duplicate checks
chunk.ts boilerplate removal and page-aware chunking
retrieve.ts distinct top-k and the naive baseline
eval.ts test-set builder, runner, scoring
ai.ts Groq generation, optional Gemini embeddings, rate-limit handling; offline mock
bm25.ts keyword search
storage.ts Vercel Blob or local folder
session.ts, auth.ts signed admin session cookie
proxy.ts serves the admin page only at the secret path and signs you in
npm install
cp .env.example .env.local # fill in GROQ_API_KEY and ADMIN_PATH (GEMINI_API_KEY optional)
npm run dev
Without BLOB_READ_WRITE_TOKEN, files are stored in ./.data. To try the app without any key, set
MOCK_AI=1 (offline stand-in: answers are not real, useful only for testing the pipeline and UI).
BLOB_READ_WRITE_TOKEN).GROQ_API_KEY and ADMIN_PATH (a long random string) as environment variables. Add GEMINI_API_KEY too for meaning-based search.https://<your-site>/<ADMIN_PATH> and upload documents.On Groq's free plan the binding limit is usually tokens per minute (8,000 for the gpt-oss models). One answer uses about 2,000 to 3,000 tokens, so expect roughly three answers a minute on the main model before the fallback model takes over. When a limit is hit:
/, and the admin page at /<ADMIN_PATH>, which only the owner knows. /admin and any wrong path return 404.ADMIN_PATH, so changing ADMIN_PATH in Vercel immediately locks out every old link and session. Do this if the link is ever shared by mistake.noindex and no-referrer, so it isn't indexed and its address isn't leaked to other sites.正在載入完整 README。
檢視完整 README ↗