212 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package modelmgr
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 
 | |
| 	"github.com/coze-dev/coze-studio/backend/api/model/ocean/cloud/developer_api"
 | |
| 	"github.com/coze-dev/coze-studio/backend/infra/contract/modelmgr"
 | |
| 	"github.com/coze-dev/coze-studio/backend/infra/impl/storage"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/i18n"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/lang/sets"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/logs"
 | |
| )
 | |
| 
 | |
| type ModelmgrApplicationService struct {
 | |
| 	Mgr       modelmgr.Manager
 | |
| 	TosClient storage.Storage
 | |
| }
 | |
| 
 | |
| var ModelmgrApplicationSVC = &ModelmgrApplicationService{}
 | |
| 
 | |
| func (m *ModelmgrApplicationService) GetModelList(ctx context.Context, _ *developer_api.GetTypeListRequest) (
 | |
| 	resp *developer_api.GetTypeListResponse, err error,
 | |
| ) {
 | |
| 	// It is generally not possible to configure so many models simultaneously
 | |
| 	const modelMaxLimit = 300
 | |
| 
 | |
| 	modelResp, err := m.Mgr.ListModel(ctx, &modelmgr.ListModelRequest{
 | |
| 		Limit:  modelMaxLimit,
 | |
| 		Cursor: nil,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	locale := i18n.GetLocale(ctx)
 | |
| 	modelList, err := slices.TransformWithErrorCheck(modelResp.ModelList, func(mm *modelmgr.Model) (*developer_api.Model, error) {
 | |
| 		logs.CtxInfof(ctx, "ChatModel DefaultParameters: %v", mm.DefaultParameters)
 | |
| 		if mm.IconURI != "" {
 | |
| 			iconUrl, err := m.TosClient.GetObjectUrl(ctx, mm.IconURI)
 | |
| 			if err == nil {
 | |
| 				mm.IconURL = iconUrl
 | |
| 			}
 | |
| 		}
 | |
| 		return modelDo2To(mm, locale)
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return &developer_api.GetTypeListResponse{
 | |
| 		Code: 0,
 | |
| 		Msg:  "success",
 | |
| 		Data: &developer_api.GetTypeListData{
 | |
| 			ModelList: modelList,
 | |
| 		},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func modelDo2To(model *modelmgr.Model, locale i18n.Locale) (*developer_api.Model, error) {
 | |
| 	mm := model.Meta
 | |
| 
 | |
| 	mps := slices.Transform(model.DefaultParameters,
 | |
| 		func(param *modelmgr.Parameter) *developer_api.ModelParameter {
 | |
| 			return parameterDo2To(param, locale)
 | |
| 		},
 | |
| 	)
 | |
| 
 | |
| 	modalSet := sets.FromSlice(mm.Capability.InputModal)
 | |
| 
 | |
| 	return &developer_api.Model{
 | |
| 		Name:             model.Name,
 | |
| 		ModelType:        model.ID,
 | |
| 		ModelClass:       mm.Protocol.TOModelClass(),
 | |
| 		ModelIcon:        model.IconURL,
 | |
| 		ModelInputPrice:  0,
 | |
| 		ModelOutputPrice: 0,
 | |
| 		ModelQuota: &developer_api.ModelQuota{
 | |
| 			TokenLimit: int32(mm.Capability.MaxTokens),
 | |
| 			TokenResp:  int32(mm.Capability.OutputTokens),
 | |
| 			// TokenSystem:       0,
 | |
| 			// TokenUserIn:       0,
 | |
| 			// TokenToolsIn:      0,
 | |
| 			// TokenToolsOut:     0,
 | |
| 			// TokenData:         0,
 | |
| 			// TokenHistory:      0,
 | |
| 			// TokenCutSwitch:    false,
 | |
| 			PriceIn:           0,
 | |
| 			PriceOut:          0,
 | |
| 			SystemPromptLimit: nil,
 | |
| 		},
 | |
| 		ModelName:      model.Name,
 | |
| 		ModelClassName: mm.Protocol.TOModelClass().String(),
 | |
| 		IsOffline:      mm.Status != modelmgr.StatusInUse,
 | |
| 		ModelParams:    mps,
 | |
| 		ModelDesc: []*developer_api.ModelDescGroup{
 | |
| 			{
 | |
| 				GroupName: "Description",
 | |
| 				Desc:      []string{model.Description.Read(locale)},
 | |
| 			},
 | |
| 		},
 | |
| 		FuncConfig:     nil,
 | |
| 		EndpointName:   nil,
 | |
| 		ModelTagList:   nil,
 | |
| 		IsUpRequired:   nil,
 | |
| 		ModelBriefDesc: model.Description.Read(locale),
 | |
| 		ModelSeries: &developer_api.ModelSeriesInfo{ // TODO: Replace with real configuration
 | |
| 			SeriesName: "热门模型",
 | |
| 		},
 | |
| 		ModelStatusDetails: nil,
 | |
| 		ModelAbility: &developer_api.ModelAbility{
 | |
| 			CotDisplay:         ptr.Of(mm.Capability.Reasoning),
 | |
| 			FunctionCall:       ptr.Of(mm.Capability.FunctionCall),
 | |
| 			ImageUnderstanding: ptr.Of(modalSet.Contains(modelmgr.ModalImage)),
 | |
| 			VideoUnderstanding: ptr.Of(modalSet.Contains(modelmgr.ModalVideo)),
 | |
| 			AudioUnderstanding: ptr.Of(modalSet.Contains(modelmgr.ModalAudio)),
 | |
| 			SupportMultiModal:  ptr.Of(len(modalSet) > 1),
 | |
| 			PrefillResp:        ptr.Of(mm.Capability.PrefillResponse),
 | |
| 		},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func parameterDo2To(param *modelmgr.Parameter, locale i18n.Locale) *developer_api.ModelParameter {
 | |
| 	if param == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	apiOptions := make([]*developer_api.Option, 0, len(param.Options))
 | |
| 	for _, opt := range param.Options {
 | |
| 		apiOptions = append(apiOptions, &developer_api.Option{
 | |
| 			Label: opt.Label,
 | |
| 			Value: opt.Value,
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	var custom string
 | |
| 	var creative, balance, precise *string
 | |
| 	if val, ok := param.DefaultVal[modelmgr.DefaultTypeDefault]; ok {
 | |
| 		custom = val
 | |
| 	}
 | |
| 
 | |
| 	if val, ok := param.DefaultVal[modelmgr.DefaultTypeCreative]; ok {
 | |
| 		creative = ptr.Of(val)
 | |
| 	}
 | |
| 
 | |
| 	if val, ok := param.DefaultVal[modelmgr.DefaultTypeBalance]; ok {
 | |
| 		balance = ptr.Of(val)
 | |
| 	}
 | |
| 
 | |
| 	if val, ok := param.DefaultVal[modelmgr.DefaultTypePrecise]; ok {
 | |
| 		precise = ptr.Of(val)
 | |
| 	}
 | |
| 
 | |
| 	return &developer_api.ModelParameter{
 | |
| 		Name:  string(param.Name),
 | |
| 		Label: param.Label.Read(locale),
 | |
| 		Desc:  param.Desc.Read(locale),
 | |
| 		Type: func() developer_api.ModelParamType {
 | |
| 			switch param.Type {
 | |
| 			case modelmgr.ValueTypeBoolean:
 | |
| 				return developer_api.ModelParamType_Boolean
 | |
| 			case modelmgr.ValueTypeInt:
 | |
| 				return developer_api.ModelParamType_Int
 | |
| 			case modelmgr.ValueTypeFloat:
 | |
| 				return developer_api.ModelParamType_Float
 | |
| 			default:
 | |
| 				return developer_api.ModelParamType_String
 | |
| 			}
 | |
| 		}(),
 | |
| 		Min:       param.Min,
 | |
| 		Max:       param.Max,
 | |
| 		Precision: int32(param.Precision),
 | |
| 		DefaultVal: &developer_api.ModelParamDefaultValue{
 | |
| 			DefaultVal: custom,
 | |
| 			Creative:   creative,
 | |
| 			Balance:    balance,
 | |
| 			Precise:    precise,
 | |
| 		},
 | |
| 		Options: apiOptions,
 | |
| 		ParamClass: &developer_api.ModelParamClass{
 | |
| 			ClassID: func() int32 {
 | |
| 				switch param.Style.Widget {
 | |
| 				case modelmgr.WidgetSlider:
 | |
| 					return 1
 | |
| 				case modelmgr.WidgetRadioButtons:
 | |
| 					return 2
 | |
| 				default:
 | |
| 					return 0
 | |
| 				}
 | |
| 			}(),
 | |
| 			Label: param.Style.Label.Read(locale),
 | |
| 		},
 | |
| 	}
 | |
| }
 |