fengsilin
3a6dec8a6c
Merge branch 'feat/remove-channel-pricing'
# Conflicts:
# model/pricing_test.go
1 неделю назад
fengsilin
6479883ddc
fix: handle object-type arguments in Responses API stream
gpt-5.4 returns `arguments` as a JSON object for some tools (e.g.
apply_patch, tool_search), but ResponsesOutput.Arguments was typed as
string, causing json.Unmarshal to fail on every such SSE event.
The failure silently dropped all output_item events and the
response.completed event from the forwarded stream, so:
- the client never received tool call content
- usage/token counts could not be extracted (billed as 0)
- client reported "stream closed before response.completed"
Fix: change Arguments to json.RawMessage and add GetArguments() which
normalises both forms to a plain string (unescapes JSON strings,
returns raw bytes for objects).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2 недель назад
fengsilin
674b96298c
refactor(model): remove channel pricing
2 недель назад
fengsilin
415174a676
test(model): switch pricing tests to global defaults
2 недель назад
fengsilin
7ecedd8e57
fix: restore clean go test baseline
2 недель назад
fengsilin
3cf84775f2
feat: add channel metrics collector, fix search pagination and vendor sort order
- Register Prometheus ChannelCollector in GetMetrics() sync.Once block
- Add MetricsMiddleware to /v1 and /v1beta relay router groups when metrics enabled
- Remove public_name field from channel creation form and validation
- Restore InvitationCard in topup page
- Extract fetchSearchPage helper in useModelsData to eliminate ~50 lines of duplication; fix setSearching with finally block; use Axios params for URL encoding; fix missing vendor_counts update during paginated search
- Fix vendor ordering in HomePricingFilters to follow vendorsMap sort_order; fix O(n²) Array.includes to use Set
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2 недель назад
fengsilin
6e81faa698
perf: lazy-read body in DoApiRequest for passthrough model mapping
DoApiRequest previously called io.ReadAll on every request body to apply
passthrough model mapping, even when the feature was disabled. This
caused unnecessary memory pressure for large request bodies (long
conversations, multipart image uploads).
Split the guard logic into needsPassthroughModelMapping() so that
ReadAll is only called when all conditions are met (feature enabled +
passthrough mode + model mapped). Non-passthrough requests now pass
the original io.Reader directly to http.NewRequest without buffering.
Rewrite tests to verify combined guard + modify behavior.
2 недель назад
fengsilin
6434a523a1
feat: passthrough model mapping
2 недель назад
fengsilin
4584a94620
Merge branch 'feat/custom-nav-link'
2 недель назад
fengsilin
d32050d081
fix: restore login widget bundle and guard custom nav link
2 недель назад
fengsilin
54573991a4
feat: add customLink configuration UI in header nav settings
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 недель назад
fengsilin
49c6755622
feat: add customLink to navigation hook with filtering logic
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 недель назад
fengsilin
79f8a18cef
feat(widget): 重构登录组件为无 UI 的 headless SDK
3 недель назад
fengsilin
60a1403ae2
fix(widget): Dockerfile 添加 Widget 构建步骤
主前端构建后执行 widget 构建,确保 login-widget.js 被 embed 打包
3 недель назад
fengsilin
aa15965467
fix: Dockerfile 使用华为云镜像源解决构建网络问题
移除 # syntax 指令,将 Docker Hub 基础镜像替换为华为云 SWR 镜像,解决 WSL 环境下无法直连 Docker Hub 的问题。
3 недель назад
fengsilin
1c5e6d03d9
fix: 禁止修改同步用户余额
同步用户余额由主节点管理,从节点不应允许管理员修改其余额。
前端禁用额度输入和添加额度按钮,后端增加校验拦截。
3 недель назад
fengsilin
fe62509b03
feat(metrics): 重试循环和错误处理中采集指标
3 недель назад
fengsilin
e51a66c5f9
feat(metrics): postConsumeQuota 中采集 token/配额/延迟指标
3 недель назад
fengsilin
123f0d95ae
feat(metrics): 注册 /metrics 端点
3 недель назад
fengsilin
87628f5469
feat(metrics): 渠道状态自定义 Collector
3 недель назад
fengsilin
67e78f2c44
feat(metrics): Gin 中间件 - 活跃请求、延迟、状态码
3 недель назад
fengsilin
9d4378dbb5
feat(metrics): 错误分类函数及测试
3 недель назад
fengsilin
688c5f8666
feat(metrics): Prometheus 指标定义和注册
3 недель назад
fengsilin
5afa4c48fc
feat: 用户表新增注册时间字段 + 用户列表显示邮箱和注册时间
- model/user.go: 新增 CreatedAt 字段,Insert 时自动填充
- UsersColumnDefs.jsx: 用户列表新增邮箱、注册时间列
- makefile: 新增 build-widget target
3 недель назад
fengsilin
0c369eba51
docs: 添加登录 Widget 使用指南
API 参考、完整示例、主题配置、常见问题等
3 недель назад
fengsilin
763cf86a7a
fix(widget): 修复跨域 CORS 问题
- CORS 中间件改用 AllowOriginFunc 回显具体 origin,替代 AllowAllOrigins:*
- userRoute 添加 CORS 中间件,登录接口支持跨域请求
- Widget fetch 移除 credentials: 'include',无需 Cookie
3 недель назад
fengsilin
de3b359dea
feat(widget): 登录 Widget v1 — 密码登录,Shadow DOM 隔离
- 新增 web/widget/ 独立 Vite 构建,IIFE 格式打包
- Shadow DOM 样式隔离,支持 light/dark 主题
- 调用现有 /api/user/login 接口,零后端改动
- 构建产物 web/dist/static/login-widget.js (146KB)
3 недель назад
fengsilin
3c5b821584
docs: 添加登录 Widget 实施计划
6 个 Task:项目骨架 → 样式 → LoginForm → 入口 → 构建集成 → E2E 验证
3 недель назад
fengsilin
08b89e6252
docs: 添加登录 Widget 设计文档
纯前端登录表单 Widget,通过 <script> 标签嵌入到第三方页面,
调用现有 /api/user/login 接口,零后端改动。
3 недель назад
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 недель назад
fengsilin
4c76265f32
test: 添加渠道选择删除 E2E 测试 + 清理临时截图 + 新增辅助脚本
- 新增 E2E 测试脚本 test/e2e_channel_removal.py,覆盖 Token 解析、
已删除路由验证、请求自动分发、channel_id 忽略、定价无默认渠道等
- 新增 anthropic_cache_test.sh 缓存测试脚本
- 新增本地开发辅助脚本 (dev.ps1, start-local.ps1 等)
- 清理根目录下 9 个临时测试截图
3 недель назад
fengsilin
c64afdc6c2
fix: 清理渠道选择删除后的代码质量问题
- router/api-router.go: 修复删除路由后的缩进异常
- model/channel_pricing.go: 清理 Insert/Update/Delete 中遗留空行
- controller/relay_test.go: newTestContext 接收 *testing.T 参数并调用 t.Helper()
3 недель назад
fengsilin
631e030411
test: 添加渠道选择功能删除后的验证测试
验证 parseTokenKey 不再解析 channelId(sk-abc123:42 中的 :42
保留为 key 一部分),shouldRetry/shouldRetryTaskRelay 不再检查
specific_channel_id,所有请求都能正常重试。
4 недель назад
fengsilin
b49842d543
refactor: 清理 Distribute 中的冗余条件判断和缩进
- 删除 tautological 的 `if channel == nil` 外层判断(channel 在该位置永远为 nil)
- 修正删除指定渠道分支后遗留的多余缩进(减少一级 tab)
- 更新通道亲和性检查注释为简洁版
4 недель назад
fengsilin
ea0d4e5cde
refactor: 完整删除前端渠道选择和默认通道 UI
4 недель назад
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 недель назад
fengsilin
547ed7e307
docs: 渠道选择功能完整删除设计方案
4 недель назад
fengsilin
f1a68027f1
Revert "feat(cache): OpenAI→Claude 转换自动注入 prompt caching"
This reverts commit ff14caed7c .
4 недель назад
fengsilin
ff14caed7c
feat(cache): OpenAI→Claude 转换自动注入 prompt caching
- ClaudeRequest 新增 CacheControl 字段
- RequestOpenAI2ClaudeMessage 自动注入顶层 cache_control: {"type":"ephemeral"}
- System 复合内容和普通消息 content block 的 CacheControl 透传
- ParseContent 新增 []MediaContent 类型断言,修复透传路径
- 新增 8 个单元测试覆盖自动注入、透传、序列化等场景
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4 недель назад
fengsilin
155aa12014
perf(docker): BuildKit 缓存加速构建 + fix: 模型列表改用 enabled 接口
Dockerfile 添加 --mount=type=cache 持久化 bun/go 缓存,
前端改代码时跳过后端构建(~10s),后端改代码时跳过前端(~30s)。
模型限流下拉改用 /api/channel/models_enabled 只返回已启用模型。
4 недель назад
fengsilin
f07f2c25f4
feat(rate-limit): 用户模型限流配置改用下拉选择模型
将添加模型限流时的文本输入改为从渠道模型列表中选择,
并自动过滤已配置的模型,提升配置体验和准确性。
4 недель назад
fengsilin
9ee5f535c8
Merge branch 'feat/relay-capture'
Relay 请求抓包日志 + 用户模型 RPM 限流
4 недель назад
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 недель назад
fengsilin
69ed7d85d7
feat(sidebar): 添加监控外部链接菜单项
在管理员菜单区域新增「监控」入口,仅 root 用户可见,
点击后在新窗口打开外部监控面板。支持在侧边栏模块管理中切换显示/隐藏。
同时在 renderWrapper 中添加外部链接的通用支持。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 месяц назад
fengsilin
bae5c1faa5
feat(pricing): 隐藏模型广场标签和端点类型筛选器
注释掉模型广场侧边栏和筛选弹窗中的 PricingTags 和 PricingEndpointTypes 组件,
添加 EndpointType 常量及相关组件的文档注释。
Co-Authored-By: Claude <noreply@anthropic.com>
1 месяц назад
fengsilin
e6b4a06557
feat(logs): 隐藏使用日志中的分组信息展示
使用注释方式隐藏分组列和分组倍率标签,便于后续恢复:
1. 注释 UsageLogsColumnDefs.jsx 中的分组列定义
2. 注释 useUsageLogsData.jsx 中的 COLUMN_KEYS.GROUP 和默认可见性配置
3. 将计费详情中的"分组倍率"改为"倍率"
后端计费逻辑不变,仍正常应用分组倍率。
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
1 месяц назад
fengsilin
f9eeb7e47e
fix(billing): 修复 Claude 计费明细未应用用户渠道折扣的问题
renderClaudeModelPrice 函数缺少 userChannelRatio 参数声明,导致运行时
ReferenceError;同时价格计算未乘以用户倍率,明细文本也未显示折扣信息。
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
1 месяц назад
fengsilin
f7ff684d0d
feat(pricing): 渠道定价展示用户折扣价格
登录用户查看渠道定价时,按用户分组倍率和渠道个人倍率计算实际折扣价
并在价格列展示划线原价与折扣价,新增 /pricing/user/*model 接口。
Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
1 месяц назад
fengsilin
e1b6aff7e1
fix(log): 对普通用户隐藏 Chat ID 和 Upstream ID
后端 GetUserLogs 返回前清空 chat_id/upstream_id(omitempty 不输出),
前端搜索框和展开行详情加 isAdminUser 守卫。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 месяц назад
fengsilin
02e0940555
fix(playground): 清空互斥模型默认列表
初始不预填任何模型,由管理员在运营设置页面手动配置。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 месяц назад