v0.0.21
✨ New Features
- Full zh/en internationalization (i18n):
- Every admin page (channels / tokens / users / plans / subscriptions / orders / admin orders / logs / redemptions / admin dashboard / system / cluster / operations / pricing / top-up / payment / personal settings), the console dashboard, landing page, login / register / password reset / OAuth, terms of service and privacy policy now support Chinese and English.
- A language switcher (
LangSwitcher) is added to the top bar and the landing navbar; the choice is persisted tolocalStorage.langand synced to<html lang>. - Menus, page copy, table columns, modals, buttons, hints, form validation and
Messagetoasts all switch in real time.
- Arco Design component localization:
App.vueinjects the Arco locale bundle (zh-cn/en-us) viaa-config-provider, localizing date pickers, pagination, empty states, Popconfirm and other built-in components. - Per-page message modules with automatic deep merge: new
src/i18n/pages/*.jspage modules are auto-loaded bysrc/i18n/pages.jsthroughimport.meta.globand recursively deep-merged, so modules sharing a namespace never clobber each other. - Token page UI improvements:
- "Remaining / Used" quota is now laid out horizontally with a baseline-aligned
/separator. - The key column gains a "view full key" modal with one-click copy and close.
- A new "Available Models" column shows
X/Unrestricted; clicking it opens a grid + dot modal listing models, falling back to all available models when the token is unrestricted.
- "Remaining / Used" quota is now laid out horizontally with a baseline-aligned
- tiktoken BPE embedded offline:
//go:embedbundles the cl100k_base / o200k_base / p50k_base / r50k_base BPE files (~6.4 MB) into the binary, so token counting is exact with zero configuration and no network, covering gpt-3.5-turbo / gpt-4 / gpt-4o and friends.
🐛 Bug Fixes
- Fixed Redis user-quota cache drift versus the real balance (multiple paths):
IncreaseUserQuotanow refreshes Redis after a direct DB write, so top-ups / admin grants / invite rewards become visible on the very next request.- In batch mode (
BatchUpdateEnabled=true),batchUpdaterefreshes the affected users' cache after flushing, keepingusers.quotaanduser_quota:<id>aligned. - Admin
UpdateUserrefreshes the cache after overwritingquota, preventing persistent false 403s after a quota edit. - The "trusted, skip pre-consume" guard in
preConsumeQuotais moved before the Redis decrement, so funded requests no longer drift the cache on every call; on pre-consume failure, the prior Redis decrement is rolled back viaRedisIncrease. - The
user_quotacache low-water refresh threshold is raised (500 → 50_000), narrowing the drift dead zone caused by high-price models (~80_000 quota per pre-consume) and fixing persistent falseinsufficient_user_quota403s.
- Fixed token-counting panic in firewalled / offline environments: the tiktoken download timeout left the fallback incomplete,
SyncOptionsflippedApproximateTokenEnabledback tofalse, andEncode()was eventually called on anilencoder; embedding the BPE files removes the whole chain. - Fixed "never expire" tokens being treated as expired: the expiry sentinel is unified from "only
-1means never expire" to "<=0means never expire" (model/token.go/controller/token.go), fixing the false "token expired" error when enabling tokens whose legacy/dirty value was0; the frontend adds abuildTokenExpiredTimehelper so "never expire" is always submitted as-1.
🔧 Refactor
httpBpeLoadernow resolves in three tiers: embedded (default, works out of the box) →TIKTOKEN_CACHE_DIR(escape hatch for custom encodings, bypassing embedded and HTTP) → HTTP download (last resort for future URL changes). The previous implicit fallback to the system tempdata-gym-cachedirectory is dropped (it was invisible and prone togo clean -cachecollateral damage).
📚 Documentation
- README roadmap updated: "Internationalization (i18n)" moved to Done and a new "More languages" item added; synced across all 8 README languages (zh / zh-TW / en / ja / ru / de / ko / ar).
🧪 Tests
preConsumeQuotaregression tests: pure-function formula, insufficient-balance 403 without DB mutation, trusted path leaving bothuser.quotaandtoken.remain_quotauntouched, normal pre-consume path, and Plan short-circuit.- User-quota and cache helper unit tests: direct-write semantics, negative-quota rejection, increase/decrease roundtrip consistency, and no-op rollback when Redis is disabled.
- tiktoken embedded loader 3-tier fallback tests: SHA1 validation of all 4 embedded files, graceful handling of unknown URLs, parsing cl100k_base, end-to-end encoding for gpt-3.5 / gpt-4 / gpt-4o,
TIKTOKEN_CACHE_DIRoverride, and HTTP fallback. - Token expiry sentinel tests: never-expire always submits
-1(never0),<=0is not treated as expired, and>0expires correctly.
⚠️ Upgrade Notes
- Zero database migration: no schema changes.
- Frontend rebuild required: changes under
web/default-pro/neednpm run buildso the assets are re-embedded into the Go binary. - Binary size grows by ~6.4 MB: the 4 embedded tiktoken BPE files buy offline operation and non-blocking startup; set
TIKTOKEN_CACHE_DIRto override with custom encodings. - Language switching: defaults to Chinese; switch from the top bar after login or from the landing navbar. The choice is stored in
localStorage.lang. - Build & test:
go build ./...passes.go test ./model/ ./controller/ ./middleware/is green.cd web/default-pro && npm run buildpasses.