Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Aangan Studio Enquiry OS: Vaani AI phone agent + rules-based qualification, Telegram/Calendly handoff, and a funnel/cost/ROI dashboard that asks: is this making more business?
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
An AI-assisted inbound phone enquiry qualification system for Aangan Studio, an interior design studio in Pune. Vaani AI answers the phone; a Next.js app (on Vercel, with Neon Postgres and Vercel AI Gateway) makes the decisions, hands off on Telegram with a Calendly booking link, and runs the dashboard.
The system is judged by enquiry → project conversion and revenue, not by how many calls the AI answered. The dashboard's first question is "Is this system generating more business?" and it answers "can't tell yet" whenever the evidence doesn't support a yes.檢視完整 README ↗An AI-assisted inbound phone enquiry qualification system for Aangan Studio, an interior design studio in Pune. Vaani AI answers the phone; a Next.js app (on Vercel, with Neon Postgres and Vercel AI Gateway) makes the decisions, hands off on Telegram with a Calendly booking link, and runs the dashboard.
The system is judged by enquiry → project conversion and revenue, not by how many calls the AI answered. The dashboard's first question is "Is this system generating more business?" and it answers "can't tell yet" whenever the evidence doesn't support a yes.
Prototype · demo data.
knowledge/*.md, the 40 sample enquiries and the baseline are invented. They are not Aangan's real services, rates, criteria or call transcripts.
services.md, and never claims a service that isn't listed there.pricing.md, always with the "varies by site" caveat. It never quotes a final price.qualified.md: QUALIFIED / NOT_QUALIFIED / NEEDS_HUMAN_REVIEW.| Route | What |
|---|---|
/ | Overview: the verdict, revenue, conversion, pipeline, response and outcomes |
/leads, /leads/:id | Enquiries; full record with outcome actions, decision change, transcript, activity |
/failures | Needs attention: review queue, missed handoffs, warnings |
/intelligence | Insights: who to call first, objections, follow-ups |
/calls | Every call and its transcript |
/analytics | Performance: before vs now, ROI, baseline editor, remove demo data |
/costs | Cost breakdown and per-call costs |
/simulate | Talk to the agent: live conversation with the real Vaani agent in the browser, or have it ring your phone |
The agent prompt, rules and architecture are deliberately not shown in the web UI. Use npm run vaani:setup to print the Vaani configuration.
PHONE / SIMULATOR / BROWSER MIC
↓
CALL INGESTION ............ /api/simulate · /api/calls/live · /api/calls/inbound
↓
CONVERSATION ENGINE ....... lib/engine/conversation.ts (slot policy, FAQ, service questions)
↓
INFORMATION EXTRACTION .... lib/engine/extract.ts (rules) + lib/engine/llm.ts (AI Gateway fills gaps)
↓
KNOWLEDGE RETRIEVAL ....... lib/knowledge.ts ← knowledge/services.md · pricing.md · qualified.md
↓
QUALIFICATION ENGINE ...... lib/engine/qualify.ts (R1–R5 from qualified.md only)
↓
PRICING ENGINE ............ lib/engine/pricing.ts (ranges + disclaimer + unapproved-₹ guard)
↓
DECISION ENGINE ........... confidence < threshold / contradiction / missing / high-value fail → human
↓
┌──────────────┬────────────────┬───────────────┐
QUALIFIED HUMAN REVIEW NOT QUALIFIED
↓ ↓ ↓
TELEGRAM REVIEW TASK POLITE RESPONSE
↓
DESIGNER → CONSULTATION → PROJECT (recorded by a person: lib/actions.ts)
↓
ANALYTICS ................ lib/metrics.ts
Each knowledge file holds the human-readable rules and a machine-readable JSON block. The engine evaluates that block, so what Nikhil reads and what the code runs come from one file, versioned in Git.
DATABASE_URL. On first load the app creates the schema and seeds the demo data.AGENT_MODEL, EXTRACT_MODEL.TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID. For the ✅/📞 buttons, also set TELEGRAM_WEBHOOK_SECRET and callhttps://api.telegram.org/bot<TOKEN>/setWebhook?url=https://<app>/api/telegram/webhook/<SECRET>CALENDLY_EVENT_URL to the free-consultation event link. Every qualified lead then gets a prefilled link (name, phone, utm_campaign=<lead id>) in the Telegram handoff and on the lead page. To sync bookings automatically (needs Calendly Standard or above), create a webhook subscription with a Calendly personal access token:
curl -X POST https://api.calendly.com/webhook_subscriptions \
-H "Authorization: Bearer <CALENDLY_TOKEN>" -H "Content-Type: application/json" \
-d '{"url":"https://<app>/api/calendly/webhook","events":["invitee.created","invitee.canceled","invitee_no_show.created","invitee_no_show.deleted"],"organization":"<org uri>","scope":"organization","signing_key":"<random secret>"}'
Then set the same secret as CALENDLY_WEBHOOK_SIGNING_KEY. Bookings move the lead to Consultation; cancellations and no-shows move it back and show up on /failures. A booking that can't be matched to a lead (no utm, unknown phone) raises a warning instead of being dropped.TELEPHONY_WEBHOOK_SECRET is required in production for /api/calls/inbound (requests are refused without it).Local development: cp .env.example .env.local, set DATABASE_URL, run npm i && npm run dev. Run npm run test:engine to put the three core scenarios through the engine.
Vaani holds the call; this app decides. Run DATABASE_URL=<neon url> APP_URL=https://<app> npm run vaani:setup to print everything to paste into Vaani, generated from knowledge/*.md: the greeting, the agent instructions, the data-collection points and the webhook URL.
VAANI_WEBHOOK_SECRET (any long random string) in Vercel.https://<app>/api/vaani/webhook/<VAANI_WEBHOOK_SECRET>. Vaani doesn't document request signing, so the secret sits in the URL.call_postprocessing the app parses the transcript and re-extracts every field with its own rules. Vaani's collected data only fills gaps. The app then qualifies against qualified.md, flags any rupee figure the agent said that isn't in pricing.md (a pricing guardrail breach on /failures), and sends the handoff or creates a review task. A caller who hangs up before speaking becomes a call-back task. Retries are deduplicated by Vaani call_id.This prototype has no Indian phone number of its own. To take real calls, a provider with an Indian DID (Exotel, Plivo, Twilio India over SIP, or Vapi with a SIP-trunked +91 number) can either:
/api/calls/inbound ({ phone, startedAt, transcript: [{ role, text, secondsFromStart }] }), or/api/calls/live (start → turn → end) and speak the returned replies.Pune callers will mix Hindi, Marathi and English. Choose STT/TTS that handles code-switching before going live.
Talk to the agent opens a live in-browser (WebRTC) conversation with the real Vaani agent; Or get a call on your phone makes it ring your mobile (Vaani's own default number — no number purchase needed). Talk as the customer; when you hang up, Vaani posts the transcript to the webhook and the enquiry appears with its decision. These are real enquiries: once any exist, all numbers and insights are computed from them only. No calls are simulated by the app; a small demo set (12 enquiries) is kept until real calls arrive.
Needs VAANI_API_KEY (Vaani → Developers → API Keys) in Vercel. Optional: VAANI_AGENT_ID (defaults to the Aangan agent), OUTBOUND_DAILY_LIMIT (default 20).
DASHBOARD_PASSWORD — set it. Without it anyone with the URL sees customer names and phone numbers. Browser asks for a password (any username). Webhooks stay reachable.npm run vaani:setup. Until then no real calls arrive.TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_WEBHOOK_SECRET, then setWebhook (step 4 above).CALENDLY_EVENT_URL; for auto-sync, CALENDLY_WEBHOOK_SIGNING_KEY + webhook subscription (paid plan).ALLOW_RESET=0 — after going live, disables the reset endpoint entirely.lib/costs.ts with invoiced figures./analytics#experiment explains how to run an alternate-day randomised test and how big the sample needs to be.lib/costs.ts is a placeholder. Replace it with invoiced rates.