Skip to content

Feature/account id dedup and subscription api#560

Open
youyao666 wants to merge 16 commits into
chenyme:mainfrom
youyao666:feature/account-id-dedup-and-subscription-api
Open

Feature/account id dedup and subscription api#560
youyao666 wants to merge 16 commits into
chenyme:mainfrom
youyao666:feature/account-id-dedup-and-subscription-api

Conversation

@youyao666
Copy link
Copy Markdown

三个改动:

  1. 新增 account_id 字段 + 按 xaiUserId 去重

同一个 xAI 账号换浏览器登录会产生不同 SSO token,但 xaiUserId 相同。原来只按 token
去重导致同一账号被重复导入、配额虚高。

  • models.py — AccountRecord 新增 account_id
  • commands.py — AccountUpsert/Patch 支持 account_id
  • backends/sql.py — 新增 account_id VARCHAR(64) 列 + 索引 + 自动迁移 + 导入时相同 account_id 的旧 token 自动软删除
  • backends/local.py — SQLite 同上
  • backends/redis.py — Redis 同上 + 补了缺失的 quota_grok_4_3 字段
  • refresh.py — 导入时先调 subscription API 拿 account_id 和 tier,再调 rate-limits API 拿配额
  • admin/tokens.py — 账号列表输出 account_id
  1. 接入 Grok 官方 /rest/subscriptions 接口

原来靠 rate-limits 的 auto.total 间接猜层级(20=basic, 50=super,
150=heavy),配额窗口过期后显示不准。现在直接查官方接口拿 tier(SUBSCRIPTION_TIER_GROK_PRO → super, GROK_PRO_HEAVY →
heavy)和 xaiUserId,结果权威。

  • 新增 xai_subscription.py — fetch_subscription() + parse_subscription() + tier_to_pool() 映射表
  • endpoint_table.py — 新增 SUBSCRIPTIONS / PRODUCTS / MODES 端点
  1. Redis 后端补全 quota_grok_4_3

Redis 的 _to_hash / _from_hash 漏了 Grok 4.3 Beta 的配额字段,读写都会丢数据。

端对端(真实 Grok API + 服务运行):

1. 启动服务

uv sync && uv run granian --interface asgi --host 127.0.0.1 --port 8000 --workers 1 app.main:app &

2. 导入真实 SSO cookie

curl -X POST http://127.0.0.1:8000/admin/api/tokens/add
-H "Authorization: Bearer grok2api"
-H "Content-Type: application/json"
-d '{"tokens": ["eyJ0eXAiOiJKV1Qi..."], "pool": "auto"}'

→ {"status":"success","count":1,"synced":true}

3. 查看结果 — account_id 和 pool 已自动填充

curl http://127.0.0.1:8000/admin/api/tokens -H "Authorization: Bearer grok2api"

→ {"token":"eyJ...","account_id":"c4492aa9-be8b-449a-b349-18ecb459b3e6","pool":"super",

"quota":{"auto":{"remaining":48,"total":50},"fast":{"remaining":140,"total":140}...}}

4. Chat API 正常

curl -X POST http://127.0.0.1:8000/v1/chat/completions
-H "Content-Type: application/json"
-d '{"model":"grok-4.20-fast","messages":[{"role":"user","content":"hello"}]}'

→ 200 OK, choices[0].message.content: "Hello! 👋 ..."

潜在问题(已知):

  • Redis 去重需全表扫描,千级以上账号池导入略慢
  • 并发导入相同 account_id 存在极低概率竞态(下次刷新自动修复)
  • 存量老账号无 account_id,手动刷新一次即填充

Related

基于 grok2api (https://github.com/chenyme/grok2api) 的 Grok Web API 逆向成果:

  • GET /rest/subscriptions → xaiUserId + tier + status
  • POST /rest/modes → 各模式基于订阅的可用性
  • GET /rest/products → 可用产品层级列表

yangyang and others added 16 commits April 14, 2026 18:01
# Conflicts:
#	app/products/openai/router.py
#	app/products/openai/video.py
1. quota_defaults: _SUPPORTED_MODE_IDS_BY_POOL 新增 "auto" 键(全集0-4),
   修复 pool="auto" 导入时只 fetch fast 模式导致 infer_pool 把
   super/heavy 误判为 basic 的问题。

2. router: chat/completions 视频流式结果不再跳过 _prime_sse,
   空生成器会正确抛出 429 而非静默返回 HTTP 200 空 SSE。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: 按 account_id 去重 + Grok 官方账号类型查询 + Cookie 注入支持

核心变更:
- 添加 account_id (xaiUserId) 字段到 AccountRecord, 实现基于账号唯一 ID 的去重,
  相同 xaiUserId 的多个 SSO token 自动合并, 只保留最新一个
- 新增 xai_subscription.py 协议模块, 调用 /rest/subscriptions 获取官方账号类型
  (SUBSCRIPTION_TIER_GROK_PRO → super, GROK_PRO_HEAVY → heavy)
- 导入时自动探测订阅层级和 account_id, 配合 rate-limits API 交叉验证
- 三个存储后端 (SQL/Redis/SQLite) 全部支持 account_id 列和去重逻辑
- Redis 后端补全缺失的 quota_grok_4_3 字段
- 添加 /rest/subscriptions, /rest/products, /rest/modes 端点
- Admin tokens API 输出 account_id
- 附带 inject_cookie.py 浏览器 Cookie 注入工具

Grok API 探索发现:
- GET /rest/subscriptions  → xaiUserId + tier + status
- POST /rest/modes         → 基于订阅的模式可用性
- GET /rest/products       → 可用产品层级列表

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
Phase 1 (_refresh_subscription): set account_id + store sub_tier/sub_active in ext
Phase 2 (_refresh_one): multi-factor inference:
  1. Primary: infer_pool from rate-limits auto.total (ground truth)
  2. Fallback: if rate-limits says basic but active subscription says super/heavy,
     subscription wins (paying customer = real super account)
  3. For basic accounts, always fetch ALL modes to see auto.total

Scenarios:
  auto=50,  any sub    -> super   (rate-limits)
  auto=7,   INACTIVE   -> basic   (genuinely downgraded)
  auto=N/A, ACTIVE sub -> super   (API fluke, subscription wins)
  auto=7,   ACTIVE sub -> super   (active sub > anomalous quota)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use inferred pool for quota normalization so auto/expert/grok_4_3
modes fetched for basic accounts aren't discarded by normalize_quota_window
(basic pool doesn't support those modes).

Before: super accounts had auto=0 expert=0 (data fetched but thrown away)
After:  super accounts have auto=19137 expert=15212 (correctly preserved)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@youyao666 youyao666 force-pushed the feature/account-id-dedup-and-subscription-api branch from 723cda3 to c0e31ad Compare May 30, 2026 16:56
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.

2 participants