一个基于 Kimi K2 大语言模型的 AI 塔罗牌占卜 Web 应用,部署于 SAP BTP Cloud Foundry 平台。
TPAC 是一款面向 ToC 用户的 AI 塔罗牌占卜应用。用户输入问题后,系统随机抽取牌阵,由 Kimi K2 驱动的 Agent Loop 生成个性化解读内容——LLM 可在回答前主动查询牌义数据库,扮演 FF14 风格的拉拉菲尔学者 Q·哈特亚为用户解读命运。应用支持用户注册登录、邮箱验证、占卜历史记录、SSE 流式输出等功能。
| 层级 | 技术 |
|---|---|
| 前端 | React 18 + Vite + TailwindCSS + Framer Motion |
| 后端 | Python Flask + flask-jwt-extended |
| 数据库 | SAP HANA Cloud |
| 缓存 / 限流 | Redis(CF Service Binding,故障时自动降级放行) |
| AI 推理 | Moonshot API(Kimi K2)via Anthropic SDK |
| AI 架构 | Agent Loop(工具调用:查牌义 / 查牌阵说明) |
| 部署平台 | SAP BTP Cloud Foundry |
TPAC/
├── frontend/ # React 前端
│ ├── public/
│ │ └── assets/
│ │ ├── cards/ # 78张塔罗牌图片
│ │ └── ambient.mp3 # 背景音乐(异度之刃2 商会夜曲)
│ ├── src/
│ │ ├── api/ # Axios 封装 + SSE tarot 接口
│ │ ├── store/ # Zustand 状态管理(auth)
│ │ ├── pages/ # 页面(Home / Login / Register / Reading)
│ │ └── components/ # 通用组件(AmbientMusic 等)
│ ├── .env.production # 生产环境变量(VITE_API_BASE_URL)
│ └── manifest.yml # CF 前端部署配置
│
├── backend/ # Flask 后端
│ ├── app/
│ │ ├── models/ # User, Reading 数据模型
│ │ ├── routes/ # auth.py, tarot.py, history.py
│ │ └── services/
│ │ ├── llm_service.py # Agent Loop 核心
│ │ ├── tarot_service.py # 抽牌 + 牌库数据
│ │ └── cache_service.py # Redis 封装(含超时/降级)
│ ├── data/cards.json # 78张牌义数据(UTF-8 BOM)
│ ├── requirements.txt
│ └── manifest.yml # CF 后端部署配置
│
└── training/ # 训练数据(保留备用,当前不使用)
后端 llm_service.py 使用 Anthropic SDK 连接 Moonshot API,实现了一个最多 8 轮的 Agent Loop:
用户问题 + 抽到的牌
↓
系统 Prompt(Q·哈特亚人格 + 占卜师指令)
↓
LLM 思考 → 可选调用工具:
• get_card_detail(card_id) 查询指定牌的详细含义
• get_spread_info(spread_type) 查询牌阵结构说明
↓
LLM 获得工具返回 → 继续生成
↓
stop_reason = "end_turn" → 完整解读文字
↓
流式(SSE)推送给前端
AI 角色:Q·哈特亚,一位来自艾欧泽亚的拉拉菲尔学者,精通萨雷安塔罗体系,为来访者以古典学术风格解读命运。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/auth/register |
用户注册(发送邮箱验证码) |
| GET | /api/auth/verify |
邮箱验证(?token=xxx) |
| POST | /api/auth/resend-verification |
重发验证邮件 |
| POST | /api/auth/login |
登录,返回 Access + Refresh Token |
| POST | /api/auth/refresh |
刷新 Access Token |
| GET | /api/auth/me |
获取当前用户信息(需 JWT) |
| 方法 | 路径 | 说明 | 认证 |
|---|---|---|---|
| GET | /api/tarot/cards |
获取完整78张牌库 | 否 |
| POST | /api/tarot/reading |
发起占卜(SSE 流式返回) | 是 |
| 方法 | 路径 | 说明 | 认证 |
|---|---|---|---|
| GET | /api/history |
获取历史列表 | 是 |
| GET | /api/history/:id |
获取单条详情 | 是 |
| DELETE | /api/history/:id |
删除记录 | 是 |
用户填写邮箱 + 密码
↓
Flask 后端注册 → 生成 Token 存入 Redis(5分钟过期)
↓
后台线程异步发送 QQ SMTP 验证邮件(不阻塞注册响应)
↓
用户点击邮件链接 → GET /api/auth/verify?token=xxx
↓
Token 验证成功 → 账号激活
↓
登录颁发 JWT Access Token(2h)+ Refresh Token(30d)
| 变量名 | 默认值 | 说明 |
|---|---|---|
RATE_LIMIT_REGISTER |
5 |
同 IP 每小时最多注册次数 |
RATE_LIMIT_REGISTER_WIN |
3600 |
时间窗口(秒) |
RATE_LIMIT_LOGIN |
10 |
同 IP 每 15 分钟最多登录尝试 |
RATE_LIMIT_LOGIN_WIN |
900 |
时间窗口(秒) |
RATE_LIMIT_RESEND |
3 |
同 IP 每 10 分钟最多重发验证邮件 |
RATE_LIMIT_RESEND_WIN |
600 |
时间窗口(秒) |
RATE_LIMIT_READING |
20 |
同用户每小时最多占卜次数 |
RATE_LIMIT_READING_WIN |
3600 |
时间窗口(秒) |
Redis 不可用时自动降级放行,不影响正常请求。
| 变量名 | 说明 |
|---|---|
JWT_SECRET_KEY |
JWT 签名密钥 |
HANA_HOST |
SAP HANA Cloud 连接地址 |
HANA_PORT |
HANA 端口(默认 443) |
HANA_USER |
HANA 用户名 |
HANA_PASSWORD |
HANA 密码 |
REDIS_URL |
Redis 连接地址(CF binding 自动解析,无需手动设置) |
DEPLOY_MODE |
0 = 自托管推理服务,1 = 外部 API(默认 1) |
EXTERNAL_API_BASE |
外部 LLM API 地址(如 https://api.moonshot.cn/v1) |
EXTERNAL_API_KEY |
API Key |
EXTERNAL_MODEL |
模型名称(如 kimi-k2-0711-preview) |
BASE_URL |
后端服务域名(用于生成邮箱验证链接) |
MAIL_SMTP_HOST |
SMTP 服务器(默认 smtp.qq.com) |
MAIL_SMTP_PORT |
SMTP 端口(默认 465) |
MAIL_USERNAME |
QQ 邮箱地址 |
MAIL_PASSWORD |
QQ 邮箱授权码 |
MAIL_SENDER |
发件人显示名称 |
| 变量名 | 说明 |
|---|---|
VITE_API_BASE_URL |
后端 API 地址(如 https://tpac-backend.cfapps.ap21.hana.ondemand.com/api) |
cd backend
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
# 复制并填写 .env
flask run --port 5000cd frontend
npm install
npm run dev当前使用 BTP Cockpit Web UI 上传 zip 包部署(不使用 cf push CLI)。
- 在 BTP Cockpit → Cloud Foundry → Spaces → 选择 Space → Applications → Deploy Application
- 将
backend/打包为 zip(排除venv/和__pycache__/) - 选择
manifest.yml
cd frontend
npm run build
# 仅打包 dist/ 目录内容(不含 node_modules,否则超过 5000 resources 限制)- 将
dist/下的所有文件 zip 打包 - 同上步骤在 BTP Cockpit 部署,使用
frontend/manifest.yml
在 BTP Cockpit 中创建 Redis 服务实例(名称:Redis),后端 manifest.yml 中已配置 services: [Redis],CF 会自动注入 VCAP_SERVICES,无需手动设置 REDIS_URL。