Files
team-api/relay/common/provider.go
T

255 lines
9.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package common
import (
"context"
"errors"
"time"
)
// ErrChannelUnavailable 没有可用渠道
var ErrChannelUnavailable = errors.New("no available channel")
// ErrModelNotFound 模型不存在
var ErrModelNotFound = errors.New("model not found")
// ErrStreamInterrupted 流式响应被客户端中断
var ErrStreamInterrupted = errors.New("stream interrupted by client disconnect")
// ErrTenantModelNotEnabled 租户未启用该模型
var ErrTenantModelNotEnabled = errors.New("model not enabled for this tenant")
// DeprecationInfo 模型弃用信息
type DeprecationInfo struct {
Deprecated bool
SunsetDate string // 格式: "2006-01-02",空表示未设置
ReplacementModel string
}
// DataProvider 是 relay 层访问业务数据的接口。
// 实现在 internal/logic/relay/provider.go 中,使用 GoFrame ORM。
// relay/ 层通过此接口获取数据,不直接依赖 GoFrame。
type DataProvider interface {
// ValidateApiKey 验证 API Key 并返回认证信息。
// rawKey 是完整的 API Key 原值(如 sk-a1b2c3d4e5f6...)。
ValidateApiKey(ctx context.Context, rawKey string) (*ApiKeyInfo, error)
// GetChannelForModel 为指定模型选择最佳渠道。
// tenantID 和 userID 用于亲和性计算。
// excludeChannelIDs 是本次请求已尝试过且失败的渠道,用于重试时排除。
GetChannelForModel(ctx context.Context, tenantID, userID int64, modelName string, excludeChannelIDs []int64) (*ChannelSelection, error)
// GetModelMapping 获取模型映射信息。
// 返回标准模型名和分类(chat/embedding/image 等)。
GetModelMapping(ctx context.Context, modelName string) (standardName string, category string, err error)
// RecordUsage 异步记录 API 调用用量日志。
RecordUsage(ctx context.Context, record *UsageRecord)
// RecordAudit 异步记录请求审计日志。
RecordAudit(ctx context.Context, record *AuditRecord)
// UpdateTaskAudit 更新异步任务的审计记录(任务完成时调用)。
// 通过 task_id 查找提交阶段写入的审计记录,补充最终结果。
UpdateTaskAudit(ctx context.Context, record *AuditRecord)
// UpdateChannelHealth 更新渠道健康度(请求成功/失败后调用)。
UpdateChannelHealth(ctx context.Context, channelID int64, success bool, latencyMs float64)
// IncrementConsecutiveFailure 递增渠道连续失败计数。
IncrementConsecutiveFailure(ctx context.Context, channelID int64)
// ResetConsecutiveFailure 重置渠道连续失败计数为 0。
ResetConsecutiveFailure(ctx context.Context, channelID int64)
// GetAvailableModels 获取指定租户可用的模型列表。
// apiKeyID > 0 时进一步按 API Key 的模型范围过滤。
GetAvailableModels(ctx context.Context, tenantID int64, apiKeyID int64) ([]ModelInfo, error)
// GetModelDetail 获取单个模型的详细信息。
// tenantID 用于权限校验(检查租户是否有权使用该模型)。
GetModelDetail(ctx context.Context, tenantID int64, modelName string) (*ModelDetail, error)
// CheckTenantModelAccess 检查租户是否有权使用指定模型。
// 返回是否启用和渠道范围(nil/空表示不限渠道)。
CheckTenantModelAccess(ctx context.Context, tenantID int64, modelName string) (enabled bool, channelScope []int64, err error)
// GetModelDeprecationInfo 获取模型弃用信息。
// 返回 nil 表示模型未弃用。
GetModelDeprecationInfo(ctx context.Context, modelName string) (*DeprecationInfo, error)
// InvalidateModelCache 清除指定模型的缓存。
InvalidateModelCache(modelName string)
// CheckMemberModelAccess 检查成员是否有权使用指定模型。
// 空 scope(无记录)表示不限制。
CheckMemberModelAccess(ctx context.Context, tenantID, userID int64, modelName string) (bool, error)
// CheckApiKeyModelAccess 检查 API Key 是否有权使用指定模型。
// 无 scope 记录表示不限制(向后兼容)。
CheckApiKeyModelAccess(ctx context.Context, apiKeyID int64, modelName string) (bool, error)
}
// ApiKeyInfo API Key 验证结果
type ApiKeyInfo struct {
ID int64
TenantID int64
UserID int64
ProjectID int64 // 项目密钥关联的项目 ID,个人密钥为 0
Scope string // full / chat_only / embeddings_only / images_only / read_only / custom
Status string // active / disabled / expired
}
// ChannelSelection 渠道选择结果
type ChannelSelection struct {
ChannelID int64
ChannelType int
ChannelName string
BaseURL string
ApiKey string // 解密后的上游 API Key
UpstreamModelName string
IsModelMapped bool
Settings ChannelSettings
}
// UsageRecord API 调用用量记录
type UsageRecord struct {
TenantID int64
UserID int64
ApiKeyID int64
ProjectID int64 // 通过 API Key 关联的项目 ID
ChannelID int64
ModelName string
RelayMode int
PromptTokens int
CompletionTokens int
TotalTokens int
CachedTokens int // 缓存读取 token 数
AudioTokens int // 音频 token 数(输入+输出)
ImageTokens int // 图像 token 数
ReasoningTokens int // 推理 token 数
LatencyMs float64
IsStream bool
Success bool
RequestID string
Status string // success / error / timeout / cancelled
ErrorMessage string
// Cache token 细分
CacheCreationTokens int // 缓存创建 token(合并)
CacheCreation5mTokens int // Claude 5分钟缓存创建
CacheCreation1hTokens int // Claude 1小时缓存创建
CacheReadTokens int // 缓存读取 token
// 音频 token 分离
AudioInputTokens int
AudioOutputTokens int
// 其他 token
ImageOutputTokens int // 图像输出 token(DALL-E)
// 请求元数据
RequestedModel string // 用户请求的模型名
UpstreamModel string // 上游实际模型名
RequestType int // 1=sync, 2=stream, 3=async, 4=websocket
UserAgent string
ClientIP string
FirstTokenMs int
ServiceTier string
ReasoningEffort string
InboundEndpoint string // 客户端请求路径
UpstreamEndpoint string // 上游实际请求路径
// 渠道详情
ChannelName string
ChannelType int
// 计费元数据
BillingMode string
BillingSource string
RateMultiplier float64
RetryIndex int
// 流式追踪
StreamEndReason string
// 图像生成
ImageCount int
ImageSize string
// 费用数据(由 relay handler 从结算结果填充)
InputCost float64
OutputCost float64
CacheCreationCost float64
CacheReadCost float64
TotalCost float64
ActualCost float64
Currency string
PreDeductAmount float64
RefundAmount float64
SupplementAmount float64
// 计费快照
BillingSnapshot string // JSON 字符串
BillingSummary string // 人类可读中文文本
// 异步任务关联
TaskID string // 异步任务公开ID(task_xxxxx),普通请求为空
}
// AuditRecord 请求审计日志记录
type AuditRecord struct {
TenantID int64
UserID int64
ApiKeyID int64
ProjectID int64 // 通过 API Key 关联的项目 ID
RequestID string
Method string
Path string
QueryParams string
StatusCode int
ClientIP string
UserAgent string
RequestBody string
ResponseBody string
LatencyMs int
FirstTokenMs int
IsStream bool
RequestHeaders map[string]string // 请求头(仅审计级别为 all 时记录)
ResponseHeaders map[string]string // 响应头(仅审计级别为 all 时记录)
ForwardingTrace *ForwardingTrace // 转发路径追踪(仅管理员可见)
// 异步任务完成字段(仅 UpdateTaskAudit 时填充)
TaskID string // 异步任务公开ID,关联 tsk_model_tasks.public_task_id
TaskStatus string // SUCCESS / FAILURE
TaskResult string // 上游最终响应体
TaskUpstreamHeaders map[string]string // 上游最终轮询的响应头
TaskCompletedAt *time.Time // 任务到达终态的时间
}
// ModelInfo 模型信息(用于 /v1/models 端点)
type ModelInfo struct {
ModelId string `json:"model_id"`
ModelName string `json:"model_name"`
Category string `json:"category"`
Status string `json:"status"`
MaxContextTokens int `json:"max_context_tokens"`
MaxOutputTokens int `json:"max_output_tokens"`
Capabilities map[string]bool `json:"capabilities"`
}
// ModelDetail 模型详细信息(用于 /v1/models/{model_id} 端点)
type ModelDetail struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
ModelName string `json:"model_name,omitempty"`
Category string `json:"category,omitempty"`
Status string `json:"status,omitempty"`
MaxContextTokens int `json:"max_context_tokens,omitempty"`
MaxOutputTokens int `json:"max_output_tokens,omitempty"`
Description string `json:"description,omitempty"`
Capabilities map[string]bool `json:"capabilities,omitempty"`
}