package app import ( "net/http" "git.echol.cn/loser/ai_proxy/server/global" "git.echol.cn/loser/ai_proxy/server/model/app" "git.echol.cn/loser/ai_proxy/server/model/app/request" "git.echol.cn/loser/ai_proxy/server/model/common/response" "git.echol.cn/loser/ai_proxy/server/service" "github.com/gin-gonic/gin" "go.uber.org/zap" ) type AiProxyApi struct{} var aiProxyService = service.ServiceGroupApp.AppServiceGroup.AiProxyService var aiApiKeyService = service.ServiceGroupApp.AppServiceGroup.AiApiKeyService // ChatCompletions OpenAI兼容的聊天补全接口 // @Tags AiProxy // @Summary 聊天补全(OpenAI兼容) // @accept application/json // @Produce application/json // @Param data body request.ChatCompletionRequest true "聊天请求" // @Success 200 {object} response.ChatCompletionResponse "聊天响应" // @Router /v1/chat/completions [post] func (a *AiProxyApi) ChatCompletions(c *gin.Context) { var req request.ChatCompletionRequest err := c.ShouldBindJSON(&req) if err != nil { response.FailWithMessage(err.Error(), c) return } // 获取 API Key 信息 apiKeyInfo, exists := c.Get("ai_api_key") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未找到API密钥信息"}) return } apiKey := apiKeyInfo.(*app.AiApiKey) // 验证模型权限 if req.Model != "" && !aiApiKeyService.CheckModelPermission(apiKey, req.Model) { c.JSON(http.StatusForbidden, gin.H{ "error": gin.H{ "message": "该API密钥无权使用此模型: " + req.Model, "type": "invalid_request_error", "code": "model_not_allowed", }, }) return } // 处理流式响应 if req.Stream { aiProxyService.ProcessChatCompletionStream(c, &req) return } // 处理普通响应 resp, err := aiProxyService.ProcessChatCompletion(c.Request.Context(), &req) if err != nil { global.GVA_LOG.Error("处理聊天请求失败!", zap.Error(err)) response.FailWithMessage(err.Error(), c) return } c.JSON(200, resp) } // ListModels 获取可用模型列表 // @Tags AiProxy // @Summary 获取可用模型列表(OpenAI兼容) // @accept application/json // @Produce application/json // @Success 200 {object} response.ModelListResponse "模型列表" // @Router /v1/models [get] func (a *AiProxyApi) ListModels(c *gin.Context) { // 获取 API Key 信息 apiKeyInfo, exists := c.Get("ai_api_key") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未找到API密钥信息"}) return } apiKey := apiKeyInfo.(*app.AiApiKey) // 获取可用模型列表 models, err := aiProxyService.GetAvailableModels(apiKey) if err != nil { global.GVA_LOG.Error("获取模型列表失败!", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(200, models) } // ClaudeMessages Claude API兼容的消息接口 // @Tags AiProxy // @Summary 消息接口(Claude兼容) // @accept application/json // @Produce application/json // @Param data body request.ClaudeMessageRequest true "消息请求" // @Success 200 {object} response.ClaudeMessageResponse "消息响应" // @Router /v1/messages [post] func (a *AiProxyApi) ClaudeMessages(c *gin.Context) { var req request.ClaudeMessageRequest err := c.ShouldBindJSON(&req) if err != nil { response.FailWithMessage(err.Error(), c) return } // 获取 API Key 信息 apiKeyInfo, exists := c.Get("ai_api_key") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未找到API密钥信息"}) return } apiKey := apiKeyInfo.(*app.AiApiKey) // 验证模型权限 if req.Model != "" && !aiApiKeyService.CheckModelPermission(apiKey, req.Model) { c.JSON(http.StatusForbidden, gin.H{ "error": gin.H{ "message": "该API密钥无权使用此模型: " + req.Model, "type": "invalid_request_error", "code": "model_not_allowed", }, }) return } // 处理流式响应 if req.Stream { aiProxyService.ProcessClaudeMessageStream(c, &req) return } // 处理普通响应 resp, err := aiProxyService.ProcessClaudeMessage(c.Request.Context(), &req) if err != nil { global.GVA_LOG.Error("处理Claude消息请求失败!", zap.Error(err)) response.FailWithMessage(err.Error(), c) return } c.JSON(200, resp) }