Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Kith is a relationship intelligence platform. It reads the messages you get, extracts the people and the companies behind them, maps how everyone is connected, and answers the question that actually matters when you are job hunting or networking: who can get me into a given company. It also runs a daily task list and a searchable, visual map of your network.
Live: https://kith-1a3z.onrender.com
This is a personal product and a portfolio project. The goal was to build something real end to end: ingestion, an AI extraction step, a relational source of truth, multi-hop warm-path search, a vector index for semantic search, an optional graph-database mirror, an evaluation harness, a single-page UI, and a public deployment.
flowchart TD
U["Browser: single page UI<br/>(vis-network graph, WebGL background, logo loop)"]
U -->|"HTTPS, JWT bearer"| API["FastAPI service"]
API -. "serves the static UI (same origin)" .-> U
subgraph APP["FastAPI application"]
AUTH["Auth: JWT + bcrypt"]
ROUTERS["Routers: auth, tasks, paste, people, companies,<br/>graph, intro, search, export, health"]
SVC["Services + Resolver (dedup)<br/>warm paths: BFS over Postgres"]
AUTH --- ROUTERS --- SVC
end
API --- APP
SVC -->|"source of truth"| PG[("PostgreSQL<br/>users, people, companies, connections,<br/>messages, tasks, contacts")]
SVC -->|"entity + relationship extraction"| LLM[["LLMClient interface"]]
LLM --> GEM["Google Gemini<br/>2.5 Flash, 2.0 Flash fallback"]
SVC -. "optional mirror (Sync)" .-> GS[["GraphStore interface"]]
GS -.-> NEO[("Neo4j Aura")]
SVC -->|"semantic search,<br/>rebuilds missing vectors"| VEC[["Embedder + VectorStore interfaces"]]
VEC --> QD[("Qdrant, embedded<br/>on local disk")]
VEC --> GEM
LLM -. "traces (when keys set)" .-> LF["Langfuse"]
LLMClient interface. Extraction is a single
structured-output Gemini call (Gemini 2.5 Flash, falling back to 2.0 Flash when the
primary is overloaded) that returns people, companies, titles, notes, and relationships
as typed JSON. On failure it raises a typed error so the API returns a clean 503 instead
of a crash. Swapping providers is a new class, nothing else changes.services/intro_paths.py. The first version ran this as a Cypher query on Neo4j Aura.
When the free Aura instance was paused and later deleted for inactivity, the feature
failed with it, so path finding moved to Postgres, which is always available. Neo4j
stays as an optional mirror behind a GraphStore interface (Tools, "Sync graph to
Neo4j"); the sync reports failure instead of erroring if Neo4j is unreachable.Embedder and
VectorStore interfaces with fakes for testing. Qdrant runs embedded on the server's
disk, which the free host wipes on every deploy, so before each search any people
missing from the index are embedded in one batched call and added. The index heals
itself from Postgres instead of needing a manual reindex.| Area | Choice |
|---|---|
| API | FastAPI (Python) |
| Auth | JWT (PyJWT) with bcrypt password hashing |
| Relational store | PostgreSQL via SQLAlchemy 2.0 (SQLite for local and tests) |
| Warm paths | Breadth-first search over PostgreSQL |
| Graph mirror | Neo4j (Aura free tier), optional |
| Vector store | Qdrant (embedded mode) with Gemini embeddings (gemini-embedding-001) |
| AI | Google Gemini 2.5 Flash with 2.0 Flash fallback, structured output, provider-agnostic interface |
| Observability | Langfuse (optional, off unless keys are set) |
| Frontend | Single static HTML page, vanilla JS, vis-network, WebGL gradient |
| Tests | pytest, hermetic (fakes for AI, graph, and vector layers; no network calls) |
| Deployment | Render web service, Neon PostgreSQL |
users: account with bcrypt-hashed password.people: a contact (name, title, current company link, source message).companies: a company, deduplicated per user by normalized name.connections: directed person-to-person edges with a relation type
(knows, referred, can_intro).messages: raw captured text plus a processed flag.contacts: one-to-one with a person, holding email, phone, and LinkedIn.tasks: a to-do with optional deadline and priority.Neo4j, when synced, mirrors people, companies, and connections as a queryable graph. Qdrant holds one embedding per person for semantic search. Both are derived from Postgres and can be rebuilt from it at any time.
All data endpoints require a JWT bearer token.
POST /auth/register, POST /auth/login, GET /auth/mePOST /paste: extract people, companies, and relationships from a messageGET /people, POST /people, GET /people/{id}, PATCH /people/{id},
DELETE /people/{id}, POST /people/reorderPATCH /companies/{id}, DELETE /companies/{id}GET /graph: the network as nodes and edgesGET /intro-paths?company=...: warm paths to a company (computed from Postgres)POST /graph/sync: mirror the user subgraph into Neo4j (best effort)GET /search?q=...: semantic search (indexes any missing people first);
POST /search/reindex: re-embed everyone, for example after editing profilesGET /tasks, POST /tasks, PATCH /tasks/{id}, DELETE /tasks/{id},
POST /tasks/reorderGET /export: all of the signed-in user's data as JSONGET /healthThe whole app runs against a local SQLite file, so nothing external is required to start.
cd backend
python -m venv .venv
.venv\Scripts\activate # Windows. macOS or Linux: source .venv/bin/activate
pip install -r requirements-dev.txt
set DATABASE_URL=sqlite:///./kith_local.db # PowerShell: $env:DATABASE_URL="sqlite:///./kith_local.db"
python -m uvicorn app.main:app --reload
Open http://localhost:8000, register an account, and start adding contacts. Pasting a
message and semantic search need a Google Gemini API key in backend/.env
(GEMINI_API_KEY=...). Warm paths need nothing extra. Neo4j credentials are only needed
for the optional graph mirror.
To fill a separate, fictional demo account (12 people, tasks, a two-hop warm path):
cd backend
python scripts/seed_demo.py # local server
python scripts/seed_demo.py --base https://... # any deployment
It never deletes anything, saves the generated password to the gitignored
backend/.demo_credentials, and checks paths and search before printing DEMO READY.
cd backend
python -m pytest -q
The suite (over 100 tests) is hermetic: the AI, graph, and vector layers use in-memory fakes, and a run with every non-local network lookup blocked passes, so no API keys or external services are needed.
Extraction quality is measured against 12 hand-labeled messages (evals/cases.py) with a
per-category precision, recall, and F1 scorer (evals/scorer.py). The runner makes real
Gemini calls and is run on demand, not on every extraction:
cd backend
python -m evals.run_evals # uses a real Gemini key, about 3 minutes
Latest run (evals/results/2026-10-27-gemini-2.5-flash.txt):
| Category | Precision | Recall | F1 |
|---|---|---|---|
| People | 1.00 | 1.00 | 1.00 |
| Companies | 1.00 | 1.00 | 1.00 |
| Relationships | 0.92 | 1.00 | 0.92 |
The one miss is a relationship the model inferred that the message does not state.
DATABASE_URL, JWT_SECRET, GEMINI_API_KEY,
and optional NEO4J_* and LANGFUSE_*.The original design (written before any code) planned two more pieces that are deliberately not built yet:
backend/
app/
main.py app wiring, static mount, keep-alive
config.py settings
database.py SQLAlchemy engine and session
security.py bcrypt and JWT
deps.py auth and dependency injection
models/ User, Company, Message, Person, Connection, Task, Contact
schemas/ request and response models
routers/ auth, paste, people, companies, graph, intro, search, tasks,
export, health
services/ ingest, resolver, intro_paths, graph_sync, graph_view, people,
companies, connections, contacts, tasks
llm/ LLMClient interface, Gemini implementation, errors
graph/ GraphStore interface, Neo4j and fake implementations
search/ Embedder and VectorStore interfaces and implementations
observability/ tracer (Langfuse or no-op)
evals/ dataset, scorer, runner, recorded results
scripts/ demo seeder and smoke checks
tests/ 20 hermetic test modules
frontend/
index.html single-page UI
privacy.html privacy policy and terms
Built by Archit Shukla and Saumya Singh. We designed the system, made the architecture and product decisions, chose the data stores and the boundaries between them, and integrated and deployed it. Claude Code (Anthropic) was used as a pair-programming assistant to help implement and review code under our direction. The design, the decisions, and the ownership of this project are ours.