修复无法选择供应商问题
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
/backend/.idea
|
||||
/bin
|
||||
.aider*
|
||||
|
||||
@@ -504,7 +504,6 @@ func (h *APIHandler) ClearRequestLogsHandler(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
|
||||
// GetLogCleanerStatusHandler 获取日志清理器状态
|
||||
func (h *APIHandler) GetLogCleanerStatusHandler(c *gin.Context) {
|
||||
if h.LogCleaner == nil {
|
||||
@@ -556,7 +555,6 @@ func (h *APIHandler) ForceLogCleanupHandler(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// ============ API Key 管理相关处理器 ============
|
||||
|
||||
// APIKeyListResponse API Key列表响应
|
||||
|
||||
@@ -77,20 +77,10 @@ func (h *APIHandler) ChatCompletions(c *gin.Context) {
|
||||
if messagesRaw, ok := jsonBody["messages"].([]interface{}); ok {
|
||||
for _, msgRaw := range messagesRaw {
|
||||
if msgMap, ok := msgRaw.(map[string]interface{}); ok {
|
||||
if reasoning, exists := msgMap["reasoning"]; exists {
|
||||
// 如果 reasoning 是对象,提取 content 字段作为字符串
|
||||
if reasoningMap, ok := reasoning.(map[string]interface{}); ok {
|
||||
if reasoningContent, ok := reasoningMap["content"].(string); ok {
|
||||
msgMap["reasoning"] = reasoningContent
|
||||
} else {
|
||||
// 如果无法提取 content,移除 reasoning 字段
|
||||
delete(msgMap, "reasoning")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取 messages 并转换为计算 token 所需的格式
|
||||
var messages []billing.ChatCompletionMessage
|
||||
@@ -138,8 +128,11 @@ func (h *APIHandler) ChatCompletions(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("接收到请求, 开始使用 %s 请求后端, 请求处理花费: %v", backendModel.Name, time.Since(requestTimestamp))
|
||||
|
||||
// 构建后端API URL
|
||||
backendURL := backendModel.Provider.BaseURL + "/v1/chat/completions"
|
||||
forwardRequestTimestamp := time.Now()
|
||||
|
||||
// 转发请求到后端
|
||||
resp, err := forwardRequest(backendURL, backendModel.Provider.ApiKey, requestBody, c.GetHeader("User-Agent"))
|
||||
@@ -156,15 +149,19 @@ func (h *APIHandler) ChatCompletions(c *gin.Context) {
|
||||
|
||||
// 记录响应时间
|
||||
responseTimestamp := time.Now()
|
||||
log.Printf("后端模型已经回应: %s, 后端响应时间: %v", backendModel.Name, time.Since(forwardRequestTimestamp))
|
||||
|
||||
// 获取API Key ID
|
||||
apiKeyID := getAPIKeyID(c)
|
||||
|
||||
// 处理流式响应
|
||||
if isStream {
|
||||
streamTimestamp := time.Now()
|
||||
log.Printf("后端模型开始流送: %s", backendModel.Name)
|
||||
handleStreamingResponse(c, resp, requestTimestamp, responseTimestamp,
|
||||
apiKeyID, modelName, backendModel, requestTokenCount,
|
||||
string(requestBody), h.DB)
|
||||
log.Printf("流送请求处理完成, 模型: %s, 流送处理时间: %v", backendModel.Name, time.Since(streamTimestamp))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -180,9 +177,6 @@ func (h *APIHandler) ChatCompletions(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Backend Response Status: %s", resp.Status)
|
||||
log.Printf("Backend Response Body: %s", string(responseBody))
|
||||
|
||||
// 计算响应token数
|
||||
responseTokenCount := extractResponseTokenCount(responseBody)
|
||||
|
||||
@@ -196,6 +190,9 @@ func (h *APIHandler) ChatCompletions(c *gin.Context) {
|
||||
cost, string(requestBody), string(responseBody))
|
||||
logger.LogRequest(h.DB, logEntry)
|
||||
|
||||
// 记录处理时间
|
||||
log.Printf("请求处理完成, 模型: %s, 总时间: %v", backendModel.Name, time.Since(requestTimestamp))
|
||||
|
||||
// 复制响应头并返回响应
|
||||
copyResponseHeaders(c, resp)
|
||||
c.Status(resp.StatusCode)
|
||||
@@ -225,25 +222,6 @@ func (h *APIHandler) ResponsesCompletions(c *gin.Context) {
|
||||
// 从 map 中提取需要的字段
|
||||
modelName, _ := jsonBody["model"].(string)
|
||||
|
||||
// 处理 input 中的 reasoning 字段,将对象转换为字符串
|
||||
if inputRaw, ok := jsonBody["input"].([]interface{}); ok {
|
||||
for _, msgRaw := range inputRaw {
|
||||
if msgMap, ok := msgRaw.(map[string]interface{}); ok {
|
||||
if reasoning, exists := msgMap["reasoning"]; exists {
|
||||
// 如果 reasoning 是对象,提取 content 字段作为字符串
|
||||
if reasoningMap, ok := reasoning.(map[string]interface{}); ok {
|
||||
if reasoningContent, ok := reasoningMap["content"].(string); ok {
|
||||
msgMap["reasoning"] = reasoningContent
|
||||
} else {
|
||||
// 如果无法提取 content,移除 reasoning 字段
|
||||
delete(msgMap, "reasoning")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取 input 并转换为计算 token 所需的格式
|
||||
var messages []billing.ChatCompletionMessage
|
||||
if inputRaw, ok := jsonBody["input"].([]interface{}); ok {
|
||||
@@ -290,6 +268,8 @@ func (h *APIHandler) ResponsesCompletions(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("接收到请求, 开始使用: %s", backendModel.Name)
|
||||
|
||||
// 构建后端API URL
|
||||
backendURL := backendModel.Provider.BaseURL + "/v1/responses"
|
||||
|
||||
@@ -308,6 +288,7 @@ func (h *APIHandler) ResponsesCompletions(c *gin.Context) {
|
||||
|
||||
// 记录响应时间
|
||||
responseTimestamp := time.Now()
|
||||
log.Printf("后端模型已经回应: %s, 后端响应时间: %v", backendModel.Name, responseTimestamp.Sub(requestTimestamp))
|
||||
|
||||
// 读取响应体
|
||||
responseBody, err := io.ReadAll(resp.Body)
|
||||
@@ -337,6 +318,10 @@ func (h *APIHandler) ResponsesCompletions(c *gin.Context) {
|
||||
cost, string(requestBody), string(responseBody))
|
||||
logger.LogRequest(h.DB, logEntry)
|
||||
|
||||
// 记录处理时间
|
||||
processingTime := responseTimestamp.Sub(requestTimestamp)
|
||||
log.Printf("请求处理完成, 模型: %s, 处理时间: %v", backendModel.Name, processingTime)
|
||||
|
||||
// 复制响应头并返回响应
|
||||
copyResponseHeaders(c, resp)
|
||||
c.Status(resp.StatusCode)
|
||||
@@ -419,6 +404,8 @@ func (h *APIHandler) Embeddings(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("接收到请求, 开始使用: %s", backendModel.Name)
|
||||
|
||||
// 构建后端API URL
|
||||
backendURL := backendModel.Provider.BaseURL + "/v1/embeddings"
|
||||
|
||||
@@ -437,6 +424,7 @@ func (h *APIHandler) Embeddings(c *gin.Context) {
|
||||
|
||||
// 记录响应时间
|
||||
responseTimestamp := time.Now()
|
||||
log.Printf("后端模型已经回应: %s, 后端响应时间: %v", backendModel.Name, responseTimestamp.Sub(requestTimestamp))
|
||||
|
||||
// 读取响应体
|
||||
responseBody, err := io.ReadAll(resp.Body)
|
||||
@@ -450,9 +438,6 @@ func (h *APIHandler) Embeddings(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Backend Response Status: %s", resp.Status)
|
||||
log.Printf("Backend Response Body: %s", string(responseBody))
|
||||
|
||||
// 从响应中提取 token 使用量
|
||||
responseTokenCount := extractEmbeddingsTokenCount(responseBody, requestTokenCount)
|
||||
|
||||
@@ -469,6 +454,10 @@ func (h *APIHandler) Embeddings(c *gin.Context) {
|
||||
cost, string(requestBody), string(responseBody))
|
||||
logger.LogRequest(h.DB, logEntry)
|
||||
|
||||
// 记录处理时间
|
||||
processingTime := responseTimestamp.Sub(requestTimestamp)
|
||||
log.Printf("请求处理完成, 模型: %s, 处理时间: %v", backendModel.Name, processingTime)
|
||||
|
||||
// 复制响应头并返回响应
|
||||
copyResponseHeaders(c, resp)
|
||||
c.Status(resp.StatusCode)
|
||||
|
||||
@@ -41,6 +41,7 @@ type AppConfig struct {
|
||||
Version string `json:"version"`
|
||||
Environment string `json:"environment"`
|
||||
LogLevel string `json:"log_level"`
|
||||
LogInDB bool `json:"log_in_db"`
|
||||
}
|
||||
|
||||
// DefaultConfig 默认配置
|
||||
|
||||
@@ -7,11 +7,21 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var saveRequestLog = false
|
||||
|
||||
// LogRequest 异步记录API请求日志
|
||||
func LogRequest(db *gorm.DB, logEntry *models.RequestLog) {
|
||||
if !saveRequestLog {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := db.Create(logEntry).Error; err != nil {
|
||||
log.Printf("Failed to save request log: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func SetSaveRequestLog(save bool) {
|
||||
saveRequestLog = save
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"ai-gateway/api"
|
||||
"ai-gateway/internal/config"
|
||||
"ai-gateway/internal/db"
|
||||
"ai-gateway/internal/logger"
|
||||
"ai-gateway/internal/middleware"
|
||||
"ai-gateway/internal/scheduler"
|
||||
"log"
|
||||
@@ -28,6 +29,8 @@ func main() {
|
||||
cfg = config.DefaultConfig()
|
||||
}
|
||||
|
||||
logger.SetSaveRequestLog(cfg.App.LogInDB)
|
||||
|
||||
// 初始化数据库连接(使用固定数据库路径)
|
||||
database, err := db.InitDB(config.DatabasePath)
|
||||
if err != nil {
|
||||
|
||||
@@ -41,9 +41,12 @@ const VirtualModelForm = ({ model, onSave, onCancel }) => {
|
||||
}, [model]);
|
||||
|
||||
const handleBackendModelChange = (index, field, value) => {
|
||||
const newBackendModels = [...backendModels];
|
||||
// 使用函数式setState来确保获取最新的状态
|
||||
setBackendModels(prevModels => {
|
||||
const newBackendModels = [...prevModels];
|
||||
newBackendModels[index] = { ...newBackendModels[index], [field]: value };
|
||||
setBackendModels(newBackendModels);
|
||||
return newBackendModels;
|
||||
});
|
||||
};
|
||||
|
||||
const addBackendModel = () => {
|
||||
|
||||
@@ -12,7 +12,7 @@ export default defineConfig({
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8080', // 后端服务器地址
|
||||
// target: 'http://10.1.39.104:9130',
|
||||
// target: 'http://82.156.222.20:6233',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user