mirror of
https://github.com/YFGaia/dify-plus.git
synced 2026-06-04 10:14:00 +08:00
fix: 规范化处理代码
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# Admin (Go Backend) Agent Guide
|
||||
|
||||
## Rules (must follow)
|
||||
|
||||
### 禁止匿名 struct
|
||||
|
||||
- **禁止在代码中出现匿名 struct**。不得使用 `var x []struct { ... }`、`var x struct { ... }` 或字面量 `struct { A int }{1}` 等匿名结构体。
|
||||
- 所有用于 GORM 查询扫描、缓存结构、API 请求/响应的结构体必须定义为**具名类型**,放在合适的 model 包(如 `model/gaia/request`、`model/gaia/response`)或当前包顶部,便于复用和规范约束。
|
||||
- 示例:用 `[]response.AppQuotaRankingRow` 替代 `[]struct { AppID string; TotalCost float64; ... }`;用 `response.AppQuotaRankingCache` 替代 `struct { List ...; Total int64 }`。
|
||||
@@ -2,13 +2,13 @@ package gaia
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
gaiaReq "github.com/flipped-aurora/gin-vue-admin/server/model/gaia/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -31,7 +31,7 @@ func (m *ModelProviderApi) GetProviderList(c *gin.Context) {
|
||||
list, err := modelProviderService.GetProviderList()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取提供商配置列表失败", zap.Error(err))
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(list, c)
|
||||
@@ -54,20 +54,20 @@ func (m *ModelProviderApi) UpdateProviderConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage("参数错误: "+err.Error(), c)
|
||||
response.FailWithMessage("参数错误:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := modelProviderService.UpdateProviderConfig(req.ProviderName, req.Enabled, req.Models); err != nil {
|
||||
global.GVA_LOG.Error("更新提供商配置失败", zap.String("provider", req.ProviderName), zap.Error(err))
|
||||
response.FailWithMessage("更新失败: "+err.Error(), c)
|
||||
response.FailWithMessage("更新失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("更新成功", c)
|
||||
}
|
||||
|
||||
// GetModels 获取开启的模型列表(OpenAI格式)
|
||||
// GetModels 获取开启的模型列表(OpenAI 格式,供第三方兼容调用;成功时返回裸 JSON,错误时与项目统一使用 response)。
|
||||
// @Tags ModelProvider
|
||||
// @Summary 获取开启的模型列表
|
||||
// @Security ApiKeyAuth
|
||||
@@ -79,14 +79,9 @@ func (m *ModelProviderApi) GetModels(c *gin.Context) {
|
||||
models, err := modelProviderService.GetEnabledModels()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取模型列表失败", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": gin.H{
|
||||
"message": "获取模型列表失败: " + err.Error(),
|
||||
},
|
||||
})
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, models)
|
||||
}
|
||||
|
||||
@@ -161,17 +156,15 @@ func (m *ModelProviderApi) Proxy(c *gin.Context) {
|
||||
func (m *ModelProviderApi) GetAvailableModels(c *gin.Context) {
|
||||
providerName := c.Query("provider_name")
|
||||
if providerName == "" {
|
||||
response.FailWithMessage("参数错误: provider_name不能为空", c)
|
||||
response.FailWithMessage("参数错误:provider_name不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
models, err := modelProviderService.GetAvailableModelsFromDify(providerName)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取可用模型失败", zap.String("provider", providerName), zap.Error(err))
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(models, c)
|
||||
}
|
||||
|
||||
@@ -187,14 +180,13 @@ func (m *ModelProviderApi) GetAvailableModels(c *gin.Context) {
|
||||
func (m *ModelProviderApi) TestProviderCredentials(c *gin.Context) {
|
||||
providerName := c.Query("provider_name")
|
||||
if providerName == "" {
|
||||
response.FailWithMessage("参数错误: provider_name不能为空", c)
|
||||
response.FailWithMessage("参数错误:provider_name不能为空", c)
|
||||
return
|
||||
}
|
||||
|
||||
creds, err := modelProviderService.GetDifyProviderCredentials(providerName)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取提供商凭证失败", zap.String("provider", providerName), zap.Error(err))
|
||||
response.FailWithMessage("获取凭证失败: "+err.Error(), c)
|
||||
response.FailWithMessage("获取凭证失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -215,7 +207,7 @@ func (m *ModelProviderApi) TestProviderCredentials(c *gin.Context) {
|
||||
response.OkWithData(result, c)
|
||||
}
|
||||
|
||||
// GetProxyLogs 获取代理日志
|
||||
// GetProxyLogs 获取代理日志(分页)
|
||||
// @Tags ModelProvider
|
||||
// @Summary 获取代理日志
|
||||
// @Security ApiKeyAuth
|
||||
@@ -223,54 +215,30 @@ func (m *ModelProviderApi) TestProviderCredentials(c *gin.Context) {
|
||||
// @Produce application/json
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "每页数量"
|
||||
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取成功"
|
||||
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
|
||||
// @Router /gaia/model-provider/logs [get]
|
||||
func (m *ModelProviderApi) GetProxyLogs(c *gin.Context) {
|
||||
page := c.DefaultQuery("page", "1")
|
||||
pageSize := c.DefaultQuery("page_size", "20")
|
||||
|
||||
var pageInt, pageSizeInt int
|
||||
if _, err := fmt.Sscanf(page, "%d", &pageInt); err != nil {
|
||||
pageInt = 1
|
||||
}
|
||||
if _, err := fmt.Sscanf(pageSize, "%d", &pageSizeInt); err != nil {
|
||||
pageSizeInt = 20
|
||||
}
|
||||
|
||||
if pageInt < 1 {
|
||||
pageInt = 1
|
||||
}
|
||||
if pageSizeInt < 1 || pageSizeInt > 100 {
|
||||
pageSizeInt = 20
|
||||
}
|
||||
|
||||
var logs []map[string]interface{}
|
||||
var total int64
|
||||
|
||||
db := global.GVA_DB.Table("model_proxy_log")
|
||||
|
||||
// 获取总数
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
global.GVA_LOG.Error("获取日志总数失败", zap.Error(err))
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
var req gaiaReq.GetProxyLogsReq
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.FailWithMessage("参数错误:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (pageInt - 1) * pageSizeInt
|
||||
if err := db.Order("created_at DESC").Limit(pageSizeInt).Offset(
|
||||
offset).Find(&logs).Error; err != nil {
|
||||
global.GVA_LOG.Error("获取日志列表失败", zap.Error(err))
|
||||
response.FailWithMessage("获取失败: "+err.Error(), c)
|
||||
if req.Page < 1 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize < 1 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
list, total, err := modelProviderService.GetProxyLogs(req)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取代理日志失败", zap.Error(err))
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"list": logs,
|
||||
"total": total,
|
||||
"page": pageInt,
|
||||
"page_size": pageSizeInt,
|
||||
}
|
||||
|
||||
response.OkWithData(result, c)
|
||||
response.OkWithDetailed(response.PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, "获取成功", c)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package request
|
||||
|
||||
// GetProxyLogsReq 代理日志分页请求
|
||||
type GetProxyLogsReq struct {
|
||||
Page int `form:"page"` // 页码,从 1 开始
|
||||
PageSize int `form:"page_size"` // 每页条数,最大 100
|
||||
}
|
||||
|
||||
// ChatRequest 聊天请求(OpenAI 兼容)
|
||||
type ChatRequest struct {
|
||||
Model string `json:"model"`
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
package response
|
||||
|
||||
// AppQuotaRankingRow 应用配额排名查询单行(仅用于 service 层 GORM 查询扫描)
|
||||
type AppQuotaRankingRow struct {
|
||||
AppID string `gorm:"column:app_id"`
|
||||
TotalCost float64 `gorm:"column:total_cost"`
|
||||
MessageCost float64 `gorm:"column:message_cost"`
|
||||
WorkflowCost float64 `gorm:"column:workflow_cost"`
|
||||
RecordNum float64 `gorm:"column:record_num"`
|
||||
}
|
||||
|
||||
// AppQuotaRankingCache 应用配额排名缓存结构(List + Total)
|
||||
type AppQuotaRankingCache struct {
|
||||
List []GetAppQuotaRankingDataRes
|
||||
Total int64
|
||||
}
|
||||
|
||||
// AiImageQuotaRankingRow AI 图片使用量排名查询单行(仅用于 service 层 GORM 查询扫描)
|
||||
type AiImageQuotaRankingRow struct {
|
||||
Address string `gorm:"column:address"`
|
||||
Path string `gorm:"column:path"`
|
||||
TotalCost float64 `gorm:"column:total_cost"`
|
||||
RecordNum int `gorm:"column:record_num"`
|
||||
Model string `gorm:"column:model"`
|
||||
}
|
||||
|
||||
// GetAccountQuotaRankingDataRes 获取账户配额排名数据的响应结构
|
||||
type GetAccountQuotaRankingDataRes struct {
|
||||
Ranking int `json:"ranking"` // 排名
|
||||
|
||||
@@ -19,7 +19,8 @@ import (
|
||||
type DashboardService struct{}
|
||||
|
||||
// GetAccountQuotaRankingData 分页获取【账号】额度排名列表
|
||||
func (dashboardService *DashboardService) GetAccountQuotaRankingData(info gaiaReq.GetAccountQuotaRankingDataReq) (list []response.GetAccountQuotaRankingDataRes, total int64, err error) {
|
||||
func (s *DashboardService) GetAccountQuotaRankingData(info gaiaReq.GetAccountQuotaRankingDataReq) (
|
||||
list []response.GetAccountQuotaRankingDataRes, total int64, err error) {
|
||||
limit := info.PageSize
|
||||
offset := info.PageSize * (info.Page - 1)
|
||||
|
||||
@@ -79,15 +80,13 @@ func (dashboardService *DashboardService) GetAccountQuotaRankingData(info gaiaRe
|
||||
}
|
||||
|
||||
// GetAppQuotaRankingData 分页获取【应用】配额排名数据
|
||||
func (dashboardService *DashboardService) GetAppQuotaRankingData(info gaiaReq.GetAppQuotaRankingDataReq) (list []response.GetAppQuotaRankingDataRes, total int64, err error) {
|
||||
func (s *DashboardService) GetAppQuotaRankingData(info gaiaReq.GetAppQuotaRankingDataReq) (
|
||||
list []response.GetAppQuotaRankingDataRes, total int64, err error) {
|
||||
|
||||
cacheKey := fmt.Sprintf("app_token_quota_ranking:%d:%d", info.Page, info.PageSize)
|
||||
var cachedResult struct {
|
||||
List []response.GetAppQuotaRankingDataRes
|
||||
Total int64
|
||||
}
|
||||
var cachedResult response.AppQuotaRankingCache
|
||||
|
||||
if found, err := dashboardService.getCachedResult(cacheKey, &cachedResult); err == nil && found {
|
||||
if found, err := s.getCachedResult(cacheKey, &cachedResult); err == nil && found {
|
||||
return cachedResult.List, cachedResult.Total, nil
|
||||
}
|
||||
|
||||
@@ -140,13 +139,7 @@ func (dashboardService *DashboardService) GetAppQuotaRankingData(info gaiaReq.Ge
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
var results []struct {
|
||||
AppID string `gorm:"column:app_id"`
|
||||
TotalCost float64 `gorm:"column:total_cost"`
|
||||
MessageCost float64 `gorm:"column:message_cost"`
|
||||
WorkflowCost float64 `gorm:"column:workflow_cost"`
|
||||
RecordNum float64 `gorm:"column:record_num"`
|
||||
}
|
||||
var results []response.AppQuotaRankingRow
|
||||
|
||||
err = query.Find(&results).Error
|
||||
if err != nil {
|
||||
@@ -269,12 +262,8 @@ func (dashboardService *DashboardService) GetAppQuotaRankingData(info gaiaReq.Ge
|
||||
}
|
||||
|
||||
// 在返回结果之前,缓存结果
|
||||
result := struct {
|
||||
List []response.GetAppQuotaRankingDataRes
|
||||
Total int64
|
||||
}{list, total}
|
||||
|
||||
if err := dashboardService.cacheResult(cacheKey, result, 24*time.Hour); err != nil {
|
||||
cachePayload := response.AppQuotaRankingCache{List: list, Total: total}
|
||||
if err := s.cacheResult(cacheKey, cachePayload, 24*time.Hour); err != nil {
|
||||
global.GVA_LOG.Error("Failed to cache result", zap.Error(err))
|
||||
}
|
||||
|
||||
@@ -282,7 +271,8 @@ func (dashboardService *DashboardService) GetAppQuotaRankingData(info gaiaReq.Ge
|
||||
}
|
||||
|
||||
// GetAppTokenQuotaRankingData 分页获取【应用密钥】配额排名数据列表
|
||||
func (dashboardService *DashboardService) GetAppTokenQuotaRankingData(info gaiaReq.GetAppTokenQuotaRankingDataReq) (list []response.GetAppTokenQuotaRankingDataRes, total int64, err error) {
|
||||
func (s *DashboardService) GetAppTokenQuotaRankingData(info gaiaReq.GetAppTokenQuotaRankingDataReq) (
|
||||
list []response.GetAppTokenQuotaRankingDataRes, total int64, err error) {
|
||||
limit := info.PageSize
|
||||
offset := info.PageSize * (info.Page - 1)
|
||||
|
||||
@@ -365,9 +355,11 @@ func (dashboardService *DashboardService) GetAppTokenQuotaRankingData(info gaiaR
|
||||
}
|
||||
|
||||
// GetAppTokenDailyQuotaData 获取每天密钥花费数据列表
|
||||
func (dashboardService *DashboardService) GetAppTokenDailyQuotaData(info gaiaReq.GetAppTokenDailyQuotaDataReq) (list []response.GetAppTokenDailyQuotaDataRes, err error) {
|
||||
func (s *DashboardService) GetAppTokenDailyQuotaData(info gaiaReq.GetAppTokenDailyQuotaDataReq) (
|
||||
list []response.GetAppTokenDailyQuotaDataRes, err error) {
|
||||
|
||||
db := global.GVA_DB.Select("DATE(stat_at) as stat_at, SUM(day_used_quota) as day_used_quota").Model(&gaia.ApiTokenMoneyDailyStatExtend{}).Order("stat_at desc").Group("DATE(stat_at)")
|
||||
db := global.GVA_DB.Select("DATE(stat_at) as stat_at, SUM(day_used_quota) as day_used_quota").Model(
|
||||
&gaia.ApiTokenMoneyDailyStatExtend{}).Order("stat_at desc").Group("DATE(stat_at)")
|
||||
var apiTokenMoneyDailyStatExtends []gaia.ApiTokenMoneyDailyStatExtend
|
||||
|
||||
if info.AppId != "" {
|
||||
@@ -397,7 +389,8 @@ func (dashboardService *DashboardService) GetAppTokenDailyQuotaData(info gaiaReq
|
||||
}
|
||||
|
||||
// GetAiImageQuotaRankingData 获取【AI图片】使用量排名数据列表
|
||||
func (dashboardService *DashboardService) GetAiImageQuotaRankingData(info gaiaReq.GetAiImageQuotaRankingDataReq) (list []response.GetAiImageQuotaRankingRes, err error) {
|
||||
func (s *DashboardService) GetAiImageQuotaRankingData(info gaiaReq.GetAiImageQuotaRankingDataReq) (
|
||||
list []response.GetAiImageQuotaRankingRes, err error) {
|
||||
limit := info.PageSize
|
||||
offset := info.PageSize * (info.Page - 1)
|
||||
|
||||
@@ -427,13 +420,7 @@ func (dashboardService *DashboardService) GetAiImageQuotaRankingData(info gaiaRe
|
||||
db = db.Limit(limit).Offset(offset)
|
||||
}
|
||||
|
||||
var results []struct {
|
||||
Address string
|
||||
Path string
|
||||
TotalCost float64
|
||||
RecordNum int
|
||||
Model string
|
||||
}
|
||||
var results []response.AiImageQuotaRankingRow
|
||||
|
||||
err = db.Find(&results).Error
|
||||
if err != nil {
|
||||
@@ -456,7 +443,7 @@ func (dashboardService *DashboardService) GetAiImageQuotaRankingData(info gaiaRe
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (dashboardService *DashboardService) cacheResult(key string, data interface{}, expiration time.Duration) error {
|
||||
func (s *DashboardService) cacheResult(key string, data interface{}, expiration time.Duration) error {
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
@@ -465,7 +452,7 @@ func (dashboardService *DashboardService) cacheResult(key string, data interface
|
||||
return global.GVA_REDIS.Set(context.Background(), key, jsonData, expiration).Err()
|
||||
}
|
||||
|
||||
func (dashboardService *DashboardService) getCachedResult(key string, result interface{}) (bool, error) {
|
||||
func (s *DashboardService) getCachedResult(key string, result interface{}) (bool, error) {
|
||||
data, err := global.GVA_REDIS.Get(context.Background(), key).Bytes()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
|
||||
@@ -1346,6 +1346,28 @@ func (s *ModelProviderService) ProxyRequest(
|
||||
return err
|
||||
}
|
||||
|
||||
// GetProxyLogs 分页查询代理日志(model_proxy_log 表)。
|
||||
func (s *ModelProviderService) GetProxyLogs(info gaiaRequest.GetProxyLogsReq) (list []map[string]interface{}, total int64, err error) {
|
||||
page, pageSize := info.Page, info.PageSize
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
db := global.GVA_DB.Table("model_proxy_log")
|
||||
if err = db.Count(&total).Error; err != nil {
|
||||
err = fmt.Errorf("查询日志总数失败:%w", err)
|
||||
return
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
if err = db.Order("created_at DESC").Limit(pageSize).Offset(offset).Find(&list).Error; err != nil {
|
||||
err = fmt.Errorf("查询日志列表失败:%w", err)
|
||||
return
|
||||
}
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
// isProviderEnabled 检查该提供商是否已启用(未校验具体模型列表,用于通用代理)。
|
||||
func (s *ModelProviderService) isProviderEnabled(providerName string) bool {
|
||||
var config gaia.ModelProviderConfig
|
||||
|
||||
Reference in New Issue
Block a user