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.