Skip to content

新增:ModelScope(魔搭)渠道(国内版 / 国际版)+ 每日签到 + 魔粒余额;修复流式 usage 静默归零 - #306

Closed
coulsontl wants to merge 3 commits into
aimod-cc:betafrom
coulsontl:feat/modelscope-channel
Closed

coulsontl wants to merge 3 commits into
aimod-cc:betafrom
coulsontl:feat/modelscope-channel

Conversation

@coulsontl

Copy link
Copy Markdown
Contributor

新增 ModelScope(魔搭)渠道,含每日签到与魔粒余额读数;另修一处会让统计静默归零的流式 usage 缺陷。

渠道本体

两个站点各一家 provider:modelscope(国内版,modelscope.cn)与 modelscope-intl(国际版,www.modelscope.ai)。无状态 OpenAI 兼容转发,骨架与 Loomy / AutoClaw / OfficeAce 同构。

  • 一枚 ms- 令牌两用:Authorization: Bearer 调推理、Cookie: m_session_id=<令牌> 读网页站(身份 / 魔粒 / 签到)。所以只有一个凭证字段。
  • 令牌不透明(不是 JWT,解不出身份)⇒ 添加账号时出网探活换取上游稳定身份(HavanaId)做账号 id,否则同一账号换一次令牌就会变成两条记录。
  • 两个站点是两套账号体系(国内令牌打国际站网页接口得 401 access forbidden)⇒ 地区做成 provider 身份而不是账号上的字段。拆家还顺带解决一个具体故障:模型目录只有一份时,两站各自 36 条、内容不同的清单会互相覆盖。
  • 模型目录 GET {推理域}/models(实测 36 条,是账号可用集而非全站模型;只有 id 字段,没有能力位,因此不编静态兜底表、也不按 id 猜思考位)。

每日签到

上游没有独立签到接口:调一次 GET {网页站}/api/v1/users/login/info 本身就触发当日魔粒签到(幂等,重复调不会重复发)。依据是 CPA 的 modelscope-ratelimit 插件源码(cmd/plugin/main.go 的午夜签到段),本实现照同一条链路、把触发时机交给本项目的自动签到框架(CHECKIN_PROVIDERS 第 14、15 家,PROVIDERS_VERSION 相应 +1)。

余额读数

query_usage 采集魔粒钱包(可用 / 冻结 / 总计)与今日已用调用数(currentUsagePerDay)。后者是附加读数,取不到时只降级、不把整条查询变失败(主问题是「我还有多少魔粒」)。

错误分类

上游把「账号条件不满足」与「速率窗口撞上」都用 429/403 表达,只能靠文案区分,而两者处置完全不同:

  • 魔粒耗尽(429 insufficient balance)与未验证邮箱(403 + 特征串)→ 冷却到下一个北京零点(充值 / 完成验证后次日自动回来),不是分钟级重试;
  • 其余 429 → 分钟级速率窗口;
  • 裸 401/403 → 令牌失效(本家无续期,如实报「请重新粘贴」)。

判据来自 CPA 插件 internal/ratelimit/apply.go(线上实测得来),逐条 curl 复核过。

⚠️ 一处会静默毁账的流式缺陷(本 PR 一并修复)

魔搭的流式响应是非标准形态:每一个 chunk 都带一个 usage 对象,值全是 0;真值只在末尾那个 choices: [] 的 usage-only 块里 —— 而那一块只在请求显式带上 stream_options.include_usage: true 时才发。实测对照(同一模型同一提问):

不带 include_usage:最后一帧是 {"choices":[{"finish_reason":"stop"}], "usage":{0,0,0}}
带   include_usage:{"choices":[], "usage":{"prompt_tokens":62,"completion_tokens":32,"total_tokens":94}}

本网关恒以流式请求上游,客户端要非流式时再由聚合器把流折成完整响应 ⇒ 不注入这个开关时,非流式请求的 usage 恒为 0:请求日志、报表与前端 token 显示一起归零,而内容完全正常(这个故障只在统计上可见,排查时极难联想到「上游少发了一帧」)。处置与 CodeArts 的既有做法一致:build_chat_request 里总是请求 usage(保留客户端已设的其余 stream_options 键)。

优化:限额文案带上恢复时刻

全部候选账号都被限流时,错误文案从

…(所有候选账号对模型 X 均已限额或禁用)

改为

…(所有候选账号对模型 X 均已限额或禁用,最早 2026/10/17 00:00:00 恢复)

客户端(会读这条文案的)才能做合法的退避等待,而不是立刻重试再撞一次同样的墙。取最早而不是最晚(账号是逐个恢复的,取最晚会让它多睡一段本不必睡的时间);只改文案、不动选路逻辑,取不到时逐字退回原句。

验证

  • cargo test 616 passed / 0 failed(新增 27 个测试守着分类顺序、include_usage 注入、区域互查、身份解析、恢复时刻取值等)
  • 前端 tsc --noEmit && vite build 通过;i18n scan.mjs --check 通过(五语言词典齐全)
  • 端到端实测(隔离实例 + 真实账号):添加账号(探活换身份 + 顺带签到)✓ / 魔粒余额读数 ✓ / 签到回上游昵称 ✓ / 模型目录 36 条 ✓ / 跨站令牌正确拒绝并点明站点 ✓ / 仓库导入导出身份合并 ✓
  • 魔粒耗尽与速率窗口的分类、以及「最早恢复时刻」文案,都用真实上游 429 报文验证过

附注

顺带给 OrcaTerm 的 6 条中文文案补上英文译文 —— 上游新增这些文案时没跑 i18n 扫描,scan.mjs 时被扫出空值(en 空值数 5→11,填完回 5)。


🤖 本条回复由 AI Agent 生成
Generated by an AI agent.

…cope-intl` 国际版),无状态 OpenAI 兼容转发。一枚 `ms-` 令牌两用:Bearer 调推理、Cookie 值读网页站(身份 / 魔粒 / 签到),所以只有**一个**凭证字段;令牌不透明(不是 JWT),添加账号时出网探活换上游稳定身份(`HavanaId`)做账号 id,否则同一账号换一次令牌就变成两条记录。两个站点是**两套账号体系**(国内令牌打国际站网页接口得 `401 access forbidden`),所以地区做成 provider 身份而不是账号上的字段;拆家还顺带解决「两站模型目录互相覆盖」(各 36 条、内容不同,缓存与刷新排期各占一格)

2. 新增:ModelScope 每日签到 —— 上游**没有独立签到接口**:调一次登录信息接口(`GET {网页站}/api/v1/users/login/info`)本身就触发当日魔粒签到(幂等),纳入自动签到框架(两个站点各打各的网页站)。链路依据是 CPA 的 `modelscope-ratelimit` 插件源码,本实现照同一条链路、把触发时机交给本项目框架
3. 新增:ModelScope 余额读数 —— 魔粒钱包(可用 / 冻结 / 总计)与今日已用调用数;后者是附加读数,取不到时只降级不把整条查询变失败
4. 新增:ModelScope 错误分类 —— 上游把「账号条件不满足」与「速率窗口撞上」都用 429/403 表达、只能靠文案区分而处置完全不同:魔粒耗尽(429 `insufficient balance`)与未验证邮箱(403 + 特征串)冷却到**下一个北京零点**(充值 / 完成验证后次日自动回来),其余 429 才是分钟级速率窗口;裸 401/403 仍归令牌失效(本家无续期,如实报「请重新粘贴」)。判据来自 CPA 插件 `apply.go` 的线上实测口径
5. 修复:流式请求注入 `stream_options.include_usage` —— 上游的流式响应是**非标准形态**(每个 chunk 都带 `usage` 对象且**值全零**),真值只在末尾那个 `choices: []` 的 usage-only 块里,而**那一块只在请求显式带上这个开关时才发**。不注入时:本网关恒以流式请求上游、非流式由聚合器折成完整响应,聚合到的最后一个 usage 就是那串全零 ⇒ **非流式请求的 usage 恒为 0**(内容完全正常,故障只在统计上可见、极难排查)。与 CodeArts 的既有处置一致:总是请求 usage
6. 优化:全部候选账号均限额时,错误文案带上**最早的恢复时刻**(`(所有候选账号对模型 X 均已限额或禁用,最早 2026/10/17 00:00:00 恢复)`)—— 此前客户端只能立刻重试、再撞一次同样的墙,带上之后才能做合法的退避等待。取最早而不是最晚(账号是逐个恢复的,取最晚会让它多睡一段本不必睡的时间);只改文案、不动选路逻辑,取不到时逐字退回原句
7. 优化:给 OrcaTerm 的 6 条中文文案补上英文译文(上游 v3.0.7 新增这些文案但没跑 i18n 扫描,`scan.mjs` 时被扫出空值)
…由 30 秒轮询触发一次,本轮账号在窗口内各自取一个确定性偏移依次执行;对上游呈现的是散在窗口里的逐个请求,而不是每天同一分钟的一串。偏移用 sha256(条目 id | 日期 | 时刻 | N | 账号 id) 派生,同一天重试落在同一时刻,面板「下次执行」与真实行为一致

2. 新增:「启动补签」全局开关(缺省开 = 保持改造前行为)—— 关掉后启动只起调度循环,今天未执行的条目等到各自窗口起点再由调度触发,避免早上开机把当天的随机窗口提前签掉
3. 优化:随机窗口的铺开走后台任务而非在 tick 里 await —— 窗口最长 4 小时,占住 tick 会延后其他条目,占住全局执行锁会拒掉所有手动签到;后台任务只在每个账号执行的几秒里抢锁,账号之间的等待全程在锁外,按墙上时钟分段重算(休眠 / 改时钟都能自愈)
4. 优化:`run_checkin` 抽出 `run_account` 与 `summarize_results`,定时铺开与批量路径共用同一段记账(落 checkinAt、签到记录台账、汇总口径),不存在两套行为;`run_checkin` 签名不变,手动路径零改动
5. 修复:随机窗口铺开的时间起点由「这一轮的日期」推出而不是「此刻的日期」—— 23:5x 的窗口跨过零点时,用现在的时间会算出次日同一分钟,所有账号要白睡约 24 小时
6. 修复(自审):铺开任务的目标解析与计划前移到 spawn 之前 —— 解析失败时能回退 `lastFiredDate` 并让下个 tick 重试,此前是一次偶发失败就让这条条目整天静默;账号集合也在 spawn 时定格,后台跑 4 小时期间账号增删不再让计划中途变形
7. 修复(自审):`spreads` 的 key 改由 `SpreadGuard` 的 Drop 清理 —— 正常结束 / 提前 return / 后台任务被 abort 三种出口都覆盖;此前只在正常路径手写清理,一次异常就让这条条目当天永久不再重试
8. 修复(自审):`acquire_running` 加 10 分钟上限 —— 另一轮签到若卡死在上游,无限等待会让铺开任务永久挂住、key 永不释放;到点如实跳过剩余账号
9. 修复(自审):本轮被提前截断(停机 / 等锁超时)时不落 `lastFiredDate` —— 剩下的账号今天还一次没签,落账会把它们整天静默掉;已签过的重试幂等
10. 修复(自审):`jitterMinutes` 的写入校验拒绝 `1e3` / 十六进制 / 前后空格等 `Number()` 会放过的写法;`submit` 加 `canSave` 守卫,回车与程序化点击也挡得住
11. 新增:19 个纯函数单测(窗口边界夹取、偏移确定性/范围/分散、触发判定、字段往返)
…nnel

1. 合并上游 v3.0.8(Linux 桌面端 / Linux 服务端包、凭证文件导入、智谱清言接入、说明文档重整进 docs/、报表与代理池多项优化),保留本分支的 ModelScope 两个站点
2. `PROVIDERS_VERSION` 是本次最危险的撞点:上游用 3 装 chatglm、本分支原用 3 装 ModelScope。两边都保留各自的版本号 —— chatglm = 3(上游 v3.0.8),ModelScope 两站 = 4,`PROVIDERS_VERSION` 取 4。覆盖任何一边都会让先升级到那一边的用户永远补不进另一家的家(版本号已写进配置)
3. `CHECKIN_PROVIDERS` 15 家:chatglm 保持上游的位置(排在 codearts 之后),ModelScope 两站接在它后面,界面复选框顺序不动存量用户
4. `billing::checkin`:上游把 `run_checkin` 抽成 `day_completed` 判据并新增 chatglm 分支,本分支把循环体抽成 `run_account` / `summarize_results`。合并后 `run_account` 用上游的 `day_completed`(活跃链路完成同样落账),铺开与批量共用同一段记账;两家 provider 分支都在
5. `accounts.rs` / `providers/*` / 前端 provider 表:Chatglm 与 Modelscope 两家的分支与缓存槽(`SCOPE_CHATGLM` / `SCOPE_MODELSCOPE_CN` / `SCOPE_MODELSCOPE_INTL`)全部保留
6. 说明文档:上游把多语言 README 移进 `docs/`,本分支的 ModelScope 行补进 `README.md` 与 `docs/` 下五种语言版本;同步把 ModelScope(魔搭)加进各语言免责声明的无关联名单。README 截图段删掉已随上游删除的 `scheduled-tasks.png` 引用(文件已不存在,留着是坏链)
7. i18n:合并双方新增的键(add-account / checkin 域),产物按 `scan.mjs` → `build.mjs` → `ui-islands build` 重新生成并入库(`ui/islands/ui.js` 的冲突因此直接以重新构建的产物解决)
@coulsontl coulsontl closed this Oct 20, 2026
@coulsontl
coulsontl deleted the feat/modelscope-channel branch October 20, 2026 14: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