feat: 新增模型管理模块功能
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"model-gateway/consts/public"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// 供应商编码常量
|
||||
const (
|
||||
SupplierAliyun = 1
|
||||
SupplierVolcengine = 2
|
||||
SupplierTencent = 3
|
||||
SupplierHuawei = 4
|
||||
SupplierBaidu = 5
|
||||
SupplierOpenAI = 6
|
||||
SupplierAzure = 7
|
||||
SupplierAWS = 8
|
||||
SupplierGoogle = 9
|
||||
SupplierDeepSeek = 10
|
||||
SupplierMoonshot = 11
|
||||
SupplierZhipu = 12
|
||||
SupplierBaichuan = 13
|
||||
SupplierMinimax = 14
|
||||
SupplierXunfei = 15
|
||||
SupplierOthers = 16
|
||||
)
|
||||
|
||||
// SupplierType 供应商编码类型
|
||||
type SupplierType *int8
|
||||
|
||||
// SupplierItem 供应商项
|
||||
type SupplierItem struct {
|
||||
Code SupplierType `json:"code"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
// 名称映射【唯一文案维护】
|
||||
var supplierNameMap = map[int]string{
|
||||
SupplierAliyun: "阿里云百炼",
|
||||
SupplierVolcengine: "火山引擎",
|
||||
SupplierTencent: "腾讯云",
|
||||
SupplierHuawei: "华为云",
|
||||
SupplierBaidu: "百度智能云",
|
||||
SupplierOpenAI: "OpenAI",
|
||||
SupplierAzure: "Azure OpenAI",
|
||||
SupplierAWS: "AWS Bedrock",
|
||||
SupplierGoogle: "Google Cloud",
|
||||
SupplierDeepSeek: "DeepSeek",
|
||||
SupplierMoonshot: "Moonshot",
|
||||
SupplierZhipu: "智谱AI",
|
||||
SupplierBaichuan: "百川智能",
|
||||
SupplierMinimax: "MiniMax",
|
||||
SupplierXunfei: "科大讯飞",
|
||||
SupplierOthers: "其他",
|
||||
}
|
||||
|
||||
// 供应商展示顺序
|
||||
var supplierOrder = []int{
|
||||
SupplierAliyun, SupplierVolcengine, SupplierTencent, SupplierHuawei, SupplierBaidu,
|
||||
SupplierOpenAI, SupplierAzure, SupplierAWS, SupplierGoogle, SupplierDeepSeek,
|
||||
SupplierMoonshot, SupplierZhipu, SupplierBaichuan, SupplierMinimax, SupplierXunfei, SupplierOthers,
|
||||
}
|
||||
|
||||
// 全局供应商实例
|
||||
var (
|
||||
SupplierItemAliyun = newSupplierItem(gconv.PtrInt8(SupplierAliyun))
|
||||
SupplierItemVolcengine = newSupplierItem(gconv.PtrInt8(SupplierVolcengine))
|
||||
SupplierItemTencent = newSupplierItem(gconv.PtrInt8(SupplierTencent))
|
||||
SupplierItemHuawei = newSupplierItem(gconv.PtrInt8(SupplierHuawei))
|
||||
SupplierItemBaidu = newSupplierItem(gconv.PtrInt8(SupplierBaidu))
|
||||
SupplierItemOpenAI = newSupplierItem(gconv.PtrInt8(SupplierOpenAI))
|
||||
SupplierItemAzure = newSupplierItem(gconv.PtrInt8(SupplierAzure))
|
||||
SupplierItemAWS = newSupplierItem(gconv.PtrInt8(SupplierAWS))
|
||||
SupplierItemGoogle = newSupplierItem(gconv.PtrInt8(SupplierGoogle))
|
||||
SupplierItemDeepSeek = newSupplierItem(gconv.PtrInt8(SupplierDeepSeek))
|
||||
SupplierItemMoonshot = newSupplierItem(gconv.PtrInt8(SupplierMoonshot))
|
||||
SupplierItemZhipu = newSupplierItem(gconv.PtrInt8(SupplierZhipu))
|
||||
SupplierItemBaichuan = newSupplierItem(gconv.PtrInt8(SupplierBaichuan))
|
||||
SupplierItemMinimax = newSupplierItem(gconv.PtrInt8(SupplierMinimax))
|
||||
SupplierItemXunfei = newSupplierItem(gconv.PtrInt8(SupplierXunfei))
|
||||
SupplierItemOthers = newSupplierItem(gconv.PtrInt8(SupplierOthers))
|
||||
)
|
||||
|
||||
func newSupplierItem(code SupplierType) SupplierItem {
|
||||
val := int(*code)
|
||||
return SupplierItem{
|
||||
Code: code,
|
||||
Desc: supplierNameMap[val],
|
||||
}
|
||||
}
|
||||
|
||||
// GetSupplierDescByCode 根据编码获取供应商名称
|
||||
func GetSupplierDescByCode(code int) string {
|
||||
return supplierNameMap[code]
|
||||
}
|
||||
|
||||
// GetSupplierOptionList 获取供应商下拉列表
|
||||
func GetSupplierOptionList() []*public.Option {
|
||||
var list []*public.Option
|
||||
for _, code := range supplierOrder {
|
||||
list = append(list, &public.Option{
|
||||
Value: code,
|
||||
Label: supplierNameMap[code],
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"model-gateway/consts/public"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// 模型类型编码常量
|
||||
const (
|
||||
TypeInference = 100 // 推理模型
|
||||
TypeImage = 200 // 图片模型
|
||||
TypeAudio = 300 // 音频模型
|
||||
TypeVector = 400 // 向量化模型
|
||||
TypeOmni = 500 // 全模态模型
|
||||
TypeVideo = 600 // 视频模型
|
||||
|
||||
// 图片子类型
|
||||
ImageSubTextToImage = 201
|
||||
ImageSubImageToImage = 202
|
||||
ImageSubImageEdit = 203
|
||||
ImageSubImageVariation = 204
|
||||
ImageSubImageTextToImage = 205
|
||||
|
||||
// 音频子类型
|
||||
AudioSubTextToSpeech = 301
|
||||
AudioSubSpeechToText = 302
|
||||
AudioSubSpeechToSpeech = 303
|
||||
|
||||
// 向量化子类型
|
||||
VectorSubEmbedding = 401
|
||||
VectorSubRerank = 402
|
||||
|
||||
// 全模态子类型
|
||||
OmniSubTextImageAudio = 501
|
||||
OmniSubVision = 502
|
||||
|
||||
// 视频子类型
|
||||
VideoSubTextToVideo = 601
|
||||
VideoSubImageToVideo = 602
|
||||
VideoSubImageTextToVideo = 603
|
||||
VideoSubVideoToVideo = 604
|
||||
)
|
||||
|
||||
// ModelType 编码类型
|
||||
type ModelType *int8
|
||||
|
||||
// ModelTypeItem 模型类型项
|
||||
type ModelTypeItem struct {
|
||||
Code ModelType `json:"code"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
// TypeTree 树形结构
|
||||
type TypeTree struct {
|
||||
Value int `json:"value"`
|
||||
Label string `json:"label"`
|
||||
Children []*public.Option `json:"children"`
|
||||
}
|
||||
|
||||
// 名称映射表【唯一文案维护入口】
|
||||
var typeNameMap = map[int]string{
|
||||
TypeInference: "推理模型",
|
||||
TypeImage: "图片模型",
|
||||
TypeAudio: "音频模型",
|
||||
TypeVector: "向量化模型",
|
||||
TypeOmni: "全模态模型",
|
||||
TypeVideo: "视频模型",
|
||||
|
||||
ImageSubTextToImage: "文生图",
|
||||
ImageSubImageToImage: "图生图",
|
||||
ImageSubImageEdit: "图片编辑",
|
||||
ImageSubImageVariation: "图片变体",
|
||||
ImageSubImageTextToImage: "图文生图",
|
||||
|
||||
AudioSubTextToSpeech: "文生音",
|
||||
AudioSubSpeechToText: "音生文",
|
||||
AudioSubSpeechToSpeech: "音生音",
|
||||
|
||||
VectorSubEmbedding: "文本嵌入",
|
||||
VectorSubRerank: "重排序",
|
||||
|
||||
OmniSubTextImageAudio: "文图音",
|
||||
OmniSubVision: "视觉理解",
|
||||
|
||||
VideoSubTextToVideo: "文生视频",
|
||||
VideoSubImageToVideo: "图生视频",
|
||||
VideoSubImageTextToVideo: "图文生视频",
|
||||
VideoSubVideoToVideo: "视频生视频",
|
||||
}
|
||||
|
||||
// 父子级映射(仅存有子项的分类)
|
||||
var parentChildMap = map[int][]int{
|
||||
TypeImage: {ImageSubTextToImage, ImageSubImageToImage, ImageSubImageEdit, ImageSubImageVariation, ImageSubImageTextToImage},
|
||||
TypeAudio: {AudioSubTextToSpeech, AudioSubSpeechToText, AudioSubSpeechToSpeech},
|
||||
TypeVector: {VectorSubEmbedding, VectorSubRerank},
|
||||
TypeOmni: {OmniSubTextImageAudio, OmniSubVision},
|
||||
TypeVideo: {VideoSubTextToVideo, VideoSubImageToVideo, VideoSubImageTextToVideo, VideoSubVideoToVideo},
|
||||
}
|
||||
|
||||
// 一级分类展示顺序
|
||||
var parentTypeOrder = []int{
|
||||
TypeInference, TypeImage, TypeAudio, TypeVector, TypeOmni, TypeVideo,
|
||||
}
|
||||
|
||||
// 全局实例:一级 + 全部二级子类型,统一通过 newItem 构造,文案仅维护在 typeNameMap
|
||||
var (
|
||||
// 一级类型
|
||||
ModelTypeInference = newItem(gconv.PtrInt8(TypeInference))
|
||||
ModelTypeImage = newItem(gconv.PtrInt8(TypeImage))
|
||||
ModelTypeAudio = newItem(gconv.PtrInt8(TypeAudio))
|
||||
ModelTypeVector = newItem(gconv.PtrInt8(TypeVector))
|
||||
ModelTypeOmni = newItem(gconv.PtrInt8(TypeOmni))
|
||||
ModelTypeVideo = newItem(gconv.PtrInt8(TypeVideo))
|
||||
|
||||
// 图片二级子类型
|
||||
ModelImageSubTextToImage = newItem(gconv.PtrInt8(ImageSubTextToImage))
|
||||
ModelImageSubImageToImage = newItem(gconv.PtrInt8(ImageSubImageToImage))
|
||||
ModelImageSubImageEdit = newItem(gconv.PtrInt8(ImageSubImageEdit))
|
||||
ModelImageSubImageVariation = newItem(gconv.PtrInt8(ImageSubImageVariation))
|
||||
ModelImageSubImageTextToImage = newItem(gconv.PtrInt8(ImageSubImageTextToImage))
|
||||
|
||||
// 音频二级子类型
|
||||
ModelAudioSubTextToSpeech = newItem(gconv.PtrInt8(AudioSubTextToSpeech))
|
||||
ModelAudioSubSpeechToText = newItem(gconv.PtrInt8(AudioSubSpeechToText))
|
||||
ModelAudioSubSpeechToSpeech = newItem(gconv.PtrInt8(AudioSubSpeechToSpeech))
|
||||
|
||||
// 向量化二级子类型
|
||||
ModelVectorSubEmbedding = newItem(gconv.PtrInt8(VectorSubEmbedding))
|
||||
ModelVectorSubRerank = newItem(gconv.PtrInt8(VectorSubRerank))
|
||||
|
||||
// 全模态二级子类型
|
||||
ModelOmniSubTextImageAudio = newItem(gconv.PtrInt8(OmniSubTextImageAudio))
|
||||
ModelOmniSubVision = newItem(gconv.PtrInt8(OmniSubVision))
|
||||
|
||||
// 视频二级子类型
|
||||
ModelVideoSubTextToVideo = newItem(gconv.PtrInt8(VideoSubTextToVideo))
|
||||
ModelVideoSubImageToVideo = newItem(gconv.PtrInt8(VideoSubImageToVideo))
|
||||
ModelVideoSubImageTextToVideo = newItem(gconv.PtrInt8(VideoSubImageTextToVideo))
|
||||
ModelVideoSubVideoToVideo = newItem(gconv.PtrInt8(VideoSubVideoToVideo))
|
||||
)
|
||||
|
||||
// newItem 构造方法:自动从 typeNameMap 读取描述
|
||||
func newItem(code ModelType) ModelTypeItem {
|
||||
val := int(*code)
|
||||
return ModelTypeItem{
|
||||
Code: code,
|
||||
Desc: typeNameMap[val],
|
||||
}
|
||||
}
|
||||
|
||||
// GetDescByCode 根据编码获取名称
|
||||
func GetDescByCode(code int) string {
|
||||
return typeNameMap[code]
|
||||
}
|
||||
|
||||
// GetTypeTreeList 生成树形数据
|
||||
func GetTypeTreeList() []*TypeTree {
|
||||
var list []*TypeTree
|
||||
for _, parentCode := range parentTypeOrder {
|
||||
tree := &TypeTree{
|
||||
Value: parentCode,
|
||||
Label: typeNameMap[parentCode],
|
||||
Children: make([]*public.Option, 0),
|
||||
}
|
||||
if childCodes, ok := parentChildMap[parentCode]; ok {
|
||||
for _, c := range childCodes {
|
||||
tree.Children = append(tree.Children, &public.Option{
|
||||
Value: c,
|
||||
Label: typeNameMap[c],
|
||||
})
|
||||
}
|
||||
}
|
||||
list = append(list, tree)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// GetAllTypeOption 全量平铺选项
|
||||
func GetAllTypeOption() []*public.Option {
|
||||
var list []*public.Option
|
||||
for code, label := range typeNameMap {
|
||||
list = append(list, &public.Option{Value: code, Label: label})
|
||||
}
|
||||
return list
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package model
|
||||
|
||||
import "github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
var (
|
||||
ResponseTypeSync = newResponseType(gconv.PtrInt8(1), "sync") // 同步
|
||||
ResponseTypeAsync = newResponseType(gconv.PtrInt8(2), "async") // 异步
|
||||
ResponseTypeStream = newResponseType(gconv.PtrInt8(3), "stream") // 流
|
||||
)
|
||||
|
||||
type ResponseType *int8
|
||||
|
||||
type responseType struct {
|
||||
code ResponseType
|
||||
desc string
|
||||
}
|
||||
|
||||
func (s responseType) Code() ResponseType {
|
||||
return s.code
|
||||
}
|
||||
func (s responseType) Desc() string {
|
||||
return s.desc
|
||||
}
|
||||
|
||||
func newResponseType(code ResponseType, desc string) responseType {
|
||||
return responseType{code: code, desc: desc}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
package public
|
||||
|
||||
// Option 通用下拉选项
|
||||
type Option struct {
|
||||
Value int `json:"value"`
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
const (
|
||||
CallModeSync = 0 // 同步调用
|
||||
CallModeAsync = 1 // 异步调用
|
||||
|
||||
@@ -5,8 +5,9 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
TableNameModel = "model_gateway_models" // 模型表
|
||||
TableNameTask = "model_gateway_task" // 任务表
|
||||
TableNameOpLog = "model_gateway_logs_op" // 操作日志表
|
||||
TableNameStat = "model_gateway_logs_stat" // 按天统计表
|
||||
TableNameModel = "model_gateway_models" // 模型表
|
||||
TableNameTask = "model_gateway_task" // 任务表
|
||||
TableNameOpLog = "model_gateway_logs_op" // 操作日志表
|
||||
TableNameStat = "model_gateway_logs_stat" // 按天统计表
|
||||
TableNameModelManage = "model_gateway_model_manage"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"model-gateway/model/dto"
|
||||
"model-gateway/service"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
// ModelManage 模型配置控制器
|
||||
var ModelManage = new(modelManage)
|
||||
|
||||
type modelManage struct{}
|
||||
|
||||
// CreateModel 添加配置
|
||||
func (c *modelManage) CreateModel(ctx context.Context, req *dto.CreateModelManageReq) (res *dto.CreateModelManageRes, err error) {
|
||||
return service.ModelManage.Create(ctx, req)
|
||||
}
|
||||
|
||||
// UpdateModel 更改配置
|
||||
func (c *modelManage) UpdateModel(ctx context.Context, req *dto.UpdateModelManageReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.ModelManage.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteModel 删除配置
|
||||
func (c *modelManage) DeleteModel(ctx context.Context, req *dto.DeleteModelManageReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.ModelManage.Delete(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// GetModel 获取配置
|
||||
func (c *modelManage) GetModel(ctx context.Context, req *dto.GetModelManageReq) (res *dto.GetModelManageRes, err error) {
|
||||
return service.ModelManage.Get(ctx, req)
|
||||
}
|
||||
|
||||
// ListModel 配置列表
|
||||
func (c *modelManage) ListModel(ctx context.Context, req *dto.ListModelManageReq) (res *dto.ListModelManageRes, err error) {
|
||||
return service.ModelManage.List(ctx, req)
|
||||
}
|
||||
|
||||
// CheckChatModel 检查是否为聊天模型
|
||||
func (c *modelManage) CheckChatModel(ctx context.Context, req *dto.CheckChatModelReq) (res *dto.CheckChatModelRes, err error) {
|
||||
return service.ModelManage.CheckChatModel(ctx, req)
|
||||
}
|
||||
|
||||
// ListType 模型类型列表
|
||||
func (c *modelManage) ListType(ctx context.Context, req *dto.ModelTypeReq) (res *dto.ModelTypeRes, err error) {
|
||||
return service.ModelManage.GetModelType(ctx, req)
|
||||
}
|
||||
|
||||
// ListOperator 运营商列表
|
||||
func (c *modelManage) ListOperator(ctx context.Context, req *dto.ModelSupplierReq) (res *dto.ModelSupplierRes, err error) {
|
||||
return service.ModelManage.GetModelSupplier(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"model-gateway/consts/public"
|
||||
"model-gateway/model/dto"
|
||||
"model-gateway/model/entity"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var ModelManage = &modelManageDao{}
|
||||
|
||||
type modelManageDao struct{}
|
||||
|
||||
// Insert 插入
|
||||
func (d *modelManageDao) Insert(ctx context.Context, req *dto.CreateModelManageReq) (id int64, err error) {
|
||||
var e = new(entity.ModelManage)
|
||||
err = gconv.Struct(req, &e)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r, err := gfdb.DB(ctx, public.DbNameModelGateway).Model(ctx, public.TableNameModelManage).Insert(e)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
func (d *modelManageDao) Update(ctx context.Context, req *dto.UpdateModelManageReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx, public.DbNameModelGateway).Model(ctx, public.TableNameModelManage).OmitEmpty().Data(req).Where(entity.ModelManageCol.Id, req.Id).Update()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
// Delete 删除
|
||||
func (d *modelManageDao) Delete(ctx context.Context, req *dto.DeleteModelManageReq) (rows int64, err error) {
|
||||
r, err := gfdb.DB(ctx, public.DbNameModelGateway).Model(ctx, public.TableNameModelManage).Where(entity.ModelManageCol.Id, req.Id).Delete()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.RowsAffected()
|
||||
}
|
||||
|
||||
func (d *modelManageDao) Get(ctx context.Context, req *dto.GetModelManage, fields ...string) (res *entity.ModelManage, err error) {
|
||||
r, err := gfdb.DB(ctx, public.DbNameModelGateway).Model(ctx, public.TableNameModelManage).Cache(ctx).
|
||||
OmitEmpty().
|
||||
Where(entity.ModelManageCol.ModelName, req.ModelName).
|
||||
Where(entity.ModelManageCol.ChatModel, req.ChatModel).
|
||||
Where(entity.ModelManageCol.Creator, req.Creator).
|
||||
Fields(fields).One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *modelManageDao) GetNotTenantId(ctx context.Context, req *dto.GetModelManageReq, fields ...string) (res *entity.ModelManage, err error) {
|
||||
// 获取表前缀
|
||||
prefix := g.Cfg().MustGet(ctx, fmt.Sprintf("database.%s.0.prefix", public.DbNameModelGateway)).String()
|
||||
table := prefix + public.TableNameModelManage
|
||||
// 动态拼接 SELECT 列
|
||||
var field string
|
||||
if !g.IsEmpty(fields) {
|
||||
for k, v := range fields {
|
||||
if k == len(fields)-1 {
|
||||
field = field + v
|
||||
} else {
|
||||
field = field + v + ","
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field = "*"
|
||||
}
|
||||
// 动态拼接 WHERE 条件
|
||||
var whereCondition string
|
||||
var queryParams []interface{}
|
||||
if !g.IsEmpty(req.Id) {
|
||||
whereCondition = fmt.Sprintf(" AND %s=(?) ", entity.ModelManageCol.Id)
|
||||
queryParams = append(queryParams, req.Id)
|
||||
}
|
||||
whereCondition = whereCondition + " AND " + entity.ModelManageCol.DeletedAt + " IS NULL "
|
||||
|
||||
sql := `SELECT ` + field + ` FROM ` + table + ` WHERE 1=1 ` + whereCondition + ``
|
||||
// 执行查询
|
||||
result, err := gfdb.DB(ctx, public.DbNameModelGateway).GetOne(ctx, sql, queryParams...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = result.Struct(&res)
|
||||
return
|
||||
}
|
||||
func (d *modelManageDao) ListNotTenantId(ctx context.Context, req *dto.ListModelManageReq, fields ...string) (res []*entity.ModelManage, total int, err error) {
|
||||
// 获取表前缀
|
||||
prefix := g.Cfg().MustGet(ctx, fmt.Sprintf("database.%s.0.prefix", public.DbNameModelGateway)).String()
|
||||
table := prefix + public.TableNameModelManage
|
||||
|
||||
// 动态拼接 SELECT 列
|
||||
var field string
|
||||
if !g.IsEmpty(fields) {
|
||||
for k, v := range fields {
|
||||
if k == len(fields)-1 {
|
||||
field = field + v
|
||||
} else {
|
||||
field = field + v + ","
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field = "*"
|
||||
}
|
||||
|
||||
// 动态拼接 WHERE 条件
|
||||
var whereCondition string
|
||||
var queryParams []interface{}
|
||||
|
||||
if !g.IsEmpty(req.ModelName) {
|
||||
whereCondition += fmt.Sprintf(" AND %s=(?) ", entity.ModelManageCol.ModelName)
|
||||
queryParams = append(queryParams, req.ModelName)
|
||||
}
|
||||
if !g.IsEmpty(req.ModelType) {
|
||||
whereCondition += fmt.Sprintf(" AND %s=(?) ", entity.ModelManageCol.ModelType)
|
||||
queryParams = append(queryParams, req.ModelType)
|
||||
}
|
||||
if !g.IsEmpty(req.Creator) {
|
||||
whereCondition += fmt.Sprintf(" AND (%s=(?) OR %s=true) ", entity.ModelManageCol.Creator, entity.ModelManageCol.SystemModel)
|
||||
queryParams = append(queryParams, req.Creator)
|
||||
}
|
||||
whereCondition = whereCondition + " AND " + entity.ModelManageCol.DeletedAt + " IS NULL "
|
||||
|
||||
// 1. 统计去重后总条数
|
||||
countSql := fmt.Sprintf(
|
||||
`SELECT COUNT(DISTINCT %s) FROM %s WHERE 1=1 %s`,
|
||||
entity.ModelManageCol.ModelName,
|
||||
table,
|
||||
whereCondition,
|
||||
)
|
||||
countResult, err := gfdb.DB(ctx, public.DbNameModelGateway).GetOne(ctx, countSql, queryParams...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
type crr struct {
|
||||
Count int64 `db:"count"`
|
||||
}
|
||||
var cr crr
|
||||
if err = countResult.Struct(&cr); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
total = int(cr.Count)
|
||||
// 2. 分页处理
|
||||
limitSql := ""
|
||||
if req.Page != nil {
|
||||
pageNum := int(req.Page.PageNum)
|
||||
pageSize := int(req.Page.PageSize)
|
||||
offset := (pageNum - 1) * pageSize
|
||||
limitSql = fmt.Sprintf(" LIMIT ? OFFSET ? ")
|
||||
// PG 语法 LIMIT 条数 OFFSET 偏移量
|
||||
queryParams = append(queryParams, pageSize, offset)
|
||||
}
|
||||
|
||||
// 排序优先级:1.分组字段ModelName 2.SystemModel升序(false在前,保留用户数据) 3.创建时间倒序
|
||||
orderSql := fmt.Sprintf(
|
||||
" ORDER BY %s, %s ASC, %s DESC ",
|
||||
entity.ModelManageCol.ModelName,
|
||||
entity.ModelManageCol.SystemModel,
|
||||
entity.ModelManageCol.CreatedAt,
|
||||
)
|
||||
|
||||
// PG DISTINCT ON 按模型名去重,同名只取第一条(用户数据)
|
||||
sql := fmt.Sprintf(
|
||||
`SELECT DISTINCT ON (%s) %s FROM %s WHERE 1=1 %s %s %s`,
|
||||
entity.ModelManageCol.ModelName,
|
||||
field,
|
||||
table,
|
||||
whereCondition,
|
||||
orderSql,
|
||||
limitSql,
|
||||
)
|
||||
|
||||
// 执行查询
|
||||
result, err := gfdb.DB(ctx, public.DbNameModelGateway).GetAll(ctx, sql, queryParams...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
err = result.Structs(&res)
|
||||
return
|
||||
}
|
||||
@@ -3,7 +3,7 @@ module model-gateway
|
||||
go 1.26.1
|
||||
|
||||
require (
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.29
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.30
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2
|
||||
github.com/gogf/gf/v2 v2.10.2
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.29 h1:5McaN5pSewvrLUHQzWMX6EaUvD+B5I5bMYoU+clHJk4=
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.29/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY=
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.30 h1:UkWYubUsLPJQUhEhc9Ca2UPg5iLC6jzURo3ngztINYg=
|
||||
gitea.redpowerfuture.com/red-future/common v0.0.30/go.mod h1:zuhqbWHd/YICalYJnmecY8Vqo5j4dtZOD63P96fiFeU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
|
||||
@@ -26,6 +26,7 @@ func main() {
|
||||
|
||||
// 注册路由
|
||||
http.RouteRegister([]interface{}{
|
||||
controller.ModelManage,
|
||||
controller.ModelGatewayModels,
|
||||
controller.ModelGatewayTask,
|
||||
controller.ModelGatewayLogsStat,
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"model-gateway/consts/model"
|
||||
"model-gateway/consts/public"
|
||||
"model-gateway/model/entity"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// CreateModelManageReq 添加模型配置
|
||||
type CreateModelManageReq struct {
|
||||
g.Meta `path:"/createModelManage" method:"post" tags:"new模型管理" summary:"new创建模型配置" dc:"new添加新的模型配置"`
|
||||
ModelSupplier model.SupplierType `json:"modelSupplier" v:"required#模型供应商不能为空" dc:"模型供应商"`
|
||||
ModelName string `json:"modelName" v:"required#模型名称不能为空" dc:"模型名称"`
|
||||
ModelType model.ModelType `json:"modelType" v:"required#模型类型不能为空" dc:"模型类型"`
|
||||
BaseURL string `json:"baseUrl" v:"required#模型服务地址不能为空" dc:"模型服务地址"`
|
||||
SystemModel *bool `json:"systemModel" dc:"系统模型"`
|
||||
HttpMethod string `json:"httpMethod" dc:"请求方式:GET/POST" d:"POST"`
|
||||
ChatModel *bool `json:"chatModel" dc:"对话模型"`
|
||||
ResponseType model.ResponseType `json:"responseType" v:"required#调用模式不能为空" dc:"调用模式:0-同步 1-异步 2-流式"`
|
||||
ApiKey string `json:"apiKey" dc:"调用凭证/密钥"`
|
||||
Enabled *bool `json:"enabled" dc:"启用"`
|
||||
RequestHeadMapping map[string]string `json:"requestHeadMapping" dc:"请求头映射"`
|
||||
RequestBodyMapping map[string]any `json:"requestBodyMapping" dc:"请求体映射"`
|
||||
ResponseMapping map[string]any `json:"responseMapping" dc:"返回映射"`
|
||||
ResponseBodyMapping map[string]string `json:"responseBodyMapping" dc:"返回体映射"`
|
||||
MaxConcurrency int `json:"maxConcurrency" dc:"最大并发数(默认10)"`
|
||||
TokenMapping *entity.TokenMapping `json:"tokenMapping" dc:"token映射"`
|
||||
AsyncTaskMapping *entity.AsyncTaskMapping `json:"asyncTaskMapping" dc:"异步任务映射"`
|
||||
TokenPredictPrice float64 `json:"tokenPredictPrice" dc:"模型Token预估价格"`
|
||||
TokenPredictPriceUnit string `json:"tokenPredictPriceUnit" dc:"模型Token预估价格单位"`
|
||||
MaxTokens int `json:"maxTokens" dc:"最大token数"`
|
||||
MaxDuration int `json:"maxDuration" dc:"最大时长"`
|
||||
LastFrame string `json:"lastFrame" dc:"视频的尾帧图像"`
|
||||
}
|
||||
|
||||
type CreateModelManageRes struct {
|
||||
Id int64 `json:"id,string" dc:"配置ID"`
|
||||
}
|
||||
|
||||
type UpdateModelManageReq struct {
|
||||
g.Meta `path:"/updateModelManage" method:"put" tags:"new模型管理" summary:"new更新模型配置" dc:"new更新指定ID的模型配置"`
|
||||
Id int64 `json:"id" v:"required#id不能为空" dc:"配置ID"`
|
||||
ModelSupplier model.SupplierType `json:"modelSupplier" dc:"模型供应商"`
|
||||
ModelName string `json:"modelName" dc:"模型名称"`
|
||||
ModelType model.ModelType `json:"modelType" dc:"模型类型"`
|
||||
BaseURL string `json:"baseUrl" dc:"模型服务地址"`
|
||||
SystemModel *bool `json:"systemModel" dc:"系统模型"`
|
||||
HttpMethod string `json:"httpMethod" dc:"请求方式:GET/POST"`
|
||||
ChatModel *bool `json:"chatModel" dc:"对话模型"`
|
||||
ResponseType model.ResponseType `json:"responseType" dc:"调用模式:0-同步 1-异步 2-流式"`
|
||||
ApiKey string `json:"apiKey" dc:"调用凭证/密钥"`
|
||||
Enabled *bool `json:"enabled" dc:"启用"`
|
||||
RequestHeadMapping map[string]string `json:"requestHeadMapping" dc:"请求头映射"`
|
||||
RequestBodyMapping map[string]any `json:"requestBodyMapping" dc:"请求体映射"`
|
||||
ResponseMapping map[string]any `json:"responseMapping" dc:"返回映射"`
|
||||
ResponseBodyMapping map[string]string `json:"responseBodyMapping" dc:"返回主体映射"`
|
||||
MaxConcurrency int `json:"maxConcurrency" dc:"最大并发数(默认10)"`
|
||||
TokenMapping *entity.TokenMapping `json:"tokenMapping" dc:"token映射"`
|
||||
AsyncTaskMapping *entity.AsyncTaskMapping `json:"asyncTaskMapping" dc:"异步任务映射"`
|
||||
TokenPredictPrice float64 `json:"tokenPredictPrice" dc:"模型Token预估价格"`
|
||||
TokenPredictPriceUnit string `json:"tokenPredictPriceUnit" dc:"模型Token预估价格单位"`
|
||||
MaxTokens int `json:"maxTokens" dc:"最大token数"`
|
||||
MaxDuration int `json:"maxDuration" dc:"最大时长"`
|
||||
LastFrame string `json:"lastFrame" dc:"视频的尾帧图像"`
|
||||
}
|
||||
|
||||
type DeleteModelManageReq struct {
|
||||
g.Meta `path:"/deleteModelManage" method:"delete" tags:"new模型管理" summary:"new删除模型配置" dc:"new删除指定ID的模型配置"`
|
||||
Id int64 `p:"id" json:"id,string" v:"required#id不能为空" dc:"配置ID"`
|
||||
}
|
||||
|
||||
type GetModelManage struct {
|
||||
ChatModel *bool `json:"chatModel" dc:"对话模型"`
|
||||
Creator string `json:"creator" dc:"创建人"`
|
||||
ModelName string `json:"modelName" dc:"模型名称"`
|
||||
}
|
||||
|
||||
type GetModelManageReq struct {
|
||||
g.Meta `path:"/getModelManage" method:"get" tags:"new模型管理" summary:"new获取模型配置" dc:"new获取指定ID的模型配置"`
|
||||
Id int64 `p:"id" json:"id,string" v:"required#id不能为空" dc:"配置ID"`
|
||||
}
|
||||
|
||||
type GetModelManageRes struct {
|
||||
*entity.ModelManage `json:"modelManage"`
|
||||
}
|
||||
|
||||
// ListModelManageReq 配置列表
|
||||
type ListModelManageReq struct {
|
||||
g.Meta `path:"/listModelManage" method:"get" tags:"new模型管理" summary:"new模型配置列表" dc:"new分页获取模型配置列表"`
|
||||
*beans.Page `json:"page"`
|
||||
ModelName string `p:"modelName" json:"modelName" dc:"模型名称(模糊查询,可选)"`
|
||||
ModelType int `p:"modelType" json:"modelType" dc:"模型类型"`
|
||||
Creator string `json:"creator" dc:"创建人"`
|
||||
}
|
||||
|
||||
type ListModelManageRes struct {
|
||||
List []*entity.ModelManage `json:"list" dc:"列表数据"`
|
||||
Total int `json:"total" dc:"总数"`
|
||||
}
|
||||
|
||||
type CheckChatModelReq struct {
|
||||
g.Meta `path:"/checkChatModel" method:"get" tags:"new模型管理" summary:"new检查是否为聊天模型" dc:"new检查是否为聊天模型"`
|
||||
}
|
||||
|
||||
type CheckChatModelRes struct {
|
||||
IsChatModel bool `json:"isChatModel" dc:"是否为聊天模型"`
|
||||
}
|
||||
|
||||
// ModelTypeReq 模型类型列表(分页)
|
||||
type ModelTypeReq struct {
|
||||
g.Meta `path:"/modelType" method:"get" tags:"new模型管理" summary:"new模型类型列表" dc:"new分页获取模型类型列表"`
|
||||
}
|
||||
|
||||
type ModelTypeRes struct {
|
||||
List []*model.TypeTree `json:"list" dc:"模型类型ID到名称的映射"`
|
||||
}
|
||||
|
||||
type ModelSupplierReq struct {
|
||||
g.Meta `path:"/modelSupplier" method:"get" tags:"new模型管理" summary:"new获取运营商列表" dc:"new获取运营商列表"`
|
||||
}
|
||||
|
||||
type ModelSupplierRes struct {
|
||||
List []*public.Option `json:"list" dc:"运营商名称到ID的映射"`
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"model-gateway/consts/model"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||
)
|
||||
|
||||
type modelManageCol struct {
|
||||
beans.SQLBaseCol
|
||||
ModelSupplier string
|
||||
ModelName string
|
||||
ModelType string
|
||||
BaseURL string
|
||||
SystemModel string
|
||||
HttpMethod string
|
||||
ChatModel string
|
||||
ResponseType string
|
||||
ApiKey string
|
||||
Enabled string
|
||||
RequestHeadMapping string
|
||||
RequestBodyMapping string
|
||||
ResponseMapping string
|
||||
ResponseBodyMapping string
|
||||
MaxConcurrency string
|
||||
TokenPredictPrice string
|
||||
TokenPredictPriceUnit string
|
||||
MaxTokens string
|
||||
MaxDuration string
|
||||
LastFrame string
|
||||
}
|
||||
|
||||
var ModelManageCol = modelManageCol{
|
||||
SQLBaseCol: beans.DefSQLBaseCol,
|
||||
ModelSupplier: "model_supplier",
|
||||
ModelName: "model_name",
|
||||
ModelType: "model_type",
|
||||
BaseURL: "base_url",
|
||||
SystemModel: "system_model",
|
||||
HttpMethod: "http_method",
|
||||
ChatModel: "chat_model",
|
||||
ResponseType: "response_type",
|
||||
ApiKey: "api_key",
|
||||
Enabled: "enabled",
|
||||
RequestHeadMapping: "request_head_mapping",
|
||||
RequestBodyMapping: "request_body_mapping",
|
||||
ResponseMapping: "response_mapping",
|
||||
ResponseBodyMapping: "response_body_mapping",
|
||||
MaxConcurrency: "max_concurrency",
|
||||
TokenPredictPrice: "token_predict_price",
|
||||
TokenPredictPriceUnit: "token_predict_price_unit",
|
||||
MaxTokens: "max_tokens",
|
||||
MaxDuration: "max_duration",
|
||||
LastFrame: "last_frame",
|
||||
}
|
||||
|
||||
type ModelManage struct {
|
||||
beans.SQLBaseDO `orm:",inline"`
|
||||
ModelSupplier model.SupplierType `orm:"model_supplier" json:"modelSupplier" description:"模型供应商"`
|
||||
ModelName string `orm:"model_name" json:"modelName" description:"模型名称"`
|
||||
ModelType model.ModelType `orm:"model_type" json:"modelType" description:"模型类型"`
|
||||
BaseURL string `orm:"base_url" json:"baseUrl" description:"模型地址"`
|
||||
SystemModel *bool `orm:"system_model" json:"systemModel" description:"系统模型"`
|
||||
HttpMethod string `orm:"http_method" json:"httpMethod" description:"http方法"`
|
||||
ChatModel *bool `orm:"chat_model" json:"ChatModel" description:"是否聊天模型"`
|
||||
ResponseType model.ResponseType `orm:"response_type" json:"responseType" description:"返回类型:1同步,2异步,3流"`
|
||||
ApiKey string `orm:"api_key" json:"apiKey" description:"api key"`
|
||||
Enabled *bool `orm:"enabled" json:"enabled" description:"是否启用"`
|
||||
RequestHeadMapping map[string]string `orm:"request_head_mapping" json:"requestHeadMapping" description:"请求头映射"`
|
||||
RequestBodyMapping map[string]any `orm:"request_body_mapping" json:"requestBodyMapping" description:"请求体映射"`
|
||||
ResponseMapping map[string]any `orm:"response_mapping" json:"responseMapping" description:"响应映射"`
|
||||
ResponseBodyMapping map[string]string `orm:"response_body_mapping" json:"responseBodyMapping" description:"响应主体映射"`
|
||||
MaxConcurrency int `orm:"max_concurrency" json:"maxConcurrency" description:"最大并发数"`
|
||||
TokenMapping *TokenMapping `orm:"token_mapping" json:"tokenMapping" description:"token映射"`
|
||||
AsyncTaskMapping *AsyncTaskMapping `orm:"async_task_mapping" json:"asyncTaskMapping" description:"异步任务映射"`
|
||||
TokenPredictPrice float64 `orm:"token_predict_price" json:"tokenPredictPrice" description:"模型Token预估价格"`
|
||||
TokenPredictPriceUnit string `orm:"token_predict_price_unit" json:"tokenPredictPriceUnit" description:"模型token预估价格单位(秒,百万Token,千Token,字数)"`
|
||||
MaxTokens int `orm:"max_tokens" json:"maxTokens" description:"最大token数"`
|
||||
MaxDuration int `orm:"max_duration" json:"maxDuration" description:"最大时长(秒)"`
|
||||
LastFrame string `orm:"last_frame" json:"lastFrame" description:"视频的尾帧图像"`
|
||||
}
|
||||
|
||||
type TokenMapping struct {
|
||||
PromptTokens string `json:"promptTokens" dc:"输入token"`
|
||||
CompletionTokens string `json:"completionTokens" dc:"输出token"`
|
||||
TotalTokens string `json:"totalTokens" dc:"总token"`
|
||||
}
|
||||
|
||||
type AsyncTaskMapping struct {
|
||||
Url string `json:"url" dc:"url"`
|
||||
HttpMethod string `json:"httpMethod" dc:"http方法" d:"POST"`
|
||||
RequestHeadMapping map[string]string `json:"requestHeadMapping" description:"请求头映射"`
|
||||
ResponseMapping map[string]any `json:"responseMapping" description:"响应映射"`
|
||||
TaskId string `json:"taskId" dc:"任务id"`
|
||||
TaskStatus string `json:"taskStatus" dc:"任务状态"`
|
||||
TaskStatusPending string `json:"taskStatusPending" dc:"任务状态-待处理"`
|
||||
TaskStatusRunning string `json:"taskStatusRunning" dc:"任务状态-运行中"`
|
||||
TaskStatusSuccess string `json:"taskStatusSuccess" dc:"任务状态-成功"`
|
||||
TaskStatusFailed string `json:"taskStatusFailed" dc:"任务状态-失败"`
|
||||
TaskStatusCancel string `json:"taskStatusCancel" dc:"任务状态-取消"`
|
||||
TaskStatusUnknown string `json:"taskStatusUnknown" dc:"任务状态-未知"`
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"model-gateway/consts/model"
|
||||
"model-gateway/consts/public"
|
||||
"model-gateway/dao"
|
||||
"model-gateway/model/dto"
|
||||
"model-gateway/model/entity"
|
||||
"model-gateway/service/gateway"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var ModelManage = &modelManageService{}
|
||||
|
||||
type modelManageService struct{}
|
||||
|
||||
// Create 创建模型
|
||||
func (s *modelManageService) Create(ctx context.Context, req *dto.CreateModelManageReq) (res *dto.CreateModelManageRes, err error) {
|
||||
err = gfdb.DB(ctx, public.DbNameModelGateway).Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
|
||||
// 1)检查是否是超管
|
||||
var isSuperAdmin bool
|
||||
isSuperAdmin, err = gateway.IsSuperAdmin(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.SystemModel = &isSuperAdmin
|
||||
// 1)如果设为会话模型,先把该用户旧会话模型取消
|
||||
err = s.CancelChatModel(ctx, req.ModelType, req.ChatModel, isSuperAdmin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 2)插入数据
|
||||
id, err := dao.ModelManage.Insert(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CreateModelManageRes{Id: id}
|
||||
return
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新模型配置
|
||||
func (s *modelManageService) Update(ctx context.Context, req *dto.UpdateModelManageReq) (err error) {
|
||||
err = gfdb.DB(ctx, public.DbNameModelGateway).Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
|
||||
var get *entity.ModelManage
|
||||
get, err = dao.ModelManage.GetNotTenantId(ctx, &dto.GetModelManageReq{
|
||||
Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var user *beans.User
|
||||
user, err = utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 1)如果不是创建者,且是系统模型,则需要拷贝
|
||||
if get.Creator != user.UserName {
|
||||
if get.SystemModel != nil && *get.SystemModel {
|
||||
if g.IsEmpty(req.ApiKey) {
|
||||
return fmt.Errorf("模型apiKey不能为空")
|
||||
}
|
||||
d := new(dto.CreateModelManageReq)
|
||||
err = gconv.Struct(req, d)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = s.Create(ctx, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
return fmt.Errorf("无权限操作")
|
||||
}
|
||||
|
||||
// 1)检查是否是超管
|
||||
var isSuperAdmin bool
|
||||
isSuperAdmin, err = gateway.IsSuperAdmin(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 1)如果设为会话模型,先把该用户旧会话模型取消
|
||||
err = s.CancelChatModel(ctx, req.ModelType, req.ChatModel, isSuperAdmin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 2)更新数据
|
||||
_, err = dao.ModelManage.Update(ctx, req)
|
||||
return
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (s *modelManageService) CancelChatModel(ctx context.Context, modelType model.ModelType, chatModel *bool, isSuperAdmin bool) (err error) {
|
||||
if !g.IsEmpty(chatModel) && *chatModel {
|
||||
if *modelType == *model.ModelTypeInference.Code {
|
||||
if isSuperAdmin {
|
||||
return fmt.Errorf("超级管理员不能设置会话模型")
|
||||
}
|
||||
// 2)获取该用户信息
|
||||
var user *beans.User
|
||||
user, err = utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 3)取消该用户之前的会话模型
|
||||
var get *entity.ModelManage
|
||||
get, err = dao.ModelManage.Get(ctx, &dto.GetModelManage{
|
||||
Creator: user.UserName,
|
||||
ChatModel: chatModel,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = dao.ModelManage.Update(ctx, &dto.UpdateModelManageReq{
|
||||
Id: get.Id,
|
||||
ChatModel: gconv.PtrBool(false),
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("只有推理模型可以设置成会话模型")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Delete 删除模型
|
||||
func (s *modelManageService) Delete(ctx context.Context, req *dto.DeleteModelManageReq) error {
|
||||
_, err := dao.ModelManage.Delete(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *modelManageService) Get(ctx context.Context, req *dto.GetModelManageReq) (res *dto.GetModelManageRes, err error) {
|
||||
get, err := dao.ModelManage.GetNotTenantId(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = gconv.Struct(get, &res)
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取模型列表
|
||||
func (s *modelManageService) List(ctx context.Context, req *dto.ListModelManageReq) (res *dto.ListModelManageRes, err error) {
|
||||
var user *beans.User
|
||||
user, err = utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Creator = user.UserName
|
||||
list, total, err := dao.ModelManage.ListNotTenantId(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.ListModelManageRes{
|
||||
Total: total,
|
||||
}
|
||||
err = gconv.Struct(list, &res.List)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *modelManageService) CheckChatModel(ctx context.Context, req *dto.CheckChatModelReq) (res *dto.CheckChatModelRes, err error) {
|
||||
user, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
get, err := dao.ModelManage.Get(ctx, &dto.GetModelManage{
|
||||
Creator: user.UserName,
|
||||
ChatModel: gconv.PtrBool(true),
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.CheckChatModelRes{
|
||||
IsChatModel: !g.IsEmpty(get),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetModelType 获取模型类型
|
||||
func (s *modelManageService) GetModelType(ctx context.Context, req *dto.ModelTypeReq) (res *dto.ModelTypeRes, err error) {
|
||||
res = &dto.ModelTypeRes{
|
||||
List: model.GetTypeTreeList(),
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetModelSupplier 获取运营商列表
|
||||
func (s *modelManageService) GetModelSupplier(ctx context.Context, req *dto.ModelSupplierReq) (res *dto.ModelSupplierRes, err error) {
|
||||
return &dto.ModelSupplierRes{
|
||||
List: model.GetSupplierOptionList(),
|
||||
}, nil
|
||||
}
|
||||
+119
-1
@@ -230,4 +230,122 @@ COMMENT ON COLUMN model_gateway_logs_op.success IS '是否成功:1成功/0失
|
||||
COMMENT ON COLUMN model_gateway_logs_op.error_msg IS '错误信息(失败时)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.cost_ms IS '耗时(毫秒)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.request_payload IS '请求 JSON';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.response_payload IS '响应 JSON';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.response_payload IS '响应 JSON';
|
||||
|
||||
-- =========================================================================================================================
|
||||
CREATE TABLE "public"."model_gateway_model_manage" (
|
||||
"id" int8 NOT NULL,
|
||||
"tenant_id" int8 NOT NULL DEFAULT 0,
|
||||
"creator" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"created_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
|
||||
"updated_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_at" timestamp(6),
|
||||
"model_supplier" varchar(32) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"model_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"model_type" varchar(32) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"base_url" varchar(512) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"system_model" bool,
|
||||
"http_method" varchar(32) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"chat_model" bool,
|
||||
"response_type" int2 NOT NULL DEFAULT 0,
|
||||
"api_key" varchar(255) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"enabled" bool,
|
||||
"request_head_mapping" jsonb DEFAULT '{}'::jsonb,
|
||||
"request_body_mapping" jsonb DEFAULT '{}'::jsonb,
|
||||
"response_mapping" jsonb DEFAULT '{}'::jsonb,
|
||||
"max_concurrency" int4 NOT NULL DEFAULT 0,
|
||||
"token_mapping" jsonb,
|
||||
"async_task_mapping" jsonb,
|
||||
"token_predict_price" numeric(12,6) NOT NULL DEFAULT 0.000000,
|
||||
"max_tokens" int4 NOT NULL DEFAULT 0,
|
||||
"last_frame" varchar(512) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
|
||||
"response_body_mapping" jsonb DEFAULT '{}'::jsonb,
|
||||
"token_predict_price_unit" varchar(32) COLLATE "pg_catalog"."default",
|
||||
"max_duration" int4,
|
||||
CONSTRAINT "model_gateway_model_manage_pkey" PRIMARY KEY ("id")
|
||||
)
|
||||
;
|
||||
|
||||
ALTER TABLE "public"."model_gateway_model_manage"
|
||||
OWNER TO "postgres";
|
||||
|
||||
CREATE INDEX "idx_model_manage_deleted_at" ON "public"."model_gateway_model_manage" USING btree (
|
||||
"deleted_at" "pg_catalog"."timestamp_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
CREATE INDEX "idx_model_manage_model_type" ON "public"."model_gateway_model_manage" USING btree (
|
||||
"model_type" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
CREATE INDEX "idx_model_manage_response_type" ON "public"."model_gateway_model_manage" USING btree (
|
||||
"response_type" "pg_catalog"."int2_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
CREATE INDEX "idx_model_manage_supplier" ON "public"."model_gateway_model_manage" USING btree (
|
||||
"model_supplier" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
CREATE INDEX "idx_model_manage_tenant_id" ON "public"."model_gateway_model_manage" USING btree (
|
||||
"tenant_id" "pg_catalog"."int8_ops" ASC NULLS LAST
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."id" IS '主键ID';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."tenant_id" IS '租户ID';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."creator" IS '创建人';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."created_at" IS '创建时间';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."updater" IS '更新人';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."updated_at" IS '更新时间';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."deleted_at" IS '删除时间(软删)';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."model_supplier" IS '模型供应商';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."model_name" IS '模型名称';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."model_type" IS '模型类型';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."base_url" IS '模型地址';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."system_model" IS '是否系统模型';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."http_method" IS 'http请求方法';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."chat_model" IS '是否聊天模型';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."response_type" IS '返回类型:1同步,2异步,3流';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."api_key" IS '接口密钥';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."enabled" IS '是否启用';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."request_head_mapping" IS '请求头映射';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."request_body_mapping" IS '请求体映射';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."response_mapping" IS '响应映射';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."max_concurrency" IS '最大并发数';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."token_mapping" IS 'token映射';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."async_task_mapping" IS '异步任务映射';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."token_predict_price" IS '模型Token预估价格';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."max_tokens" IS '最大token数';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."last_frame" IS '视频尾帧图像地址';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."response_body_mapping" IS '响应主体映射';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."token_predict_price_unit" IS '模型token预估价格单位(秒,百万Token,千Token,字数)';
|
||||
|
||||
COMMENT ON COLUMN "public"."model_gateway_model_manage"."max_duration" IS '最大时长(秒)';
|
||||
|
||||
COMMENT ON TABLE "public"."model_gateway_model_manage" IS '模型管理表';
|
||||
Reference in New Issue
Block a user