TikTok Shop Video Generator
只需一次点击,即可将任何病毒式 TikTok 视频转换为您自家产品的广告。适用于 TikTok Shop 卖家和联盟伙伴——无需拍摄、无需剪辑。免费试用。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证AI support chat widget for Indian businesses: answers in English, Hindi, Tamil and English, captures leads, one-line install
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗An embeddable AI support assistant, one per client business, installed with one script tag. Multi-tenant: Next.js (App Router) + Supabase (Postgres, Auth, RLS) + Claude (Haiku 4.5 by default).
Status: Phases 1, 2 and 3 built. See PLAN.md for the architecture and every place this build departs from the spec, and Status at the bottom.
You need Node 20+ and a Supabase project (a free hosted project is easiest; the Supabase CLI with Docker also works).
npm install
cp .env.example .env.local # fill in the values, see comments in the file
Database. Apply the migrations in order, then (optionally) the demo seed:
supabase link --project-ref <ref> then supabase db pushsupabase/migrations/0001_schema.sql … 0005_phase3.sql into the SQL editor, in order (already ran 0001–0003? just run 0004 and 0005)supabase/seed.sql the same way. It creates Ananya Handlooms with approved knowledge, public key pk_ananya_demo_0001 and test token tt_ananya_demo_private_0001_change_me_in_production. Rotate that test link in Settings if you keep the demo in production.Auth. In Supabase → Authentication → URL configuration, set Site URL to http://localhost:3000 and add http://localhost:3000/auth/callback (and later your production URL + /auth/callback) to Redirect URLs. Supabase's built-in email sender only allows a few emails per hour; for real use, point Supabase Auth at Resend's SMTP (Authentication → SMTP settings).
npm run check # setup doctor: tests .env.local, Supabase, migrations, RLS, Anthropic, Resend
npm run dev # builds public/widget.js, then starts Next.js on :3000
If something is missing, npm run check says exactly what and where to get it, and the dashboard shows a Finish setting up page instead of crashing. After editing .env.local, always stop and restart npm run dev. GET /api/health returns 200 when config and the database are working (use it for uptime monitoring). It does not call the model.
Open http://localhost:3000, sign in with an address listed in ADMIN_EMAILS. The first sign-in makes you the platform admin.
Botly can run on a free OpenAI-compatible API instead of Claude while you test. Put two lines in
.env.local (and in Vercel → Settings → Environment Variables, then redeploy):
| Provider | LLM_PROVIDER= | Get the key | Free tier (check current limits) |
|---|---|---|---|
| Google Gemini (recommended) | gemini | https://aistudio.google.com/apikey | Best Tamil/Hindi, large token allowance, no card. Free tier may train on data |
| Cerebras (fastest) | cerebras | https://cloud.cerebras.ai | Trial credit (30 days), ~1M tokens/day, 5 req/min |
| Mistral | mistral | https://console.mistral.ai/api-keys | "Experiment" plan, generous monthly tokens, needs phone verification, may train on data |
| Groq | groq | https://console.groq.com/keys | Very fast, ~1,000 req/day but ~8k tokens/min: small knowledge bases only |
| GitHub Models | github | https://github.com/settings/personal-access-tokens (fine-grained, "Models: read") | ~150 req/day, ~8k input tokens per request |
| OpenRouter | openrouter + LLM_MODEL=<id>:free | https://openrouter.ai/keys | ~50 req/day (1,000 after a $10 top-up) |
| NVIDIA | nvidia | https://build.nvidia.com | Shared queue; big models (Llama 3.3 70B) often time out |
Put the key in LLM_API_KEY. NVIDIA models that respond quickly (try in this order): qwen/qwen3-next-80b-a3b-instruct (default),
openai/gpt-oss-120b (add LLM_REASONING_EFFORT=low), openai/gpt-oss-20b, nvidia/nemotron-3.5-lightning-30b-a3b.
Avoid 70B+ dense models and "thinking" variants on the free queue.
Optional: LLM_MODEL to pick another model (confirm the exact id in the provider's console),
LLM_REASONING_EFFORT=off|low|medium for thinking models (Gemini and Groq presets use low),
LLM_TIMEOUT_MS (default 25000) before a slow reply gives up and shows the contact card.
Then run npm run llm:check. It tests streaming, tool calling ("I don't know" reporting) and a Tamil reply, with timings.
What changes with a free tier:
LLM_PROVIDER=anthropic (or a paid key) before you sell.npm run build also builds the widget)..env.example in Project → Settings → Environment Variables. Set NEXT_PUBLIC_APP_URL to your production URL (e.g. https://app.botly.in).https://YOUR_DOMAIN/auth/callback to Supabase Auth redirect URLs.https://YOUR_DOMAIN/widget.js.Notes: notifications run with after() so they never slow the chat stream. Onboarding (crawl + drafting) can take 1–3 minutes; its route asks for 300 s. If your Vercel plan caps functions lower, reduce CRAWL_MAX_PAGES.
| File | What it does |
|---|---|
0001_schema.sql | All tables (§3 of the spec) plus rate_limits, notifications (delivery log), eval_runs (go-live gate). RLS enabled everywhere. |
0002_functions.sql | Atomic rate limiter, quota-checked begin_conversation, usage/cost accounting, 80% warning claim, unanswered-question merging (trigram similarity). Callable only by the service role. |
0003_rls.sql | admin sees everything; owner reads their own org (and may change a lead's status); anon sees nothing. |
0004_phase2.sql | Client invites, owner answer suggestions (a trigger limits owners to suggesting), token/cost columns hidden from owners, knowledge_chunks with pgvector + full-text for retrieval mode, bot_report() for monthly reports, delete_visitor_data() and purge_expired_data(). Enables the vector extension. |
0005_phase3.sql | bot_integrations for Shopify/WooCommerce order lookup. Credentials are encrypted in the app; browser roles can't read even the ciphertext. |
seed.sql | Generated from evals/ananya-handlooms.yaml by npm run seed:gen. Don't edit by hand. |
Add new migrations as 0004_…sql and so on.
robots.txt, then sitemap.xml (or follows links), up to 40 pages, and pulls the product catalogue from /products.json on Shopify stores. Claude then drafts 20–40 FAQs, a policy summary and a tone-of-voice line. Everything lands as draft.name, price, sizes, stock note, url) or upload PDF/DOCX price lists. Click Use this tone if the suggested tone fits. Only approved knowledge reaches the assistant, and edits apply to the next message.http://localhost:3000 to allowed domains if you want to test the script tag on your machine.npm run eval -- --bot <bot-id>. Every prompt-injection case must pass before Go live is allowed. For a client's own in-knowledge cases, copy evals/ananya-handlooms.yaml to evals/<bot-id>.yaml and change the questions; otherwise evals/generic.yaml is used.Bot → Overview → Client access → enter their email → Give access. They get an email with the sign-in link (or send them /login). They see only their business: Conversations, Leads, Unanswered (they can suggest answers, which you approve with one click), Reports and the install snippet. No cost, model settings or other clients.
read_orders, plus read_all_orders for orders older than 60 days) or WooCommerce (site URL + a Read REST API key/secret). Botly tests the connection before saving and stores the credentials encrypted (ENCRYPTION_KEY).callback lead and the owner is notified.Anyone can now sign up at your site, build an assistant from their public profiles, try it free, and pay monthly.
Roles
ADMIN_EMAILS. Sees /app/admin: MRR, active trials, trial→paid conversion, AI cost and estimated margin, and can extend a trial, set a plan for offline/done-for-you clients, or suspend an account. Also sees cost, model and eval details on every bot.Customer journey
/ → Start free → /login (Google or email link)./start: business name and type, website, social profile links and pasted bios, contact details and hours.TRIAL_DAYS days and TRIAL_REPLIES AI replies (preview replies count), once per email. When it ends, visitors see the business's phone/WhatsApp/email instead of AI replies, and the owner sees "Choose a plan"./app/billing → Razorpay Checkout (UPI, cards, net banking) → subscription active → plan quota applies. Renewals, failures and cancellations arrive by webhook.Why social profiles aren't scraped: Instagram, Facebook, LinkedIn and Google Maps forbid automated reading of their pages, and Google's Places API terms don't allow storing its data. Customers paste their bios instead; the links are kept in their profile.
Setup for payments and sign-in
supabase/migrations/0006_saas.sql in the Supabase SQL Editor.https://<your-project>.supabase.co/auth/v1/callback. Paste the client ID and secret in Supabase → Authentication → Sign In / Providers → Google, and enable it. Other providers (Microsoft, GitHub, Facebook, LinkedIn) work the same way; list them in NEXT_PUBLIC_AUTH_PROVIDERS.BUSINESS_LEGAL_NAME, SUPPORT_EMAIL, GRIEVANCE_OFFICER for the Terms and Privacy Policy pages (templates: have a lawyer review them).Super admin → Demos. Paste a business's website and, two to four minutes later, you get a private link (/demo/<long-random-id>) showing a copy of their homepage with a Botly assistant trained on their site. Send it to the owner or open it on a call.
@sparticuz/chromium on Vercel, your own Chrome locally), which also reads a few of their pages for the assistant. DEMO_RENDER=off switches this off.DEMO_REPLY_LIMIT AI replies (150) and expires after DEMO_DEFAULT_DAYS (14); both are enforced by the same gate as free trials. A single conversation also stops after DEMO_MAX_AI_REPLIES_PER_CONVERSATION model replies (15). When any of those run out the chat shows your contact details (DEMO_CONTACT_*) and that turn is not counted. Leads and "talk to a person" requests from a demo are emailed to you, marked [DEMO].AI_BUDGET_DEMO_SHARE (0.15) of the per-minute and per-day request and token budgets. Demo builds do not use AI_BUDGET_ONBOARDING_RESERVE. When the demo slice is used up, demos get the busy/contact fallback and customer chats keep the rest of the budget.trial_ends_at has passed, even before the daily job runs. "+14 days" moves the expiry forward, sets trial_replies_used back to 0 and clears the trial-ended state so the chat works again.Setup: run supabase/migrations/0009_demos.sql and supabase/migrations/0013_demo_guards.sql in the Supabase SQL editor and set DEMO_CONTACT_PHONE / DEMO_CONTACT_WHATSAPP on Vercel. Until 0013 is applied, the demo budget slice is not enforced (customer budget from 0011 is unchanged). Demos are separate organizations flagged is_demo, left out of the client list, revenue numbers and trial emails.
BUSINESS_LEGAL_NAME, SUPPORT_EMAIL, SUPPORT_PHONE, BUSINESS_ADDRESS, BUSINESS_CITY, GRIEVANCE_OFFICER. They appear on /contact, /terms, /privacy-policy and /refund-policy (all linked in the footer).RAZORPAY_KEY_ID (rzp_test_…) and RAZORPAY_KEY_SECRET.plan_… ids into RAZORPAY_PLAN_STARTER / RAZORPAY_PLAN_GROWTH. The amounts must match PRICE_STARTER_INR / PRICE_GROWTH_INR. The site shows these as flat monthly prices.https://YOUR_DOMAIN/api/billing/webhook, a secret you make up (put the same value in RAZORPAY_WEBHOOK_SECRET), events: all subscription.*.npm run check confirms the keys work, both plans exist in the same mode, they're monthly INR, and their prices match the website.How it behaves:
billing_events (visible in Super admin). A webhook that can't be applied returns 500 so Razorpay retries it.ALERT_EMAIL (or the first ADMIN_EMAILS address), at most once per 15 minutes per kind of error, including across serverless instances once migration 0011 is applied. Needs RESEND_API_KEY. For uptime, point a free monitor (UptimeRobot, Better Stack) at https://YOUR_DOMAIN/api/health (no deep=1). That check is public and does not call the model. GET /api/health?deep=1 does call the model: send Authorization: Bearer $CRON_SECRET (the secret must be at least 16 characters), or open it while signed in as an admin. Without that, deep=1 only repeats a result cached for 5 minutes and never starts a new call.supabase/migrations/0011_launch_guards.sql in the Supabase SQL editor before or with this deploy. Until it is applied, trial replies are still counted up front and the shared budget is not enforced (chats keep working).supabase/migrations/0013_demo_guards.sql in the Supabase SQL editor. It replaces ai_budget_try / ai_budget_add from 0011 with the same names plus a demo lane. Customer calls omit the new arguments and behave as before..env.example): RATE_LIMIT_BOT_PER_MIN=30, MAX_AI_REPLIES_PER_CONVERSATION=30 (same for every plan, including Growth; set MAX_AI_REPLIES_PER_CONVERSATION_GROWTH to override one plan), DEMO_MAX_AI_REPLIES_PER_CONVERSATION=15 (demo conversations only), AI_BUDGET_REQUESTS_PER_MIN=40, AI_BUDGET_TOKENS_PER_MIN=200000, AI_BUDGET_REQUESTS_PER_DAY=10000, AI_BUDGET_TOKENS_PER_DAY=15000000, AI_BUDGET_DEMO_SHARE=0.15. Set these in Vercel even if you like the defaults, so a previously saved RATE_LIMIT_BOT_PER_MIN=120 does not stay in force. A model id on a bot that is not LLM_MODEL, a fallback, or LLM_EXTRA_MODELS is rewritten to the default. Optional cleanup if select id, name, model from bots where model not in ('openai/gpt-oss-120b','openai/gpt-oss-20b') shows rows you do not want to keep: update bots set model = 'openai/gpt-oss-120b' where model not in ('openai/gpt-oss-120b','openai/gpt-oss-20b');The whole install is one line. Put it just before </body>:
<script src="https://YOUR_DOMAIN/widget.js" data-key="BOT_PUBLIC_KEY" async></script>
The client's domain must be in the bot's allowed domains (Settings). On any other domain the widget stays silent: no bubble and no console errors.
Shopify. Online Store → Themes → ⋯ → Edit code → layout/theme.liquid. Paste the line just above </body> and save. Add both the store domain and your-store.myshopify.com (or *.myshopify.com) to allowed domains.
WordPress. Easiest: install the free "WPCode" (Insert Headers and Footers) plugin → Code Snippets → Header & Footer → paste into Footer → Save. Or, in a child theme, paste it before </body> in footer.php.
Wix. Settings → Custom code (under Advanced; needs a paid plan with a connected domain) → Add custom code → paste → Place code in Body – end → Apply to All pages → Load code once. Add both your custom domain and *.wixsite.com if you use the free subdomain for testing.
Any other site. Paste before </body> in the shared layout/footer template.
Power users can drive it from the page:
Botly.open(); Botly.close();
Botly.sendMessage("Do you ship to Dubai?");
Botly.identify({ name: "Priya", phone: "9876543210", email: "[email protected]" }); // prefills the lead form
To switch a client off (cancellation), untick Active in Settings: the bubble disappears from their site on the next page load. Nothing to remove on their side.
npm test # unit tests (Vitest): prompt builder, knowledge cap, quota, rate limiter, origin
# check, markdown sanitiser, phone validation, chat engine, crawler, CSV, eval checks
npm run widget:size # builds the widget and prints raw/gzipped size (fails over 35 KB gzipped)
npm run eval -- --fixture evals/ananya-handlooms.yaml # 34 eval cases against real Claude, no database needed
npm run eval -- --bot <bot-id> # same, against a bot in Supabase; records the result
The eval needs the active provider's key (ANTHROPIC_API_KEY, or LLM_API_KEY with LLM_PROVIDER=nvidia). --scripted runs the harness with a fake model to check the plumbing; its scores mean nothing.
Database and end-to-end tests without Supabase. A local test harness runs the real app against plain Postgres + PostgREST, with a minimal auth stand-in that writes magic links to a file and a fake Resend that records emails. It is for automated tests only; use the Supabase CLI for day-to-day local development.
DB=botly_test bash scripts/local-db.sh # migrations + seed into local Postgres
DATABASE_URL=postgres://postgres:postgres@localhost:5432/botly_test npm run test:db # RLS + SQL function tests
# End-to-end (needs a PostgREST binary and a build made with the harness env; see scripts/local-stack/start.sh):
POSTGREST_BIN=/path/to/postgrest bash scripts/local-stack/e2e.sh
Playwright embeds the widget on hostile pages served from a different origin: aggressive global CSS (* { all: unset }, button { background: red !important }), a sticky header with a huge z-index, a plain page, a disallowed origin, and a 375 px phone. It also signs in to the dashboard and walks through knowledge, settings, playground, conversations, leads and an onboarding crawl.
Measured in this build: widget 10.4 KB gzipped (budget 35 KB). Lighthouse performance on a plain host page: 100 without the widget, 100 with it (3 runs each, CLS 0).
vercel.json schedules two Vercel Cron jobs; set CRON_SECRET so only Vercel can call them:
/api/cron/retention nightly at 03:00 IST: deletes conversations and leads older than each client's retention setting (default 12 months)./api/cron/weekly Mondays at 09:00 IST: weekly summary email for Growth clients.| What | Where | Used for |
|---|---|---|
| Supabase project | supabase.com | Database, auth. NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY |
| Anthropic API key | console.anthropic.com | Chat replies, onboarding drafts, evals. ANTHROPIC_API_KEY |
| Resend API key + verified domain | resend.com | Lead emails. Until a domain is verified you can only send to your own Resend address. RESEND_API_KEY, EMAIL_FROM |
| WhatsApp Cloud API (Phase 2) | developers.facebook.com → WhatsApp | A permanent System User token, phone number ID, and an approved utility template named new_lead with 4 body variables, e.g. "New lead for {{1}}: {{2}}, {{3}}. Need: {{4}}". Until then each lead logs "WhatsApp pending" and email still goes out. |
CRON_SECRET | any long random string | Protects the scheduled jobs |
ENCRYPTION_KEY (Growth) | openssl rand -base64 32 | Encrypts store credentials. Never change it after connecting stores. |
| Voyage AI key (optional) | voyageai.com | Semantic search when a client's knowledge exceeds 25k tokens. Without it, retrieval uses keyword search. |
| Shopify custom app / WooCommerce API key (Growth, per client) | the client's store admin | Order lookup |
| Vercel project + domain | vercel.com | Hosting the app and widget.js |
Phase 1: migrations + RLS; clients and bots; knowledge editor with approve flow, CSV/PDF/DOCX import; website crawler with Claude-drafted FAQ/policy/tone; the widget; streaming /api/chat with prompt caching and the four core tools; email notifications; private test page; playground; conversations; leads; usage and cost logging; quotas; eval runner and the Ananya Handlooms eval set; go-live gate.
Phase 2: unanswered inbox with one-step answering and owner suggestions; client (owner) logins and views, with cost hidden at the database level; WhatsApp Cloud API notifications (active once WHATSAPP_* is set); monthly reports with printable view and CSV; retrieval mode for large knowledge bases (pinned policies + hybrid vector/keyword search, English rewrite for Tamil/Hindi questions); conversation export; visitor data deletion; nightly retention clean-up; 80% quota warning.
Phase 3: Shopify and WooCommerce order lookup with customer verification and encrypted per-bot credentials; callback/appointment booking with a date/slot card; weekly report email.
Needs your accounts to run for real: Anthropic (replies, evals), Resend (emails), WhatsApp Cloud API (template approval), Voyage (optional), a client's Shopify/WooCommerce store. Everything else is tested end to end on a local harness.
supabase/migrations/0007_billing_details.sql in the Supabase SQL editor after pulling this update.supabase/migrations/0010_demos_upgrade.sql. It is safe to run on any database.supabase/migrations/0008_hours_not_set.sql the same way. It also resets existing bots that still carry the untouched old default; a business that really keeps those hours re-enters them in Settings.