4b0b5356c2
CI / docker (push) Successful in 2m55s
Text keys use OpenAI routes; image keys use predictions with ingress Model ID, OpenAPI input schemas, protocol-aware admin whitelist, and in-app API docs aligned to UI conventions. Co-authored-by: Cursor <cursoragent@cursor.com>
245 lines
11 KiB
Go
245 lines
11 KiB
Go
package model
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
type ProviderType string
|
|
|
|
const (
|
|
ProviderOpenAI ProviderType = "openai"
|
|
ProviderAnthropic ProviderType = "anthropic"
|
|
ProviderCustom ProviderType = "custom"
|
|
ProviderAzureOpenAI ProviderType = "azure_openai"
|
|
ProviderOpenRouter ProviderType = "openrouter"
|
|
ProviderOllama ProviderType = "ollama"
|
|
ProviderComfyUI ProviderType = "comfyui"
|
|
)
|
|
|
|
type WorkflowType string
|
|
|
|
const (
|
|
WorkflowTxt2Img WorkflowType = "txt2img"
|
|
WorkflowImg2Img WorkflowType = "img2img"
|
|
)
|
|
|
|
type PredictionStatus string
|
|
|
|
const (
|
|
PredictionStarting PredictionStatus = "starting"
|
|
PredictionProcessing PredictionStatus = "processing"
|
|
PredictionSucceeded PredictionStatus = "succeeded"
|
|
PredictionFailed PredictionStatus = "failed"
|
|
PredictionCanceled PredictionStatus = "canceled"
|
|
)
|
|
|
|
type ProviderStatus string
|
|
|
|
const (
|
|
ProviderHealthy ProviderStatus = "healthy"
|
|
ProviderUnhealthy ProviderStatus = "unhealthy"
|
|
ProviderUnknown ProviderStatus = "unknown"
|
|
)
|
|
|
|
type Provider struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
Name string `gorm:"uniqueIndex;not null" json:"name"`
|
|
Type ProviderType `gorm:"not null" json:"type"`
|
|
Category ProviderCategory `gorm:"not null;default:llm" json:"category"`
|
|
BaseURL string `json:"base_url"`
|
|
AllowedEndpointsJSON string `gorm:"default:'[\"list_models\",\"chat_completion\"]'" json:"allowed_endpoints_json"`
|
|
EndpointPathsJSON string `gorm:"default:'{}'" json:"endpoint_paths_json"`
|
|
Status ProviderStatus `gorm:"default:unknown" json:"status"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
Keys []ProviderKey `gorm:"foreignKey:ProviderID" json:"keys,omitempty"`
|
|
Models []ModelEntry `gorm:"foreignKey:ProviderID" json:"models,omitempty"`
|
|
}
|
|
|
|
type ProviderKey struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
ProviderID uint `gorm:"index;not null" json:"provider_id"`
|
|
Name string `gorm:"not null" json:"name"`
|
|
APIKeyEnc string `gorm:"not null" json:"-"`
|
|
Weight float64 `gorm:"default:1" json:"weight"`
|
|
ModelsJSON string `gorm:"default:'[\"*\"]'" json:"models_json"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
MaxRequestsPerDay int `gorm:"default:0" json:"max_requests_per_day"`
|
|
MaxTokensPerDay int64 `gorm:"default:0" json:"max_tokens_per_day"`
|
|
RequestsToday int `gorm:"default:0" json:"requests_today"`
|
|
TokensToday int64 `gorm:"default:0" json:"tokens_today"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type ModelEntry struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
ProviderID uint `gorm:"index;not null" json:"provider_id"`
|
|
ModelID string `gorm:"not null" json:"model_id"`
|
|
Alias string `gorm:"index" json:"alias"`
|
|
DisplayName string `json:"display_name"`
|
|
WorkflowType WorkflowType `gorm:"default:txt2img" json:"workflow_type"`
|
|
WorkflowJSON string `gorm:"type:text" json:"workflow_json"`
|
|
InputBindingJSON string `gorm:"type:text" json:"input_binding_json"`
|
|
VersionHash string `gorm:"index" json:"version_hash"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type IngressKey struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
Name string `gorm:"not null" json:"name"`
|
|
KeyHash string `gorm:"uniqueIndex;not null" json:"-"`
|
|
Prefix string `gorm:"not null" json:"prefix"`
|
|
Protocol IngressKeyProtocol `gorm:"not null;default:text" json:"protocol"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
BudgetLimit float64 `gorm:"default:0" json:"budget_limit"`
|
|
BudgetUsed float64 `gorm:"default:0" json:"budget_used"`
|
|
RateLimitRPM int `gorm:"default:0" json:"rate_limit_rpm"`
|
|
RateLimitTPM int `gorm:"default:0" json:"rate_limit_tpm"`
|
|
AllowedProvidersJSON string `gorm:"default:'[\"*\"]'" json:"allowed_providers_json"`
|
|
AllowedModelsJSON string `gorm:"default:'[\"*\"]'" json:"allowed_models_json"`
|
|
RequestCount int64 `gorm:"default:0" json:"request_count"`
|
|
TokenCount int64 `gorm:"default:0" json:"token_count"`
|
|
ExpiresAt *time.Time `json:"expires_at"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type AdminUser struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
Username string `gorm:"uniqueIndex;not null" json:"username"`
|
|
PasswordHash string `gorm:"not null" json:"-"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type AdminSession struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
TokenHash string `gorm:"uniqueIndex;not null" json:"-"`
|
|
ExpiresAt time.Time `gorm:"index" json:"expires_at"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type IPRuleType string
|
|
|
|
const (
|
|
IPRuleAllow IPRuleType = "allow"
|
|
IPRuleDeny IPRuleType = "deny"
|
|
)
|
|
|
|
type IPRuleScope string
|
|
|
|
const (
|
|
IPScopeAdmin IPRuleScope = "admin"
|
|
IPScopeProxy IPRuleScope = "proxy"
|
|
IPScopeAll IPRuleScope = "all"
|
|
)
|
|
|
|
type IPRule struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
CIDR string `gorm:"column:cidr;not null" json:"cidr"`
|
|
Type IPRuleType `gorm:"not null" json:"type"`
|
|
Scope IPRuleScope `gorm:"not null;default:proxy" json:"scope"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type UsageRecord struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
IngressKeyID uint `gorm:"index" json:"ingress_key_id"`
|
|
ProviderID uint `gorm:"index" json:"provider_id"`
|
|
ProviderKeyID uint `gorm:"index" json:"provider_key_id"`
|
|
ClientIP string `gorm:"index" json:"client_ip"`
|
|
Endpoint string `json:"endpoint"`
|
|
Model string `json:"model"`
|
|
TokensIn int `json:"tokens_in"`
|
|
TokensOut int `json:"tokens_out"`
|
|
Cost float64 `json:"cost"`
|
|
LatencyMs int64 `json:"latency_ms"`
|
|
Status string `json:"status"`
|
|
Stream bool `json:"stream"`
|
|
ErrorMsg string `json:"error_msg"`
|
|
RequestBody string `gorm:"type:text" json:"request_body,omitempty"`
|
|
ResponseBody string `gorm:"type:text" json:"response_body,omitempty"`
|
|
CreatedAt time.Time `gorm:"index" json:"created_at"`
|
|
}
|
|
|
|
const (
|
|
MaxUsageLogRecords = 500
|
|
EndpointAdminLogin = "admin_login"
|
|
EndpointPrediction = "prediction"
|
|
)
|
|
|
|
type Prediction struct {
|
|
ID string `gorm:"primaryKey" json:"id"`
|
|
IngressKeyID uint `gorm:"index;not null" json:"ingress_key_id"`
|
|
ProviderID uint `gorm:"index;not null" json:"provider_id"`
|
|
ProviderKeyID uint `gorm:"index" json:"provider_key_id"`
|
|
ModelEntryID uint `gorm:"index" json:"model_entry_id"`
|
|
Version string `json:"version"`
|
|
Model string `json:"model"`
|
|
InputJSON string `gorm:"type:text" json:"input_json"`
|
|
Status PredictionStatus `gorm:"index;not null;default:starting" json:"status"`
|
|
ComfyPromptID string `json:"comfy_prompt_id"`
|
|
ClientID string `json:"client_id"`
|
|
OutputJSON string `gorm:"type:text" json:"output_json"`
|
|
Error string `gorm:"type:text" json:"error"`
|
|
Logs string `gorm:"type:text" json:"logs"`
|
|
MetricsJSON string `gorm:"type:text" json:"metrics_json"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
StartedAt *time.Time `json:"started_at"`
|
|
CompletedAt *time.Time `json:"completed_at"`
|
|
}
|
|
|
|
type StoredImage struct {
|
|
ID string `gorm:"primaryKey" json:"id"`
|
|
PredictionID string `gorm:"index;not null" json:"prediction_id"`
|
|
Filename string `json:"filename"`
|
|
LocalPath string `json:"-"`
|
|
Mime string `json:"mime"`
|
|
Size int64 `json:"size"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// RoutingRule Virtual Key 路由:按模型匹配绑定 Provider / ProviderKey
|
|
type RoutingRule struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
IngressKeyID uint `gorm:"index;not null" json:"ingress_key_id"`
|
|
ModelPattern string `gorm:"not null" json:"model_pattern"`
|
|
ProviderID uint `gorm:"not null" json:"provider_id"`
|
|
ProviderKeyID uint `gorm:"default:0" json:"provider_key_id"`
|
|
Priority int `gorm:"default:0" json:"priority"`
|
|
Enabled bool `gorm:"default:true" json:"enabled"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// SystemSettings singleton (id=1) for runtime configuration managed via admin UI.
|
|
type SystemSettings struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
EncryptionKey string `gorm:"not null" json:"-"`
|
|
SessionTTLSeconds int64 `gorm:"not null;default:86400" json:"session_ttl_seconds"`
|
|
LoginMaxAttempts int `gorm:"not null;default:5" json:"login_max_attempts"`
|
|
LoginLockoutSeconds int64 `gorm:"not null;default:900" json:"login_lockout_seconds"`
|
|
TrustedProxiesJSON string `gorm:"default:'[]'" json:"trusted_proxies_json"`
|
|
UsageFlushSeconds int64 `gorm:"not null;default:5" json:"usage_flush_seconds"`
|
|
HealthCheckSeconds int64 `gorm:"not null;default:30" json:"health_check_seconds"`
|
|
GatewayMaxRetries int `gorm:"not null;default:3" json:"gateway_max_retries"`
|
|
GatewayRetryBackoffMs int `gorm:"not null;default:200" json:"gateway_retry_backoff_ms"`
|
|
ImageStoragePath string `gorm:"default:'images'" json:"image_storage_path"`
|
|
PublicBaseURL string `json:"public_base_url"`
|
|
SignedURLTTLSeconds int64 `gorm:"not null;default:3600" json:"signed_url_ttl_seconds"`
|
|
PredictionWaitSeconds int64 `gorm:"not null;default:60" json:"prediction_wait_seconds"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type HealthCheckRecord struct {
|
|
ID uint `gorm:"primaryKey" json:"id"`
|
|
ProviderID uint `gorm:"index" json:"provider_id"`
|
|
Status ProviderStatus `json:"status"`
|
|
LatencyMs int64 `json:"latency_ms"`
|
|
ErrorMsg string `json:"error_msg"`
|
|
CheckedAt time.Time `gorm:"index" json:"checked_at"`
|
|
}
|