forked from xiaohei/taiji-AI-PAD
备份
This commit is contained in:
@@ -61,13 +61,14 @@ def generate_verification_code() -> str:
|
||||
return ''.join(random.choices(string.digits, k=VERIFICATION_CODE_LENGTH))
|
||||
|
||||
|
||||
async def send_verification_code(email: str, code: str) -> bool:
|
||||
async def send_verification_code(email: str, code: str, purpose: str = "register") -> bool:
|
||||
"""
|
||||
发送验证码邮件
|
||||
|
||||
Args:
|
||||
email: 收件人邮箱
|
||||
code: 验证码
|
||||
purpose: 用途,"register" 表示注册,"reset_password" 表示重置密码
|
||||
|
||||
Returns:
|
||||
是否发送成功
|
||||
@@ -81,10 +82,27 @@ async def send_verification_code(email: str, code: str) -> bool:
|
||||
msg = MIMEMultipart()
|
||||
msg['From'] = SMTP_EMAIL
|
||||
msg['To'] = email
|
||||
msg['Subject'] = "Taiji AI-PAD 注册验证码"
|
||||
|
||||
# 邮件正文
|
||||
body = f"""
|
||||
# 根据用途设置不同的邮件主题和正文
|
||||
if purpose == "reset_password":
|
||||
msg['Subject'] = "Taiji AI-PAD 密码重置验证码"
|
||||
body = f"""
|
||||
尊敬的用户:
|
||||
|
||||
您正在进行密码重置操作,验证码是:{code}
|
||||
|
||||
验证码有效期为10分钟,请勿泄露给他人。
|
||||
|
||||
如果您没有进行密码重置操作,请忽略此邮件,您的账户仍然安全。
|
||||
|
||||
此邮件由系统自动发送,请勿回复。
|
||||
|
||||
---
|
||||
Taiji AI-PAD 团队
|
||||
"""
|
||||
else:
|
||||
msg['Subject'] = "Taiji AI-PAD 注册验证码"
|
||||
body = f"""
|
||||
尊敬的用户:
|
||||
|
||||
您的注册验证码是:{code}
|
||||
@@ -290,12 +308,13 @@ async def verify_code(email: str, code: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
async def send_and_store_verification_code(email: str) -> Optional[str]:
|
||||
async def send_and_store_verification_code(email: str, purpose: str = "register") -> Optional[str]:
|
||||
"""
|
||||
生成、发送并存储验证码
|
||||
|
||||
Args:
|
||||
email: 邮箱地址
|
||||
purpose: 用途,"register" 表示注册,"reset_password" 表示重置密码
|
||||
|
||||
Returns:
|
||||
验证码(如果成功),None(如果失败)
|
||||
@@ -306,11 +325,11 @@ async def send_and_store_verification_code(email: str) -> Optional[str]:
|
||||
# 先存储验证码(即使邮件发送失败,验证码也已存储,可以手动查看Redis)
|
||||
store_success = await store_verification_code(email, code)
|
||||
if not store_success:
|
||||
logger.error("验证码存储失败,无法继续", email=email)
|
||||
logger.error("验证码存储失败,无法继续", email=email, purpose=purpose)
|
||||
return None
|
||||
|
||||
# 发送邮件
|
||||
send_success = await send_verification_code(email, code)
|
||||
# 发送邮件(传递 purpose 参数以使用不同的邮件模板)
|
||||
send_success = await send_verification_code(email, code, purpose=purpose)
|
||||
|
||||
# 测试模式:即使邮件发送失败也返回验证码(仅用于开发/测试环境)
|
||||
test_mode = os.getenv("ENABLE_TEST_MODE", "false").lower() == "true" or os.getenv("DEBUG", "false").lower() == "true"
|
||||
@@ -322,6 +341,7 @@ async def send_and_store_verification_code(email: str) -> Optional[str]:
|
||||
"测试模式:邮件发送失败,但验证码已存储到Redis",
|
||||
email=email,
|
||||
verification_code=code,
|
||||
purpose=purpose,
|
||||
hint="验证码已存储到Redis,可通过Redis获取或查看日志(仅测试环境)"
|
||||
)
|
||||
# 设置发送频率限制
|
||||
@@ -329,12 +349,25 @@ async def send_and_store_verification_code(email: str) -> Optional[str]:
|
||||
return code
|
||||
else:
|
||||
# 生产模式:邮件发送失败则不返回验证码
|
||||
logger.error("邮件发送失败,验证码已存储但未发送", email=email)
|
||||
logger.error("邮件发送失败,验证码已存储但未发送", email=email, purpose=purpose)
|
||||
return None
|
||||
|
||||
# 发送成功后设置频率限制
|
||||
await set_rate_limit(email)
|
||||
|
||||
logger.info("验证码已发送并存储", email=email)
|
||||
logger.info("验证码已发送并存储", email=email, purpose=purpose)
|
||||
return code
|
||||
|
||||
|
||||
async def send_password_reset_code(email: str) -> Optional[str]:
|
||||
"""
|
||||
发送密码重置验证码(便捷函数)
|
||||
|
||||
Args:
|
||||
email: 邮箱地址
|
||||
|
||||
Returns:
|
||||
验证码(如果成功),None(如果失败)
|
||||
"""
|
||||
return await send_and_store_verification_code(email, purpose="reset_password")
|
||||
|
||||
|
||||
@@ -29,11 +29,13 @@ from app.schemas import (
|
||||
SuccessResponse,
|
||||
TokenResponse,
|
||||
PasswordChangeRequest,
|
||||
ForgotPasswordRequest,
|
||||
ResetPasswordRequest,
|
||||
APIKeyInfo,
|
||||
RegenerateAPIKeyResponse,
|
||||
UserCreate,
|
||||
)
|
||||
from app.email_verification import verify_code, send_and_store_verification_code, check_rate_limit
|
||||
from app.email_verification import verify_code, send_and_store_verification_code, check_rate_limit, send_password_reset_code
|
||||
from app.agent_manager_client import get_agent_manager_client, AgentManagerError
|
||||
from app.litellm_client import get_litellm_client, LiteLLMClientError
|
||||
from config import settings
|
||||
@@ -904,3 +906,112 @@ async def register(req: UserCreate, db: AsyncSession = Depends(get_db)):
|
||||
message="注册成功"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/forgot-password/send-code", response_model=SuccessResponse)
|
||||
async def forgot_password_send_code(
|
||||
req: ForgotPasswordRequest,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
忘记密码 - 发送验证码
|
||||
|
||||
向用户注册邮箱发送密码重置验证码。
|
||||
|
||||
频率限制:同一邮箱60秒内只能发送一次
|
||||
|
||||
请求体:
|
||||
{
|
||||
"email": "user@example.com"
|
||||
}
|
||||
|
||||
响应:
|
||||
- 成功:返回验证码已发送的消息
|
||||
- 失败:邮箱不存在、发送频率限制等
|
||||
"""
|
||||
# 1. 检查发送频率限制
|
||||
can_send, remaining_seconds = await check_rate_limit(req.email)
|
||||
if not can_send:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
||||
detail=f"请等待{remaining_seconds}秒后再重新发送验证码"
|
||||
)
|
||||
|
||||
# 2. 检查邮箱是否存在(必须是已注册用户)
|
||||
result = await db.execute(select(User).where(User.email == req.email))
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if not user:
|
||||
# 为了安全,不直接告知邮箱不存在,但记录日志
|
||||
logger.warning("忘记密码请求:邮箱不存在", email=req.email)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="该邮箱未注册"
|
||||
)
|
||||
|
||||
# 3. 发送密码重置验证码(使用专门的密码重置邮件模板)
|
||||
code = await send_password_reset_code(req.email)
|
||||
if not code:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="验证码发送失败,请稍后重试"
|
||||
)
|
||||
|
||||
logger.info("忘记密码验证码已发送", email=req.email, user_id=str(user.id))
|
||||
|
||||
return SuccessResponse(
|
||||
message="验证码已发送到您的邮箱,请查收"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/forgot-password/reset", response_model=SuccessResponse)
|
||||
async def forgot_password_reset(
|
||||
req: ResetPasswordRequest,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
忘记密码 - 重置密码
|
||||
|
||||
验证邮箱验证码并重置密码。
|
||||
|
||||
请求体:
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"verification_code": "123456",
|
||||
"new_password": "newPassword123"
|
||||
}
|
||||
|
||||
响应:
|
||||
- 成功:密码重置成功
|
||||
- 失败:验证码错误、邮箱不存在等
|
||||
"""
|
||||
# 1. 检查邮箱是否存在
|
||||
result = await db.execute(select(User).where(User.email == req.email))
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="该邮箱未注册"
|
||||
)
|
||||
|
||||
# 2. 验证验证码
|
||||
is_valid = await verify_code(req.email, req.verification_code)
|
||||
if not is_valid:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="验证码错误或已过期"
|
||||
)
|
||||
|
||||
# 3. 更新密码
|
||||
new_hash = get_password_hash(req.new_password)
|
||||
user.password_hash = new_hash
|
||||
user.hashed_password = new_hash # 兼容旧字段
|
||||
|
||||
await db.commit()
|
||||
|
||||
logger.info("密码重置成功", email=req.email, user_id=str(user.id))
|
||||
|
||||
return SuccessResponse(
|
||||
message="密码重置成功,请使用新密码登录"
|
||||
)
|
||||
|
||||
|
||||
@@ -51,6 +51,18 @@ class PasswordChangeRequest(BaseModel):
|
||||
new_password: str
|
||||
|
||||
|
||||
class ForgotPasswordRequest(BaseModel):
|
||||
"""忘记密码 - 发送验证码请求"""
|
||||
email: EmailStr = Field(..., description="注册时使用的邮箱地址")
|
||||
|
||||
|
||||
class ResetPasswordRequest(BaseModel):
|
||||
"""忘记密码 - 重置密码请求"""
|
||||
email: EmailStr = Field(..., description="注册时使用的邮箱地址")
|
||||
verification_code: str = Field(..., min_length=6, max_length=6, description="邮箱验证码,6位数字")
|
||||
new_password: str = Field(..., min_length=8, description="新密码,至少8个字符")
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
"""创建用户请求(自由注册)"""
|
||||
username: str = Field(..., min_length=3, max_length=50, description="用户名,3-50个字符")
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
# MCP-Server 第一阶段状态报告
|
||||
|
||||
> 文档版本:v1.0
|
||||
> 更新日期:2026-03-19
|
||||
> 状态:第一阶段(底座和主链路)基本完成
|
||||
|
||||
---
|
||||
|
||||
## 一、第一阶段目标
|
||||
|
||||
第一阶段的核心目标是搭建 **"底座和主链路"**,为整个 AI Agent 平台提供基础能力支撑:
|
||||
|
||||
1. **多角色用户体系**:支持租户、渠道、管理员等多种角色的登录和权限管理
|
||||
2. **Agent 全生命周期管理**:支持平台 Agent 和自定义 Agent 的创建、启动、停止、删除
|
||||
3. **计费主链路**:支持 Agent 运行时长计费和模型 Token 调用计费
|
||||
4. **资源配额管理**:支持余额管理、配额分配、预警通知
|
||||
5. **模型网关集成**:与 LiteLLM 集成,支持多模型供应商接入
|
||||
|
||||
---
|
||||
|
||||
## 二、已完成项
|
||||
|
||||
### 2.1 用户与权限管理 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 统一登录 | ✅ 完成 | 支持租户、渠道、管理员通过同一入口登录 |
|
||||
| 用户注册 | ✅ 完成 | 支持邮箱注册(需验证码) |
|
||||
| 角色权限 | ✅ 完成 | 支持 user、channel_admin、billing_admin、operations_admin、admin、super_admin 等角色 |
|
||||
| API Key 管理 | ✅ 完成 | 支持创建、列出、删除 API Key,用于开发者集成 |
|
||||
| Token 刷新 | ✅ 完成 | 支持 Access Token 过期后通过 Refresh Token 刷新 |
|
||||
| 登出功能 | ✅ 完成 | 支持主动登出,Token 立即失效 |
|
||||
|
||||
### 2.2 渠道管理 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 渠道创建 | ✅ 完成 | 管理员可创建渠道合作伙伴 |
|
||||
| 渠道登录 | ✅ 完成 | 渠道管理员独立登录入口 |
|
||||
| 租户管理 | ✅ 完成 | 渠道可创建和管理下属租户 |
|
||||
| 资源分配 | ✅ 完成 | 渠道可将平台 Agent 和模型配额分配给租户 |
|
||||
| 佣金配置 | ✅ 完成 | 支持配置渠道佣金比例 |
|
||||
| 授信额度 | ✅ 完成 | 支持配置渠道授信额度 |
|
||||
|
||||
### 2.3 Agent 管理 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模板列表 | ✅ 完成 | 获取所有可用的 Agent 模板(平台模板 + 自定义模板) |
|
||||
| 平台 Agent | ✅ 完成 | 预定义的 Agent 类型,无需配置即可使用 |
|
||||
| 自定义 Agent | ✅ 完成 | 用户可配置环境变量创建自定义 Agent |
|
||||
| Agent 创建 | ✅ 完成 | 创建 Agent 并自动部署到 Kubernetes |
|
||||
| Agent 状态查询 | ✅ 完成 | 查询 Agent 运行状态、Pod 信息 |
|
||||
| Agent 删除 | ✅ 完成 | 删除 Agent 并清理 Kubernetes 资源 |
|
||||
| 健康检查 | ✅ 完成 | 监控 Agent 健康状态 |
|
||||
|
||||
### 2.4 工具管理 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 模板工具 | ✅ 完成 | 基于 Agent 模板创建的工具(如 MySQL、PostgreSQL) |
|
||||
| API 工具 | ✅ 完成 | 自定义 API 调用配置 |
|
||||
| 外部数据工具 | ✅ 完成 | 用户上传工具配置,自动生成 Pydantic 工具文件 |
|
||||
| 工具集 | ✅ 完成 | 将多个工具组合成工具集,方便部署 |
|
||||
|
||||
### 2.5 计费系统 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| EU 计费单位 | ✅ 完成 | 1 EU = 1 美元,统一计费单位 |
|
||||
| Agent 运行时计费 | ✅ 完成 | 按 Agent 运行时长和资源使用量计费 |
|
||||
| 模型 Token 计费 | ✅ 完成 | 按模型调用的 Token 数量计费(通过 LiteLLM) |
|
||||
| 余额管理 | ✅ 完成 | 支持查询余额、充值、扣款 |
|
||||
| 授信额度 | ✅ 完成 | 支持配置用户授信额度,余额不足时可透支 |
|
||||
| PayPal 充值 | ✅ 完成 | 支持通过 PayPal 进行充值 |
|
||||
| 计费记录查询 | ✅ 完成 | 支持按时间、Agent、模型等维度查询计费记录 |
|
||||
|
||||
### 2.6 配额管理 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 平台 Agent 配额 | ✅ 完成 | 管理员分配给渠道,渠道分配给租户 |
|
||||
| 自定义 Agent 配额 | ✅ 完成 | CPU/内存配额管理 |
|
||||
| 模型配额 | ✅ 完成 | RPM(每分钟请求数)/ TPM(每分钟 Token 数)限制 |
|
||||
| 配额预警 | ✅ 完成 | 余额低于阈值时自动预警 |
|
||||
| 速率限制 | ✅ 完成 | 防止 API 滥用 |
|
||||
|
||||
### 2.7 模型供应商管理 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 供应商创建 | ✅ 完成 | 管理员可添加模型供应商(OpenAI、Azure、Anthropic 等) |
|
||||
| 模型列表 | ✅ 完成 | 获取 LiteLLM 中配置的所有可用模型 |
|
||||
| 供应商授权 | ✅ 完成 | 管理员授权渠道使用特定供应商 |
|
||||
| 健康检查 | ✅ 完成 | 监控供应商 API 可用性 |
|
||||
|
||||
### 2.8 监控与统计 ✅
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 系统健康检查 | ✅ 完成 | 检查数据库、微服务状态 |
|
||||
| 租户仪表盘 | ✅ 完成 | 展示 EU 消耗、模型使用、API 调用统计 |
|
||||
| 全局 API 统计 | ✅ 完成 | 总调用次数、今日调用、成功/失败统计 |
|
||||
| 审计日志 | ✅ 完成 | 记录关键操作日志 |
|
||||
|
||||
---
|
||||
|
||||
## 三、未完成项
|
||||
|
||||
### 3.1 Agent 运维功能
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| Agent 扩缩容 | ❌ 未实现 | 动态调整 Agent 副本数量 |
|
||||
| Agent 日志查看 | ❌ 未实现 | 查看 Agent 运行日志 |
|
||||
| Agent 重启 | ❌ 未实现 | 重启异常的 Agent |
|
||||
|
||||
### 3.2 前端集成待确认
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 工作流编排 | ⚠️ 待确认 | 多 Agent 串联执行(最多 3 个节点) |
|
||||
| 实时消息推送 | ⚠️ 待确认 | WebSocket 实时通知 |
|
||||
|
||||
---
|
||||
|
||||
## 四、当前遗留问题
|
||||
|
||||
### 4.1 功能完整性
|
||||
|
||||
| 问题 | 严重程度 | 说明 |
|
||||
|------|----------|------|
|
||||
| 邮箱验证服务 | 中 | 注册需要邮箱验证码,但邮件发送服务未配置 |
|
||||
| 周期性计费任务 | 中 | 需要配置定时任务触发周期性计费 |
|
||||
| Agent 停止计费 | 中 | 需确认 Agent 删除时计费是否正确结算 |
|
||||
|
||||
### 4.2 安全相关
|
||||
|
||||
| 问题 | 严重程度 | 说明 |
|
||||
|------|----------|------|
|
||||
| 默认密钥配置 | 高 | 生产环境必须通过环境变量覆盖默认密钥 |
|
||||
|
||||
### 4.3 数据清理
|
||||
|
||||
| 问题 | 严重程度 | 说明 |
|
||||
|------|----------|------|
|
||||
| 废弃数据表 | 低 | 旧版计费表已废弃,可在后续版本清理 |
|
||||
|
||||
---
|
||||
|
||||
## 五、系统架构概览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 前端应用 │
|
||||
│ (租户端 / 渠道端 / 管理端) │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ MCP-Server │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 用户认证 │ │ Agent管理 │ │ 计费系统 │ │
|
||||
│ │ 权限控制 │ │ 工具管理 │ │ 配额管理 │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ Agent Manager │ │ LiteLLM │ │ PostgreSQL │
|
||||
│ (K8s Pods) │ │ Gateway │ │ + Redis │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、下一阶段建议
|
||||
|
||||
### 6.1 优先级高
|
||||
|
||||
1. **Agent 运维功能**:实现扩缩容、日志查看、重启功能
|
||||
2. **邮件服务配置**:完成邮箱验证功能
|
||||
3. **周期性计费**:配置定时任务确保计费准确
|
||||
|
||||
### 6.2 优先级中
|
||||
|
||||
1. **工作流编排**:确认前端需求后实现多 Agent 串联
|
||||
2. **实时通知**:确认前端需求后实现 WebSocket 推送
|
||||
|
||||
### 6.3 优先级低
|
||||
|
||||
1. **数据清理**:清理废弃的数据表
|
||||
2. **性能优化**:根据实际负载优化查询性能
|
||||
|
||||
---
|
||||
|
||||
## 七、核心业务流程
|
||||
|
||||
### 7.1 租户使用 Agent 流程
|
||||
|
||||
```
|
||||
1. 租户登录 → 2. 查看可用 Agent 模板 → 3. 创建 Agent
|
||||
↓
|
||||
4. Agent 部署到 K8s ← 5. 系统检查配额 ← 6. 系统检查余额
|
||||
↓
|
||||
7. Agent 运行 → 8. 系统记录计费 → 9. 定期扣款
|
||||
```
|
||||
|
||||
### 7.2 渠道分配资源流程
|
||||
|
||||
```
|
||||
1. 渠道申请资源 → 2. 管理员审批 → 3. 分配配额给渠道
|
||||
↓
|
||||
4. 渠道创建租户 → 5. 渠道分配配额给租户 → 6. 租户使用资源
|
||||
```
|
||||
|
||||
### 7.3 计费流程
|
||||
|
||||
```
|
||||
Agent 运行时计费:
|
||||
Agent 启动 → 记录开始时间 → Agent 停止 → 计算时长 → 计算费用 → 扣款
|
||||
|
||||
模型 Token 计费:
|
||||
调用模型 → LiteLLM 处理 → 回调通知 → 记录 Token 用量 → 计算费用 → 扣款
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*文档结束*
|
||||
Reference in New Issue
Block a user