tokenFactory/model/supplier_capability.go

198 lines
9.3 KiB
Go

package model
import (
"errors"
"fmt"
"strings"
"sync"
"time"
"gorm.io/gorm"
)
// SupplierCapability 供应商技术能力档案表(与 supplier_applications 一对一)。
type SupplierCapability struct {
ID int `json:"id" gorm:"primaryKey;comment:主键ID"`
SupplierApplicationID int `json:"supplier_application_id" gorm:"uniqueIndex;not null;comment:供应商申请ID"`
CoreServiceTypes string `json:"core_service_types" gorm:"type:text;comment:核心服务类型(JSON数组)"`
SupportedModels string `json:"supported_models" gorm:"type:text;comment:支持的模型(JSON数组)"`
SupportedModelNotes string `json:"supported_model_notes" gorm:"type:text;comment:支持模型补充说明"`
SupportedAPIEndpoints string `json:"supported_api_endpoints" gorm:"type:text;comment:支持的API接口(JSON数组)"`
SupportedAPIEndpointExtra string `json:"supported_api_endpoint_extra" gorm:"type:text;comment:API接口补充说明"`
SupportedParams string `json:"supported_params" gorm:"type:text;comment:支持参数配置(JSON数组)"`
SupportedParamsExtra string `json:"supported_params_extra" gorm:"type:text;comment:参数配置补充说明"`
StreamingSupported bool `json:"streaming_supported" gorm:"type:boolean;default:false;comment:是否支持流式响应"`
StreamingNotes string `json:"streaming_notes" gorm:"type:text;comment:流式响应说明"`
StructuredOutputSupported bool `json:"structured_output_supported" gorm:"type:boolean;default:false;comment:是否支持结构化输出"`
StructuredOutputNotes string `json:"structured_output_notes" gorm:"type:text;comment:结构化输出说明"`
MultimodalTypes string `json:"multimodal_types" gorm:"type:text;comment:多模态支持类型(JSON数组)"`
MultimodalExtra string `json:"multimodal_extra" gorm:"type:text;comment:多模态补充说明"`
PricingModes string `json:"pricing_modes" gorm:"type:text;comment:定价模式(JSON数组)"`
ReferenceInputPrice string `json:"reference_input_price" gorm:"type:varchar(64);comment:参考输入单价(USD/1K Token)"`
ReferenceOutputPrice string `json:"reference_output_price" gorm:"type:varchar(64);comment:参考输出单价(USD/1K Token)"`
FailureBillingMode string `json:"failure_billing_mode" gorm:"type:varchar(32);comment:故障计费规则(bill/no_bill)"`
FailureBillingNotes string `json:"failure_billing_notes" gorm:"type:text;comment:故障计费说明"`
APIBaseURLs string `json:"api_base_urls" gorm:"type:text;comment:API接口地址(JSON数组)"`
OpenAICompatible bool `json:"openai_compatible" gorm:"column:open_ai_compatible;type:boolean;default:false;comment:是否兼容OpenAI规范"`
TruthCommitmentConfirmed bool `json:"truth_commitment_confirmed" gorm:"type:boolean;default:false;comment:信息真实性承诺"`
CreatedAt int64 `json:"created_at" gorm:"type:bigint;index;comment:创建时间戳"`
UpdatedAt int64 `json:"updated_at" gorm:"type:bigint;comment:更新时间戳"`
}
var (
ensureSupplierCapabilitySchemaOnce sync.Once
ensureSupplierCapabilitySchemaErr error
)
// EnsureSupplierCapabilitySchemaColumns 确保供应商能力表关键布尔字段已存在(兼容旧库漏迁移场景)。
func EnsureSupplierCapabilitySchemaColumns() error {
ensureSupplierCapabilitySchemaOnce.Do(func() {
// 兼容旧版本数据库缺列导致 upsert 报 "Unknown column"。
if !DB.Migrator().HasColumn(&SupplierCapability{}, "OpenAICompatible") {
if err := DB.Migrator().AddColumn(&SupplierCapability{}, "OpenAICompatible"); err != nil {
ensureSupplierCapabilitySchemaErr = fmt.Errorf("add column openai_compatible failed: %w", err)
return
}
}
if !DB.Migrator().HasColumn(&SupplierCapability{}, "TruthCommitmentConfirmed") {
if err := DB.Migrator().AddColumn(&SupplierCapability{}, "TruthCommitmentConfirmed"); err != nil {
ensureSupplierCapabilitySchemaErr = fmt.Errorf("add column truth_commitment_confirmed failed: %w", err)
return
}
}
})
return ensureSupplierCapabilitySchemaErr
}
// GetSupplierCapabilityByApplicationID 根据申请ID查询供应商技术能力档案。
func GetSupplierCapabilityByApplicationID(applicationID int) (*SupplierCapability, error) {
var item SupplierCapability
if err := DB.Where("supplier_application_id = ?", applicationID).First(&item).Error; err != nil {
return nil, err
}
return &item, nil
}
// UpsertSupplierCapabilityByApplicationID 按申请ID新增或更新供应商技术能力档案。
func UpsertSupplierCapabilityByApplicationID(applicationID int, capability *SupplierCapability) (*SupplierCapability, error) {
if err := EnsureSupplierCapabilitySchemaColumns(); err != nil {
return nil, err
}
tx := DB.Begin()
if tx.Error != nil {
return nil, tx.Error
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
now := time.Now().Unix()
var existing SupplierCapability
if err := tx.Where("supplier_application_id = ?", applicationID).First(&existing).Error; err != nil {
if err == gorm.ErrRecordNotFound {
capability.SupplierApplicationID = applicationID
capability.CreatedAt = now
capability.UpdatedAt = now
if err = tx.Create(capability).Error; err != nil {
tx.Rollback()
return nil, err
}
if err = tx.Commit().Error; err != nil {
return nil, err
}
return capability, nil
}
tx.Rollback()
return nil, err
}
updates := map[string]any{
"core_service_types": capability.CoreServiceTypes,
"supported_models": capability.SupportedModels,
"supported_model_notes": capability.SupportedModelNotes,
"supported_api_endpoints": capability.SupportedAPIEndpoints,
"supported_api_endpoint_extra": capability.SupportedAPIEndpointExtra,
"supported_params": capability.SupportedParams,
"supported_params_extra": capability.SupportedParamsExtra,
"streaming_supported": capability.StreamingSupported,
"streaming_notes": capability.StreamingNotes,
"structured_output_supported": capability.StructuredOutputSupported,
"structured_output_notes": capability.StructuredOutputNotes,
"multimodal_types": capability.MultimodalTypes,
"multimodal_extra": capability.MultimodalExtra,
"pricing_modes": capability.PricingModes,
"reference_input_price": capability.ReferenceInputPrice,
"reference_output_price": capability.ReferenceOutputPrice,
"failure_billing_mode": capability.FailureBillingMode,
"failure_billing_notes": capability.FailureBillingNotes,
"api_base_urls": capability.APIBaseURLs,
"open_ai_compatible": capability.OpenAICompatible,
"truth_commitment_confirmed": capability.TruthCommitmentConfirmed,
"updated_at": now,
}
if err := tx.Model(&SupplierCapability{}).Where("supplier_application_id = ?", applicationID).Updates(updates).Error; err != nil {
tx.Rollback()
return nil, err
}
existing.CoreServiceTypes = capability.CoreServiceTypes
existing.SupportedModels = capability.SupportedModels
existing.SupportedModelNotes = capability.SupportedModelNotes
existing.SupportedAPIEndpoints = capability.SupportedAPIEndpoints
existing.SupportedAPIEndpointExtra = capability.SupportedAPIEndpointExtra
existing.SupportedParams = capability.SupportedParams
existing.SupportedParamsExtra = capability.SupportedParamsExtra
existing.StreamingSupported = capability.StreamingSupported
existing.StreamingNotes = capability.StreamingNotes
existing.StructuredOutputSupported = capability.StructuredOutputSupported
existing.StructuredOutputNotes = capability.StructuredOutputNotes
existing.MultimodalTypes = capability.MultimodalTypes
existing.MultimodalExtra = capability.MultimodalExtra
existing.PricingModes = capability.PricingModes
existing.ReferenceInputPrice = capability.ReferenceInputPrice
existing.ReferenceOutputPrice = capability.ReferenceOutputPrice
existing.FailureBillingMode = capability.FailureBillingMode
existing.FailureBillingNotes = capability.FailureBillingNotes
existing.APIBaseURLs = capability.APIBaseURLs
existing.OpenAICompatible = capability.OpenAICompatible
existing.TruthCommitmentConfirmed = capability.TruthCommitmentConfirmed
existing.UpdatedAt = now
if err := tx.Commit().Error; err != nil {
return nil, err
}
return &existing, nil
}
// IsSupplierCapabilityNotFound 判断是否未找到供应商技术能力档案。
func IsSupplierCapabilityNotFound(err error) bool {
return errors.Is(err, gorm.ErrRecordNotFound)
}
// IsSupplierCapabilityComplete 判断供应商技术能力档案是否满足审批通过最低必填条件。
func IsSupplierCapabilityComplete(capability *SupplierCapability) bool {
if capability == nil {
return false
}
if strings.TrimSpace(capability.CoreServiceTypes) == "" {
return false
}
if strings.TrimSpace(capability.SupportedModels) == "" {
return false
}
if strings.TrimSpace(capability.SupportedAPIEndpoints) == "" {
return false
}
if strings.TrimSpace(capability.SupportedParams) == "" {
return false
}
if strings.TrimSpace(capability.PricingModes) == "" {
return false
}
if strings.TrimSpace(capability.FailureBillingMode) == "" {
return false
}
if strings.TrimSpace(capability.APIBaseURLs) == "" {
return false
}
return capability.TruthCommitmentConfirmed
}