package ai import ( "time" "gorm.io/gorm" "eai_agentplatform/backend/internal/model" "eai_agentplatform/backend/internal/store" ) // ────────────────────────────────────────────── // 按用户算力点计费 // ────────────────────────────────────────────── // AI 能力常量 const ( CapabilityAIChat = "ai_chat" // PathCoach 对话(每轮扣 1 点) CapabilityTextGen = "text_gen" // 快捷动作(情景演练/查佣金/产品对比,扣 1 点) CapabilityImageGen = "image_gen" // 文生图(按次扣点) CapabilityEmbed = "embed" // 知识检索内部 embedding(不扣点,仅审计) CapabilityEssayGrade = "essay_grade" // 简答题 LLM 评分(系统自动,不扣点,仅审计) ) // CapabilityCredits 各能力扣点成本 var CapabilityCredits = map[string]int{ CapabilityAIChat: 1, CapabilityTextGen: 1, CapabilityImageGen: 1, CapabilityEmbed: 0, CapabilityEssayGrade: 0, } // ComputeCredits 扣点决策:仅「成功」才扣点;失败不扣。 func ComputeCredits(capability string, success bool) int { if !success { return 0 } return CapabilityCredits[capability] } // LogEntry 一次 AI 调用的审计入参 type LogEntry struct { UserID uint Capability string // SpecialistKey 本次调用以哪个专员的身份进行;空 = 通用助手 SpecialistKey string Provider string AIRouteID string Model string TokensInput int TokensOutput int Success bool ErrorMessage string LatencyMs int } // LogCall 写 ai_call_log;成功且需扣点时从用户余额扣点。审计写入失败不阻断主流程。 func LogCall(e LogEntry) { credits := ComputeCredits(e.Capability, e.Success) status := "success" if !e.Success { status = "failed" } rec := model.AiCallLog{ UserID: e.UserID, Capability: e.Capability, SpecialistKey: e.SpecialistKey, Provider: e.Provider, AIRouteID: e.AIRouteID, Model: e.Model, TokensInput: e.TokensInput, TokensOutput: e.TokensOutput, CreditsCharged: credits, Status: status, ErrorMessage: e.ErrorMessage, LatencyMs: e.LatencyMs, CreatedAt: time.Now(), } if err := store.DB.Create(&rec).Error; err != nil { return } if credits > 0 { store.DB.Model(&model.User{}).Where("id = ?", e.UserID). UpdateColumn("ai_points", gorm.Expr("ai_points - ?", credits)) } }