🎨 优化模型配置 && 新增apikey功能 && 完善通用接口
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
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"
|
||||
"git.echol.cn/loser/ai_proxy/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -13,11 +15,11 @@ import (
|
||||
type AiProxyApi struct{}
|
||||
|
||||
var aiProxyService = service.ServiceGroupApp.AppServiceGroup.AiProxyService
|
||||
var aiApiKeyService = service.ServiceGroupApp.AppServiceGroup.AiApiKeyService
|
||||
|
||||
// ChatCompletions OpenAI兼容的聊天补全接口
|
||||
// @Tags AiProxy
|
||||
// @Summary 聊天补全(OpenAI兼容)
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Param data body request.ChatCompletionRequest true "聊天请求"
|
||||
@@ -31,16 +33,46 @@ func (a *AiProxyApi) ChatCompletions(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
userId := utils.GetUserID(c)
|
||||
// 获取 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.PresetName != "" && !aiApiKeyService.CheckPresetPermission(apiKey, req.PresetName) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": gin.H{
|
||||
"message": "该API密钥无权使用此预设: " + req.PresetName,
|
||||
"type": "invalid_request_error",
|
||||
"code": "preset_not_allowed",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 处理流式响应
|
||||
if req.Stream {
|
||||
aiProxyService.ProcessChatCompletionStream(c, userId, &req)
|
||||
aiProxyService.ProcessChatCompletionStream(c, &req)
|
||||
return
|
||||
}
|
||||
|
||||
// 处理普通响应
|
||||
resp, err := aiProxyService.ProcessChatCompletion(c.Request.Context(), userId, &req)
|
||||
resp, err := aiProxyService.ProcessChatCompletion(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("处理聊天请求失败!", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
@@ -49,3 +81,95 @@ func (a *AiProxyApi) ChatCompletions(c *gin.Context) {
|
||||
|
||||
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.PresetName != "" && !aiApiKeyService.CheckPresetPermission(apiKey, req.PresetName) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": gin.H{
|
||||
"message": "该API密钥无权使用此预设: " + req.PresetName,
|
||||
"type": "invalid_request_error",
|
||||
"code": "preset_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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user