# 多厂商AI API适配器设计方案 ## 📋 目标 支持接入多个AI服务提供商,包括: 1. **OpenAI格式API**(当前使用的api.apiyi.com) 2. **RunningHub API** 3. 未来的其他厂商 ## 🏗️ 架构设计 ``` ┌─────────────────────────────────────────────────────────┐ │ AiTaskService │ │ (业务逻辑层,不变) │ └────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ AIProviderService (新增) │ │ 根据模型配置选择对应的Provider │ └────────────────────┬────────────────────────────────────┘ │ ┌───────────┴───────────┐ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ OpenAIProvider │ │ RunningHubProvider│ │ (适配器1) │ │ (适配器2) │ └──────────────────┘ └──────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ api.apiyi.com │ │ www.runninghub.cn│ │ (第三方API) │ │ (第三方API) │ └──────────────────┘ └──────────────────┘ ``` ## 📝 实现步骤 ### 1. 定义统一的Provider接口 ```java public interface AIProvider { /** * 提交任务到AI服务商 * @return 统一的任务响应对象 */ ProviderTaskResponse submitTask(ProviderTaskRequest request); /** * 查询任务状态 */ ProviderTaskStatus queryTaskStatus(String providerTaskId); /** * 获取任务结果 */ ProviderTaskResult getTaskResult(String providerTaskId); /** * 获取服务商名称 */ String getProviderName(); } ``` ### 2. 扩展数据库表 #### points_config表新增字段 ```sql ALTER TABLE `points_config` ADD COLUMN `provider_type` VARCHAR(50) NOT NULL DEFAULT 'openai' COMMENT 'AI服务提供商类型:openai, runninghub', ADD COLUMN `provider_config` TEXT NULL COMMENT '服务商特定配置(JSON格式)'; ``` #### ai_task表新增字段 ```sql ALTER TABLE `ai_task` ADD COLUMN `provider_type` VARCHAR(50) NULL COMMENT 'AI服务提供商类型', ADD COLUMN `provider_task_id` VARCHAR(100) NULL COMMENT '服务商返回的任务ID', ADD COLUMN `provider_response` TEXT NULL COMMENT '服务商原始响应(JSON)'; ``` ### 3. 配置文件扩展 ```yaml # application.yml ai: providers: openai: enabled: true base-url: https://api.apiyi.com/v1/chat/completions api-key: sk-xxx timeout: 300000 runninghub: enabled: true base-url: https://www.runninghub.cn submit-url: /task/openapi/ai-app/run status-url: /task/openapi/status output-url: /task/openapi/outputs default-webapp-id: "1973555977595301890" api-key: 5c44cef12da3470e9f24da70c63787dc polling-interval: 5000 # 轮询间隔(毫秒) max-polling-times: 120 # 最大轮询次数(10分钟) ``` ## 🔧 RunningHub特殊处理 ### 模型映射配置 在`points_config`表中配置RunningHub模型: ```sql INSERT INTO `points_config` (model_name, points_cost, description, is_enabled, provider_type, provider_config) VALUES ('rh_sora2_portrait', 160, 'RunningHub Sora2 竖屏视频', 1, 'runninghub', '{"webappId":"1973555977595301890","duration":10,"model":"portrait"}'), ('rh_sora2_landscape', 160, 'RunningHub Sora2 横屏视频', 1, 'runninghub', '{"webappId":"1973555977595301890","duration":10,"model":"landscape"}'), ('rh_sora2_portrait_hd', 420, 'RunningHub Sora2 高清竖屏', 1, 'runninghub', '{"webappId":"1973555977595301890","duration":10,"model":"portrait-hd"}'); ``` ### 异步任务处理流程 RunningHub是异步API,需要特殊处理: ``` 1. 提交任务 → 获得taskId 2. 更新数据库:provider_task_id = taskId, status = 'processing' 3. 启动轮询任务: - 每5秒查询一次状态 - RUNNING → 继续轮询 - SUCCESS → 获取结果 → 更新status='completed' - FAILED → 更新status='failed' - 超时 → 更新status='failed' ``` ## 📦 核心类设计 ### ProviderTaskRequest(统一请求) ```java @Data public class ProviderTaskRequest { private String modelName; private String prompt; private String imageUrl; private String imageBase64; private String aspectRatio; private Integer duration; // 视频时长 private Map extraParams; // 扩展参数 } ``` ### ProviderTaskResponse(统一响应) ```java @Data public class ProviderTaskResponse { private String providerTaskId; // 服务商任务ID private TaskSubmitStatus status; // SUBMITTED, PROCESSING, COMPLETED, FAILED private String resultUrl; // 如果是同步返回,直接有结果 private String errorMessage; private Map rawResponse; // 原始响应 } ``` ### RunningHubNodeInfo(RunningHub请求节点) ```java @Data public class RunningHubNodeInfo { private String nodeId; private String fieldName; private String fieldValue; private String fieldData; // 可选 private String description; } ``` ## 🔄 任务轮询设计 ### 新增定时任务 ```java @Scheduled(fixedDelay = 5000) // 每5秒执行一次 public void pollAsyncTasks() { // 1. 查询所有 status='processing' 且 provider_type='runninghub' 的任务 // 2. 对每个任务调用 queryTaskStatus // 3. 根据状态更新数据库 // 4. 如果完成,调用 getTaskResult 获取结果 } ``` ## 📊 数据流转 ### OpenAI格式(同步) ``` 用户提交 → OpenAIProvider.submitTask() → 直接返回结果URL → 更新status='completed' ``` ### RunningHub格式(异步) ``` 用户提交 → RunningHubProvider.submitTask() → 返回taskId,status='RUNNING' → 定时任务轮询 → 检测到SUCCESS → getTaskResult()获取结果URL → 更新status='completed' ``` ## ⚠️ 注意事项 1. **配置隔离**:不同厂商的配置独立管理 2. **错误处理**:统一异常类型,便于业务层处理 3. **日志记录**:记录每次API调用的原始请求和响应 4. **超时控制**:异步任务需要设置最大轮询次数 5. **并发控制**:轮询任务需要考虑并发和限流 6. **配置热更新**:支持动态切换服务商 ## 🎯 优势 1. ✅ **扩展性**:新增厂商只需实现AIProvider接口 2. ✅ **解耦**:业务层无需关心底层API差异 3. ✅ **灵活性**:同一个模型类型可以配置多个厂商 4. ✅ **可维护性**:每个厂商的逻辑独立封装 5. ✅ **容错性**:某个厂商故障不影响其他厂商 ## 📈 未来扩展 - 支持厂商负载均衡 - 支持厂商降级和熔断 - 支持厂商价格对比和智能选择 - 支持多厂商并行调用(取最快)