feat(dashboard): add traffic flow sankey chart (#5465)

* feat(dashboard): add traffic flow sankey chart

Add dashboard flow APIs and a Sankey-based flow view with user, optional API key, model, and channel layers.\n\nReuse the dashboard VChart palette, add precise link/node tooltips and interactions, and cover filtering, layer ordering, color stability, and error states with tests.

* feat: build flow chart from quota data

---------

Co-authored-by: CaIon <i@caion.me>
This commit is contained in:
Quaternijkon
2026-06-20 18:57:47 +08:00
committed by GitHub
co-authored by CaIon
parent f9e508bdae
commit a68041f7d6
29 changed files with 2659 additions and 77 deletions
+25 -5
View File
@@ -262,6 +262,7 @@
"Ali": "阿里百炼",
"Alipay": "支付宝",
"All": "全部",
"All API tokens": "全部 API 密钥",
"All categories": "全部分类",
"All conditions must match before this tier is used.": "所有条件都匹配后才会使用此阶梯。",
"All edits are overwrite operations. Leave fields empty to keep current values unchanged.": "所有编辑都是覆盖操作。留空字段将保持当前值不变。",
@@ -277,6 +278,7 @@
"All Tags": "所有标签",
"All Types": "所有类型",
"All upstream data is trusted": "所有上游数据均受信任",
"All users": "全部用户",
"All Vendors": "所有供应商",
"All-time": "全部时间",
"Allocated Memory": "已分配内存",
@@ -684,13 +686,13 @@
"Channel Affinity": "渠道亲和性",
"Channel affinity reuses the last successful channel based on keys extracted from the request context or JSON body.": "渠道亲和性会基于从请求上下文或 JSON Body 提取的 Key,优先复用上一次成功的渠道。",
"Channel Affinity: Upstream Cache Hit": "渠道亲和性:上游缓存命中",
"Channel health checks": "渠道健康检查",
"Channel copied successfully": "渠道复制成功",
"Channel created successfully": "渠道创建成功",
"Channel deleted successfully": "渠道删除成功",
"Channel disabled successfully": "渠道禁用成功",
"Channel enabled successfully": "渠道启用成功",
"Channel Extra Settings": "渠道额外设置",
"Channel health checks": "渠道健康检查",
"Channel ID": "渠道 ID",
"Channel ID is required": "缺少渠道 ID",
"Channel key": "渠道密钥",
@@ -786,6 +788,7 @@
"Cleared log files": "清理日志文件",
"Click \"Create Plan\" to create your first subscription plan": "点击「新建套餐」创建您的第一个订阅套餐",
"Click \"Generate\" to create a token": "点击“生成”以创建令牌",
"Click a stage to show or hide that column": "点击某个阶段可显示或隐藏对应的列",
"Click any category to drill into its models, apps, and trends": "点击任意分类可下钻查看其模型、应用与趋势",
"Click for details": "点击查看详情",
"Click save when you're done.": "完成後點擊保存。",
@@ -1216,6 +1219,7 @@
"Delete selected channels": "删除所选渠道",
"Delete selected models": "删除选定的模型",
"Deleted": "已注销",
"Deleted ({{id}})": "已删除({{id}})",
"Deleted {{count}} failed models": "已删除 {{count}} 个失败模型",
"Deleted a custom OAuth provider": "删除了一个自定义 OAuth 提供方",
"Deleted a deployment": "删除了一个部署",
@@ -1845,6 +1849,7 @@
"Filter models by type, endpoint, vendor, group and tags": "按类型、端点、供应商、分组和标签筛选模型",
"Filter models...": "筛选模型...",
"Filter the model analytics view by time range and user.": "按时间范围和用户筛选模型分析视图。",
"Filter the traffic flow view by time range and user.": "按时间范围和用户筛选分流图视图。",
"Filter...": "筛选...",
"Filters": "筛选器",
"Filters active": "筛选已启用",
@@ -1861,6 +1866,8 @@
"Fixed price (USD)": "固定价格 (USD)",
"Fixed request price": "固定按次价格",
"Floating": "浮动",
"Flow": "分流",
"Flow Filters": "分流筛选",
"FluentRead extension not detected. Please ensure it is installed and active.": "未检测到 FluentRead 扩展。请确保已安装并激活。",
"Flush interval (minutes)": "刷库间隔(分钟)",
"Follow the guided steps to prepare your workspace before the first login.": "请按照引导步骤在首次登录前准备您的工作区。",
@@ -2393,10 +2400,10 @@
"Max Disk Cache Size (MB)": "磁盘缓存最大总量 (MB)",
"Max Entries": "最大条目数",
"Max output": "最大输出",
"Max Retries": "最大重试",
"Max Requests (incl. failures)": "最大请求数(包括失败)",
"Max Requests (including failures)": "最大请求数(包括失败)",
"Max requests per period": "每周期最大请求数",
"Max Retries": "最大重试",
"Max Success": "最大成功数",
"Max successful requests": "最大成功请求数",
"Max Successful Requests": "最大成功请求数",
@@ -2420,8 +2427,6 @@
"Merchant ID is required": "商户 ID 为必填项",
"Message Priority": "消息优先级",
"Metadata": "元信息",
"MjProxy": "MjProxy",
"MjProxyPlus": "MjProxyPlus",
"min downtime": "分钟停机",
"Min Top-up": "最低充值",
"Min Top-up:": "最低充值:",
@@ -2446,6 +2451,8 @@
"Missing Models": "缺失的模型",
"Missing user data from Passkey login response": "Passkey 登录响应中缺少用户数据",
"Mistral": "Mistral",
"MjProxy": "MjProxy",
"MjProxyPlus": "MjProxyPlus",
"Modalities": "模态",
"Modality": "模态",
"Mode": "模式",
@@ -2636,6 +2643,7 @@
"No API keys available. Create your first API key to get started.": "没有可用的 API 密钥。创建您的第一个 API 密钥即可开始使用。",
"No API Keys Found": "未找到 API 密钥",
"No API routes configured": "未配置 API 路由",
"No API tokens": "无 API 密钥",
"No app usage data available for this model.": "该模型暂无应用使用数据。",
"No apps match the selected filters": "没有匹配筛选条件的应用",
"No Auth": "无认证",
@@ -2675,6 +2683,7 @@
"No FAQ entries available": "暂无 FAQ 条目",
"No FAQ entries yet. Click \"Add FAQ\" to create one.": "暂无常见问题条目。点击“添加常见问题”来创建一个。",
"No files match the accepted types.": "没有文件匹配接受的类型。",
"No flow data available": "暂无分流数据",
"No group found.": "未找到分组。",
"No group-based rate limits configured. Click \"Add group\" to get started.": "未配置基于组的速率限制。点击“添加组”开始使用。",
"No groups match your search": "没有组匹配您的搜索",
@@ -2694,6 +2703,7 @@
"No matching items": "没有匹配项",
"No matching results": "无匹配结果",
"No matching rules": "没有匹配的规则",
"No matching token and channel usage was found.": "未找到匹配的令牌与渠道用量。",
"No messages yet": "暂无消息",
"No missing models found.": "未找到缺失的模型。",
"No model found.": "未找到模型。",
@@ -2768,10 +2778,12 @@
"No usage logs available. Logs will appear here once API calls are made.": "暂无使用日志。发起 API 调用后日志将显示在此处。",
"No user information available": "暂无用户信息",
"No user selected": "未选择用户",
"No users": "无用户",
"No users available. Try adjusting your search or filters.": "没有可用的用户。请尝试调整您的搜索或筛选条件。",
"No Users Found": "未找到用户",
"No vendor data available": "暂无厂商数据",
"No X Found": "未找到 X",
"Node": "节点",
"Node Name": "节点名称",
"Non-stream": "非流式",
"Non-zero invitation rewards require compliance confirmation in Payment Gateway settings.": "非零邀请奖励需要先在支付网关设置中确认合规条款。",
@@ -3481,11 +3493,13 @@
"Request Model": "请求模型",
"Request Model:": "请求模型:",
"Request overrides, routing behavior, and upstream model automation": "请求覆盖、路由行为和上游模型自动化",
"Request retry": "请求重试",
"Request rule pricing": "请求规则计费",
"Request success rate sampled over the last 24 hours": "最近 24 小时按时间桶采样的请求成功率",
"Request success rate; {{incidents}} incident buckets in the last 24 hours": "请求成功率;最近 24 小时 {{incidents}} 个异常桶",
"Request timed out, please refresh and restart GitHub login": "请求超时,请刷新页面后重新发起 GitHub 登录",
"Request-based": "含请求条件",
"Requests": "请求数",
"Requests (24h)": "请求数(24 小时)",
"Requests / 24h": "请求 / 24 小时",
"Requests per minute": "每分钟请求数",
@@ -3544,7 +3558,6 @@
"Restore defaults": "恢复默认",
"Restrict user model request frequency (may impact high concurrency performance)": "限制用户模型请求频率(可能会影响高并发性能)",
"Result": "结果",
"Request retry": "请求重试",
"Retain last N days": "保留最近N天",
"Retain last N files": "保留最近 N 个文件",
"Retention days": "保留天数",
@@ -3838,6 +3851,7 @@
"Show All": "显示全部",
"Show all providers including unbound": "显示所有提供商(包括未绑定)",
"Show only bound providers": "仅显示已绑定的提供商",
"Show or hide flow columns": "显示或隐藏分流列",
"Show prices in currency instead of quota.": "以货币而非配额显示价格。",
"Show setup guide": "显示设置引导",
"Show token usage statistics in the UI": "在用户界面中显示令牌使用统计信息",
@@ -4106,9 +4120,11 @@
"The administrator has not configured a privacy policy yet.": "管理员尚未配置隐私政策。",
"The administrator has not configured a user agreement yet.": "管理员尚未配置用户协议。",
"The administrator has not configured any about content yet. You can set it in the settings page, supporting HTML or URL.": "管理员尚未配置任何关于内容。您可以在设置页面中进行设置,支持 HTML 或 URL。",
"The API key used for the requests": "请求所使用的 API 密钥",
"The binding will complete automatically after authorization": "授权后绑定将自动完成",
"The bound Product powers wallet top-ups: when a user enters any amount, new-api runs the checkout against this single Pancake product and overrides the price per session — no need to pre-create $1 / $5 / $10 SKUs.": "已绑定产品用于钱包充值:当用户输入任意金额时,new-api 会基于这个单一 Pancake 产品发起结账,并按会话覆盖价格,无需预先创建 $1 / $5 / $10 的 SKU。",
"The bound Store is the parent container for every Pancake product new-api creates from this admin — both the wallet top-up product and any subscription-plan products. One store is enough; pin a different one only if you genuinely run separate Pancake catalogs.": "已绑定店铺是 new-api 从此管理端创建的所有 Pancake 产品的父容器,包括钱包充值产品和订阅套餐产品。一个店铺通常足够;只有在确实运营多个 Pancake 目录时才需要绑定不同店铺。",
"The deployment node that handled the requests": "处理请求的部署节点",
"The effective domain for Passkey registration. Must match the current domain or be its parent domain.": "用于 Passkey 注册的有效域。必须与当前域匹配或为其父域。",
"The entered text does not match the required text.": "输入文本与要求文本不匹配。",
"The environment (test vs production) is decided by the key you paste here — use the Test key while integrating, then swap to the Production key when going live.": "环境(测试或生产)由你在此粘贴的密钥决定。集成期间使用测试密钥,上线时再切换为生产密钥。",
@@ -4116,6 +4132,7 @@
"The following models have billing type conflicts (fixed price vs ratio billing). Confirm to proceed with the changes.": "以下模型存在计费类型冲突(固定价格 vs 比例计费)。确认以继续更改。",
"The following models in the model redirect have not been added to the \"Models\" list and may fail during invocation due to missing available models:": "模型重定向里的下列模型尚未添加到\"模型\"列表,调用时会因为缺少可用模型而失败:",
"The mapped upstream model(s)": "映射的上游模型",
"The model that was requested": "被请求的模型",
"The model you're looking for doesn't exist.": "您查找的模型不存在。",
"The name displayed across the application": "在整个应用程序中显示的名称",
"The public URL of your server, used for OAuth callbacks, webhooks, and other external integrations": "服务器的公开URL,用于OAuth回调、Webhook和其他外部集成",
@@ -4128,7 +4145,10 @@
"The token group that will have a custom ratio": "将具有自定义比例的令牌分组",
"The unique identifier for this model": "此模型的唯一标识符",
"The unique name for this vendor": "此供应商的唯一名称",
"The upstream channel that served the requests": "处理请求的上游渠道",
"The URL for this chat client.": "此聊天客户端的 URL。",
"The user group applied to the requests": "请求所应用的用户分组",
"The user who made the requests": "发起请求的用户",
"Theme": "主题",
"Theme preset": "主题预设",
"Theme Settings": "主题设置",