一个可运行的 AI 视频生成 SaaS 参考项目:Next.js + MiniMax + Supabase + Stripe + Cloudflare R2 + Vercel。
AI Kissing Generator 是一个完整的 AI 生成服务网站。用户上传一张或两张图片后,系统会完成图片处理与内容审核,调用 MiniMax 创建视频,将结果保存到 Cloudflare R2,并通过 Supabase 管理登录、作品记录与积分,通过 Stripe 完成积分购买。
它不只是一个调用模型 API 的演示,而是覆盖了 AI SaaS 常见的产品闭环:
- 用户登录与会话管理
- 单图、双图上传与图片合成
- 生成前内容安全审核
- 异步任务提交、轮询与失败处理
- 视频存储、历史记录与分享
- 积分余额、消费记录与失败退款
- Stripe Checkout 与 Webhook 充值
- 响应式页面、定价、博客和基础 SEO
- Vercel 部署与 Cloudflare R2 存储
你可以保留 AI 亲吻视频场景,也可以替换模型、提示词和页面文案,把它改造成其他图片或视频生成服务。
Important
这是参考实现,不是一键上线模板。完整运行前,需要配置自己的服务商账号、环境变量、Supabase 数据结构、域名和安全策略。
| 模块 | 已包含能力 |
|---|---|
| AI 生成 | MiniMax 图生视频任务提交、状态轮询、结果获取和失败处理 |
| 图片流程 | 单图/双图输入、服务端图片处理、合并与比例适配 |
| 内容审核 | 生成前使用 Sightengine 检查上传图片 |
| 用户系统 | Supabase 会话与 Google OAuth 登录流程 |
| 数据记录 | 用户资料、图片/视频、生成历史、反馈和积分流水 |
| 积分系统 | 余额校验、积分扣除、开发模式模拟与失败退款 |
| 支付系统 | Stripe Checkout、积分套餐、签名 Webhook 与充值 |
| 对象存储 | 通过 S3 兼容 API 上传图片和生成视频到 Cloudflare R2 |
| 产品页面 | 首页、生成器、定价、登录、历史/分享、博客、暗色模式 |
| 增长基础 | Metadata、Sitemap、Robots、分析/广告钩子与 llms.txt |
flowchart LR
U["用户"] --> UI["Next.js 前端"]
UI --> AUTH["Supabase Auth"]
UI --> API["Next.js Route Handlers"]
API --> MOD["Sightengine 审核"]
API --> AI["MiniMax 视频生成"]
AI --> API
API --> R2["Cloudflare R2"]
API --> DB["Supabase Postgres"]
UI --> STRIPE["Stripe Checkout"]
STRIPE --> WEBHOOK["Stripe Webhook"]
WEBHOOK --> DB
典型生成流程:
- 用户通过 Supabase 登录。
- 用户上传一张或两张图片。
- 服务端验证、审核并按需合并图片。
- 应用检查用户积分余额。
- 创建 MiniMax 视频生成任务。
- 客户端轮询任务状态。
- 生成完成后,服务端把视频复制到 R2。
- Supabase 保存作品记录并更新积分流水。
- 如果生成失败,系统尝试退还已扣除积分。
- Next.js 13 App Router
- React 18、TypeScript、Tailwind CSS、Radix UI
- Supabase:认证与 Postgres 数据
- Stripe:Checkout 与 Webhook
- MiniMax:图生视频
- Cloudflare R2:对象存储
- Sightengine:图片内容审核
- Vercel:部署
git clone https://github.com/Brewnut-98/aikissing.git
cd aikissing
npm install在项目根目录创建 .env.local。只填写你自己的值,切勿提交该文件。
# Application
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
# AI generation
ENABLE_VIDEO_GENERATION=false
MINIMAX_API_KEY=your_minimax_api_key
# Cloudflare R2
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
# Image moderation
SIGHTENGINE_API_USER=your_sightengine_api_user
SIGHTENGINE_API_KEY=your_sightengine_api_key
# Stripe
STRIPE_SECRET_KEY=your_stripe_test_secret_key
STRIPE_WEBHOOK_SECRET=your_stripe_webhook_signing_secret
NEXT_PUBLIC_STRIPE_PRICE_BASIC=your_basic_price_id
NEXT_PUBLIC_STRIPE_PRICE_STANDARD=your_standard_price_id
NEXT_PUBLIC_STRIPE_PRICE_PREMIUM=your_premium_price_id
# Optional development fallback
DEV_USER_ID=your_supabase_user_uuid
DEV_USER_EMAIL=dev@example.comENABLE_VIDEO_GENERATION=false 会使用模拟生成流程。完成 MiniMax、R2、Supabase 和积分系统配置后,再将它设为 true。
只有浏览器确实需要的变量才能使用 NEXT_PUBLIC_ 前缀。Service Role Key、Stripe Secret、R2 Secret 和模型 API Key 等服务端密钥绝不能加此前缀。
- 创建项目并配置需要的登录方式。
- 当前界面包含 Google 登录,需要在 Supabase 中配置 Google OAuth 和允许的回调地址。
- 代码引用了用户、作品、图片、支付与积分流水相关表和 RPC。
- 仓库暂未提供完整数据库迁移;使用前需要建立兼容的数据表、RLS、触发器和函数。
- 代码中同时出现连字符和下划线形式的图片表名,新部署前应统一。
- 创建 R2 Bucket 和最小权限 API Token。
- 当前部分服务端路由仍硬编码 R2 Endpoint、Bucket 名和公共资源域名,需要替换为自己的配置。
- 这些 Endpoint、Bucket 名、Account ID 和公共域名属于基础设施标识,本身不能授权访问;真正敏感的是
R2_ACCESS_KEY_ID与R2_SECRET_ACCESS_KEY。 - 如果内容不是公开资源,请使用私有 Bucket、短期签名 URL 或带鉴权的应用接口。
建议将这些常量改为仅服务端可读的环境变量:
R2_ENDPOINT=https://<your-account-id>.r2.cloudflarestorage.com
R2_BUCKET_NAME=<your-bucket-name>
R2_PUBLIC_BASE_URL=<your-public-asset-domain>
- 创建产品与一次性价格。
- 将 Price ID 写入对应的
NEXT_PUBLIC_STRIPE_PRICE_*变量。 - 将 Webhook 指向
https://your-domain.com/api/webhooks/stripe。 - 至少订阅
checkout.session.completed。 - 将签名密钥保存为
STRIPE_WEBHOOK_SECRET。
正式收款前,请在测试模式验证积分 RPC、重复事件处理、成功/取消页面和失败退款。
npm run devnpm run dev # 开发服务器
npm run build # 生产构建
npm run start # 启动生产服务器
npm run lint # 代码检查- 将仓库导入 Vercel。
- 在项目设置中添加环境变量。
- 测试环境和生产环境使用不同凭据。
- 更新 Supabase 回调地址与 Stripe Webhook 地址。
- 替换项目专用域名、R2 标识、分析 ID 和广告 ID。
- 部署后完整测试登录、生成、支付、Webhook、积分变化和失败退款。
不要在 next.config.js 的 env 中配置服务端密钥,Next.js 可能会把这些值内联到客户端 JavaScript。服务端路由应直接读取 process.env。
公开仓库需要明确区分“公开标识”和“访问凭据”:
- 域名、公共资源域名、Bucket 名、服务商 API 地址、Cloudflare Account ID、Supabase 项目 URL、Stripe Price ID 和 Supabase Anon Key 通常是公开配置标识,可能暴露基础设施信息,但不能单独授予管理权限。
R2_SECRET_ACCESS_KEY、SUPABASE_SERVICE_ROLE_KEY、STRIPE_SECRET_KEY、STRIPE_WEBHOOK_SECRET、MINIMAX_API_KEY和SIGHTENGINE_API_KEY是服务端密钥,绝不能提交、记录日志或返回给浏览器。R2_ACCESS_KEY_ID虽然不能单独完成认证,也应只保存在服务端配置中。- 真实值应保存在本地
.env.local或部署平台的 Secrets 中。 - 如果密钥曾经进入 Git 历史,先撤销或轮换。仅删除文件或改写历史,不能让已经被复制的密钥重新安全。
提交代码前建议执行密钥扫描,并检查 git diff --cached 中是否出现 .env、私钥、Token、Webhook Secret 或生产日志。
app/
├── api/ # AI、存储、认证、历史、积分和 Stripe 接口
├── auth/ # OAuth 回调与登录页面
├── context/ # 客户端认证上下文
├── dashboard/ # 积分流水界面
├── kissing-generator/ # 主要生成体验
├── pricing/ # 积分套餐与 Checkout
└── video/ # 视频展示与分享页面
components/ # 首页、生成器、上传、定价和 UI 组件
public/ # 图标与静态资源
middleware.ts # Supabase 会话刷新
next.config.js # Next.js 配置
vercel.json # Vercel 配置
主要的产品定制入口:
- 修改
app/api/generate-video/route.ts中的模型与生成提示词。 - 替换 MiniMax 的任务提交和状态查询逻辑。
- 调整上传、审核、图片合成与比例规则。
- 修改定价组件中的积分套餐。
- 替换品牌、域名、示例、SEO、分析和广告配置。
- 将硬编码的 R2 与域名配置迁移到服务端环境变量。
- 让 Supabase Schema 与自己的数据模型保持一致。
- 补充并测试 Supabase migrations 与 RLS。
- 统一不一致的数据库表名。
- 删除或保护调试接口和测试页面。
- 为 Stripe Webhook 增加幂等处理。
- 在服务端验证付款金额与 Price ID。
- 增加文件类型/大小限制、限流与滥用防护。
- 检查日志,避免记录 Token、会话、个人信息或服务商原始响应。
- 增加监控、备份、内容保留与删除规则、隐私政策和用户协议。
AI 生成媒体可能影响真实人物。请只上传自己拥有或已获授权的素材,获得可识别人物的同意,避免欺骗、骚扰或其他有害内容,并遵守模型、存储、支付和托管服务商的政策。运营者应提供明确规则、举报、审核、删除和滥用响应机制。
如果你在使用、二次开发或部署过程中遇到问题,可以提交 GitHub Issue,也可以扫码添加微信。添加时请备注 AI Kissing Generator。
欢迎提交 Issue 和 Pull Request。较大的修改请先说明使用场景、预期行为,以及涉及的数据库或服务商变化。
提交代码时请:
- 不要包含真实密钥或
.env文件; - 为新增环境变量补充文档;
- 修改持久化数据结构时提供迁移;
- 测试模拟流程和受影响的服务商集成;
- 确保服务端密钥不会进入客户端 Bundle。
此仓库目前尚未附加软件许可证。公开源码不代表自动授权复制、修改或商用。仓库所有者应在接受外部复用前选择并添加 MIT、Apache-2.0 或其他合适的许可证。
