Compare commits

..

2 Commits

Author SHA1 Message Date
OpenClaw Bot
c38f3eb467 Phase 8 Task 4: AI 能力增强
- 创建 ai_manager.py - AI 能力增强管理模块
  - 自定义模型训练(领域特定实体识别)
  - 多模态大模型集成(GPT-4V、Claude 3、Gemini、Kimi-VL)
  - 智能摘要与问答(基于知识图谱的 RAG)
  - 预测性分析(趋势预测、异常检测、实体增长、关系演变)

- 更新 schema.sql - 添加 AI 能力增强相关数据库表
  - custom_models, training_samples
  - multimodal_analyses
  - kg_rag_configs, rag_queries
  - smart_summaries
  - prediction_models, prediction_results

- 更新 main.py - 添加 30+ 个 AI 相关 API 端点
  - 自定义模型管理(创建、训练、预测)
  - 多模态分析
  - 知识图谱 RAG
  - 智能摘要
  - 预测模型(创建、训练、预测、反馈)

- 创建 test_phase8_task4.py - 测试脚本
- 更新 README.md 和 STATUS.md
2026-02-26 00:10:10 +08:00
OpenClaw Bot
911e891451 Phase 8: 完成多租户SaaS架构、订阅计费系统、企业级功能
- 任务1: 多租户SaaS架构 (tenant_manager.py)
- 任务2: 订阅与计费系统 (subscription_manager.py)
- 任务3: 企业级功能 (enterprise_manager.py)
- 更新 schema.sql 添加所有相关表
- 更新 main.py 添加所有API端点
- 更新 README.md 进度表
2026-02-25 18:42:29 +08:00
21 changed files with 9811 additions and 659 deletions

328
README.md
View File

@@ -205,17 +205,140 @@ MIT
---
## Phase 8: 商业化与规模化 - 进行中 🚧
基于 Phase 1-7 的完整功能Phase 8 聚焦**商业化落地**和**规模化运营**
### 1. 多租户 SaaS 架构 🏢
**优先级: P0** | **状态: ✅ 已完成**
- ✅ 租户隔离(数据、配置、资源完全隔离)
- ✅ 自定义域名绑定CNAME 支持)
- ✅ 品牌白标Logo、主题色、自定义 CSS
- ✅ 租户级权限管理(超级管理员、管理员、成员)
### 2. 订阅与计费系统 💳
**优先级: P0** | **状态: ✅ 已完成**
- ✅ 多层级订阅计划Free/Pro/Enterprise
- ✅ 按量计费转录时长、存储空间、API 调用次数)
- ✅ 支付集成Stripe、支付宝、微信支付
- ✅ 发票管理、退款处理、账单历史
### 3. 企业级功能 🏭
**优先级: P1** | **状态: ✅ 已完成**
- ✅ SSO/SAML 单点登录企业微信、钉钉、飞书、Okta
- ✅ SCIM 用户目录同步
- ✅ 审计日志导出SOC2/ISO27001 合规)
- ✅ 数据保留策略(自动归档、数据删除)
### 4. 运营与增长工具 📈
**优先级: P1**
- 用户行为分析Mixpanel/Amplitude 集成)
- A/B 测试框架
- 邮件营销自动化(欢迎序列、流失挽回)
- 推荐系统(邀请返利、团队升级激励)
### 5. 开发者生态 🛠️
**优先级: P2**
- SDK 发布Python/JavaScript/Go
- 模板市场(行业模板、预训练模型)
- 插件市场(第三方插件审核与分发)
- 开发者文档与示例代码
### 6. 全球化与本地化 🌍
**优先级: P2**
- 多语言支持i18n至少 10 种语言)
- 区域数据中心(北美、欧洲、亚太)
- 本地化支付(各国主流支付方式)
- 时区与日历本地化
### 7. AI 能力增强 🤖
**优先级: P1** | **状态: ✅ 已完成**
- ✅ 自定义模型训练(领域特定实体识别)
- ✅ 多模态大模型集成GPT-4V、Claude 3
- ✅ 智能摘要与问答(基于知识图谱的 RAG
- ✅ 预测性分析(趋势预测、异常检测)
### 8. 运维与监控 🔧
**优先级: P2**
- 实时告警系统PagerDuty/Opsgenie 集成)
- 容量规划与自动扩缩容
- 灾备与故障转移(多活架构)
- 成本优化(资源利用率监控)
---
### Phase 8 任务 7 完成内容
**全球化与本地化**
- ✅ 创建 localization_manager.py - 全球化与本地化管理模块
- LocalizationManager: 全球化与本地化管理主类
- LanguageCode: 支持12种语言英语、简体中文、繁体中文、日语、韩语、德语、法语、西班牙语、葡萄牙语、俄语、阿拉伯语、印地语
- RegionCode/DataCenterRegion: 区域和数据中心配置(北美、欧洲、亚太、中国等)
- Translation: 翻译管理(支持命名空间、回退语言、审核流程)
- LanguageConfig: 语言配置RTL支持、日期时间格式、数字格式、日历类型
- DataCenter: 数据中心管理9个数据中心支持全球分布
- TenantDataCenterMapping: 租户数据中心映射(主备数据中心、数据驻留策略)
- LocalizedPaymentMethod: 本地化支付方式12种支付方式支持国家/货币过滤)
- CountryConfig: 国家配置(语言、货币、时区、税率等)
- TimezoneConfig: 时区配置管理
- CurrencyConfig: 货币配置管理
- LocalizationSettings: 租户本地化设置
- 日期时间格式化支持Babel本地化
- 数字和货币格式化
- 时区转换
- 日历信息获取
- 用户偏好自动检测
- ✅ 更新 schema.sql - 添加本地化相关数据库表
- translations: 翻译表
- language_configs: 语言配置表
- data_centers: 数据中心表
- tenant_data_center_mappings: 租户数据中心映射表
- localized_payment_methods: 本地化支付方式表
- country_configs: 国家配置表
- timezone_configs: 时区配置表
- currency_configs: 货币配置表
- localization_settings: 租户本地化设置表
- 相关索引优化
- ✅ 更新 main.py - 添加本地化相关 API 端点35个端点
- GET /api/v1/translations/{language}/{key} - 获取翻译
- POST /api/v1/translations/{language} - 创建翻译
- PUT /api/v1/translations/{language}/{key} - 更新翻译
- DELETE /api/v1/translations/{language}/{key} - 删除翻译
- GET /api/v1/translations - 列出翻译
- GET /api/v1/languages - 列出语言
- GET /api/v1/languages/{code} - 获取语言详情
- GET /api/v1/data-centers - 列出数据中心
- GET /api/v1/data-centers/{dc_id} - 获取数据中心详情
- GET /api/v1/tenants/{tenant_id}/data-center - 获取租户数据中心
- POST /api/v1/tenants/{tenant_id}/data-center - 设置租户数据中心
- GET /api/v1/payment-methods - 列出支付方式
- GET /api/v1/payment-methods/localized - 获取本地化支付方式
- GET /api/v1/countries - 列出国家
- GET /api/v1/countries/{code} - 获取国家详情
- GET /api/v1/tenants/{tenant_id}/localization - 获取租户本地化设置
- POST /api/v1/tenants/{tenant_id}/localization - 创建租户本地化设置
- PUT /api/v1/tenants/{tenant_id}/localization - 更新租户本地化设置
- POST /api/v1/format/datetime - 格式化日期时间
- POST /api/v1/format/number - 格式化数字
- POST /api/v1/format/currency - 格式化货币
- POST /api/v1/convert/timezone - 转换时区
- GET /api/v1/detect/locale - 检测用户本地化偏好
- GET /api/v1/calendar/{calendar_type} - 获取日历信息
---
## Phase 8 开发进度
| 任务 | 状态 | 完成时间 |
|------|------|----------|
| 1. 多租户 SaaS 架构 | ✅ 已完成 | 2026-02-25 |
| 2. 订阅与计费系统 | 🚧 进行中 | - |
| 3. 企业级功能 | ⏳ 待开始 | - |
| 4. AI 能力增强 | ⏳ 待开始 | - |
| 2. 订阅与计费系统 | ✅ 已完成 | 2026-02-25 |
| 3. 企业级功能 | ✅ 已完成 | 2026-02-25 |
| 7. 全球化与本地化 | ✅ 已完成 | 2026-02-25 |
| 4. AI 能力增强 | ✅ 已完成 | 2026-02-26 |
| 5. 运营与增长工具 | ⏳ 待开始 | - |
| 6. 开发者生态 | ⏳ 待开始 | - |
| 7. 全球化与本地化 | ⏳ 待开始 | - |
| 8. 运维与监控 | ⏳ 待开始 | - |
### Phase 8 任务 1 完成内容
@@ -249,72 +372,145 @@ MIT
- GET /api/v1/tenants/{id}/limits/{type} - 资源限制检查
- GET /api/v1/resolve-tenant - 域名解析租户
### Phase 8 任务 2 完成内容
**订阅与计费系统**
- ✅ 创建 subscription_manager.py - 订阅与计费管理模块
- SubscriptionPlan: 订阅计划模型Free/Pro/Enterprise
- Subscription: 订阅记录(支持试用、周期计费)
- UsageRecord: 用量记录转录时长、存储空间、API 调用)
- Payment: 支付记录(支持 Stripe/支付宝/微信支付)
- Invoice: 发票管理
- Refund: 退款处理
- BillingHistory: 账单历史
- ✅ 更新 schema.sql - 添加订阅相关数据库表
- subscription_plans: 订阅计划表
- subscriptions: 订阅表
- usage_records: 用量记录表
- payments: 支付记录表
- invoices: 发票表
- refunds: 退款表
- billing_history: 账单历史表
- ✅ 更新 main.py - 添加订阅相关 API 端点26个端点
- GET /api/v1/subscription-plans - 获取订阅计划列表
- POST/GET /api/v1/tenants/{id}/subscriptions - 订阅管理
- POST /api/v1/tenants/{id}/subscriptions/{id}/cancel - 取消订阅
- POST /api/v1/tenants/{id}/subscriptions/{id}/change-plan - 变更计划
- GET /api/v1/tenants/{id}/usage - 用量统计
- POST /api/v1/tenants/{id}/usage/record - 记录用量
- POST /api/v1/tenants/{id}/payments - 创建支付
- GET /api/v1/tenants/{id}/payments - 支付历史
- POST/GET /api/v1/tenants/{id}/invoices - 发票管理
- POST/GET /api/v1/tenants/{id}/refunds - 退款管理
- POST /api/v1/tenants/{id}/refunds/{id}/process - 处理退款
- GET /api/v1/tenants/{id}/billing-history - 账单历史
- POST /api/v1/payments/stripe/create - Stripe 支付
- POST /api/v1/payments/alipay/create - 支付宝支付
- POST /api/v1/payments/wechat/create - 微信支付
- POST /webhooks/stripe - Stripe Webhook
- POST /webhooks/alipay - 支付宝 Webhook
- POST /webhooks/wechat - 微信支付 Webhook
### Phase 8 任务 3 完成内容
**企业级功能**
- ✅ 创建 enterprise_manager.py - 企业级功能管理模块
- SSOConfig: SSO/SAML 配置数据模型支持企业微信、钉钉、飞书、Okta、Azure AD、Google、自定义 SAML
- SCIMConfig/SCIMUser: SCIM 用户目录同步配置和用户数据模型
- AuditLogExport: 审计日志导出记录(支持 SOC2/ISO27001/GDPR/HIPAA/PCI DSS 合规)
- DataRetentionPolicy/DataRetentionJob: 数据保留策略和任务管理
- SAMLAuthRequest/SAMLAuthResponse: SAML 认证请求和响应管理
- SSO 配置管理(创建、更新、删除、列表、元数据生成)
- SCIM 用户同步(配置管理、手动同步、用户列表)
- 审计日志导出(创建导出任务、处理、下载、合规标准支持)
- 数据保留策略(创建、执行、归档/删除/匿名化、任务追踪)
- ✅ 更新 schema.sql - 添加企业级功能相关数据库表
- sso_configs: SSO 配置表SAML/OAuth 配置、属性映射、域名限制)
- saml_auth_requests: SAML 认证请求表
- saml_auth_responses: SAML 认证响应表
- scim_configs: SCIM 配置表
- scim_users: SCIM 用户表
- audit_log_exports: 审计日志导出表
- data_retention_policies: 数据保留策略表
- data_retention_jobs: 数据保留任务表
- 相关索引优化
- ✅ 更新 main.py - 添加企业级功能相关 API 端点25个端点
- POST/GET /api/v1/tenants/{id}/sso-configs - SSO 配置管理
- GET/PUT/DELETE /api/v1/tenants/{id}/sso-configs/{id} - SSO 配置详情/更新/删除
- GET /api/v1/tenants/{id}/sso-configs/{id}/metadata - 获取 SAML 元数据
- POST/GET /api/v1/tenants/{id}/scim-configs - SCIM 配置管理
- PUT /api/v1/tenants/{id}/scim-configs/{id} - 更新 SCIM 配置
- POST /api/v1/tenants/{id}/scim-configs/{id}/sync - 执行 SCIM 同步
- GET /api/v1/tenants/{id}/scim-users - 列出 SCIM 用户
- POST /api/v1/tenants/{id}/audit-exports - 创建审计日志导出
- GET /api/v1/tenants/{id}/audit-exports - 列出审计日志导出
- GET /api/v1/tenants/{id}/audit-exports/{id} - 获取导出详情
- POST /api/v1/tenants/{id}/audit-exports/{id}/download - 下载导出文件
- POST /api/v1/tenants/{id}/retention-policies - 创建数据保留策略
- GET /api/v1/tenants/{id}/retention-policies - 列出保留策略
- GET /api/v1/tenants/{id}/retention-policies/{id} - 获取策略详情
- PUT /api/v1/tenants/{id}/retention-policies/{id} - 更新保留策略
- DELETE /api/v1/tenants/{id}/retention-policies/{id} - 删除保留策略
- POST /api/v1/tenants/{id}/retention-policies/{id}/execute - 执行保留策略
- GET /api/v1/tenants/{id}/retention-policies/{id}/jobs - 列出保留任务
### Phase 8 任务 4 完成内容
**AI 能力增强**
- ✅ 创建 ai_manager.py - AI 能力增强管理模块
- AIManager: AI 能力管理主类
- CustomModel/ModelType/ModelStatus: 自定义模型管理(支持领域特定实体识别)
- TrainingSample: 训练样本管理
- MultimodalAnalysis/MultimodalProvider: 多模态分析(支持 GPT-4V、Claude 3、Gemini、Kimi-VL
- KnowledgeGraphRAG: 基于知识图谱的 RAG 配置管理
- RAGQuery: RAG 查询记录
- SmartSummary: 智能摘要extractive/abstractive/key_points/timeline
- PredictionModel/PredictionType: 预测模型管理(趋势预测、异常检测、实体增长预测、关系演变预测)
- PredictionResult: 预测结果管理
- 自定义模型训练流程(创建、添加样本、训练、预测)
- 多模态分析流程(图片、视频、音频、混合输入)
- 知识图谱 RAG 检索与生成
- 智能摘要生成
- 预测性分析(趋势、异常、增长、演变)
- ✅ 更新 schema.sql - 添加 AI 能力增强相关数据库表
- custom_models: 自定义模型表
- training_samples: 训练样本表
- multimodal_analyses: 多模态分析表
- kg_rag_configs: 知识图谱 RAG 配置表
- rag_queries: RAG 查询记录表
- smart_summaries: 智能摘要表
- prediction_models: 预测模型表
- prediction_results: 预测结果表
- 相关索引优化
- ✅ 更新 main.py - 添加 AI 能力增强相关 API 端点30+个端点)
- POST /api/v1/tenants/{tenant_id}/ai/custom-models - 创建自定义模型
- GET /api/v1/tenants/{tenant_id}/ai/custom-models - 列出自定义模型
- GET /api/v1/ai/custom-models/{model_id} - 获取模型详情
- POST /api/v1/ai/custom-models/{model_id}/samples - 添加训练样本
- GET /api/v1/ai/custom-models/{model_id}/samples - 获取训练样本
- POST /api/v1/ai/custom-models/{model_id}/train - 训练模型
- POST /api/v1/ai/custom-models/predict - 模型预测
- POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/multimodal - 多模态分析
- GET /api/v1/tenants/{tenant_id}/ai/multimodal - 获取多模态分析历史
- POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/kg-rag - 创建知识图谱 RAG
- GET /api/v1/tenants/{tenant_id}/ai/kg-rag - 列出 RAG 配置
- POST /api/v1/ai/kg-rag/query - 知识图谱 RAG 查询
- POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/summarize - 生成智能摘要
- POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/prediction-models - 创建预测模型
- GET /api/v1/tenants/{tenant_id}/ai/prediction-models - 列出预测模型
- GET /api/v1/ai/prediction-models/{model_id} - 获取预测模型详情
- POST /api/v1/ai/prediction-models/{model_id}/train - 训练预测模型
- POST /api/v1/ai/prediction-models/predict - 进行预测
- GET /api/v1/ai/prediction-models/{model_id}/results - 获取预测结果历史
- POST /api/v1/ai/prediction-results/feedback - 更新预测反馈
**预计 Phase 8 完成时间**: 6-8 周
---
## Phase 8: 商业化与规模化 - 进行中 🚧
基于 Phase 1-7 的完整功能Phase 8 聚焦**商业化落地**和**规模化运营**
### 1. 多租户 SaaS 架构 🏢
**优先级: P0** | **状态: ✅ 已完成**
- ✅ 租户隔离(数据、配置、资源完全隔离)
- ✅ 自定义域名绑定CNAME 支持)
- ✅ 品牌白标Logo、主题色、自定义 CSS
- ✅ 租户级权限管理(超级管理员、管理员、成员)
### 2. 订阅与计费系统 💳
**优先级: P0**
- 多层级订阅计划Free/Pro/Enterprise
- 按量计费转录时长、存储空间、API 调用次数)
- 支付集成Stripe、支付宝、微信支付
- 发票管理、退款处理、账单历史
### 3. 企业级功能 🏭
**优先级: P1**
- SSO/SAML 单点登录企业微信、钉钉、飞书、Okta
- SCIM 用户目录同步
- 审计日志导出SOC2/ISO27001 合规)
- 数据保留策略(自动归档、数据删除)
### 4. 运营与增长工具 📈
**优先级: P1**
- 用户行为分析Mixpanel/Amplitude 集成)
- A/B 测试框架
- 邮件营销自动化(欢迎序列、流失挽回)
- 推荐系统(邀请返利、团队升级激励)
### 5. 开发者生态 🛠️
**优先级: P2**
- SDK 发布Python/JavaScript/Go
- 模板市场(行业模板、预训练模型)
- 插件市场(第三方插件审核与分发)
- 开发者文档与示例代码
### 6. 全球化与本地化 🌍
**优先级: P2**
- 多语言支持i18n至少 10 种语言)
- 区域数据中心(北美、欧洲、亚太)
- 本地化支付(各国主流支付方式)
- 时区与日历本地化
### 7. AI 能力增强 🤖
**优先级: P1**
- 自定义模型训练(领域特定实体识别)
- 多模态大模型集成GPT-4V、Claude 3
- 智能摘要与问答(基于知识图谱的 RAG
- 预测性分析(趋势预测、异常检测)
### 8. 运维与监控 🔧
**优先级: P2**
- 实时告警系统PagerDuty/Opsgenie 集成)
- 容量规划与自动扩缩容
- 灾备与故障转移(多活架构)
- 成本优化(资源利用率监控)
---
**建议开发顺序**: 1 → 2 → 3 → 7 → 4 → 5 → 6 → 8
**预计 Phase 8 完成时间**: 6-8 周

229
backend/STATUS.md Normal file
View File

@@ -0,0 +1,229 @@
# InsightFlow 开发状态
## 项目概述
InsightFlow 是一个智能知识管理平台,支持从会议记录、文档中提取实体和关系,构建知识图谱。
## 当前阶段Phase 8 - 商业化与规模化
### 已完成任务
#### Phase 8 Task 1: 多租户 SaaS 架构 (P0 - 最高优先级) ✅
**功能实现:**
1. **租户隔离**(数据、配置、资源完全隔离)✅
- 租户数据隔离方案设计 - 使用表前缀隔离
- 数据库级别的租户隔离 - 通过 `table_prefix` 字段实现
- API 层面的租户上下文管理 - `TenantContext`
2. **自定义域名绑定**CNAME 支持)✅
- 租户自定义域名配置 - `tenant_domains`
- 域名验证机制 - DNS TXT 记录验证
- 基于域名的租户路由 - `get_tenant_by_domain()` 方法
3. **品牌白标**Logo、主题色、自定义 CSS
- 租户品牌配置存储 - `tenant_branding`
- 动态主题加载 - `get_branding_css()` 方法
- 自定义 CSS 支持 - `custom_css` 字段
4. **租户级权限管理**
- 租户管理员角色 - `TenantRole` (owner, admin, member, viewer)
- 成员邀请与管理 - `invite_member()`, `accept_invitation()`
- 角色权限配置 - `ROLE_PERMISSIONS` 映射
**技术实现:**
-`tenant_manager.py` - 租户管理核心模块
-`schema.sql` - 更新数据库表结构
- `tenants` - 租户主表
- `tenant_domains` - 租户域名绑定表
- `tenant_branding` - 租户品牌配置表
- `tenant_members` - 租户成员表
- `tenant_permissions` - 租户权限表
- `tenant_usage` - 租户资源使用统计表
-`main.py` - 添加租户相关 API 端点
-`requirements.txt` - 无需新增依赖
-`test_tenant.py` - 测试脚本
#### Phase 8 Task 2: 订阅与计费系统 (P0 - 最高优先级) ✅
**功能实现:**
1. **多层级订阅计划**Free/Pro/Enterprise
2. **按量计费**转录时长、存储空间、API 调用次数)✅
3. **支付集成**Stripe、支付宝、微信支付
4. **发票管理、退款处理、账单历史**
**技术实现:**
-`subscription_manager.py` - 订阅与计费管理模块
-`schema.sql` - 添加订阅相关数据库表
-`main.py` - 添加 26 个 API 端点
#### Phase 8 Task 3: 企业级功能 (P1 - 高优先级) ✅
**功能实现:**
1. **SSO/SAML 单点登录**企业微信、钉钉、飞书、Okta
2. **SCIM 用户目录同步**
3. **审计日志导出**SOC2/ISO27001 合规)✅
4. **数据保留策略**(自动归档、数据删除)✅
**技术实现:**
-`enterprise_manager.py` - 企业级功能管理模块
-`schema.sql` - 添加企业级功能相关数据库表
-`main.py` - 添加 25 个 API 端点
#### Phase 8 Task 4: AI 能力增强 (P1 - 高优先级) ✅
**功能实现:**
1. **自定义模型训练**(领域特定实体识别)✅
- CustomModel/ModelType/ModelStatus 数据模型
- TrainingSample 训练样本管理
- 模型训练流程(创建、添加样本、训练、预测)
2. **多模态大模型集成**GPT-4V、Claude 3
- MultimodalAnalysis 多模态分析
- 支持 GPT-4V、Claude 3、Gemini、Kimi-VL
- 图片、视频、音频、混合输入分析
3. **智能摘要与问答**(基于知识图谱的 RAG
- KnowledgeGraphRAG 配置管理
- RAGQuery 查询记录
- SmartSummary 智能摘要extractive/abstractive/key_points/timeline
4. **预测性分析**(趋势预测、异常检测)✅
- PredictionModel/PredictionType 预测模型管理
- 趋势预测、异常检测、实体增长预测、关系演变预测
- PredictionResult 预测结果管理
**技术实现:**
-`ai_manager.py` - AI 能力增强管理模块1330+ 行代码)
- AIManager: AI 能力管理主类
- 自定义模型训练流程
- 多模态分析GPT-4V、Claude 3、Gemini、Kimi-VL
- 知识图谱 RAG 检索与生成
- 智能摘要生成(多种类型)
- 预测性分析(趋势、异常、增长、演变)
-`schema.sql` - 添加 AI 能力增强相关数据库表
- `custom_models` - 自定义模型表
- `training_samples` - 训练样本表
- `multimodal_analyses` - 多模态分析表
- `kg_rag_configs` - 知识图谱 RAG 配置表
- `rag_queries` - RAG 查询记录表
- `smart_summaries` - 智能摘要表
- `prediction_models` - 预测模型表
- `prediction_results` - 预测结果表
-`main.py` - 添加 30+ 个 API 端点
- 自定义模型管理(创建、训练、预测)
- 多模态分析
- 知识图谱 RAG配置、查询
- 智能摘要
- 预测模型(创建、训练、预测、反馈)
-`test_phase8_task4.py` - 测试脚本
**API 端点:**
自定义模型管理:
- `POST /api/v1/tenants/{tenant_id}/ai/custom-models` - 创建自定义模型
- `GET /api/v1/tenants/{tenant_id}/ai/custom-models` - 列出自定义模型
- `GET /api/v1/ai/custom-models/{model_id}` - 获取模型详情
- `POST /api/v1/ai/custom-models/{model_id}/samples` - 添加训练样本
- `GET /api/v1/ai/custom-models/{model_id}/samples` - 获取训练样本
- `POST /api/v1/ai/custom-models/{model_id}/train` - 训练模型
- `POST /api/v1/ai/custom-models/predict` - 模型预测
多模态分析:
- `POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/multimodal` - 多模态分析
- `GET /api/v1/tenants/{tenant_id}/ai/multimodal` - 获取多模态分析历史
知识图谱 RAG
- `POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/kg-rag` - 创建 RAG 配置
- `GET /api/v1/tenants/{tenant_id}/ai/kg-rag` - 列出 RAG 配置
- `POST /api/v1/ai/kg-rag/query` - 知识图谱 RAG 查询
智能摘要:
- `POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/summarize` - 生成智能摘要
预测模型:
- `POST /api/v1/tenants/{tenant_id}/projects/{project_id}/ai/prediction-models` - 创建预测模型
- `GET /api/v1/tenants/{tenant_id}/ai/prediction-models` - 列出预测模型
- `GET /api/v1/ai/prediction-models/{model_id}` - 获取预测模型详情
- `POST /api/v1/ai/prediction-models/{model_id}/train` - 训练预测模型
- `POST /api/v1/ai/prediction-models/predict` - 进行预测
- `GET /api/v1/ai/prediction-models/{model_id}/results` - 获取预测结果历史
- `POST /api/v1/ai/prediction-results/feedback` - 更新预测反馈
**测试状态:** ✅ 核心功能测试通过
运行测试:
```bash
cd /root/.openclaw/workspace/projects/insightflow/backend
python3 test_phase8_task4.py
```
## 历史阶段
### Phase 7 - 插件与集成 (已完成)
- 工作流自动化
- 多模态支持(视频、图片)
- 数据安全与合规
- 协作与共享
- 报告生成器
- 高级搜索与发现
- 性能优化与扩展
### Phase 6 - API 平台 (已完成)
- API Key 管理
- Swagger 文档
- 限流控制
### Phase 5 - 属性扩展 (已完成)
- 属性模板系统
- 实体属性管理
- 属性变更历史
### Phase 4 - Agent 助手 (已完成)
- RAG 问答
- 知识推理
- 智能总结
### Phase 3 - 知识生长 (已完成)
- 实体对齐
- 多文件融合
- 术语表
### Phase 2 - 编辑功能 (已完成)
- 实体编辑
- 关系编辑
- 转录编辑
### Phase 1 - 基础功能 (已完成)
- 项目管理
- 音频转录
- 实体提取
## 待办事项
### Phase 8 后续任务
- [ ] Task 5: 运营与增长工具
- [ ] Task 6: 开发者生态
- [ ] Task 8: 运维与监控
### 技术债务
- [ ] 完善单元测试覆盖
- [ ] API 性能优化
- [ ] 文档完善
## 最近更新
- 2026-02-26: Phase 8 Task 4 完成 - AI 能力增强
- 2026-02-25: Phase 8 Task 1/2/3/7 完成 - 多租户、订阅计费、企业级功能、全球化
- 2026-02-24: Phase 7 完成 - 插件与集成
- 2026-02-23: Phase 6 完成 - API 平台

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1359
backend/ai_manager.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1060,125 +1060,666 @@ CREATE INDEX IF NOT EXISTS idx_usage_tenant ON tenant_usage(tenant_id);
CREATE INDEX IF NOT EXISTS idx_usage_date ON tenant_usage(date);
-- ============================================
-- Phase 8: Multi-Tenant SaaS Architecture
-- Phase 8 Task 2: 订阅与计费系统
-- ============================================
-- 租户主
CREATE TABLE IF NOT EXISTS tenants (
-- 订阅计划
CREATE TABLE IF NOT EXISTS subscription_plans (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL, -- URL 友好的唯一标识
description TEXT DEFAULT '',
status TEXT DEFAULT 'active', -- active, suspended, trial, expired, pending
plan TEXT DEFAULT 'free', -- free, starter, professional, enterprise
max_projects INTEGER DEFAULT 5,
max_members INTEGER DEFAULT 10,
max_storage_gb REAL DEFAULT 1.0,
max_api_calls_per_day INTEGER DEFAULT 1000,
billing_email TEXT DEFAULT '',
subscription_start TEXT,
subscription_end TEXT,
tier TEXT UNIQUE NOT NULL, -- free/pro/enterprise
description TEXT,
price_monthly REAL DEFAULT 0,
price_yearly REAL DEFAULT 0,
currency TEXT DEFAULT 'CNY',
features TEXT DEFAULT '[]', -- JSON array
limits TEXT DEFAULT '{}', -- JSON object
is_active INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by TEXT DEFAULT '', -- 创建者用户ID
db_schema TEXT DEFAULT '', -- 数据库 schema 名称
table_prefix TEXT DEFAULT '' -- 表前缀
metadata TEXT DEFAULT '{}'
);
-- 租户域名绑定
CREATE TABLE IF NOT EXISTS tenant_domains (
-- 订阅
CREATE TABLE IF NOT EXISTS subscriptions (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
domain TEXT NOT NULL, -- 自定义域名
status TEXT DEFAULT 'pending', -- pending, verified, active, failed, expired
verification_record TEXT DEFAULT '', -- DNS TXT 记录值
verification_expires_at TEXT,
ssl_enabled INTEGER DEFAULT 0,
ssl_cert_path TEXT,
ssl_key_path TEXT,
ssl_expires_at TEXT,
plan_id TEXT NOT NULL,
status TEXT DEFAULT 'pending', -- active/cancelled/expired/past_due/trial/pending
current_period_start TIMESTAMP,
current_period_end TIMESTAMP,
cancel_at_period_end INTEGER DEFAULT 0,
canceled_at TIMESTAMP,
trial_start TIMESTAMP,
trial_end TIMESTAMP,
payment_provider TEXT, -- stripe/alipay/wechat/bank_transfer
provider_subscription_id TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
verified_at TEXT,
UNIQUE(tenant_id, domain),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata TEXT DEFAULT '{}',
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (plan_id) REFERENCES subscription_plans(id)
);
-- 用量记录表
CREATE TABLE IF NOT EXISTS usage_records (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
resource_type TEXT NOT NULL, -- transcription/storage/api_call/export
quantity REAL DEFAULT 0,
unit TEXT NOT NULL, -- minutes/mb/count/page
recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
cost REAL DEFAULT 0,
description TEXT,
metadata TEXT DEFAULT '{}',
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 租户品牌配置表(白标)
CREATE TABLE IF NOT EXISTS tenant_branding (
-- 支付记录表
CREATE TABLE IF NOT EXISTS payments (
id TEXT PRIMARY KEY,
tenant_id TEXT UNIQUE NOT NULL,
logo_url TEXT,
logo_dark_url TEXT, -- 深色模式 Logo
favicon_url TEXT,
primary_color TEXT DEFAULT '#3B82F6',
secondary_color TEXT DEFAULT '#10B981',
accent_color TEXT DEFAULT '#F59E0B',
background_color TEXT DEFAULT '#FFFFFF',
text_color TEXT DEFAULT '#1F2937',
dark_primary_color TEXT DEFAULT '#60A5FA',
dark_background_color TEXT DEFAULT '#111827',
dark_text_color TEXT DEFAULT '#F9FAFB',
font_family TEXT DEFAULT 'Inter, system-ui, sans-serif',
heading_font_family TEXT,
custom_css TEXT DEFAULT '',
custom_js TEXT DEFAULT '',
app_name TEXT DEFAULT 'InsightFlow',
login_page_title TEXT DEFAULT '登录到 InsightFlow',
login_page_description TEXT DEFAULT '',
footer_text TEXT DEFAULT '© 2024 InsightFlow',
tenant_id TEXT NOT NULL,
subscription_id TEXT,
invoice_id TEXT,
amount REAL NOT NULL,
currency TEXT DEFAULT 'CNY',
provider TEXT NOT NULL, -- stripe/alipay/wechat/bank_transfer
provider_payment_id TEXT,
status TEXT DEFAULT 'pending', -- pending/processing/completed/failed/refunded/partial_refunded
payment_method TEXT,
payment_details TEXT DEFAULT '{}', -- JSON
paid_at TIMESTAMP,
failed_at TIMESTAMP,
failure_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (subscription_id) REFERENCES subscriptions(id) ON DELETE SET NULL,
FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE SET NULL
);
-- 发票表
CREATE TABLE IF NOT EXISTS invoices (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
subscription_id TEXT,
invoice_number TEXT UNIQUE NOT NULL,
status TEXT DEFAULT 'draft', -- draft/issued/paid/overdue/void/credit_note
amount_due REAL DEFAULT 0,
amount_paid REAL DEFAULT 0,
currency TEXT DEFAULT 'CNY',
period_start TIMESTAMP,
period_end TIMESTAMP,
description TEXT,
line_items TEXT DEFAULT '[]', -- JSON array
due_date TIMESTAMP,
paid_at TIMESTAMP,
voided_at TIMESTAMP,
void_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (subscription_id) REFERENCES subscriptions(id) ON DELETE SET NULL
);
-- 退款表
CREATE TABLE IF NOT EXISTS refunds (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
payment_id TEXT NOT NULL,
invoice_id TEXT,
amount REAL NOT NULL,
currency TEXT DEFAULT 'CNY',
reason TEXT,
status TEXT DEFAULT 'pending', -- pending/approved/rejected/completed/failed
requested_by TEXT NOT NULL,
requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
approved_by TEXT,
approved_at TIMESTAMP,
completed_at TIMESTAMP,
provider_refund_id TEXT,
metadata TEXT DEFAULT '{}',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (payment_id) REFERENCES payments(id) ON DELETE CASCADE,
FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE SET NULL
);
-- 账单历史表
CREATE TABLE IF NOT EXISTS billing_history (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
type TEXT NOT NULL, -- subscription/usage/payment/refund
amount REAL NOT NULL,
currency TEXT DEFAULT 'CNY',
description TEXT,
reference_id TEXT, -- 关联的订阅/支付/退款ID
balance_after REAL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata TEXT DEFAULT '{}',
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 订阅相关索引
CREATE INDEX IF NOT EXISTS idx_subscriptions_tenant ON subscriptions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status);
CREATE INDEX IF NOT EXISTS idx_subscriptions_plan ON subscriptions(plan_id);
CREATE INDEX IF NOT EXISTS idx_usage_records_tenant ON usage_records(tenant_id);
CREATE INDEX IF NOT EXISTS idx_usage_records_type ON usage_records(resource_type);
CREATE INDEX IF NOT EXISTS idx_usage_records_recorded ON usage_records(recorded_at);
CREATE INDEX IF NOT EXISTS idx_payments_tenant ON payments(tenant_id);
CREATE INDEX IF NOT EXISTS idx_payments_status ON payments(status);
CREATE INDEX IF NOT EXISTS idx_payments_provider ON payments(provider);
CREATE INDEX IF NOT EXISTS idx_invoices_tenant ON invoices(tenant_id);
CREATE INDEX IF NOT EXISTS idx_invoices_status ON invoices(status);
CREATE INDEX IF NOT EXISTS idx_invoices_number ON invoices(invoice_number);
CREATE INDEX IF NOT EXISTS idx_refunds_tenant ON refunds(tenant_id);
CREATE INDEX IF NOT EXISTS idx_refunds_status ON refunds(status);
CREATE INDEX IF NOT EXISTS idx_refunds_payment ON refunds(payment_id);
CREATE INDEX IF NOT EXISTS idx_billing_history_tenant ON billing_history(tenant_id);
CREATE INDEX IF NOT EXISTS idx_billing_history_created ON billing_history(created_at);
CREATE INDEX IF NOT EXISTS idx_billing_history_type ON billing_history(type);
-- ============================================
-- Phase 8 Task 3: 企业级功能
-- ============================================
-- SSO 配置表
CREATE TABLE IF NOT EXISTS sso_configs (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
provider TEXT NOT NULL, -- wechat_work/dingtalk/feishu/okta/azure_ad/google/custom_saml
status TEXT DEFAULT 'disabled', -- disabled/pending/active/error
entity_id TEXT,
sso_url TEXT,
slo_url TEXT,
certificate TEXT, -- X.509 证书
metadata_url TEXT,
metadata_xml TEXT,
client_id TEXT,
client_secret TEXT,
authorization_url TEXT,
token_url TEXT,
userinfo_url TEXT,
scopes TEXT DEFAULT '["openid", "email", "profile"]',
attribute_mapping TEXT DEFAULT '{}', -- JSON: 属性映射
auto_provision INTEGER DEFAULT 1, -- 自动创建用户
default_role TEXT DEFAULT 'member',
domain_restriction TEXT DEFAULT '[]', -- JSON: 允许的邮箱域名
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_tested_at TIMESTAMP,
last_error TEXT,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- SAML 认证请求表
CREATE TABLE IF NOT EXISTS saml_auth_requests (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
sso_config_id TEXT NOT NULL,
request_id TEXT NOT NULL UNIQUE,
relay_state TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL,
used INTEGER DEFAULT 0,
used_at TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (sso_config_id) REFERENCES sso_configs(id) ON DELETE CASCADE
);
-- SAML 认证响应表
CREATE TABLE IF NOT EXISTS saml_auth_responses (
id TEXT PRIMARY KEY,
request_id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
user_id TEXT,
email TEXT,
name TEXT,
attributes TEXT DEFAULT '{}', -- JSON: SAML 属性
session_index TEXT,
processed INTEGER DEFAULT 0,
processed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (request_id) REFERENCES saml_auth_requests(request_id) ON DELETE CASCADE,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- SCIM 配置表
CREATE TABLE IF NOT EXISTS scim_configs (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
provider TEXT NOT NULL,
status TEXT DEFAULT 'disabled',
scim_base_url TEXT,
scim_token TEXT,
sync_interval_minutes INTEGER DEFAULT 60,
last_sync_at TIMESTAMP,
last_sync_status TEXT,
last_sync_error TEXT,
last_sync_users_count INTEGER DEFAULT 0,
attribute_mapping TEXT DEFAULT '{}',
sync_rules TEXT DEFAULT '{}',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 租户成员
CREATE TABLE IF NOT EXISTS tenant_members (
-- SCIM 用户
CREATE TABLE IF NOT EXISTS scim_users (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
user_id TEXT NOT NULL,
external_id TEXT NOT NULL,
user_name TEXT NOT NULL,
email TEXT NOT NULL,
name TEXT DEFAULT '',
role TEXT DEFAULT 'viewer', -- owner, admin, editor, viewer, guest
status TEXT DEFAULT 'invited', -- active, invited, suspended, removed
invited_by TEXT,
invited_at TEXT,
invitation_token TEXT,
invitation_expires_at TEXT,
joined_at TEXT,
last_active_at TEXT,
custom_permissions TEXT DEFAULT '[]', -- JSON 数组
display_name TEXT,
given_name TEXT,
family_name TEXT,
active INTEGER DEFAULT 1,
groups TEXT DEFAULT '[]',
raw_data TEXT DEFAULT '{}',
synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, user_id),
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
UNIQUE(tenant_id, external_id)
);
-- 审计日志导出表
CREATE TABLE IF NOT EXISTS audit_log_exports (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
export_format TEXT NOT NULL, -- json/csv/pdf/xlsx
start_date TIMESTAMP NOT NULL,
end_date TIMESTAMP NOT NULL,
filters TEXT DEFAULT '{}',
compliance_standard TEXT, -- soc2/iso27001/gdpr/hipaa/pci_dss
status TEXT DEFAULT 'pending', -- pending/processing/completed/failed
file_path TEXT,
file_size INTEGER,
record_count INTEGER,
checksum TEXT,
downloaded_by TEXT,
downloaded_at TIMESTAMP,
expires_at TIMESTAMP,
created_by TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP,
error_message TEXT,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 租户角色
CREATE TABLE IF NOT EXISTS tenant_roles (
-- 数据保留策略
CREATE TABLE IF NOT EXISTS data_retention_policies (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT DEFAULT '',
permissions TEXT DEFAULT '[]', -- JSON 数组
is_system INTEGER DEFAULT 0, -- 1=系统预设, 0=自定义
description TEXT,
resource_type TEXT NOT NULL, -- project/transcript/entity/audit_log/user_data
retention_days INTEGER NOT NULL,
action TEXT NOT NULL, -- archive/delete/anonymize
conditions TEXT DEFAULT '{}',
auto_execute INTEGER DEFAULT 0,
execute_at TEXT, -- cron 表达式
notify_before_days INTEGER DEFAULT 7,
archive_location TEXT,
archive_encryption INTEGER DEFAULT 1,
is_active INTEGER DEFAULT 1,
last_executed_at TIMESTAMP,
last_execution_result TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 租户相关索引
CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug);
CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);
CREATE INDEX IF NOT EXISTS idx_domains_tenant ON tenant_domains(tenant_id);
CREATE INDEX IF NOT EXISTS idx_domains_domain ON tenant_domains(domain);
CREATE INDEX IF NOT EXISTS idx_domains_status ON tenant_domains(status);
CREATE INDEX IF NOT EXISTS idx_members_tenant ON tenant_members(tenant_id);
CREATE INDEX IF NOT EXISTS idx_members_user ON tenant_members(user_id);
CREATE INDEX IF NOT EXISTS idx_members_role ON tenant_members(role);
CREATE INDEX IF NOT EXISTS idx_members_status ON tenant_members(status);
CREATE INDEX IF NOT EXISTS idx_members_token ON tenant_members(invitation_token);
CREATE INDEX IF NOT EXISTS idx_roles_tenant ON tenant_roles(tenant_id);
-- 数据保留任务表
CREATE TABLE IF NOT EXISTS data_retention_jobs (
id TEXT PRIMARY KEY,
policy_id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
status TEXT DEFAULT 'pending', -- pending/running/completed/failed
started_at TIMESTAMP,
completed_at TIMESTAMP,
affected_records INTEGER DEFAULT 0,
archived_records INTEGER DEFAULT 0,
deleted_records INTEGER DEFAULT 0,
error_count INTEGER DEFAULT 0,
details TEXT DEFAULT '{}',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (policy_id) REFERENCES data_retention_policies(id) ON DELETE CASCADE,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 更新项目表,添加租户关联(可选,支持租户隔离)
ALTER TABLE projects ADD COLUMN tenant_id TEXT;
CREATE INDEX IF NOT EXISTS idx_projects_tenant ON projects(tenant_id);
-- 企业级功能相关索引
CREATE INDEX IF NOT EXISTS idx_sso_tenant ON sso_configs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_sso_provider ON sso_configs(provider);
CREATE INDEX IF NOT EXISTS idx_saml_requests_config ON saml_auth_requests(sso_config_id);
CREATE INDEX IF NOT EXISTS idx_saml_requests_expires ON saml_auth_requests(expires_at);
CREATE INDEX IF NOT EXISTS idx_saml_responses_request ON saml_auth_responses(request_id);
CREATE INDEX IF NOT EXISTS idx_scim_config_tenant ON scim_configs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_scim_users_tenant ON scim_users(tenant_id);
CREATE INDEX IF NOT EXISTS idx_scim_users_external ON scim_users(external_id);
CREATE INDEX IF NOT EXISTS idx_audit_export_tenant ON audit_log_exports(tenant_id);
CREATE INDEX IF NOT EXISTS idx_audit_export_status ON audit_log_exports(status);
CREATE INDEX IF NOT EXISTS idx_retention_tenant ON data_retention_policies(tenant_id);
CREATE INDEX IF NOT EXISTS idx_retention_type ON data_retention_policies(resource_type);
CREATE INDEX IF NOT EXISTS idx_retention_jobs_policy ON data_retention_jobs(policy_id);
CREATE INDEX IF NOT EXISTS idx_retention_jobs_status ON data_retention_jobs(status);
-- ============================================
-- Phase 8 Task 7: 全球化与本地化
-- ============================================
-- 翻译表
CREATE TABLE IF NOT EXISTS translations (
id TEXT PRIMARY KEY,
key TEXT NOT NULL,
language TEXT NOT NULL,
value TEXT NOT NULL,
namespace TEXT DEFAULT 'common',
context TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_reviewed INTEGER DEFAULT 0,
reviewed_by TEXT,
reviewed_at TIMESTAMP,
UNIQUE(key, language, namespace)
);
-- 语言配置表
CREATE TABLE IF NOT EXISTS language_configs (
code TEXT PRIMARY KEY,
name TEXT NOT NULL,
name_local TEXT NOT NULL,
is_rtl INTEGER DEFAULT 0,
is_active INTEGER DEFAULT 1,
is_default INTEGER DEFAULT 0,
fallback_language TEXT,
date_format TEXT,
time_format TEXT,
datetime_format TEXT,
number_format TEXT,
currency_format TEXT,
first_day_of_week INTEGER DEFAULT 1,
calendar_type TEXT DEFAULT 'gregorian'
);
-- 数据中心表
CREATE TABLE IF NOT EXISTS data_centers (
id TEXT PRIMARY KEY,
region_code TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
location TEXT NOT NULL,
endpoint TEXT NOT NULL,
status TEXT DEFAULT 'active',
priority INTEGER DEFAULT 1,
supported_regions TEXT DEFAULT '[]',
capabilities TEXT DEFAULT '{}',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 租户数据中心映射表
CREATE TABLE IF NOT EXISTS tenant_data_center_mappings (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL UNIQUE,
primary_dc_id TEXT NOT NULL,
secondary_dc_id TEXT,
region_code TEXT NOT NULL,
data_residency TEXT DEFAULT 'regional',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (primary_dc_id) REFERENCES data_centers(id),
FOREIGN KEY (secondary_dc_id) REFERENCES data_centers(id)
);
-- 本地化支付方式表
CREATE TABLE IF NOT EXISTS localized_payment_methods (
id TEXT PRIMARY KEY,
provider TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
name_local TEXT DEFAULT '{}',
supported_countries TEXT DEFAULT '[]',
supported_currencies TEXT DEFAULT '[]',
is_active INTEGER DEFAULT 1,
config TEXT DEFAULT '{}',
icon_url TEXT,
display_order INTEGER DEFAULT 0,
min_amount REAL,
max_amount REAL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 国家配置表
CREATE TABLE IF NOT EXISTS country_configs (
code TEXT PRIMARY KEY,
code3 TEXT NOT NULL,
name TEXT NOT NULL,
name_local TEXT DEFAULT '{}',
region TEXT NOT NULL,
default_language TEXT NOT NULL,
supported_languages TEXT DEFAULT '[]',
default_currency TEXT NOT NULL,
supported_currencies TEXT DEFAULT '[]',
timezone TEXT NOT NULL,
calendar_type TEXT DEFAULT 'gregorian',
date_format TEXT,
time_format TEXT,
number_format TEXT,
address_format TEXT,
phone_format TEXT,
vat_rate REAL,
is_active INTEGER DEFAULT 1
);
-- 时区配置表
CREATE TABLE IF NOT EXISTS timezone_configs (
id TEXT PRIMARY KEY,
timezone TEXT NOT NULL UNIQUE,
utc_offset TEXT NOT NULL,
dst_offset TEXT,
country_code TEXT NOT NULL,
region TEXT NOT NULL,
is_active INTEGER DEFAULT 1
);
-- 货币配置表
CREATE TABLE IF NOT EXISTS currency_configs (
code TEXT PRIMARY KEY,
name TEXT NOT NULL,
name_local TEXT DEFAULT '{}',
symbol TEXT NOT NULL,
decimal_places INTEGER DEFAULT 2,
decimal_separator TEXT DEFAULT '.',
thousands_separator TEXT DEFAULT ',',
is_active INTEGER DEFAULT 1
);
-- 租户本地化设置表
CREATE TABLE IF NOT EXISTS localization_settings (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL UNIQUE,
default_language TEXT DEFAULT 'en',
supported_languages TEXT DEFAULT '["en"]',
default_currency TEXT DEFAULT 'USD',
supported_currencies TEXT DEFAULT '["USD"]',
default_timezone TEXT DEFAULT 'UTC',
default_date_format TEXT,
default_time_format TEXT,
default_number_format TEXT,
calendar_type TEXT DEFAULT 'gregorian',
first_day_of_week INTEGER DEFAULT 1,
region_code TEXT DEFAULT 'global',
data_residency TEXT DEFAULT 'regional',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 本地化相关索引
CREATE INDEX IF NOT EXISTS idx_translations_key ON translations(key);
CREATE INDEX IF NOT EXISTS idx_translations_lang ON translations(language);
CREATE INDEX IF NOT EXISTS idx_translations_ns ON translations(namespace);
CREATE INDEX IF NOT EXISTS idx_dc_region ON data_centers(region_code);
CREATE INDEX IF NOT EXISTS idx_dc_status ON data_centers(status);
CREATE INDEX IF NOT EXISTS idx_tenant_dc ON tenant_data_center_mappings(tenant_id);
CREATE INDEX IF NOT EXISTS idx_payment_provider ON localized_payment_methods(provider);
CREATE INDEX IF NOT EXISTS idx_payment_active ON localized_payment_methods(is_active);
CREATE INDEX IF NOT EXISTS idx_country_region ON country_configs(region);
CREATE INDEX IF NOT EXISTS idx_tz_country ON timezone_configs(country_code);
CREATE INDEX IF NOT EXISTS idx_locale_settings_tenant ON localization_settings(tenant_id);
-- ============================================
-- Phase 8 Task 4: AI 能力增强
-- ============================================
-- 自定义模型表
CREATE TABLE IF NOT EXISTS custom_models (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
model_type TEXT NOT NULL, -- custom_ner, multimodal, summarization, prediction
status TEXT DEFAULT 'pending', -- pending, training, ready, failed, archived
training_data TEXT DEFAULT '{}',
hyperparameters TEXT DEFAULT '{}',
metrics TEXT DEFAULT '{}',
model_path TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
trained_at TIMESTAMP,
created_by TEXT NOT NULL,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
-- 训练样本表
CREATE TABLE IF NOT EXISTS training_samples (
id TEXT PRIMARY KEY,
model_id TEXT NOT NULL,
text TEXT NOT NULL,
entities TEXT DEFAULT '[]', -- JSON: [{"start": 0, "end": 5, "label": "PERSON", "text": "..."}]
metadata TEXT DEFAULT '{}',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (model_id) REFERENCES custom_models(id) ON DELETE CASCADE
);
-- 多模态分析表
CREATE TABLE IF NOT EXISTS multimodal_analyses (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
project_id TEXT NOT NULL,
provider TEXT NOT NULL, -- gpt-4-vision, claude-3, gemini-pro-vision, kimi-vl
input_type TEXT NOT NULL, -- image, video, audio, mixed
input_urls TEXT DEFAULT '[]',
prompt TEXT NOT NULL,
result TEXT DEFAULT '{}',
tokens_used INTEGER DEFAULT 0,
cost REAL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);
-- 知识图谱 RAG 配置表
CREATE TABLE IF NOT EXISTS kg_rag_configs (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
project_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
kg_config TEXT DEFAULT '{}', -- 知识图谱配置
retrieval_config TEXT DEFAULT '{}', -- 检索配置
generation_config TEXT DEFAULT '{}', -- 生成配置
is_active INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);
-- RAG 查询记录表
CREATE TABLE IF NOT EXISTS rag_queries (
id TEXT PRIMARY KEY,
rag_id TEXT NOT NULL,
query TEXT NOT NULL,
context TEXT DEFAULT '{}',
answer TEXT NOT NULL,
sources TEXT DEFAULT '[]',
confidence REAL DEFAULT 0,
tokens_used INTEGER DEFAULT 0,
latency_ms INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (rag_id) REFERENCES kg_rag_configs(id) ON DELETE CASCADE
);
-- 智能摘要表
CREATE TABLE IF NOT EXISTS smart_summaries (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
project_id TEXT NOT NULL,
source_type TEXT NOT NULL, -- transcript, entity, project
source_id TEXT NOT NULL,
summary_type TEXT NOT NULL, -- extractive, abstractive, key_points, timeline
content TEXT NOT NULL,
key_points TEXT DEFAULT '[]',
entities_mentioned TEXT DEFAULT '[]',
confidence REAL DEFAULT 0,
tokens_used INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);
-- 预测模型表
CREATE TABLE IF NOT EXISTS prediction_models (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
project_id TEXT NOT NULL,
name TEXT NOT NULL,
prediction_type TEXT NOT NULL, -- trend, anomaly, entity_growth, relation_evolution
target_entity_type TEXT,
features TEXT DEFAULT '[]',
model_config TEXT DEFAULT '{}',
accuracy REAL,
last_trained_at TIMESTAMP,
prediction_count INTEGER DEFAULT 0,
is_active INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);
-- 预测结果表
CREATE TABLE IF NOT EXISTS prediction_results (
id TEXT PRIMARY KEY,
model_id TEXT NOT NULL,
prediction_type TEXT NOT NULL,
target_id TEXT,
prediction_data TEXT DEFAULT '{}',
confidence REAL DEFAULT 0,
explanation TEXT,
actual_value TEXT,
is_correct INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (model_id) REFERENCES prediction_models(id) ON DELETE CASCADE
);
-- AI 能力增强相关索引
CREATE INDEX IF NOT EXISTS idx_custom_models_tenant ON custom_models(tenant_id);
CREATE INDEX IF NOT EXISTS idx_custom_models_type ON custom_models(model_type);
CREATE INDEX IF NOT EXISTS idx_custom_models_status ON custom_models(status);
CREATE INDEX IF NOT EXISTS idx_training_samples_model ON training_samples(model_id);
CREATE INDEX IF NOT EXISTS idx_multimodal_tenant ON multimodal_analyses(tenant_id);
CREATE INDEX IF NOT EXISTS idx_multimodal_project ON multimodal_analyses(project_id);
CREATE INDEX IF NOT EXISTS idx_kg_rag_tenant ON kg_rag_configs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_kg_rag_project ON kg_rag_configs(project_id);
CREATE INDEX IF NOT EXISTS idx_rag_queries_rag ON rag_queries(rag_id);
CREATE INDEX IF NOT EXISTS idx_smart_summaries_tenant ON smart_summaries(tenant_id);
CREATE INDEX IF NOT EXISTS idx_smart_summaries_project ON smart_summaries(project_id);
CREATE INDEX IF NOT EXISTS idx_prediction_models_tenant ON prediction_models(tenant_id);
CREATE INDEX IF NOT EXISTS idx_prediction_models_project ON prediction_models(project_id);
CREATE INDEX IF NOT EXISTS idx_prediction_results_model ON prediction_results(model_id);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
#!/usr/bin/env python3
"""
InsightFlow Phase 8 Task 2 测试脚本 - 订阅与计费系统
"""
import sys
import os
import tempfile
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from subscription_manager import (
get_subscription_manager, SubscriptionManager,
SubscriptionStatus, PaymentProvider, PaymentStatus, InvoiceStatus, RefundStatus
)
def test_subscription_manager():
"""测试订阅管理器"""
print("=" * 60)
print("InsightFlow Phase 8 Task 2 - 订阅与计费系统测试")
print("=" * 60)
# 使用临时文件数据库进行测试
db_path = tempfile.mktemp(suffix='.db')
try:
manager = SubscriptionManager(db_path=db_path)
print("\n1. 测试订阅计划管理")
print("-" * 40)
# 获取默认计划
plans = manager.list_plans()
print(f"✓ 默认计划数量: {len(plans)}")
for plan in plans:
print(f" - {plan.name} ({plan.tier}): ¥{plan.price_monthly}/月")
# 通过 tier 获取计划
free_plan = manager.get_plan_by_tier("free")
pro_plan = manager.get_plan_by_tier("pro")
enterprise_plan = manager.get_plan_by_tier("enterprise")
assert free_plan is not None, "Free 计划应该存在"
assert pro_plan is not None, "Pro 计划应该存在"
assert enterprise_plan is not None, "Enterprise 计划应该存在"
print(f"✓ Free 计划: {free_plan.name}")
print(f"✓ Pro 计划: {pro_plan.name}")
print(f"✓ Enterprise 计划: {enterprise_plan.name}")
print("\n2. 测试订阅管理")
print("-" * 40)
tenant_id = "test-tenant-001"
# 创建订阅
subscription = manager.create_subscription(
tenant_id=tenant_id,
plan_id=pro_plan.id,
payment_provider=PaymentProvider.STRIPE.value,
trial_days=14
)
print(f"✓ 创建订阅: {subscription.id}")
print(f" - 状态: {subscription.status}")
print(f" - 计划: {pro_plan.name}")
print(f" - 试用开始: {subscription.trial_start}")
print(f" - 试用结束: {subscription.trial_end}")
# 获取租户订阅
tenant_sub = manager.get_tenant_subscription(tenant_id)
assert tenant_sub is not None, "应该能获取到租户订阅"
print(f"✓ 获取租户订阅: {tenant_sub.id}")
print("\n3. 测试用量记录")
print("-" * 40)
# 记录转录用量
usage1 = manager.record_usage(
tenant_id=tenant_id,
resource_type="transcription",
quantity=120,
unit="minute",
description="会议转录"
)
print(f"✓ 记录转录用量: {usage1.quantity} {usage1.unit}, 费用: ¥{usage1.cost:.2f}")
# 记录存储用量
usage2 = manager.record_usage(
tenant_id=tenant_id,
resource_type="storage",
quantity=2.5,
unit="gb",
description="文件存储"
)
print(f"✓ 记录存储用量: {usage2.quantity} {usage2.unit}, 费用: ¥{usage2.cost:.2f}")
# 获取用量汇总
summary = manager.get_usage_summary(tenant_id)
print(f"✓ 用量汇总:")
print(f" - 总费用: ¥{summary['total_cost']:.2f}")
for resource, data in summary['breakdown'].items():
print(f" - {resource}: {data['quantity']}{data['cost']:.2f})")
print("\n4. 测试支付管理")
print("-" * 40)
# 创建支付
payment = manager.create_payment(
tenant_id=tenant_id,
amount=99.0,
currency="CNY",
provider=PaymentProvider.ALIPAY.value,
payment_method="qrcode"
)
print(f"✓ 创建支付: {payment.id}")
print(f" - 金额: ¥{payment.amount}")
print(f" - 提供商: {payment.provider}")
print(f" - 状态: {payment.status}")
# 确认支付
confirmed = manager.confirm_payment(payment.id, "alipay_123456")
print(f"✓ 确认支付完成: {confirmed.status}")
# 列出支付记录
payments = manager.list_payments(tenant_id)
print(f"✓ 支付记录数量: {len(payments)}")
print("\n5. 测试发票管理")
print("-" * 40)
# 列出发票
invoices = manager.list_invoices(tenant_id)
print(f"✓ 发票数量: {len(invoices)}")
if invoices:
invoice = invoices[0]
print(f" - 发票号: {invoice.invoice_number}")
print(f" - 金额: ¥{invoice.amount_due}")
print(f" - 状态: {invoice.status}")
print("\n6. 测试退款管理")
print("-" * 40)
# 申请退款
refund = manager.request_refund(
tenant_id=tenant_id,
payment_id=payment.id,
amount=50.0,
reason="服务不满意",
requested_by="user_001"
)
print(f"✓ 申请退款: {refund.id}")
print(f" - 金额: ¥{refund.amount}")
print(f" - 原因: {refund.reason}")
print(f" - 状态: {refund.status}")
# 批准退款
approved = manager.approve_refund(refund.id, "admin_001")
print(f"✓ 批准退款: {approved.status}")
# 完成退款
completed = manager.complete_refund(refund.id, "refund_123456")
print(f"✓ 完成退款: {completed.status}")
# 列出退款记录
refunds = manager.list_refunds(tenant_id)
print(f"✓ 退款记录数量: {len(refunds)}")
print("\n7. 测试账单历史")
print("-" * 40)
history = manager.get_billing_history(tenant_id)
print(f"✓ 账单历史记录数量: {len(history)}")
for h in history:
print(f" - [{h.type}] {h.description}: ¥{h.amount}")
print("\n8. 测试支付提供商集成")
print("-" * 40)
# Stripe Checkout
stripe_session = manager.create_stripe_checkout_session(
tenant_id=tenant_id,
plan_id=enterprise_plan.id,
success_url="https://example.com/success",
cancel_url="https://example.com/cancel"
)
print(f"✓ Stripe Checkout 会话: {stripe_session['session_id']}")
# 支付宝订单
alipay_order = manager.create_alipay_order(
tenant_id=tenant_id,
plan_id=pro_plan.id
)
print(f"✓ 支付宝订单: {alipay_order['order_id']}")
# 微信支付订单
wechat_order = manager.create_wechat_order(
tenant_id=tenant_id,
plan_id=pro_plan.id
)
print(f"✓ 微信支付订单: {wechat_order['order_id']}")
# Webhook 处理
webhook_result = manager.handle_webhook("stripe", {
"event_type": "checkout.session.completed",
"data": {"object": {"id": "cs_test"}}
})
print(f"✓ Webhook 处理: {webhook_result}")
print("\n9. 测试订阅变更")
print("-" * 40)
# 更改计划
changed = manager.change_plan(
subscription_id=subscription.id,
new_plan_id=enterprise_plan.id
)
print(f"✓ 更改计划: {changed.plan_id} (Enterprise)")
# 取消订阅
cancelled = manager.cancel_subscription(
subscription_id=subscription.id,
at_period_end=True
)
print(f"✓ 取消订阅: {cancelled.status}")
print(f" - 周期结束时取消: {cancelled.cancel_at_period_end}")
print("\n" + "=" * 60)
print("所有测试通过! ✓")
print("=" * 60)
finally:
# 清理临时数据库
if os.path.exists(db_path):
os.remove(db_path)
print(f"\n清理临时数据库: {db_path}")
if __name__ == "__main__":
try:
test_subscription_manager()
except Exception as e:
print(f"\n❌ 测试失败: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

View File

@@ -0,0 +1,383 @@
#!/usr/bin/env python3
"""
InsightFlow Phase 8 Task 4 测试脚本
测试 AI 能力增强功能
"""
import asyncio
import sys
import os
# Add backend directory to path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from ai_manager import (
get_ai_manager, CustomModel, TrainingSample, MultimodalAnalysis,
KnowledgeGraphRAG, SmartSummary, PredictionModel, PredictionResult,
ModelType, ModelStatus, MultimodalProvider, PredictionType
)
def test_custom_model():
"""测试自定义模型功能"""
print("\n=== 测试自定义模型 ===")
manager = get_ai_manager()
# 1. 创建自定义模型
print("1. 创建自定义模型...")
model = manager.create_custom_model(
tenant_id="tenant_001",
name="领域实体识别模型",
description="用于识别医疗领域实体的自定义模型",
model_type=ModelType.CUSTOM_NER,
training_data={
"entity_types": ["DISEASE", "SYMPTOM", "DRUG", "TREATMENT"],
"domain": "medical"
},
hyperparameters={
"epochs": 15,
"learning_rate": 0.001,
"batch_size": 32
},
created_by="user_001"
)
print(f" 创建成功: {model.id}, 状态: {model.status.value}")
# 2. 添加训练样本
print("2. 添加训练样本...")
samples = [
{
"text": "患者张三患有高血压,正在服用降压药治疗。",
"entities": [
{"start": 2, "end": 4, "label": "PERSON", "text": "张三"},
{"start": 6, "end": 9, "label": "DISEASE", "text": "高血压"},
{"start": 14, "end": 17, "label": "DRUG", "text": "降压药"}
]
},
{
"text": "李四因感冒发烧到医院就诊,医生开具了退烧药。",
"entities": [
{"start": 0, "end": 2, "label": "PERSON", "text": "李四"},
{"start": 3, "end": 5, "label": "SYMPTOM", "text": "感冒"},
{"start": 5, "end": 7, "label": "SYMPTOM", "text": "发烧"},
{"start": 21, "end": 24, "label": "DRUG", "text": "退烧药"}
]
},
{
"text": "王五接受了心脏搭桥手术,术后恢复良好。",
"entities": [
{"start": 0, "end": 2, "label": "PERSON", "text": "王五"},
{"start": 5, "end": 11, "label": "TREATMENT", "text": "心脏搭桥手术"}
]
}
]
for sample_data in samples:
sample = manager.add_training_sample(
model_id=model.id,
text=sample_data["text"],
entities=sample_data["entities"],
metadata={"source": "manual"}
)
print(f" 添加样本: {sample.id}")
# 3. 获取训练样本
print("3. 获取训练样本...")
all_samples = manager.get_training_samples(model.id)
print(f" 共有 {len(all_samples)} 个训练样本")
# 4. 列出自定义模型
print("4. 列出自定义模型...")
models = manager.list_custom_models(tenant_id="tenant_001")
print(f" 找到 {len(models)} 个模型")
for m in models:
print(f" - {m.name} ({m.model_type.value}): {m.status.value}")
return model.id
async def test_train_and_predict(model_id: str):
"""测试训练和预测"""
print("\n=== 测试模型训练和预测 ===")
manager = get_ai_manager()
# 1. 训练模型
print("1. 训练模型...")
try:
trained_model = await manager.train_custom_model(model_id)
print(f" 训练完成: {trained_model.status.value}")
print(f" 指标: {trained_model.metrics}")
except Exception as e:
print(f" 训练失败: {e}")
return
# 2. 使用模型预测
print("2. 使用模型预测...")
test_text = "赵六患有糖尿病,正在使用胰岛素治疗。"
try:
entities = await manager.predict_with_custom_model(model_id, test_text)
print(f" 输入: {test_text}")
print(f" 预测实体: {entities}")
except Exception as e:
print(f" 预测失败: {e}")
def test_prediction_models():
"""测试预测模型"""
print("\n=== 测试预测模型 ===")
manager = get_ai_manager()
# 1. 创建趋势预测模型
print("1. 创建趋势预测模型...")
trend_model = manager.create_prediction_model(
tenant_id="tenant_001",
project_id="project_001",
name="实体数量趋势预测",
prediction_type=PredictionType.TREND,
target_entity_type="PERSON",
features=["entity_count", "time_period", "document_count"],
model_config={
"algorithm": "linear_regression",
"window_size": 7
}
)
print(f" 创建成功: {trend_model.id}")
# 2. 创建异常检测模型
print("2. 创建异常检测模型...")
anomaly_model = manager.create_prediction_model(
tenant_id="tenant_001",
project_id="project_001",
name="实体增长异常检测",
prediction_type=PredictionType.ANOMALY,
target_entity_type=None,
features=["daily_growth", "weekly_growth"],
model_config={
"threshold": 2.5,
"sensitivity": "medium"
}
)
print(f" 创建成功: {anomaly_model.id}")
# 3. 列出预测模型
print("3. 列出预测模型...")
models = manager.list_prediction_models(tenant_id="tenant_001")
print(f" 找到 {len(models)} 个预测模型")
for m in models:
print(f" - {m.name} ({m.prediction_type.value})")
return trend_model.id, anomaly_model.id
async def test_predictions(trend_model_id: str, anomaly_model_id: str):
"""测试预测功能"""
print("\n=== 测试预测功能 ===")
manager = get_ai_manager()
# 1. 训练趋势预测模型
print("1. 训练趋势预测模型...")
historical_data = [
{"date": "2024-01-01", "value": 10},
{"date": "2024-01-02", "value": 12},
{"date": "2024-01-03", "value": 15},
{"date": "2024-01-04", "value": 14},
{"date": "2024-01-05", "value": 18},
{"date": "2024-01-06", "value": 20},
{"date": "2024-01-07", "value": 22}
]
trained = await manager.train_prediction_model(trend_model_id, historical_data)
print(f" 训练完成,准确率: {trained.accuracy}")
# 2. 趋势预测
print("2. 趋势预测...")
trend_result = await manager.predict(
trend_model_id,
{"historical_values": [10, 12, 15, 14, 18, 20, 22]}
)
print(f" 预测结果: {trend_result.prediction_data}")
# 3. 异常检测
print("3. 异常检测...")
anomaly_result = await manager.predict(
anomaly_model_id,
{
"value": 50,
"historical_values": [10, 12, 11, 13, 12, 14, 13]
}
)
print(f" 检测结果: {anomaly_result.prediction_data}")
def test_kg_rag():
"""测试知识图谱 RAG"""
print("\n=== 测试知识图谱 RAG ===")
manager = get_ai_manager()
# 创建 RAG 配置
print("1. 创建知识图谱 RAG 配置...")
rag = manager.create_kg_rag(
tenant_id="tenant_001",
project_id="project_001",
name="项目知识问答",
description="基于项目知识图谱的智能问答",
kg_config={
"entity_types": ["PERSON", "ORG", "PROJECT", "TECH"],
"relation_types": ["works_with", "belongs_to", "depends_on"]
},
retrieval_config={
"top_k": 5,
"similarity_threshold": 0.7,
"expand_relations": True
},
generation_config={
"temperature": 0.3,
"max_tokens": 1000,
"include_sources": True
}
)
print(f" 创建成功: {rag.id}")
# 列出 RAG 配置
print("2. 列出 RAG 配置...")
rags = manager.list_kg_rags(tenant_id="tenant_001")
print(f" 找到 {len(rags)} 个配置")
return rag.id
async def test_kg_rag_query(rag_id: str):
"""测试 RAG 查询"""
print("\n=== 测试知识图谱 RAG 查询 ===")
manager = get_ai_manager()
# 模拟项目实体和关系
project_entities = [
{"id": "e1", "name": "张三", "type": "PERSON", "definition": "项目经理"},
{"id": "e2", "name": "李四", "type": "PERSON", "definition": "技术负责人"},
{"id": "e3", "name": "Project Alpha", "type": "PROJECT", "definition": "核心产品项目"},
{"id": "e4", "name": "Kubernetes", "type": "TECH", "definition": "容器编排平台"},
{"id": "e5", "name": "TechCorp", "type": "ORG", "definition": "科技公司"}
]
project_relations = [
{"source_entity_id": "e1", "target_entity_id": "e3", "source_name": "张三", "target_name": "Project Alpha", "relation_type": "works_with", "evidence": "张三负责 Project Alpha 的管理工作"},
{"source_entity_id": "e2", "target_entity_id": "e3", "source_name": "李四", "target_name": "Project Alpha", "relation_type": "works_with", "evidence": "李四负责 Project Alpha 的技术架构"},
{"source_entity_id": "e3", "target_entity_id": "e4", "source_name": "Project Alpha", "target_name": "Kubernetes", "relation_type": "depends_on", "evidence": "项目使用 Kubernetes 进行部署"},
{"source_entity_id": "e1", "target_entity_id": "e5", "source_name": "张三", "target_name": "TechCorp", "relation_type": "belongs_to", "evidence": "张三是 TechCorp 的员工"}
]
# 执行查询
print("1. 执行 RAG 查询...")
query_text = "Project Alpha 项目有哪些人参与?使用了什么技术?"
try:
result = await manager.query_kg_rag(
rag_id=rag_id,
query=query_text,
project_entities=project_entities,
project_relations=project_relations
)
print(f" 查询: {result.query}")
print(f" 回答: {result.answer[:200]}...")
print(f" 置信度: {result.confidence}")
print(f" 来源: {len(result.sources)} 个实体")
print(f" 延迟: {result.latency_ms}ms")
except Exception as e:
print(f" 查询失败: {e}")
async def test_smart_summary():
"""测试智能摘要"""
print("\n=== 测试智能摘要 ===")
manager = get_ai_manager()
# 模拟转录文本
transcript_text = """
今天的会议主要讨论了 Project Alpha 的进展情况。张三作为项目经理,
汇报了当前的项目进度,表示已经完成了 80% 的开发工作。李四提出了
一些关于 Kubernetes 部署的问题,建议我们采用新的部署策略。
会议还讨论了下一步的工作计划,包括测试、文档编写和上线准备。
大家一致认为项目进展顺利,预计可以按时交付。
"""
content_data = {
"text": transcript_text,
"entities": [
{"name": "张三", "type": "PERSON"},
{"name": "李四", "type": "PERSON"},
{"name": "Project Alpha", "type": "PROJECT"},
{"name": "Kubernetes", "type": "TECH"}
]
}
# 生成不同类型的摘要
summary_types = ["extractive", "abstractive", "key_points"]
for summary_type in summary_types:
print(f"1. 生成 {summary_type} 类型摘要...")
try:
summary = await manager.generate_smart_summary(
tenant_id="tenant_001",
project_id="project_001",
source_type="transcript",
source_id="transcript_001",
summary_type=summary_type,
content_data=content_data
)
print(f" 摘要类型: {summary.summary_type}")
print(f" 内容: {summary.content[:150]}...")
print(f" 关键要点: {summary.key_points[:3]}")
print(f" 置信度: {summary.confidence}")
except Exception as e:
print(f" 生成失败: {e}")
async def main():
"""主测试函数"""
print("=" * 60)
print("InsightFlow Phase 8 Task 4 - AI 能力增强测试")
print("=" * 60)
try:
# 测试自定义模型
model_id = test_custom_model()
# 测试训练和预测
await test_train_and_predict(model_id)
# 测试预测模型
trend_model_id, anomaly_model_id = test_prediction_models()
# 测试预测功能
await test_predictions(trend_model_id, anomaly_model_id)
# 测试知识图谱 RAG
rag_id = test_kg_rag()
# 测试 RAG 查询
await test_kg_rag_query(rag_id)
# 测试智能摘要
await test_smart_summary()
print("\n" + "=" * 60)
print("所有测试完成!")
print("=" * 60)
except Exception as e:
print(f"\n测试失败: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -1,507 +0,0 @@
#!/usr/bin/env python3
"""
InsightFlow Phase 8 - Multi-Tenant SaaS Test Script
多租户 SaaS 架构测试脚本
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from tenant_manager import (
get_tenant_manager, TenantManager, Tenant, TenantDomain, TenantBranding,
TenantMember, TenantStatus, TenantTier, TenantRole, DomainStatus,
TenantContext
)
def test_tenant_management():
"""测试租户管理功能"""
print("=" * 60)
print("测试租户管理功能")
print("=" * 60)
# 使用测试数据库
test_db = "test_tenant.db"
if os.path.exists(test_db):
os.remove(test_db)
manager = get_tenant_manager(test_db)
# 1. 创建租户
print("\n1. 创建租户...")
try:
tenant = manager.create_tenant(
name="Test Company",
owner_id="user_001",
tier="pro",
description="A test tenant for validation",
settings={"theme": "dark"}
)
print(f" ✓ 租户创建成功: {tenant.id}")
print(f" - 名称: {tenant.name}")
print(f" - Slug: {tenant.slug}")
print(f" - 层级: {tenant.tier}")
print(f" - 状态: {tenant.status}")
print(f" - 资源限制: {tenant.resource_limits}")
except Exception as e:
print(f" ✗ 租户创建失败: {e}")
import traceback
traceback.print_exc()
return False
# 2. 获取租户
print("\n2. 获取租户...")
try:
fetched = manager.get_tenant(tenant.id)
assert fetched is not None
assert fetched.name == tenant.name
print(f" ✓ 通过 ID 获取租户成功")
fetched_by_slug = manager.get_tenant_by_slug(tenant.slug)
assert fetched_by_slug is not None
assert fetched_by_slug.id == tenant.id
print(f" ✓ 通过 Slug 获取租户成功")
except Exception as e:
print(f" ✗ 获取租户失败: {e}")
import traceback
traceback.print_exc()
return False
# 3. 更新租户
print("\n3. 更新租户...")
try:
updated = manager.update_tenant(
tenant.id,
name="Test Company Updated",
tier="enterprise"
)
assert updated is not None
assert updated.name == "Test Company Updated"
assert updated.tier == "enterprise"
print(f" ✓ 租户更新成功")
print(f" - 新名称: {updated.name}")
print(f" - 新层级: {updated.tier}")
except Exception as e:
print(f" ✗ 租户更新失败: {e}")
import traceback
traceback.print_exc()
return False
# 4. 列出租户
print("\n4. 列出租户...")
try:
tenants = manager.list_tenants()
assert len(tenants) >= 1
print(f" ✓ 列出租户成功,共 {len(tenants)} 个租户")
except Exception as e:
print(f" ✗ 列出租户失败: {e}")
return False
return tenant.id
def test_domain_management(tenant_id: str):
"""测试域名管理功能"""
print("\n" + "=" * 60)
print("测试域名管理功能")
print("=" * 60)
manager = get_tenant_manager("test_tenant.db")
# 1. 添加域名
print("\n1. 添加自定义域名...")
try:
domain = manager.add_domain(tenant_id, "app.example.com", is_primary=True)
print(f" ✓ 域名添加成功: {domain.id}")
print(f" - 域名: {domain.domain}")
print(f" - 状态: {domain.status}")
print(f" - 验证令牌: {domain.verification_token}")
print(f" - 是否主域名: {domain.is_primary}")
except Exception as e:
print(f" ✗ 域名添加失败: {e}")
import traceback
traceback.print_exc()
return False
# 2. 获取域名验证指导
print("\n2. 获取域名验证指导...")
try:
instructions = manager.get_domain_verification_instructions(domain.id)
assert instructions is not None
print(f" ✓ 获取验证指导成功")
print(f" - DNS 记录: {instructions['dns_record']}")
except Exception as e:
print(f" ✗ 获取验证指导失败: {e}")
return False
# 3. 验证域名
print("\n3. 验证域名...")
try:
success = manager.verify_domain(tenant_id, domain.id)
if success:
print(f" ✓ 域名验证成功")
else:
print(f" ! 域名验证返回 False可能是模拟验证")
except Exception as e:
print(f" ✗ 域名验证失败: {e}")
return False
# 4. 获取域名列表
print("\n4. 获取域名列表...")
try:
domains = manager.list_domains(tenant_id)
assert len(domains) >= 1
print(f" ✓ 获取域名列表成功,共 {len(domains)} 个域名")
for d in domains:
print(f" - {d.domain} ({d.status})")
except Exception as e:
print(f" ✗ 获取域名列表失败: {e}")
return False
# 5. 通过域名获取租户
print("\n5. 通过域名解析租户...")
try:
resolved = manager.get_tenant_by_domain("app.example.com")
if resolved:
assert resolved.id == tenant_id
print(f" ✓ 域名解析租户成功")
else:
print(f" ! 域名解析租户返回 None可能域名未激活")
except Exception as e:
print(f" ✗ 域名解析失败: {e}")
return False
return True
def test_branding_management(tenant_id: str):
"""测试品牌配置管理功能"""
print("\n" + "=" * 60)
print("测试品牌配置管理功能")
print("=" * 60)
manager = get_tenant_manager("test_tenant.db")
# 1. 更新品牌配置
print("\n1. 更新品牌配置...")
try:
branding = manager.update_branding(
tenant_id,
logo_url="https://example.com/logo.png",
favicon_url="https://example.com/favicon.ico",
primary_color="#FF5733",
secondary_color="#33FF57",
custom_css="body { font-size: 14px; }",
custom_js="console.log('Custom JS loaded');"
)
assert branding is not None
print(f" ✓ 品牌配置更新成功")
print(f" - Logo: {branding.logo_url}")
print(f" - 主色调: {branding.primary_color}")
print(f" - 次色调: {branding.secondary_color}")
except Exception as e:
print(f" ✗ 品牌配置更新失败: {e}")
import traceback
traceback.print_exc()
return False
# 2. 获取品牌配置
print("\n2. 获取品牌配置...")
try:
fetched = manager.get_branding(tenant_id)
assert fetched is not None
assert fetched.primary_color == "#FF5733"
print(f" ✓ 获取品牌配置成功")
except Exception as e:
print(f" ✗ 获取品牌配置失败: {e}")
return False
# 3. 生成品牌 CSS
print("\n3. 生成品牌 CSS...")
try:
css = manager.get_branding_css(tenant_id)
assert "--tenant-primary" in css
assert "#FF5733" in css
print(f" ✓ 品牌 CSS 生成成功")
print(f" - CSS 长度: {len(css)} 字符")
except Exception as e:
print(f" ✗ 品牌 CSS 生成失败: {e}")
return False
return True
def test_member_management(tenant_id: str):
"""测试成员管理功能"""
print("\n" + "=" * 60)
print("测试成员管理功能")
print("=" * 60)
manager = get_tenant_manager("test_tenant.db")
# 1. 邀请成员
print("\n1. 邀请成员...")
try:
member = manager.invite_member(
tenant_id=tenant_id,
email="user@example.com",
role="admin",
invited_by="user_001"
)
print(f" ✓ 成员邀请成功: {member.id}")
print(f" - 邮箱: {member.email}")
print(f" - 角色: {member.role}")
print(f" - 状态: {member.status}")
print(f" - 权限: {member.permissions}")
except Exception as e:
print(f" ✗ 成员邀请失败: {e}")
import traceback
traceback.print_exc()
return False
# 2. 获取成员列表
print("\n2. 获取成员列表...")
try:
members = manager.list_members(tenant_id)
assert len(members) >= 2 # owner + invited member
print(f" ✓ 获取成员列表成功,共 {len(members)} 个成员")
for m in members:
print(f" - {m.email} ({m.role}, {m.status})")
except Exception as e:
print(f" ✗ 获取成员列表失败: {e}")
return False
# 3. 接受邀请
print("\n3. 接受邀请...")
try:
# 注意accept_invitation 使用的是 member id 而不是 token
# 修正:查看源码后发现它接受的是 invitation_id即 member id
accepted = manager.accept_invitation(member.id, "user_002")
if accepted:
print(f" ✓ 邀请接受成功")
else:
print(f" ! 邀请接受返回 False可能是状态不对")
except Exception as e:
print(f" ✗ 邀请接受失败: {e}")
import traceback
traceback.print_exc()
return False
# 4. 更新成员角色
print("\n4. 更新成员角色...")
try:
success = manager.update_member_role(
tenant_id=tenant_id,
member_id=member.id,
role="member"
)
if success:
print(f" ✓ 成员角色更新成功")
else:
print(f" ! 成员角色更新返回 False")
except Exception as e:
print(f" ✗ 成员角色更新失败: {e}")
import traceback
traceback.print_exc()
return False
# 5. 检查权限
print("\n5. 检查用户权限...")
try:
# 检查 owner 权限
has_permission = manager.check_permission(
tenant_id=tenant_id,
user_id="user_001",
resource="project",
action="create"
)
print(f" ✓ 权限检查成功")
print(f" - Owner 是否有 project:create 权限: {has_permission}")
except Exception as e:
print(f" ✗ 权限检查失败: {e}")
return False
# 6. 获取用户租户列表
print("\n6. 获取用户租户列表...")
try:
user_tenants = manager.get_user_tenants("user_001")
assert len(user_tenants) >= 1
print(f" ✓ 获取用户租户列表成功,共 {len(user_tenants)} 个租户")
except Exception as e:
print(f" ✗ 获取用户租户列表失败: {e}")
return False
return True
def test_usage_stats(tenant_id: str):
"""测试使用统计功能"""
print("\n" + "=" * 60)
print("测试使用统计功能")
print("=" * 60)
manager = get_tenant_manager("test_tenant.db")
# 1. 记录使用
print("\n1. 记录资源使用...")
try:
manager.record_usage(
tenant_id=tenant_id,
storage_bytes=1024 * 1024 * 50, # 50MB
transcription_seconds=600, # 10分钟
api_calls=100,
projects_count=5,
entities_count=50,
members_count=3
)
print(f" ✓ 资源使用记录成功")
except Exception as e:
print(f" ✗ 资源使用记录失败: {e}")
import traceback
traceback.print_exc()
return False
# 2. 获取使用统计
print("\n2. 获取使用统计...")
try:
stats = manager.get_usage_stats(tenant_id)
print(f" ✓ 使用统计获取成功")
print(f" - 存储: {stats['storage_mb']:.2f} MB")
print(f" - 转录: {stats['transcription_minutes']:.2f} 分钟")
print(f" - API 调用: {stats['api_calls']}")
print(f" - 项目数: {stats['projects_count']}")
print(f" - 实体数: {stats['entities_count']}")
print(f" - 成员数: {stats['members_count']}")
print(f" - 配额: {stats['limits']}")
except Exception as e:
print(f" ✗ 使用统计获取失败: {e}")
import traceback
traceback.print_exc()
return False
# 3. 检查资源限制
print("\n3. 检查资源限制...")
try:
allowed, current, limit = manager.check_resource_limit(tenant_id, "storage")
print(f" ✓ 资源限制检查成功")
print(f" - 存储: {allowed}, 当前: {current}, 限制: {limit}")
except Exception as e:
print(f" ✗ 资源限制检查失败: {e}")
import traceback
traceback.print_exc()
return False
return True
def test_tenant_context():
"""测试租户上下文管理"""
print("\n" + "=" * 60)
print("测试租户上下文管理")
print("=" * 60)
# 1. 设置和获取租户上下文
print("\n1. 设置和获取租户上下文...")
try:
TenantContext.set_current_tenant("tenant_123")
tenant_id = TenantContext.get_current_tenant()
assert tenant_id == "tenant_123"
print(f" ✓ 租户上下文设置成功: {tenant_id}")
except Exception as e:
print(f" ✗ 租户上下文设置失败: {e}")
return False
# 2. 设置和获取用户上下文
print("\n2. 设置和获取用户上下文...")
try:
TenantContext.set_current_user("user_456")
user_id = TenantContext.get_current_user()
assert user_id == "user_456"
print(f" ✓ 用户上下文设置成功: {user_id}")
except Exception as e:
print(f" ✗ 用户上下文设置失败: {e}")
return False
# 3. 清除上下文
print("\n3. 清除上下文...")
try:
TenantContext.clear()
assert TenantContext.get_current_tenant() is None
assert TenantContext.get_current_user() is None
print(f" ✓ 上下文清除成功")
except Exception as e:
print(f" ✗ 上下文清除失败: {e}")
return False
return True
def cleanup():
"""清理测试数据"""
print("\n" + "=" * 60)
print("清理测试数据")
print("=" * 60)
test_db = "test_tenant.db"
if os.path.exists(test_db):
os.remove(test_db)
print(f"✓ 删除测试数据库: {test_db}")
def main():
"""主测试函数"""
print("\n" + "=" * 60)
print("InsightFlow Phase 8 - Multi-Tenant SaaS 测试")
print("=" * 60)
all_passed = True
tenant_id = None
try:
# 测试租户上下文
if not test_tenant_context():
all_passed = False
# 测试租户管理
tenant_id = test_tenant_management()
if not tenant_id:
all_passed = False
# 测试域名管理
if not test_domain_management(tenant_id):
all_passed = False
# 测试品牌配置
if not test_branding_management(tenant_id):
all_passed = False
# 测试成员管理
if not test_member_management(tenant_id):
all_passed = False
# 测试使用统计
if not test_usage_stats(tenant_id):
all_passed = False
except Exception as e:
print(f"\n测试过程中发生错误: {e}")
import traceback
traceback.print_exc()
all_passed = False
finally:
cleanup()
print("\n" + "=" * 60)
if all_passed:
print("✓ 所有测试通过!")
else:
print("✗ 部分测试失败")
print("=" * 60)
return 0 if all_passed else 1
if __name__ == "__main__":
sys.exit(main())