Synaplan
开源 AI 软件平台,面向企业:自托管 AI 代理,符合 GDPR 的聊天机器人小部件,RAG 知识库,WhatsApp 与 Outlook AI,MCP,多模型路由。支持 Docker、Kubernetes 或在 Germ 托管。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Every phone enquiry goes to a voice agent (Vaani Labs) at any hour. The agent qualifies the caller against Nikhil's rules and books a consultation on the call (Cal.com). After the call, Gemini Flash classifies the transcript. Qualified leads become HubSpot deals, and the designer gets a brief by email (Resend) within two minutes. Nikhil follows it all on a mobile dashboard.
Next.js 16 (App Router, TypeScript) on Vercel · Neon Postgres · HubSpot free CRM · Resend · Cal.com · Gemini.
| Part | State |
|---|---|
| Database schema + seed | ✅ db/0001_init.sql, db/seed.sql (every app query checked against real Postgres) |
| Replay test | ✅ npm run replay -- --stub passes. Real-Gemini run needs the 12 transcripts in tests/fixtures/transcripts/ |
| Classification (Gemini) | ✅ written, not yet run against real transcripts |
| Routing + emails | ✅ written, not yet run against live Neon/Resend |
| Cal.com tools | ✅ live: Consultation event 7422764 (Mon–Sat 10:00–19:00 IST, 12 h notice, 30 min buffer), slots verified 10 Oct 2026 |
| Vaani adapter | ⏳ stub: src/lib/vaani/adapter.ts returns 501 until written against Vaani's API docs |
| HubSpot | ✅ written, not yet run live |
| Dashboard | ✅ |
| Crons | ✅ (see the cron note below) |
Caller ─▶ Vaani agent ──(mid-call)──▶ POST /api/tools/availability ─▶ Cal.com slots for the assigned designer
└─(mid-call)──▶ POST /api/tools/book ─▶ Cal.com booking (or "a designer will call within 2 hours")
call ends ──▶ POST /api/webhooks/vaani
1. verify signature 2. store raw payload 3. 200 OK
4. after(): Gemini classify → validate → confidence gate → route
qualified → designer email (+ack button) → HubSpot contact + deal
existing_client → [URGENT] email to Nikhil + escalation address
needs_review → email Nikhil (+ "pending review" brief to the designer if already booked)
declined/not_a_lead/dropped → log only (dropped with a number → call-back list)
agent said a price → compliance incident + email Nikhil
Crons: ack-check every 15 min (escalate after 2h, retry failed processing) · HubSpot sync hourly · digest 08:45 IST
Only src/lib/vaani/ knows Vaani's payload shapes. Everything else uses NormalizedInteraction / NormalizedToolCall (src/lib/types.ts). The calls table has a channel column, so WhatsApp or a web form can come in later as another adapter with no schema change.
db/0001_init.sql, then db/seed.sql. From a terminal, psql "$DATABASE_URL" -f db/0001_init.sql does the same.areas (Pune localities they prefer), and calcom_event_type_id (step 3).DATABASE_URL. The app talks to Neon over HTTPS with @neondatabase/serverless, which suits Vercel functions: there's no connection pool to manage.DATABASE_URL for you.Only the server holds DATABASE_URL. The browser never talks to the database.
Copy .env.example → .env.local for local dev, and set the same keys in Vercel. EMAIL_TEST_MODE defaults to true: every email goes to EMAIL_TEST_RECIPIENT with a [TEST → real recipient] prefix. Set it to false only when going live.
designers.calcom_event_type_id. Designers without an ID are never offered to callers during a call.CALCOM_API_KEY.CALCOM_FALLBACK_ATTENDEE_EMAIL.Qualified calls become a HubSpot contact plus a deal in the Consultation booked stage, and the dashboard's pipeline panel syncs hourly.
crm.objects.contacts.read/write, crm.objects.deals.read/write and crm.schemas.deals.read/write. Put the token in .env.local and Vercel as HUBSPOT_ACCESS_TOKEN.npm run hubspot:setup. It checks the token, creates a test pipeline "Aangan enquiries (test)" (or, on the free plan's single pipeline, adds a Consultation booked stage to it) and prints HUBSPOT_PIPELINE_ID and HUBSPOT_STAGE_CONSULTATION_BOOKED. Set both in .env.local and Vercel, then redeploy.Deals never get an amount from this system. The dashboard's "won value" only sums amounts a person typed into HubSpot on won deals.
Verify your sending domain, create an API key → RESEND_API_KEY, and set RESEND_FROM.
Pending API docs. Once the adapter is written:
agent/vaani-system-prompt.md into the agent. Apply the platform settings and run the red-team test script in agent/README.md before go-live and after every prompt change.check_availability → POST <APP_URL>/api/tools/availability. Args: location (string), consultation_mode (home | studio).book_consultation → POST <APP_URL>/api/tools/book. Args: slot (ISO start time returned by check_availability), caller_name, phone, location, consultation_mode.POST <APP_URL>/api/webhooks/vaani with VAANI_WEBHOOK_SECRET.APP_URL to the production URL.vercel.json schedules the daily digest at 15 3 * * * (03:15 UTC = 08:45 IST)..github/workflows/crons.yml). Add the repo secrets APP_URL and CRON_SECRET. GitHub can start scheduled runs a few minutes late, which is fine for these jobs. On Vercel Pro you can move both into vercel.json and delete the workflow.Authorization: Bearer $CRON_SECRET.npm run replay -- --stub # no network: gate, routing plan, email rendering, price guard
npm run replay # real Gemini over tests/fixtures/transcripts/T*.txt (needs GEMINI_API_KEY)
npm run replay -- T07 T10 # selected cases
Hard failures: outcome, decline_reason, pricing_requested, price_mentioned_by_agent (must be false), routing (T09 must never create a deal or handoff), and any price figure in a rendered email or deal. Flags are free text, so they are printed side by side but never fail the run.
src/lib/price-guard.ts). Caller-derived text is redacted before rendering. Every email and deal description is scanned again before sending, and a hit blocks the send and logs an incident. A volunteered budget shows as "Mentioned by caller (amount withheld)". The dashboard transcript view hides amounts too.incidents row + immediate email to Nikhil.src/lib/log.ts strips them from logs.(provider, external_id). Processing claims the row atomically, reuses an existing classification, and every side effect has its own dedupe record (handoffs, hubspot_sync, incidents, emails.dedupe_key).needs_review: the designer still gets the brief, marked "pending review", so the slot isn't missed. Nikhil gets the review email. No HubSpot deal is created until Nikhil decides.areas match the caller's location. The pointer moves only when a booking is made, or when a handoff is assigned post-call.