From 332f2cf59b93c66ca8069da7ee7de18998e53e2d Mon Sep 17 00:00:00 2001 From: dark Date: Sat, 14 Feb 2026 22:05:39 +0800 Subject: [PATCH] feat: add 7 AI entity models + AutoMigrate - AIProvider, AIModel, AIApiKey (platform config) - AIConversation, AIChatMessage (chat data) - AIUsageRecord, AIUserQuota (billing data) - AutoMigrate updated in servicecontext.go --- backend/internal/svc/servicecontext.go | 10 +++++++++- backend/model/ai_api_key_entity.go | 20 +++++++++++++++++++ backend/model/ai_chat_message_entity.go | 21 ++++++++++++++++++++ backend/model/ai_conversation_entity.go | 22 +++++++++++++++++++++ backend/model/ai_model_entity.go | 26 +++++++++++++++++++++++++ backend/model/ai_provider_entity.go | 22 +++++++++++++++++++++ backend/model/ai_usage_record_entity.go | 24 +++++++++++++++++++++++ backend/model/ai_user_quota_entity.go | 19 ++++++++++++++++++ 8 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 backend/model/ai_api_key_entity.go create mode 100644 backend/model/ai_chat_message_entity.go create mode 100644 backend/model/ai_conversation_entity.go create mode 100644 backend/model/ai_model_entity.go create mode 100644 backend/model/ai_provider_entity.go create mode 100644 backend/model/ai_usage_record_entity.go create mode 100644 backend/model/ai_user_quota_entity.go diff --git a/backend/internal/svc/servicecontext.go b/backend/internal/svc/servicecontext.go index 9e92cff..2e1cdbc 100644 --- a/backend/internal/svc/servicecontext.go +++ b/backend/internal/svc/servicecontext.go @@ -64,7 +64,15 @@ func NewServiceContext(c config.Config) *ServiceContext { } // 自动迁移表 - err = db.AutoMigrate(&model.User{}, &model.Profile{}, &model.File{}, &model.Menu{}, &model.Role{}, &model.RoleMenu{}, &model.Organization{}, &model.UserOrganization{}) + err = db.AutoMigrate( + &model.User{}, &model.Profile{}, &model.File{}, + &model.Menu{}, &model.Role{}, &model.RoleMenu{}, + &model.Organization{}, &model.UserOrganization{}, + // AI models + &model.AIProvider{}, &model.AIModel{}, &model.AIApiKey{}, + &model.AIConversation{}, &model.AIChatMessage{}, + &model.AIUsageRecord{}, &model.AIUserQuota{}, + ) if err != nil { panic("Failed to migrate database: " + err.Error()) } diff --git a/backend/model/ai_api_key_entity.go b/backend/model/ai_api_key_entity.go new file mode 100644 index 0000000..129e79a --- /dev/null +++ b/backend/model/ai_api_key_entity.go @@ -0,0 +1,20 @@ +package model + +import "time" + +// AIApiKey AI API密钥 +type AIApiKey struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + ProviderId int64 `gorm:"column:provider_id;index;not null" json:"providerId"` + UserId int64 `gorm:"column:user_id;index;default:0" json:"userId"` + KeyValue string `gorm:"column:key_value;type:text;not null" json:"-"` + IsActive bool `gorm:"column:is_active;default:true" json:"isActive"` + Remark string `gorm:"column:remark;type:varchar(255)" json:"remark"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"createdAt"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updatedAt"` +} + +// TableName 指定表名 +func (AIApiKey) TableName() string { + return "ai_api_key" +} diff --git a/backend/model/ai_chat_message_entity.go b/backend/model/ai_chat_message_entity.go new file mode 100644 index 0000000..a12715a --- /dev/null +++ b/backend/model/ai_chat_message_entity.go @@ -0,0 +1,21 @@ +package model + +import "time" + +// AIChatMessage AI聊天消息 +type AIChatMessage struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + ConversationId int64 `gorm:"column:conversation_id;index;not null" json:"conversationId"` + Role string `gorm:"column:role;type:varchar(20);not null" json:"role"` + Content string `gorm:"column:content;type:longtext" json:"content"` + TokenCount int `gorm:"column:token_count;default:0" json:"tokenCount"` + Cost float64 `gorm:"column:cost;type:decimal(10,6);default:0" json:"cost"` + ModelId string `gorm:"column:model_id;type:varchar(100)" json:"modelId"` + LatencyMs int `gorm:"column:latency_ms;default:0" json:"latencyMs"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"createdAt"` +} + +// TableName 指定表名 +func (AIChatMessage) TableName() string { + return "ai_chat_message" +} diff --git a/backend/model/ai_conversation_entity.go b/backend/model/ai_conversation_entity.go new file mode 100644 index 0000000..eec123a --- /dev/null +++ b/backend/model/ai_conversation_entity.go @@ -0,0 +1,22 @@ +package model + +import "time" + +// AIConversation AI对话 +type AIConversation struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + UserId int64 `gorm:"column:user_id;index;not null" json:"userId"` + Title string `gorm:"column:title;type:varchar(200);default:'新对话'" json:"title"` + ModelId string `gorm:"column:model_id;type:varchar(100)" json:"modelId"` + ProviderId int64 `gorm:"column:provider_id;default:0" json:"providerId"` + TotalTokens int64 `gorm:"column:total_tokens;default:0" json:"totalTokens"` + TotalCost float64 `gorm:"column:total_cost;type:decimal(10,6);default:0" json:"totalCost"` + IsArchived bool `gorm:"column:is_archived;default:false" json:"isArchived"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"createdAt"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updatedAt"` +} + +// TableName 指定表名 +func (AIConversation) TableName() string { + return "ai_conversation" +} diff --git a/backend/model/ai_model_entity.go b/backend/model/ai_model_entity.go new file mode 100644 index 0000000..b847ba4 --- /dev/null +++ b/backend/model/ai_model_entity.go @@ -0,0 +1,26 @@ +package model + +import "time" + +// AIModel AI模型配置 +type AIModel struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + ProviderId int64 `gorm:"column:provider_id;index;not null" json:"providerId"` + ModelId string `gorm:"column:model_id;type:varchar(100);not null" json:"modelId"` + DisplayName string `gorm:"column:display_name;type:varchar(100)" json:"displayName"` + InputPrice float64 `gorm:"column:input_price;type:decimal(10,6);default:0" json:"inputPrice"` + OutputPrice float64 `gorm:"column:output_price;type:decimal(10,6);default:0" json:"outputPrice"` + MaxTokens int `gorm:"column:max_tokens;default:4096" json:"maxTokens"` + ContextWindow int `gorm:"column:context_window;default:128000" json:"contextWindow"` + SupportsStream bool `gorm:"column:supports_stream;default:true" json:"supportsStream"` + SupportsVision bool `gorm:"column:supports_vision;default:false" json:"supportsVision"` + IsActive bool `gorm:"column:is_active;default:true" json:"isActive"` + SortOrder int `gorm:"column:sort_order;default:0" json:"sortOrder"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"createdAt"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updatedAt"` +} + +// TableName 指定表名 +func (AIModel) TableName() string { + return "ai_model" +} diff --git a/backend/model/ai_provider_entity.go b/backend/model/ai_provider_entity.go new file mode 100644 index 0000000..d030ce1 --- /dev/null +++ b/backend/model/ai_provider_entity.go @@ -0,0 +1,22 @@ +package model + +import "time" + +// AIProvider AI供应商模型 +type AIProvider struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Name string `gorm:"column:name;type:varchar(50);uniqueIndex;not null" json:"name"` + DisplayName string `gorm:"column:display_name;type:varchar(100);not null" json:"displayName"` + BaseUrl string `gorm:"column:base_url;type:varchar(255)" json:"baseUrl"` + SdkType string `gorm:"column:sdk_type;type:varchar(20);default:'openai_compat'" json:"sdkType"` + Protocol string `gorm:"column:protocol;type:varchar(20);default:'openai'" json:"protocol"` + IsActive bool `gorm:"column:is_active;default:true" json:"isActive"` + SortOrder int `gorm:"column:sort_order;default:0" json:"sortOrder"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"createdAt"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updatedAt"` +} + +// TableName 指定表名 +func (AIProvider) TableName() string { + return "ai_provider" +} diff --git a/backend/model/ai_usage_record_entity.go b/backend/model/ai_usage_record_entity.go new file mode 100644 index 0000000..1c49946 --- /dev/null +++ b/backend/model/ai_usage_record_entity.go @@ -0,0 +1,24 @@ +package model + +import "time" + +// AIUsageRecord AI使用记录 +type AIUsageRecord struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + UserId int64 `gorm:"column:user_id;index;not null" json:"userId"` + ProviderId int64 `gorm:"column:provider_id;index" json:"providerId"` + ModelId string `gorm:"column:model_id;type:varchar(100)" json:"modelId"` + InputTokens int `gorm:"column:input_tokens;default:0" json:"inputTokens"` + OutputTokens int `gorm:"column:output_tokens;default:0" json:"outputTokens"` + Cost float64 `gorm:"column:cost;type:decimal(10,6);default:0" json:"cost"` + ApiKeyId int64 `gorm:"column:api_key_id;default:0" json:"apiKeyId"` + Status string `gorm:"column:status;type:varchar(20);default:'ok'" json:"status"` + LatencyMs int `gorm:"column:latency_ms;default:0" json:"latencyMs"` + ErrorMessage string `gorm:"column:error_message;type:text" json:"errorMessage"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"createdAt"` +} + +// TableName 指定表名 +func (AIUsageRecord) TableName() string { + return "ai_usage_record" +} diff --git a/backend/model/ai_user_quota_entity.go b/backend/model/ai_user_quota_entity.go new file mode 100644 index 0000000..2d8d910 --- /dev/null +++ b/backend/model/ai_user_quota_entity.go @@ -0,0 +1,19 @@ +package model + +import "time" + +// AIUserQuota AI用户额度 +type AIUserQuota struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + UserId int64 `gorm:"column:user_id;uniqueIndex;not null" json:"userId"` + Balance float64 `gorm:"column:balance;type:decimal(10,4);default:0" json:"balance"` + TotalRecharged float64 `gorm:"column:total_recharged;type:decimal(10,4);default:0" json:"totalRecharged"` + TotalConsumed float64 `gorm:"column:total_consumed;type:decimal(10,4);default:0" json:"totalConsumed"` + FrozenAmount float64 `gorm:"column:frozen_amount;type:decimal(10,4);default:0" json:"frozenAmount"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updatedAt"` +} + +// TableName 指定表名 +func (AIUserQuota) TableName() string { + return "ai_user_quota" +}