Skip to content

Modify - #2555

Closed
KleinerSource wants to merge 13 commits into
QuantumNous:mainfrom
KleinerSource:modify
Closed

Modify#2555
KleinerSource wants to merge 13 commits into
QuantumNous:mainfrom
KleinerSource:modify

Conversation

@KleinerSource

@KleinerSource KleinerSource commented Dec 31, 2025

Copy link
Copy Markdown

Summary by CodeRabbit

Release Notes

  • New Features
    • Added token balance endpoint to retrieve token status, remaining quota, and usage amount.
    • Introduced streaming passthrough API endpoint for chat requests with usage tracking.
    • Enhanced token status information with human-readable status descriptions (enabled, disabled, expired, exhausted).

✏️ Tip: You can customize this high-level summary in your review settings.

新增传透模式功能,允许直接转发请求到上游服务商,
不做额外处理或转换,支持SSE流式响应的透传。

feat(controller): 添加Token余额查询接口

新增GET /usage/api/balance接口,用于获取Token余额信息,
包括余额、配额、状态等详细信息。

feat(relay): 实现传透模式响应透传功能

实现传透模式下的响应透传,支持流式和非流式响应的直接转发,
包含完整的错误处理和重试机制。
- 移除token余额查询接口的/api前缀,从/api/usage/api/balance调整为/usage/api/balance
- 将chat-stream透传模式路由从/api/chat-stream调整为/chat-stream
- 统一路由分组结构,提升路由配置的清晰度
- 添加关键限流中间件到余额查询接口
refactor(relay_passthrough): 重构传透模式中继信息生成逻辑

- 将返回语句拆分为变量赋值和返回两步,提高代码可读性
- 添加ChannelMeta初始化逻辑,从上下文获取渠道信息
- 优化代码结构,便于后续维护和扩展
```
feat(router): 添加chat-stream透传模式路由

- 新增/chat-stream路由组,用于处理透传模式请求
- 配置TokenAuth、ModelRequestRateLimit和Distribute中间件
- 将chat-stream路由从registerMjRouterGroup函数中移出并独立配置
- 添加POST方法处理RelayPassthrough控制器
```
fix(controller): 修复中继透传中价格助手的空指针错误

- 在RelayPassthrough函数中,将nil参数替换为TokenCountMeta{}实例
- 避免在ModelPriceHelper调用时出现空指针异常
- 确保价格数据获取逻辑的稳定性
```
- 引入ChatStreamRequest结构体,统一加密请求格式解析
- 实现usage信息提取功能,支持流式和非流式响应的usage获取
- 重构计费逻辑,支持上游usage和本地估算相结合的计费方式
- 添加模型映射、渠道重试时重新初始化ChannelMeta等功能
- 优化输入token估算算法,支持图片等多类型内容估算
- 维护兼容性,保留旧接口并提供新接口带usage返回
- 添加敏感词检测功能,仅检测data字段内容
- 实现精确的token计算,替代原有的估算方法
- 支持对data、images、model字段进行精确token计算
- 添加图片token的精确计算逻辑,失败时使用默认值
- 集成用户组倍率信息到消费记录中
- 公开GetImageTokenForPassthrough方法供透传模式使用
将日志记录从logger.SysLog改为common.SysLog,确保在图像token计算失败时
能够正确记录日志信息,提高系统的可观测性。
- 在 genPassthroughRelayInfo 中调用 InitFirstResponseTime 确保首字时间正确初始化
- 新增 InitFirstResponseTime 方法用于手动创建 RelayInfo 场景的首字时间设置
- 保持与 genBaseRelayInfo 一致的初始化行为
- 在GetTokenBalance函数中添加注释说明强制从数据库读取的原因
- 将model.GetTokenByKey的第二个参数改为true,强制从数据库读取
  而不是使用缓存,以确保返回的余额数据是最新的准确数据
- 移除未使用的 strings 包导入
- 将 RemainQuota 字段类型从 int 改为 int64 以支持更大数值
- 从 Authorization header 获取 token 改为从 context 获取 token_id
- 直接通过 token_id 查询数据库获取 token 信息,提高查询效率
- 保持与 GetSubscription 接口的一致性
- 修复 token 验证逻辑,提高安全性
- 移除 BalanceResponse 结构体,直接使用 gin.H 返回数据
- 修改认证方式,从 Authorization header 中解析 token
- 添加 Bearer token 验证逻辑
- 强制从数据库读取 token 信息,确保余额数据准确性
- 更新 remain_amount 计算说明注释
当用户配置为无限制配额(unlimited_quota)时,显示token的剩余配额;
当用户配置为有限配额时,显示用户的总配额余额。

该修改解决了无限制配额用户无法正确显示余额的问题,
并增强了余额获取的逻辑以支持不同配额类型的用户。
@coderabbitai

coderabbitai Bot commented Dec 31, 2025

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

Walkthrough

This PR introduces a new token balance retrieval endpoint and a passthrough relay handler for streaming requests. The balance endpoint authenticates via Bearer token and returns token quota/status information. The passthrough handler manages chat-stream requests with retry logic, quota pre-consumption, and usage extraction from upstream responses.

Changes

Cohort / File(s) Summary
Token Balance API
controller/balance.go, router/api-router.go
Adds GetTokenBalance handler that authenticates via Bearer token, retrieves token data from DB (strips sk- prefix), computes quota/amount based on unlimited flag, maps token status to human-readable text, and returns JSON response. New route group /usage/api with /balance endpoint applies CriticalRateLimit and TokenAuth middleware.
Passthrough Relay Handler
controller/relay_passthrough.go, relay/passthrough_handler.go, router/relay-router.go
Introduces RelayPassthrough controller with ChatStreamRequest type for encrypted payload handling. Manages request validation, channel/adaptor selection, model mapping, quota pre-consumption with rollback, retry loop (bounded by limit), and deferred error serialization. PassthroughHelperWithUsage extracts usage from streaming/non-streaming responses, handles Server-Sent Events parsing, and falls back to estimated tokens. New POST /chat-stream route with token auth and model rate limiting middleware.
Supporting Utilities
relay/common/relay_info.go, service/token_counter.go
Adds InitFirstResponseTime method to RelayInfo for manual timing initialization. Exposes GetImageTokenForPassthrough wrapper function delegating to internal image token counting with passthrough flag.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant RelayPassthrough
    participant Service
    participant ChannelAdaptor
    participant UpstreamAPI
    participant PassthroughHandler

    Client->>RelayPassthrough: POST /chat-stream (encrypted payload)
    RelayPassthrough->>RelayPassthrough: Validate model & data
    RelayPassthrough->>RelayPassthrough: Perform sensitive content checks
    
    loop Retry Loop (bounded)
        RelayPassthrough->>Service: getPassthroughChannel()
        Service-->>RelayPassthrough: Channel (with adaptor)
        RelayPassthrough->>RelayPassthrough: Apply model mapping
        RelayPassthrough->>Service: calculateInputTokens()
        Service-->>RelayPassthrough: Token count
        RelayPassthrough->>Service: PreConsumeQuota()
        alt Quota Available
            Service-->>RelayPassthrough: Success (set defer rollback)
        else Insufficient Quota
            Service-->>RelayPassthrough: Error
            RelayPassthrough->>RelayPassthrough: Return error
        end
        
        RelayPassthrough->>PassthroughHandler: PassthroughHelperWithUsage()
        PassthroughHandler->>ChannelAdaptor: DoRequest(request body)
        ChannelAdaptor->>UpstreamAPI: Forward request
        UpstreamAPI-->>ChannelAdaptor: Response (streaming/non-streaming)
        ChannelAdaptor-->>PassthroughHandler: Response
        
        alt Streaming Response
            PassthroughHandler->>PassthroughHandler: Stream to client while extracting usage
            PassthroughHandler->>PassthroughHandler: Parse Server-Sent Events (data: lines)
            PassthroughHandler->>PassthroughHandler: Extract usage from event
        else Non-Streaming Response
            PassthroughHandler->>PassthroughHandler: Extract usage from response JSON
            PassthroughHandler->>Client: Send response
        end
        
        PassthroughHandler-->>RelayPassthrough: Usage (or estimated tokens on fallback)
        
        alt Success
            RelayPassthrough->>Service: postPassthroughConsumeQuotaWithUsage()
            Service-->>RelayPassthrough: Confirm consumption
            RelayPassthrough-->>Client: Success response
            RelayPassthrough->>RelayPassthrough: Exit retry loop
        else Retry Eligible Error
            RelayPassthrough->>RelayPassthrough: Log retry attempt
            RelayPassthrough->>Service: ReturnPreConsumedQuota() (defer)
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45-60 minutes

Possibly related PRs

Suggested reviewers

  • Calcium-Ion
  • creamlike1024

Poem

🐰 A token hops through balance lanes,
With streams of data, usage chains,
Retry loops that gently bound,
And quotas counted, safe and sound,
Through passthroughs wide, the data flows! ✨

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b808b96 and 5f23da4.

📒 Files selected for processing (7)
  • controller/balance.go
  • controller/relay_passthrough.go
  • relay/common/relay_info.go
  • relay/passthrough_handler.go
  • router/api-router.go
  • router/relay-router.go
  • service/token_counter.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@KleinerSource
KleinerSource deleted the modify branch December 31, 2025 03:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant