fengsilin
763cf86a7a
fix(widget): 修复跨域 CORS 问题
- CORS 中间件改用 AllowOriginFunc 回显具体 origin,替代 AllowAllOrigins:*
- userRoute 添加 CORS 中间件,登录接口支持跨域请求
- Widget fetch 移除 credentials: 'include',无需 Cookie
3 weeks ago
fengsilin
84eb6d6a88
feat: 端点格式限制功能 + 完善测试
当开启端点格式限制后,不同协议的渠道只能通过对应的端点访问:
- Anthropic 渠道只能用 /v1/messages
- Gemini 渠道只能用 /v1beta/models/*
- OpenAI 系渠道只能用 /v1/chat/completions 等
- VertexAI/阿里云等支持多协议的渠道不受限
核心实现:EndpointFormatGuard 中间件从请求路径推导协议家族,
不依赖 gin context 中的 relay_format(因 group middleware 执行
时 context 中尚无此值)。
修复了 /v1/models/*path 和 /v1/engines/ 路径被错误归类为
openai 家族的 bug(实际是 Gemini 格式)。
单元测试 58 个,E2E 测试 15 个,覆盖:
- 路径分类边界(含 Gemini relay 路径修复验证)
- 渠道类型覆盖(含非 LLM 渠道透传)
- 并发安全、运行时开关切换
- 错误消息 JSON 结构和内容验证
3 weeks ago
fengsilin
631e030411
test: 添加渠道选择功能删除后的验证测试
验证 parseTokenKey 不再解析 channelId(sk-abc123:42 中的 :42
保留为 key 一部分),shouldRetry/shouldRetryTaskRelay 不再检查
specific_channel_id,所有请求都能正常重试。
4 weeks ago
fengsilin
b49842d543
refactor: 清理 Distribute 中的冗余条件判断和缩进
- 删除 tautological 的 `if channel == nil` 外层判断(channel 在该位置永远为 nil)
- 修正删除指定渠道分支后遗留的多余缩进(减少一级 tab)
- 更新通道亲和性检查注释为简洁版
4 weeks ago
fengsilin
baed9754d0
refactor: 完整删除渠道选择功能后端代码
删除了用户通过 sk-{key}:{channelId} 指定渠道、Playground 下拉框选择渠道、
以及管理员设置默认渠道 (is_default) 的所有后端代码。
涉及修改:
- middleware/auth.go: 简化 parseTokenKey,移除 specific_channel_id 设置
- middleware/distributor.go: 移除指定渠道分发逻辑、默认通道检查、ModelRequest.ChannelId
- constant/context_key.go: 移除 ContextKeyTokenSpecificChannelId
- controller/playground_channels.go: 整个文件删除
- controller/relay.go: 移除 shouldRetry/shouldRetryTaskRelay 中的指定渠道跳过
- controller/channel.go: 移除 GetUserChannelsForBinding
- controller/channel_pricing.go: 移除 SetDefaultChannel/ClearDefaultChannel
- model/ability.go: 移除 GetModelChannelsForGroup
- model/channel.go: 移除 GetAllChannelsForBinding
- model/channel_pricing.go: 移除默认通道缓存及所有相关函数
- model/pricing.go: 移除 DefaultChannelName 字段
- router/api-router.go: 移除 4 条路由
- i18n: 移除 channel.id_format_error 和 distributor.invalid_channel_id
4 weeks ago
fengsilin
714d8239d1
feat: Relay 请求抓包日志 + 用户模型 RPM 限流
两个独立功能:
1. Relay Capture:对开启 capture_relay 的用户记录完整请求/响应到本地文件
- 单 writer goroutine + 128 槽 channel 架构,无 OOM 风险
- 支持流式 SSE 和非流式请求
- 30s 超时保护
2. User-Model RPM Rate Limiting:按 用户+模型 维度的 RPM 限流
- Redis 令牌桶 + 内存滑动窗口双路径,Redis 故障自动降级
- 请求失败时退还令牌/配额(Redis Refund Lua 脚本 + 内存 Refund)
- Redis pipeline 错误处理:失败时清理缓存 key
- 前端用户编辑弹窗新增模型限流配置面板
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4 weeks ago
fengsilin
73d10b5799
feat: 错误日志记录上游 request-id 和响应体,Playground 渠道路由改为 header 传递
- 错误日志新增 upstream_request_id(从 Anthropic/OpenAI 响应 header 提取)和 upstream_body(截断 2KB)
- 修复 RelayErrorHandler 内部 WithOpenAIError/NewOpenAIError 分支丢失上游字段的 bug
- Playground 渠道和分组改为通过 X-Channel-Id/X-Group header 传递,而非 body 字段
- Distributor 中间件支持从 header 回退读取 channel_id 和 group
Co-Authored-By: Claude <noreply@anthropic.com>
1 month ago
fengsilin
74cc8c0d56
feat(playground): 添加渠道选择功能,支持指定渠道体验模型
- 新增 /api/user/model_channels 接口,返回模型可用渠道及默认渠道
- Playground 设置面板添加渠道选择下拉框
- Distribute 中间件支持从请求体读取 channel_id 指定渠道
- 支持 URL 参数 ?model=xxx 直接选择模型
Co-Authored-By: Claude <noreply@anthropic.com>
1 month ago
fengsilin
3a29f3772f
feat(channel): 添加模型默认通道功能,支持优先路由和卡片标识
- 新增 is_default 字段和缓存层,支持管理员为模型指定默认通道
- Distribute 中间件优先级调整:Token 指定 → 默认通道 → 亲和性 → 随机
- 模型定价卡片和详情弹窗展示默认通道 amber 标识
- 管理后台定价页面新增星标切换默认通道
- 新增 set_default / clear_default API 和 6 个单元测试
- 简化卡片价格显示(移除内联缓存价格,改为详情弹窗展示)
Co-Authored-By: Claude <noreply@anthropic.com>
1 month ago
fengsilin
1cecd5349d
feat: 跨区域配额同步(Master-Slave Region Sync)
实现 Master-Slave 架构的跨区域用户和配额同步功能,支持国内主节点与
海外从节点之间的用户创建推送、余额同步、预扣费批量回传。
主要变更:
- 新增 region_sync 服务层(SyncManager/SyncClient/推送逻辑)
- User 模型扩展 Source/RemoteUserId/SyncedQuota/LastSyncAt 字段
- BillingSession 支持 SyncedUserFunding 资金来源
- 新增 SyncAuth 中间件(X-Sync-API-Key + 常量时间比较)
- 新增 PendingSyncRecord/QuotaSyncLog 数据模型
- 前端新增区域同步配置面板
- 支持 SESSION_NAME 环境变量避免多节点 cookie 冲突
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 months ago
fengsilin
c58d01f628
refactor: improve code quality for token dynamic channel feature
1. Extract parseTokenKey helper function to eliminate code duplication
2. Add channelId validation to prevent invalid formats like sk-abc:def:ghi
3. Add database migration to drop deprecated bound_channel_id column
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 months ago
fengsilin
bfa7cc7b97
feat(token): support dynamic channel specification via colon separator
- Add support for sk-{key}:{channelId} format to specify channel dynamically
- Remove BoundChannelId field and related code
- All users can now specify channels, not just admins
- Add model validation when channel is specified
- Remove bound channel UI from token management
Breaking change: tokens can no longer be bound to channels at creation time.
Use sk-{key}:{channelId} format instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 months ago
fengsilin
d006b24f2f
feat: use BoundChannelId for channel selection in distributor
When a token has BoundChannelId set, the distributor now uses that channel
instead of the normal channel selection process. The bound channel is still
validated to ensure it is enabled and supports the requested model.
Changes:
- Add ContextKeyTokenBoundChannelId constant
- Set bound channel in context during token authentication
- Check and use bound channel in distributor before normal selection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 months ago
winter
08164cd0ae
fix
3 months ago