feat(server): meter AI point usage across tenant AI features

Adds an ai_point_usage_logs ledger and a reserve/refund/complete pipeline
that charges AI points for article selection optimize, template analyze
/title/outline, and KOL prompt generate/optimize. Pending reservations
are reconciled when the kol-assist worker and template-assist tasks
finish or fail, so points refund automatically on errors. Workspace now
exposes the AI quota status and a paginated usage ledger.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 11:33:47 +08:00
parent 794a2d89db
commit e307a048d1
18 changed files with 1270 additions and 27 deletions
+34 -6
View File
@@ -23,12 +23,17 @@ type RecentArticle struct {
}
type QuotaSummary struct {
PlanCode string `json:"plan_code"`
PlanName string `json:"plan_name"`
TotalQuota int `json:"total_quota"`
UsedQuota int `json:"used_quota"`
Balance int `json:"balance"`
ResetAt *time.Time `json:"reset_at"`
PlanCode string `json:"plan_code"`
PlanName string `json:"plan_name"`
TotalQuota int `json:"total_quota"`
UsedQuota int `json:"used_quota"`
Balance int `json:"balance"`
ResetAt *time.Time `json:"reset_at"`
AIPointsTotal int `json:"ai_points_total"`
AIPointsUsed int `json:"ai_points_used"`
AIPointsBalance int `json:"ai_points_balance"`
AIPointBaseChars int `json:"ai_point_base_chars"`
AIPointsResetAt *time.Time `json:"ai_points_reset_at"`
}
type KolWorkspaceCard struct {
@@ -41,3 +46,26 @@ type KolWorkspaceCard struct {
PackageCover *string `json:"package_cover"`
KolDisplayName string `json:"kol_display_name"`
}
type AIPointUsageLog struct {
ID int64 `json:"id"`
UsageType string `json:"usage_type"`
ResourceType *string `json:"resource_type"`
ResourceID *int64 `json:"resource_id"`
ResourceUID *string `json:"resource_uid"`
RequestChars int `json:"request_chars"`
BaseChars int `json:"base_chars"`
Points int `json:"points"`
Status string `json:"status"`
Model *string `json:"model"`
ErrorMessage *string `json:"error_message"`
CompletedAt *time.Time `json:"completed_at"`
CreatedAt time.Time `json:"created_at"`
}
type AIPointUsageListResponse struct {
Items []AIPointUsageLog `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}