diff --git a/README.en.md b/README.en.md index cc274eb9..b0e21f0c 100644 --- a/README.en.md +++ b/README.en.md @@ -53,9 +53,10 @@ > This is an open-source project developed based on [One API](https://github.com/songquanpeng/one-api) > [!IMPORTANT] -> - This project is for personal learning purposes only, with no guarantee of stability or technical support -> - Users must comply with OpenAI's [Terms of Use](https://openai.com/policies/terms-of-use) and **applicable laws and regulations**, and must not use it for illegal purposes -> - According to the [《Interim Measures for the Management of Generative Artificial Intelligence Services》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm), please do not provide any unregistered generative AI services to the public in China. +> - This project is intended solely for lawful and authorized AI API gateway, organization-level authentication, multi-model management, usage analytics, cost accounting, and private deployment scenarios. +> - Users must lawfully obtain upstream API keys, accounts, model services, and interface permissions, and must comply with upstream terms of service and applicable laws and regulations. +> - Users should ensure their use complies with upstream terms of service and applicable laws and regulations. +> - When providing generative AI services to the public, users should comply with applicable regulatory requirements and fulfill all filing, licensing, content safety, real-name verification, log retention, tax, and upstream authorization obligations required by their jurisdiction. --- @@ -146,6 +147,9 @@ docker run --name new-api -d --restart always \ 🎉 After deployment is complete, visit `http://localhost:3000` to start using! +> [!WARNING] +> When operating this project as a public generative AI service or API resale service, users should first complete all required filing, licensing, content safety, real-name verification, log retention, tax, payment, and upstream authorization obligations. + 📖 For more deployment methods, please refer to [Deployment Guide](https://docs.newapi.pro/en/docs/installation) --- @@ -184,12 +188,12 @@ docker run --name new-api -d --restart always \ | 📈 Data Dashboard | Visual console and statistical analysis | | 🔒 Permission Management | Token grouping, model restrictions, user management | -### 💰 Payment and Billing +### 💰 Authorized Usage Accounting and Billing -- ✅ Online recharge (EPay, Stripe) -- ✅ Pay-per-use model pricing -- ✅ Cache billing support (OpenAI, Azure, DeepSeek, Claude, Qwen and all supported models) -- ✅ Flexible billing policy configuration +- ✅ Internal top-up and quota allocation for lawful authorized scenarios (EPay, Stripe) +- ✅ Organization-level per-request, usage-based, and cache-hit cost accounting +- ✅ Cache billing statistics for OpenAI, Azure, DeepSeek, Claude, Qwen, and supported models +- ✅ Flexible billing policies for internal management or authorized enterprise customers ### 🔐 Authorization and Security @@ -248,7 +252,7 @@ docker run --name new-api -d --restart always \ ## 🤖 Model Support -> For details, please refer to [API Documentation - Relay Interface](https://docs.newapi.pro/en/docs/api) +> For details, please refer to [API Documentation - Gateway Interface](https://docs.newapi.pro/en/docs/api) | Model Type | Description | Documentation | |---------|------|------| @@ -259,7 +263,7 @@ docker run --name new-api -d --restart always \ | 💬 Claude | Messages format | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message) | | 🌐 Gemini | Google Gemini format | [Documentation](https://doc.newapi.pro/en/api/google-gemini-chat) | | 🔧 Dify | ChatFlow mode | - | -| 🎯 Custom | Supports complete call address | - | +| 🎯 Custom upstream | Supports configuring legally authorized upstream endpoints | - | ### 📡 Supported Interfaces diff --git a/README.fr.md b/README.fr.md index f7d83997..7a175561 100644 --- a/README.fr.md +++ b/README.fr.md @@ -55,9 +55,10 @@ ## 📝 Description du projet > [!IMPORTANT] -> - Ce projet est uniquement destiné à des fins d'apprentissage personnel, sans garantie de stabilité ni de support technique. -> - Les utilisateurs doivent se conformer aux [Conditions d'utilisation](https://openai.com/policies/terms-of-use) d'OpenAI et aux **lois et réglementations applicables**, et ne doivent pas l'utiliser à des fins illégales. -> - Conformément aux [《Mesures provisoires pour la gestion des services d'intelligence artificielle générative》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm), veuillez ne fournir aucun service d'IA générative non enregistré au public en Chine. +> - Ce projet est exclusivement destiné aux scénarios de passerelle API d'IA légalement autorisés, d'authentification organisationnelle, de gestion multi-modèles, d'analyse d'utilisation, de comptabilisation des coûts et de déploiement privé. +> - Les utilisateurs doivent obtenir légalement les clés API, comptes, services de modèles et autorisations d'interface en amont, et doivent respecter les conditions d'utilisation en amont et les lois et réglementations applicables. +> - Les utilisateurs doivent s'assurer que leur utilisation est conforme aux conditions d'utilisation en amont et aux lois et réglementations applicables. +> - Lors de la fourniture de services d'IA générative au public, les utilisateurs doivent se conformer aux exigences réglementaires applicables et remplir toutes les obligations d'enregistrement, de licence, de sécurité du contenu, de vérification d'identité, de conservation des journaux, de fiscalité et d'autorisation en amont requises par leur juridiction. --- @@ -151,6 +152,9 @@ docker run --name new-api -d --restart always \ 🎉 Après le déploiement, visitez `http://localhost:3000` pour commencer à utiliser! +> [!WARNING] +> Lorsque vous exploitez ce projet en tant que service public d'IA générative ou service de revente d'API, les utilisateurs doivent d'abord remplir toutes les obligations requises en matière d'enregistrement, de licence, de sécurité du contenu, de vérification d'identité, de conservation des journaux, de fiscalité, de paiement et d'autorisation en amont. + 📖 Pour plus de méthodes de déploiement, veuillez vous référer à [Guide de déploiement](https://docs.newapi.pro/en/docs/installation) --- @@ -189,12 +193,12 @@ docker run --name new-api -d --restart always \ | 📈 Tableau de bord des données | Console visuelle et analyse statistique | | 🔒 Gestion des permissions | Regroupement de jetons, restrictions de modèles, gestion des utilisateurs | -### 💰 Paiement et facturation +### 💰 Comptabilisation et facturation des usages autorisés -- ✅ Recharge en ligne (EPay, Stripe) -- ✅ Tarification des modèles de paiement à l'utilisation -- ✅ Prise en charge de la facturation du cache (OpenAI, Azure, DeepSeek, Claude, Qwen et tous les modèles pris en charge) -- ✅ Configuration flexible des politiques de facturation +- ✅ Rechargement interne et allocation de quotas pour les scénarios légalement autorisés (EPay, Stripe) +- ✅ Comptabilisation des coûts par requête, par utilisation et par hit de cache au niveau organisationnel +- ✅ Statistiques de facturation du cache pour OpenAI, Azure, DeepSeek, Claude, Qwen et les modèles pris en charge +- ✅ Politiques de facturation flexibles pour la gestion interne ou les clients entreprise autorisés ### 🔐 Autorisation et sécurité @@ -254,7 +258,7 @@ docker run --name new-api -d --restart always \ ## 🤖 Prise en charge des modèles -> Pour les détails, veuillez vous référer à [Documentation de l'API - Interface de relais](https://docs.newapi.pro/en/docs/api) +> Pour les détails, veuillez vous référer à [Documentation de l'API - Interface de passerelle](https://docs.newapi.pro/en/docs/api) | Type de modèle | Description | Documentation | |---------|------|------| @@ -266,7 +270,7 @@ docker run --name new-api -d --restart always \ | 💬 Claude | Format Messages | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/createmessage) | | 🌐 Gemini | Format Google Gemini | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/gemini/geminirelayv1beta) | | 🔧 Dify | Mode ChatFlow | - | -| 🎯 Personnalisé | Prise en charge de l'adresse d'appel complète | - | +| 🎯 Amont personnalisé | Configuration des points d'accès amont légalement autorisés | - | ### 📡 Interfaces prises en charge diff --git a/README.ja.md b/README.ja.md index 77e3f845..f91b2fa9 100644 --- a/README.ja.md +++ b/README.ja.md @@ -55,9 +55,10 @@ ## 📝 プロジェクト説明 > [!IMPORTANT] -> - 本プロジェクトは個人学習用のみであり、安定性の保証や技術サポートは提供しません。 -> - ユーザーは、OpenAIの[利用規約](https://openai.com/policies/terms-of-use)および**法律法規**を遵守する必要があり、違法な目的で使用してはいけません。 -> - [《生成式人工智能服务管理暂行办法》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm)の要求に従い、中国地域の公衆に未登録の生成式AI サービスを提供しないでください。 +> - 本プロジェクトは、合法的に許可された AI API ゲートウェイ、組織レベルの認証、マルチモデル管理、利用量分析、コスト管理、プライベートデプロイのシナリオのみを対象としています。 +> - ユーザーは、上流の API キー、アカウント、モデルサービス、インターフェース権限を合法的に取得し、上流のサービス利用規約および適用される法律法規を遵守する必要があります。 +> - ユーザーは、利用方法が上流のサービス利用規約および適用される法律法規に準拠していることを確認してください。 +> - 生成 AI サービスを公衆に提供する場合、ユーザーは適用される規制要件を遵守し、管轄区域で求められる届出、ライセンス、コンテンツセキュリティ、本人確認、ログ保持、税務、上流認可などのすべての義務を履行してください。 --- @@ -151,6 +152,9 @@ docker run --name new-api -d --restart always \ 🎉 デプロイが完了したら、`http://localhost:3000` にアクセスして使用を開始してください! +> [!WARNING] +> 本プロジェクトを公衆向け生成 AI サービスまたは API 再販サービスとして運営する場合、ユーザーは届出、コンテンツセキュリティ、本人確認、ログ保持、税務、決済、上流認可などの必要なコンプライアンス義務を先に完了してください。 + 📖 その他のデプロイ方法については[デプロイガイド](https://docs.newapi.pro/ja/docs/installation)を参照してください。 --- @@ -189,12 +193,12 @@ docker run --name new-api -d --restart always \ | 📈 データダッシュボード | ビジュアルコンソールと統計分析 | | 🔒 権限管理 | トークングループ化、モデル制限、ユーザー管理 | -### 💰 支払いと課金 +### 💰 認可済み利用量とコスト管理 -- ✅ オンライン充電(EPay、Stripe) -- ✅ モデルの従量課金 -- ✅ キャッシュ課金サポート(OpenAI、Azure、DeepSeek、Claude、Qwenなどすべてのサポートされているモデル) -- ✅ 柔軟な課金ポリシー設定 +- ✅ 合法的に許可されたシナリオでの内部チャージとクォータ割り当て(EPay、Stripe) +- ✅ 組織レベルのリクエスト単位、使用量ベース、キャッシュヒットのコスト会計 +- ✅ OpenAI、Azure、DeepSeek、Claude、Qwen などのモデルのキャッシュ課金統計 +- ✅ 内部管理または認可済み企業顧客向けの柔軟な課金ポリシー ### 🔐 認証とセキュリティ @@ -256,7 +260,7 @@ docker run --name new-api -d --restart always \ ## 🤖 モデルサポート -> 詳細については[APIドキュメント - 中継インターフェース](https://docs.newapi.pro/ja/docs/api) +> 詳細については[APIドキュメント - ゲートウェイインターフェース](https://docs.newapi.pro/ja/docs/api) | モデルタイプ | 説明 | ドキュメント | |---------|------|------| @@ -268,7 +272,7 @@ docker run --name new-api -d --restart always \ | 💬 Claude | Messagesフォーマット | [ドキュメント](https://docs.newapi.pro/ja/docs/api/ai-model/chat/createmessage) | | 🌐 Gemini | Google Geminiフォーマット | [ドキュメント](https://docs.newapi.pro/ja/docs/api/ai-model/chat/gemini/geminirelayv1beta) | | 🔧 Dify | ChatFlowモード | - | -| 🎯 カスタム | 完全な呼び出しアドレスの入力をサポート | - | +| 🎯 カスタム上流 | 合法的に許可された上流エンドポイントの設定をサポート | - | ### 📡 サポートされているインターフェース diff --git a/README.md b/README.md index 59239f0a..7d6ad5b7 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,10 @@ ## 📝 Project Description > [!IMPORTANT] -> - This project is for personal learning purposes only, with no guarantee of stability or technical support -> - Users must comply with OpenAI's [Terms of Use](https://openai.com/policies/terms-of-use) and **applicable laws and regulations**, and must not use it for illegal purposes -> - According to the [《Interim Measures for the Management of Generative Artificial Intelligence Services》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm), please do not provide any unregistered generative AI services to the public in China. +> - This project is intended solely for lawful and authorized AI API gateway, organization-level authentication, multi-model management, usage analytics, cost accounting, and private deployment scenarios. +> - Users must lawfully obtain upstream API keys, accounts, model services, and interface permissions, and must comply with upstream terms of service and applicable laws and regulations. +> - Users should ensure their use complies with upstream terms of service and applicable laws and regulations. +> - When providing generative AI services to the public, users should comply with applicable regulatory requirements and fulfill all filing, licensing, content safety, real-name verification, log retention, tax, and upstream authorization obligations required by their jurisdiction. --- @@ -151,6 +152,9 @@ docker run --name new-api -d --restart always \ 🎉 After deployment is complete, visit `http://localhost:3000` to start using! +> [!WARNING] +> When operating this project as a public generative AI service or API resale service, users should first complete all required filing, licensing, content safety, real-name verification, log retention, tax, payment, and upstream authorization obligations. + 📖 For more deployment methods, please refer to [Deployment Guide](https://docs.newapi.pro/en/docs/installation) --- @@ -189,12 +193,12 @@ docker run --name new-api -d --restart always \ | 📈 Data Dashboard | Visual console and statistical analysis | | 🔒 Permission Management | Token grouping, model restrictions, user management | -### 💰 Payment and Billing +### 💰 Authorized Usage Accounting and Billing -- ✅ Online recharge (EPay, Stripe) -- ✅ Pay-per-use model pricing -- ✅ Cache billing support (OpenAI, Azure, DeepSeek, Claude, Qwen and all supported models) -- ✅ Flexible billing policy configuration +- ✅ Internal top-up and quota allocation for lawful authorized scenarios (EPay, Stripe) +- ✅ Organization-level per-request, usage-based, and cache-hit cost accounting +- ✅ Cache billing statistics for OpenAI, Azure, DeepSeek, Claude, Qwen, and supported models +- ✅ Flexible billing policies for internal management or authorized enterprise customers ### 🔐 Authorization and Security @@ -254,7 +258,7 @@ docker run --name new-api -d --restart always \ ## 🤖 Model Support -> For details, please refer to [API Documentation - Relay Interface](https://docs.newapi.pro/en/docs/api) +> For details, please refer to [API Documentation - Gateway Interface](https://docs.newapi.pro/en/docs/api) | Model Type | Description | Documentation | |---------|------|------| @@ -266,7 +270,7 @@ docker run --name new-api -d --restart always \ | 💬 Claude | Messages format | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/createmessage) | | 🌐 Gemini | Google Gemini format | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/gemini/geminirelayv1beta) | | 🔧 Dify | ChatFlow mode | - | -| 🎯 Custom | Supports complete call address | - | +| 🎯 Custom upstream | Supports configuring legally authorized upstream endpoints | - | ### 📡 Supported Interfaces diff --git a/README.zh_CN.md b/README.zh_CN.md index 725df2b5..f07a2c66 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -55,9 +55,10 @@ ## 📝 项目说明 > [!IMPORTANT] -> - 本项目仅供个人学习使用,不保证稳定性,且不提供任何技术支持 -> - 使用者必须在遵循 OpenAI 的 [使用条款](https://openai.com/policies/terms-of-use) 以及**法律法规**的情况下使用,不得用于非法用途 -> - 根据 [《生成式人工智能服务管理暂行办法》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm) 的要求,请勿对中国地区公众提供一切未经备案的生成式人工智能服务 +> - 本项目仅面向合法授权的 AI API 网关、组织内部鉴权、多模型管理、用量统计、成本核算和私有化部署场景。 +> - 使用者必须合法取得上游 API Key、账号、模型服务或接口权限,并遵守上游服务条款及适用法律法规。 +> - 使用者应确保其使用方式符合上游服务条款及适用法律法规。 +> - 面向公众提供生成式人工智能服务时,使用者应遵守[《生成式人工智能服务管理暂行办法》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm)等监管要求,自行完成所在司法辖区要求的备案、许可、内容安全、实名、日志留存、税务和上游授权等合规义务。 --- @@ -151,6 +152,9 @@ docker run --name new-api -d --restart always \ 🎉 部署完成后,访问 `http://localhost:3000` 即可使用! +> [!WARNING] +> 将本项目作为面向公众的生成式 AI 服务或 API 转售服务运营时,使用者应先完成备案、内容安全、实名、日志留存、税务、支付和上游授权等合规义务。 + 📖 更多部署方式请参考 [部署指南](https://docs.newapi.pro/zh/docs/installation) --- @@ -189,12 +193,12 @@ docker run --name new-api -d --restart always \ | 📈 数据看板 | 可视化控制台与统计分析 | | 🔒 权限管理 | 令牌分组、模型限制、用户管理 | -### 💰 支付与计费 +### 💰 授权用量与成本管理 -- ✅ 在线充值(易支付、Stripe) -- ✅ 模型按次数收费 -- ✅ 缓存计费支持(OpenAI、Azure、DeepSeek、Claude、Qwen等所有支持的模型) -- ✅ 灵活的计费策略配置 +- ✅ 合法授权场景下的内部充值与额度分配(易支付、Stripe) +- ✅ 组织内按次、按量或缓存命中成本核算 +- ✅ 支持 OpenAI、Azure、DeepSeek、Claude、Qwen 等模型的缓存计费统计 +- ✅ 面向内部管理或企业客户的灵活计费策略配置 ### 🔐 授权与安全 @@ -254,7 +258,7 @@ docker run --name new-api -d --restart always \ ## 🤖 模型支持 -> 详情请参考 [接口文档 - 中继接口](https://docs.newapi.pro/zh/docs/api) +> 详情请参考 [接口文档 - 网关接口](https://docs.newapi.pro/zh/docs/api) | 模型类型 | 说明 | 文档 | |---------|------|------| @@ -266,7 +270,7 @@ docker run --name new-api -d --restart always \ | 💬 Claude | Messages 格式 | [文档](https://docs.newapi.pro/zh/docs/api/ai-model/chat/createmessage) | | 🌐 Gemini | Google Gemini 格式 | [文档](https://docs.newapi.pro/zh/docs/api/ai-model/chat/gemini/geminirelayv1beta) | | 🔧 Dify | ChatFlow 模式 | - | -| 🎯 自定义 | 支持完整调用地址 | - | +| 🎯 自定义上游 | 支持配置合法授权的上游接口地址 | - | ### 📡 支持的接口 diff --git a/README.zh_TW.md b/README.zh_TW.md index 9041215e..0b2d7e7d 100644 --- a/README.zh_TW.md +++ b/README.zh_TW.md @@ -55,9 +55,10 @@ ## 📝 項目說明 > [!IMPORTANT] -> - 本項目僅供個人學習使用,不保證穩定性,且不提供任何技術支援 -> - 使用者必須在遵循 OpenAI 的 [使用條款](https://openai.com/policies/terms-of-use) 以及**法律法規**的情況下使用,不得用於非法用途 -> - 根據 [《生成式人工智慧服務管理暫行辦法》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm) 的要求,請勿對中國地區公眾提供一切未經備案的生成式人工智慧服務 +> - 本專案僅面向合法授權的 AI API 閘道、組織內部鑑權、多模型管理、用量統計、成本核算和私有化部署場景。 +> - 使用者必須合法取得上游 API Key、帳號、模型服務或介面權限,並遵守上游服務條款及適用法律法規。 +> - 使用者應確保其使用方式符合上游服務條款及適用法律法規。 +> - 面向公眾提供生成式人工智慧服務時,使用者應遵守[《生成式人工智慧服務管理暫行辦法》](http://www.cac.gov.cn/2023-07/13/c_1690898327029107.htm)等監管要求,自行完成所在司法轄區要求的備案、許可、內容安全、實名、日誌留存、稅務和上游授權等合規義務。 --- @@ -151,6 +152,9 @@ docker run --name new-api -d --restart always \ 🎉 部署完成後,訪問 `http://localhost:3000` 即可使用! +> [!WARNING] +> 將本專案作為面向公眾的生成式 AI 服務或 API 轉售服務運營時,使用者應先完成備案、內容安全、實名、日誌留存、稅務、支付和上游授權等合規義務。 + 📖 更多部署方式請參考 [部署指南](https://docs.newapi.pro/zh/docs/installation) --- @@ -189,12 +193,12 @@ docker run --name new-api -d --restart always \ | 📈 數據看板 | 視覺化控制檯與統計分析 | | 🔒 權限管理 | 令牌分組、模型限制、用戶管理 | -### 💰 支付與計費 +### 💰 授權用量與成本管理 -- ✅ 在線儲值(易支付、Stripe) -- ✅ 模型按次數收費 -- ✅ 快取計費支援(OpenAI、Azure、DeepSeek、Claude、Qwen等所有支援的模型) -- ✅ 靈活的計費策略配置 +- ✅ 合法授權場景下的內部儲值與額度分配(易支付、Stripe) +- ✅ 組織內按次、按量或快取命中成本核算 +- ✅ 支援 OpenAI、Azure、DeepSeek、Claude、Qwen 等模型的快取計費統計 +- ✅ 面向內部管理或企業客戶的靈活計費策略配置 ### 🔐 授權與安全 @@ -254,7 +258,7 @@ docker run --name new-api -d --restart always \ ## 🤖 模型支援 -> 詳情請參考 [接口文件 - 中繼接口](https://docs.newapi.pro/zh/docs/api) +> 詳情請參考 [接口文件 - 閘道接口](https://docs.newapi.pro/zh/docs/api) | 模型類型 | 說明 | 文件 | |---------|------|------| @@ -266,7 +270,7 @@ docker run --name new-api -d --restart always \ | 💬 Claude | Messages 格式 | [文件](https://docs.newapi.pro/zh/docs/api/ai-model/chat/createmessage) | | 🌐 Gemini | Google Gemini 格式 | [文件](https://docs.newapi.pro/zh/docs/api/ai-model/chat/gemini/geminirelayv1beta) | | 🔧 Dify | ChatFlow 模式 | - | -| 🎯 自訂 | 支援完整調用位址 | - | +| 🎯 自訂上游 | 支援配置合法授權的上游介面位址 | - | ### 📡 支援的接口 diff --git a/pkg/perf_metrics/metrics.go b/pkg/perf_metrics/metrics.go index c61d17ea..e258ae1a 100644 --- a/pkg/perf_metrics/metrics.go +++ b/pkg/perf_metrics/metrics.go @@ -187,7 +187,7 @@ func QuerySummaryAll(hours int) (SummaryAllResult, error) { }) } sort.Slice(models, func(i, j int) bool { - return models[i].ModelName < models[j].ModelName + return models[i].RequestCount > models[j].RequestCount }) return SummaryAllResult{Models: models}, nil diff --git a/pkg/perf_metrics/types.go b/pkg/perf_metrics/types.go index f4f8a949..af68eb88 100644 --- a/pkg/perf_metrics/types.go +++ b/pkg/perf_metrics/types.go @@ -52,7 +52,7 @@ type ModelSummary struct { AvgLatencyMs int64 `json:"avg_latency_ms"` SuccessRate float64 `json:"success_rate"` AvgTps float64 `json:"avg_tps"` - RequestCount int64 `json:"request_count"` + RequestCount int64 `json:"-"` } type SummaryAllResult struct { diff --git a/web/classic/src/i18n/locales/en.json b/web/classic/src/i18n/locales/en.json index 829a9e4b..e9ed14ff 100644 --- a/web/classic/src/i18n/locales/en.json +++ b/web/classic/src/i18n/locales/en.json @@ -1927,7 +1927,7 @@ "更多": "Expand more", "更多信息请参考": "For more information, please refer to", "更多参数请参考": "For more parameters, please refer to", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "Better price, better stability, no subscription required, just replace the model BASE URL with: ", + "多模型统一接入,只需将基址替换为:": "Unified multi-model access, just replace the base URL with: ", "更新": "Update", "更新 Creem 设置": "Update Creem Settings", "更新 Stripe 设置": "Update Stripe settings", diff --git a/web/classic/src/i18n/locales/fr.json b/web/classic/src/i18n/locales/fr.json index e433dc8f..22e200f4 100644 --- a/web/classic/src/i18n/locales/fr.json +++ b/web/classic/src/i18n/locales/fr.json @@ -1920,7 +1920,7 @@ "更多": "Développer plus", "更多信息请参考": "Pour plus d'informations, veuillez vous référer à", "更多参数请参考": "Pour plus de paramètres, veuillez vous référer à", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "Meilleur prix, meilleure stabilité, aucun abonnement requis, il suffit de remplacer l'URL de BASE du modèle par : ", + "多模型统一接入,只需将基址替换为:": "Accès unifié multi-modèles, remplacez simplement l'URL de base par : ", "更新": "Mettre à jour", "更新 Creem 设置": "Mettre à jour les paramètres Creem", "更新 Stripe 设置": "Mettre à jour les paramètres Stripe", diff --git a/web/classic/src/i18n/locales/ja.json b/web/classic/src/i18n/locales/ja.json index 5cfa0a26..8de2af2a 100644 --- a/web/classic/src/i18n/locales/ja.json +++ b/web/classic/src/i18n/locales/ja.json @@ -1891,7 +1891,7 @@ "更多": "もっと見る", "更多信息请参考": "詳細については、こちらをご参照ください", "更多参数请参考": "その他のパラメータについては、こちらをご参照ください", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "よりお得な料金、さらに向上した安定性。モデルのベースURLを以下に置換するだけで、すぐにご利用いただけます:", + "多模型统一接入,只需将基址替换为:": "マルチモデル統一アクセス。ベースURLを以下に置換するだけでご利用いただけます:", "更新": "更新", "更新 Creem 设置": "Update Creem Settings", "更新 Stripe 设置": "Stripe設定の更新", diff --git a/web/classic/src/i18n/locales/ru.json b/web/classic/src/i18n/locales/ru.json index f4950bfe..7269d572 100644 --- a/web/classic/src/i18n/locales/ru.json +++ b/web/classic/src/i18n/locales/ru.json @@ -1938,7 +1938,7 @@ "更多": "Больше", "更多信息请参考": "Для получения дополнительной информации см.", "更多参数请参考": "Для получения дополнительных параметров см.", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "Лучшая цена, лучшая стабильность, просто замените базовый адрес модели на:", + "多模型统一接入,只需将基址替换为:": "Единый доступ к множеству моделей, просто замените базовый адрес на:", "更新": "Обновить", "更新 Creem 设置": "Обновить настройки Creem", "更新 Stripe 设置": "Обновить настройки Stripe", diff --git a/web/classic/src/i18n/locales/vi.json b/web/classic/src/i18n/locales/vi.json index 1d83bf6b..c48c69f2 100644 --- a/web/classic/src/i18n/locales/vi.json +++ b/web/classic/src/i18n/locales/vi.json @@ -1892,7 +1892,7 @@ "更多": "Mở rộng thêm", "更多信息请参考": "Để biết thêm thông tin, vui lòng tham khảo", "更多参数请参考": "Để biết thêm tham số, vui lòng tham khảo", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "Giá tốt hơn, ổn định hơn, không cần đăng ký, chỉ cần thay thế URL CƠ SỞ mô hình bằng: ", + "多模型统一接入,只需将基址替换为:": "Truy cập thống nhất đa mô hình, chỉ cần thay thế URL cơ sở bằng: ", "更新": "Cập nhật", "更新 Creem 设置": "Cập nhật cài đặt Creem", "更新 Stripe 设置": "Cập nhật cài đặt Stripe", diff --git a/web/classic/src/i18n/locales/zh-CN.json b/web/classic/src/i18n/locales/zh-CN.json index 2156b46d..fcb0b78a 100644 --- a/web/classic/src/i18n/locales/zh-CN.json +++ b/web/classic/src/i18n/locales/zh-CN.json @@ -1886,7 +1886,7 @@ "更多": "更多", "更多信息请参考": "更多信息请参考", "更多参数请参考": "更多参数请参考", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "更好的价格,更好的稳定性,只需要将模型基址替换为:", + "多模型统一接入,只需将基址替换为:": "多模型统一接入,只需将基址替换为:", "更新": "更新", "更新 Creem 设置": "更新 Creem 设置", "更新 Stripe 设置": "更新 Stripe 设置", diff --git a/web/classic/src/i18n/locales/zh-TW.json b/web/classic/src/i18n/locales/zh-TW.json index 98d8e892..86a7cb35 100644 --- a/web/classic/src/i18n/locales/zh-TW.json +++ b/web/classic/src/i18n/locales/zh-TW.json @@ -1896,7 +1896,7 @@ "更多": "更多", "更多信息请参考": "更多資訊請參考", "更多参数请参考": "更多參數請參考", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "更好的價格,更好的穩定性,只需要將模型基址替換為:", + "多模型统一接入,只需将基址替换为:": "多模型統一接入,只需將基址替換為:", "更新": "更新", "更新 Creem 设置": "更新 Creem 設定", "更新 Stripe 设置": "更新 Stripe 設定", diff --git a/web/classic/src/i18n/locales/zh.json b/web/classic/src/i18n/locales/zh.json index e23930f5..38c0b9ee 100644 --- a/web/classic/src/i18n/locales/zh.json +++ b/web/classic/src/i18n/locales/zh.json @@ -1304,7 +1304,7 @@ "更多": "更多", "更多信息请参考": "更多信息请参考", "更多参数请参考": "更多参数请参考", - "更好的价格,更好的稳定性,只需要将模型基址替换为:": "更好的价格,更好的稳定性,只需要将模型基址替换为:", + "多模型统一接入,只需将基址替换为:": "多模型统一接入,只需将基址替换为:", "更新": "更新", "更新 Creem 设置": "更新 Creem 设置", "更新 Stripe 设置": "更新 Stripe 设置", diff --git a/web/classic/src/pages/Home/index.jsx b/web/classic/src/pages/Home/index.jsx index c153c1b3..c242e086 100644 --- a/web/classic/src/pages/Home/index.jsx +++ b/web/classic/src/pages/Home/index.jsx @@ -176,7 +176,7 @@ const Home = () => {

- {t('更好的价格,更好的稳定性,只需要将模型基址替换为:')} + {t('多模型统一接入,只需将基址替换为:')}

{/* BASE URL 与端点选择 */}
diff --git a/web/default/src/features/dashboard/components/models/performance-overview.tsx b/web/default/src/features/dashboard/components/models/performance-overview.tsx index 927c1eed..5e67bb8a 100644 --- a/web/default/src/features/dashboard/components/models/performance-overview.tsx +++ b/web/default/src/features/dashboard/components/models/performance-overview.tsx @@ -18,19 +18,10 @@ For commercial licensing, please contact support@quantumnous.com */ import { useMemo } from 'react' import { useQuery } from '@tanstack/react-query' -import { Activity, Gauge, HeartPulse, Timer } from 'lucide-react' +import { Gauge, HeartPulse, Timer } from 'lucide-react' import { useTranslation } from 'react-i18next' -import { formatNumber } from '@/lib/format' import { cn } from '@/lib/utils' import { Skeleton } from '@/components/ui/skeleton' -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table' import { getPerfMetricsSummary } from '@/features/performance-metrics/api' import { formatLatency, @@ -40,7 +31,7 @@ import { import type { PerfModelSummary } from '@/features/performance-metrics/types' const PERFORMANCE_WINDOW_HOURS = 24 -const TOP_MODEL_LIMIT = 8 +const TOP_MODEL_LIMIT = 5 type WeightedMetric = 'avg_latency_ms' | 'avg_tps' | 'success_rate' @@ -51,121 +42,55 @@ type PerformanceSummary = { successRate: number } -function weightedAverage( +function simpleAverage( rows: PerfModelSummary[], metric: WeightedMetric, isValid: (value: number) => boolean ): number { let total = 0 - let weight = 0 + let count = 0 for (const row of rows) { const value = Number(row[metric]) - const requestCount = Number(row.request_count) || 0 - if (requestCount <= 0 || !isValid(value)) continue - - total += value * requestCount - weight += requestCount + if (!isValid(value)) continue + total += value + count++ } - return weight > 0 ? total / weight : 0 + return count > 0 ? total / count : NaN } function buildPerformanceSummary(rows: PerfModelSummary[]): PerformanceSummary { - const totalRequests = rows.reduce( - (sum, row) => sum + (Number(row.request_count) || 0), - 0 - ) - return { - totalRequests, + totalRequests: rows.length, avgLatencyMs: Math.round( - weightedAverage( + simpleAverage( rows, 'avg_latency_ms', (value) => Number.isFinite(value) && value > 0 ) ), - avgTps: weightedAverage( + avgTps: simpleAverage( rows, 'avg_tps', (value) => Number.isFinite(value) && value > 0 ), - successRate: weightedAverage(rows, 'success_rate', Number.isFinite), + successRate: simpleAverage(rows, 'success_rate', Number.isFinite), } } function successRateClassName(successRate: number): string { - if (successRate >= 99.9) return 'text-emerald-600 dark:text-emerald-400' - if (successRate >= 99) return 'text-amber-600 dark:text-amber-400' - return 'text-rose-600 dark:text-rose-400' + if (!Number.isFinite(successRate)) return 'text-muted-foreground' + if (successRate >= 99.9) return 'text-success' + if (successRate >= 99) return 'text-warning' + return 'text-destructive' } function successDotClassName(successRate: number): string { - if (successRate >= 99.9) return 'bg-emerald-500' - if (successRate >= 99) return 'bg-amber-500' - return 'bg-rose-500' -} - -function PerformanceMetricItem(props: { - icon: React.ComponentType<{ className?: string }> - label: string - value: string - hint: string - loading?: boolean - valueClassName?: string -}) { - const Icon = props.icon - - return ( -
-
-
- {props.loading ? ( -
- - -
- ) : ( - <> -
- {props.value} -
-
- {props.hint} -
- - )} -
- ) -} - -function PerformanceTableHeader(props: { description: string }) { - const { t } = useTranslation() - - return ( -
-
- -
- {t('Model performance metrics')} -
-
- {props.description} -
- ) + if (!Number.isFinite(successRate)) return 'bg-muted-foreground' + if (successRate >= 99.9) return 'bg-success' + if (successRate >= 99) return 'bg-warning' + return 'bg-destructive' } export function PerformanceOverview() { @@ -178,139 +103,136 @@ export function PerformanceOverview() { }) const models = useMemo( - () => - [...(metricsQuery.data?.data.models ?? [])] - .filter((model) => Number(model.request_count) > 0) - .sort((a, b) => b.request_count - a.request_count), + () => metricsQuery.data?.data.models ?? [], [metricsQuery.data] ) const summary = useMemo(() => buildPerformanceSummary(models), [models]) const topModels = useMemo(() => models.slice(0, TOP_MODEL_LIMIT), [models]) const loading = metricsQuery.isLoading const hasData = models.length > 0 - const description = t('Performance metrics for the last 24 hours') + + if (!loading && !hasData) { + return ( +
+ {t('No performance data available')} +
+ ) + } return ( -
-
-
- - - - +
+ {/* Title */} +
+
-
-
- - {!loading && !hasData ? ( -
- {t('No performance data available')} + {/* Separator */} +
+ + {/* 3 KPI inline metrics */} + {loading ? ( +
+ {Array.from({ length: 3 }).map((_, i) => ( +
+ + +
+ ))}
) : ( -
- - - - {t('Model')} - - {t('Requests (24h)')} - - - {t('Average latency')} - - - {t('Throughput')} - - - {t('Success rate')} - - - - - {loading - ? Array.from({ length: 4 }).map((_, index) => ( - - - - - - - - - - - - - - - - - - )) - : topModels.map((model) => ( - - - {model.model_name} - - - {formatNumber(model.request_count)} - - - {formatLatency(model.avg_latency_ms)} - - - {formatThroughput(model.avg_tps)} - - - - - - - ))} - -
+
+ + + +
+ )} + + {/* Separator */} +
+ + {/* Top models inline badges */} + {!loading && hasData && ( +
+ {topModels.map((model) => ( + + ))}
)}
-
+
+ ) +} + +function InlineMetric(props: { + icon: React.ComponentType<{ className?: string }> + label: string + value: string + valueClassName?: string +}) { + const Icon = props.icon + + return ( +
+
+ ) +} + +function ModelBadge(props: { model: PerfModelSummary }) { + const model = props.model + + return ( + + + {model.model_name} + + ) } diff --git a/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx b/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx index 20e1a657..df5d1b53 100644 --- a/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx +++ b/web/default/src/features/dashboard/components/overview/overview-dashboard.tsx @@ -56,6 +56,7 @@ import { useApiInfo } from '../../hooks/use-status-data' import { AnnouncementsPanel } from './announcements-panel' import { ApiInfoPanel } from './api-info-panel' import { FAQPanel } from './faq-panel' +import { PerformanceHealthPanel } from './performance-health-panel' import { SummaryCards } from './summary-cards' import { UptimePanel } from './uptime-panel' @@ -716,6 +717,11 @@ export function OverviewDashboard() {
+ {isAdmin && ( + + + + )} diff --git a/web/default/src/features/dashboard/components/overview/performance-health-panel.tsx b/web/default/src/features/dashboard/components/overview/performance-health-panel.tsx new file mode 100644 index 00000000..bfe0f500 --- /dev/null +++ b/web/default/src/features/dashboard/components/overview/performance-health-panel.tsx @@ -0,0 +1,207 @@ +/* +Copyright (C) 2023-2026 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ +import { useMemo } from 'react' +import { useQuery } from '@tanstack/react-query' +import { Gauge, HeartPulse, Timer } from 'lucide-react' +import { useTranslation } from 'react-i18next' +import { cn } from '@/lib/utils' +import { Skeleton } from '@/components/ui/skeleton' +import { getPerfMetricsSummary } from '@/features/performance-metrics/api' +import { + formatLatency, + formatThroughput, + formatUptimePct, +} from '@/features/performance-metrics/lib/format' +import type { PerfModelSummary } from '@/features/performance-metrics/types' + +const PERFORMANCE_WINDOW_HOURS = 24 +const TOP_MODEL_LIMIT = 5 + +type WeightedMetric = 'avg_latency_ms' | 'avg_tps' | 'success_rate' + +function simpleAverage( + rows: PerfModelSummary[], + metric: WeightedMetric, + isValid: (value: number) => boolean +): number { + let total = 0 + let count = 0 + for (const row of rows) { + const value = Number(row[metric]) + if (!isValid(value)) continue + total += value + count++ + } + return count > 0 ? total / count : NaN +} + +function rateTextClass(rate: number): string { + if (!Number.isFinite(rate)) return 'text-muted-foreground' + if (rate >= 99.9) return 'text-success' + if (rate >= 99) return 'text-warning' + return 'text-destructive' +} + +function rateDotClass(rate: number): string { + if (!Number.isFinite(rate)) return 'bg-muted-foreground' + if (rate >= 99.9) return 'bg-success' + if (rate >= 99) return 'bg-warning' + return 'bg-destructive' +} + +export function PerformanceHealthPanel() { + const { t } = useTranslation() + const metricsQuery = useQuery({ + queryKey: ['perf-metrics-summary', PERFORMANCE_WINDOW_HOURS], + queryFn: () => getPerfMetricsSummary(PERFORMANCE_WINDOW_HOURS), + staleTime: 60 * 1000, + retry: false, + }) + + const models = useMemo( + () => metricsQuery.data?.data.models ?? [], + [metricsQuery.data] + ) + + const summary = useMemo(() => { + return { + avgLatencyMs: Math.round( + simpleAverage(models, 'avg_latency_ms', (v) => Number.isFinite(v) && v > 0) + ), + avgTps: simpleAverage(models, 'avg_tps', (v) => Number.isFinite(v) && v > 0), + successRate: simpleAverage(models, 'success_rate', Number.isFinite), + } + }, [models]) + + const topModels = useMemo(() => models.slice(0, TOP_MODEL_LIMIT), [models]) + const loading = metricsQuery.isLoading + const hasData = models.length > 0 + + return ( +
+
+
+ +
+ {/* KPI metrics */} +
+ + + +
+ + {/* Top models */} +
+ + {t('Top models by traffic')} + + {loading ? ( +
+ {Array.from({ length: 3 }).map((_, i) => ( + + ))} +
+ ) : !hasData ? ( + + {t('No performance data available')} + + ) : ( +
+ {topModels.map((model) => ( +
+ + {model.model_name} + + + +
+ ))} +
+ )} +
+
+
+ ) +} + +function MetricCell(props: { + icon: React.ComponentType<{ className?: string }> + label: string + value: string + loading: boolean + valueClassName?: string +}) { + const Icon = props.icon + return ( +
+
+
+ {props.loading ? ( + + ) : ( +
+ {props.value} +
+ )} +
+ ) +} diff --git a/web/default/src/features/dashboard/components/overview/summary-cards.tsx b/web/default/src/features/dashboard/components/overview/summary-cards.tsx index c2423256..21839692 100644 --- a/web/default/src/features/dashboard/components/overview/summary-cards.tsx +++ b/web/default/src/features/dashboard/components/overview/summary-cards.tsx @@ -19,12 +19,18 @@ For commercial licensing, please contact support@quantumnous.com import { useMemo } from 'react' import { useQuery } from '@tanstack/react-query' import { Link } from '@tanstack/react-router' -import { ArrowRight, CreditCard } from 'lucide-react' +import { + ArrowRight, + Flame, + ShieldCheck, + TrendingDown, +} from 'lucide-react' import { useTranslation } from 'react-i18next' import { useAuthStore } from '@/stores/auth-store' import { getCurrencyLabel, isCurrencyDisplayEnabled } from '@/lib/currency' import { formatNumber, formatQuota } from '@/lib/format' import { computeTimeRange } from '@/lib/time' +import { cn } from '@/lib/utils' import { useStatus } from '@/hooks/use-status' import { Button } from '@/components/ui/button' import { StaggerContainer, StaggerItem } from '@/components/page-transition' @@ -87,12 +93,62 @@ function buildSummarySparklines( } } +function getSummarySparkline( + key: string, + sparklineData: Record +): number[] | undefined { + if (key === 'usage') return sparklineData.usage + if (key === 'requests') return sparklineData.requests + return undefined +} + +function getRunwayDays(remainQuota: number, recentUsage: number): number | null { + if (remainQuota <= 0 || recentUsage <= 0) return null + const days = remainQuota / recentUsage + if (!Number.isFinite(days)) return null + return days +} + +type HealthLevel = 'healthy' | 'caution' | 'critical' + +function getHealthLevel( + remainQuota: number, + recentUsage: number +): HealthLevel { + if (remainQuota <= 0) return 'critical' + const days = getRunwayDays(remainQuota, recentUsage) + if (days !== null && days < 3) return 'caution' + return 'healthy' +} + +const HEALTH_CONFIG: Record< + HealthLevel, + { dotClass: string; labelKey: string } +> = { + healthy: { + dotClass: 'bg-success', + labelKey: 'Healthy', + }, + caution: { + dotClass: 'bg-warning', + labelKey: 'Low balance', + }, + critical: { + dotClass: 'bg-destructive', + labelKey: 'Balance depleted', + }, +} + + export function SummaryCards() { const { t } = useTranslation() const user = useAuthStore((state) => state.auth.user) const { status, loading } = useStatus() const summaryTimeRange = useMemo(() => computeTimeRange(1), []) + const remainQuota = Number(user?.quota ?? 0) + const usedQuota = Number(user?.used_quota ?? 0) + const requestCount = Number(user?.request_count ?? 0) const usageTrendQuery = useQuery({ queryKey: [ @@ -112,16 +168,11 @@ export function SummaryCards() { }) const summaryValues = useMemo(() => { - const remainQuota = Number(user?.quota ?? 0) - const usedQuota = Number(user?.used_quota ?? 0) - const requestCount = Number(user?.request_count ?? 0) - return { - remainDisplay: formatQuota(remainQuota), usedDisplay: formatQuota(usedQuota), requestCountDisplay: formatNumber(requestCount), } - }, [user]) + }, [requestCount, usedQuota]) const currencyEnabledFromStore = isCurrencyDisplayEnabled() const statusCurrencyFlag = @@ -138,37 +189,53 @@ export function SummaryCards() { () => buildSummarySparklines( usageTrendQuery.data?.data ?? [], - Number(user?.quota ?? 0), + remainQuota, summaryTimeRange.start_timestamp, summaryTimeRange.end_timestamp ), [ + remainQuota, summaryTimeRange.end_timestamp, summaryTimeRange.start_timestamp, usageTrendQuery.data?.data, - user?.quota, ] ) + const recentUsage = useMemo( + () => + (usageTrendQuery.data?.data ?? []).reduce( + (total, item) => total + (Number(item.quota) || 0), + 0 + ), + [usageTrendQuery.data?.data] + ) + + const healthLevel = getHealthLevel(remainQuota, recentUsage) + const healthCfg = HEALTH_CONFIG[healthLevel] + const runwayDays = getRunwayDays(remainQuota, recentUsage) + + const todayUsageDisplay = formatQuota(recentUsage) + const items = useSummaryCardsConfig({ ...summaryValues, + todayUsageDisplay, currencyEnabled, currencyLabel, }).map((config, index) => { const tones = ['rose', 'teal', 'gray'] as const return { + key: config.key, title: config.title, value: config.value, desc: config.description, icon: config.icon, tone: tones[index] ?? 'gray', sparkline: - config.key === 'balance' - ? sparklineData.balance - : config.key === 'usage' - ? sparklineData.usage - : sparklineData.requests, + config.key === 'todayUsage' + ? sparklineData.usage + : getSummarySparkline(config.key, sparklineData), + sparklineVariant: 'line' as const, } }) @@ -189,7 +256,7 @@ export function SummaryCards() { {items.map((it) => ( @@ -206,28 +274,78 @@ export function SummaryCards() {
-
-
-
- {t('Credit remaining')} -
-
- - {summaryValues.remainDisplay} +
+
+
+ + {t('Credit remaining')} + + + -
-

- {currencyEnabled - ? `${t('Displayed in')} ${currencyLabel}` - : t('Balance is shown in quota units')} -

+ +
+ {formatQuota(remainQuota)} +
+ +
+
+
+
+
+ {formatQuota(recentUsage)} +
+
+
+
+ {runwayDays !== null && runwayDays < 3 ? ( +
+
+ {runwayDays !== null + ? runwayDays < 1 + ? t('Less than 1 day left') + : runwayDays > 999 + ? `999+ ${t('days')}` + : `~${formatNumber(Math.floor(runwayDays))} ${t('days')}` + : remainQuota <= 0 + ? t('Balance depleted') + : t('No recent usage')} +
+
+
-
diff --git a/web/default/src/features/dashboard/components/ui/stat-card.tsx b/web/default/src/features/dashboard/components/ui/stat-card.tsx index 910389bf..0cc541f2 100644 --- a/web/default/src/features/dashboard/components/ui/stat-card.tsx +++ b/web/default/src/features/dashboard/components/ui/stat-card.tsx @@ -16,12 +16,25 @@ along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ -import type { ReactNode } from 'react' +import { useId, type ReactNode } from 'react' import { type LucideIcon } from 'lucide-react' import { cn } from '@/lib/utils' import { Skeleton } from '@/components/ui/skeleton' type StatCardTone = 'rose' | 'teal' | 'gray' +type StatCardSparklineVariant = 'bars' | 'line' +type StatCardDetailTone = + | 'default' + | 'muted' + | 'success' + | 'warning' + | 'destructive' + +export interface StatCardDetail { + label: string + value: string + tone?: StatCardDetailTone +} interface StatCardProps { title: string @@ -29,6 +42,8 @@ interface StatCardProps { description: string icon: LucideIcon sparkline?: number[] + sparklineVariant?: StatCardSparklineVariant + details?: StatCardDetail[] tone?: StatCardTone loading?: boolean error?: boolean @@ -41,6 +56,20 @@ const TONE_CLASSES: Record = { gray: 'from-muted-foreground/50 via-muted-foreground/20 to-transparent dark:from-muted-foreground/40 dark:via-muted-foreground/20', } +const LINE_TONE_CLASSES: Record = { + rose: 'text-warning', + teal: 'text-primary', + gray: 'text-muted-foreground', +} + +const DETAIL_TONE_CLASSES: Record = { + default: 'text-foreground', + muted: 'text-muted-foreground', + success: 'text-success', + warning: 'text-warning', + destructive: 'text-destructive', +} + function normalizeSparkline(values?: number[]): number[] { if (!values?.length) return [] @@ -51,10 +80,133 @@ function normalizeSparkline(values?: number[]): number[] { return sanitized.map((value) => Math.max(8, (value / max) * 100)) } +function buildLineSparkline(values?: number[]) { + if (!values?.length) return null + + const sanitized = values.map((value) => Math.max(0, Number(value) || 0)) + const width = 160 + const height = 36 + const padding = 3 + const max = Math.max(...sanitized) + const min = Math.min(...sanitized) + const range = max - min + + const points = sanitized.map((value, index) => { + const x = + sanitized.length === 1 + ? width / 2 + : (index / (sanitized.length - 1)) * width + const normalized = + range > 0 ? (value - min) / range : max > 0 ? 0.5 : 0 + const y = height - padding - normalized * (height - padding * 2) + + return { x, y } + }) + + const linePath = points + .map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x} ${point.y}`) + .join(' ') + const firstPoint = points[0] + const lastPoint = points[points.length - 1] + const areaPath = `${linePath} L ${lastPoint.x} ${height} L ${firstPoint.x} ${height} Z` + + return { + areaPath, + linePath, + } +} + +function LineSparkline(props: { values?: number[]; tone: StatCardTone }) { + const rawGradientId = useId() + const gradientId = `stat-card-line-${rawGradientId.replace(/:/g, '')}` + const paths = buildLineSparkline(props.values) + + if (!paths) return ) } diff --git a/web/default/src/features/dashboard/hooks/use-dashboard-config.tsx b/web/default/src/features/dashboard/hooks/use-dashboard-config.tsx index 0da170de..1ef03896 100644 --- a/web/default/src/features/dashboard/hooks/use-dashboard-config.tsx +++ b/web/default/src/features/dashboard/hooks/use-dashboard-config.tsx @@ -22,7 +22,7 @@ import { Layers, Gauge, Zap, - Wallet, + Flame, TrendingUp, Activity, type LucideIcon, @@ -83,7 +83,7 @@ export function useModelStatCardsConfig(): StatCardConfig[] { } export function useSummaryCardsConfig(totals: { - remainDisplay: string + todayUsageDisplay: string usedDisplay: string requestCountDisplay: string currencyLabel: string @@ -93,13 +93,13 @@ export function useSummaryCardsConfig(totals: { return [ { - key: 'balance', - title: t('Current Balance'), - value: totals.remainDisplay, + key: 'todayUsage', + title: t('Last 24h usage'), + value: totals.todayUsageDisplay, description: totals.currencyEnabled - ? `${t('Remaining quota')} (${totals.currencyLabel})` - : t('Remaining quota units'), - icon: Wallet, + ? `${t('Consumed in the last 24 hours')} (${totals.currencyLabel})` + : t('Consumed in the last 24 hours'), + icon: Flame, }, { key: 'usage', diff --git a/web/default/src/features/dashboard/index.tsx b/web/default/src/features/dashboard/index.tsx index 61c5608f..399221b0 100644 --- a/web/default/src/features/dashboard/index.tsx +++ b/web/default/src/features/dashboard/index.tsx @@ -109,25 +109,23 @@ function ModelChartsFallback() { function PerformanceOverviewFallback() { return ( -
-
-
- {Array.from({ length: 4 }).map((_, i) => ( -
- - - -
+
+
+
+ +
+ {Array.from({ length: 3 }).map((_, i) => ( +
+ + +
+ ))} +
+ {Array.from({ length: 2 }).map((_, i) => ( + ))}
-
-
- - -
- -
) } @@ -267,12 +265,14 @@ export function Dashboard() { /> + {isAdmin && ( + + }> + + + + )} - }> - - - - }> - + }> . For commercial licensing, please contact support@quantumnous.com */ export function formatThroughput(tps: number): string { - if (tps <= 0) return '—' + if (!Number.isFinite(tps) || tps <= 0) return '—' if (tps >= 1_000) return `${(tps / 1_000).toFixed(1)}K t/s` return `${tps.toFixed(tps < 10 ? 2 : 1)} t/s` } diff --git a/web/default/src/features/performance-metrics/types.ts b/web/default/src/features/performance-metrics/types.ts index 5f6460d5..fcf3c298 100644 --- a/web/default/src/features/performance-metrics/types.ts +++ b/web/default/src/features/performance-metrics/types.ts @@ -48,7 +48,7 @@ export type PerfModelSummary = { avg_latency_ms: number success_rate: number avg_tps: number - request_count: number + request_count?: number } export type PerfSummaryAllData = { diff --git a/web/default/src/features/pricing/components/model-card-grid.tsx b/web/default/src/features/pricing/components/model-card-grid.tsx index a8f1b0ef..2c8932dc 100644 --- a/web/default/src/features/pricing/components/model-card-grid.tsx +++ b/web/default/src/features/pricing/components/model-card-grid.tsx @@ -59,9 +59,7 @@ export function ModelCardGrid(props: ModelCardGridProps) { const perfMap = useMemo(() => { const map = new Map() for (const model of perfQuery.data?.data?.models ?? []) { - if (model.request_count > 0) { - map.set(model.model_name, model) - } + map.set(model.model_name, model) } return map }, [perfQuery.data]) diff --git a/web/default/src/features/wallet/components/recharge-form-card.tsx b/web/default/src/features/wallet/components/recharge-form-card.tsx index f7e4a3b5..814e2a71 100644 --- a/web/default/src/features/wallet/components/recharge-form-card.tsx +++ b/web/default/src/features/wallet/components/recharge-form-card.tsx @@ -475,14 +475,14 @@ export function RechargeFormCard({
{topupLink && (

- {t('Need a code?')}{' '} + {t('Need a redemption code?')}{' '} - {t('Purchase here')} + {t('Get one here')}

diff --git a/web/default/src/features/wallet/components/subscription-plans-card.tsx b/web/default/src/features/wallet/components/subscription-plans-card.tsx index da009a11..5e35b732 100644 --- a/web/default/src/features/wallet/components/subscription-plans-card.tsx +++ b/web/default/src/features/wallet/components/subscription-plans-card.tsx @@ -254,7 +254,7 @@ export function SubscriptionPlansCard({ <> } contentClassName='space-y-4 sm:space-y-5' > @@ -499,7 +499,7 @@ export function SubscriptionPlansCard({ {!hasAny && (

- {t('Purchase a plan to enjoy model benefits')} + {t('Subscribe to a plan for model access')}

)}
diff --git a/web/default/src/i18n/locales/_reports/ja.untranslated.json b/web/default/src/i18n/locales/_reports/ja.untranslated.json index 2e6d3ca8..da64d219 100644 --- a/web/default/src/i18n/locales/_reports/ja.untranslated.json +++ b/web/default/src/i18n/locales/_reports/ja.untranslated.json @@ -4,6 +4,7 @@ "/status/": "/status/", "/your/endpoint": "/your/endpoint", "AIGC2D": "AIGC2D", + "Alipay": "Alipay", "Anthropic": "Anthropic", "API URL": "API URL", "API2GPT": "API2GPT", @@ -86,9 +87,8 @@ "VolcEngine": "VolcEngine", "Webhook URL": "Webhook URL", "Webhook URL:": "Webhook URL:", + "WeChat Pay": "WeChat Pay", "whsec_xxx": "whsec_xxx", "Xinference": "Xinference", - "Xunfei": "Xunfei", - "Alipay": "Alipay", - "WeChat Pay": "WeChat Pay" + "Xunfei": "Xunfei" } diff --git a/web/default/src/i18n/locales/_reports/ru.untranslated.json b/web/default/src/i18n/locales/_reports/ru.untranslated.json index 0727e081..ce0fea16 100644 --- a/web/default/src/i18n/locales/_reports/ru.untranslated.json +++ b/web/default/src/i18n/locales/_reports/ru.untranslated.json @@ -8,6 +8,7 @@ "AccessKey / SecretAccessKey": "AccessKey / SecretAccessKey", "AI Proxy": "AI Proxy", "AIGC2D": "AIGC2D", + "Alipay": "Alipay", "All conditions must match before this tier is used.": "All conditions must match before this tier is used.", "Anthropic": "Anthropic", "API2GPT": "API2GPT", @@ -100,10 +101,9 @@ "Vertex AI": "Vertex AI", "VolcEngine": "VolcEngine", "WeChat": "WeChat", + "WeChat Pay": "WeChat Pay", "whsec_xxx": "whsec_xxx", "Xinference": "Xinference", "Xunfei": "Xunfei", - "Alipay": "Alipay", - "WeChat Pay": "WeChat Pay", "Zhipu V4": "Zhipu V4" } diff --git a/web/default/src/i18n/locales/en.json b/web/default/src/i18n/locales/en.json index ed77ba19..bb8496d1 100644 --- a/web/default/src/i18n/locales/en.json +++ b/web/default/src/i18n/locales/en.json @@ -100,6 +100,7 @@ "A billing multiplier. Lower ratios mean lower API call costs.": "A billing multiplier. Lower ratios mean lower API call costs.", "A focused home for keys, balance, routing, and service health.": "A focused home for keys, balance, routing, and service health.", "About": "About", + "About {{days}} days left": "About {{days}} days left", "Accept Unpriced Models": "Accept Unpriced Models", "Accepts a JSON array of model identifiers that support the Imagine API.": "Accepts a JSON array of model identifiers that support the Imagine API.", "Accepts comma-separated status codes and inclusive ranges.": "Accepts comma-separated status codes and inclusive ranges.", @@ -239,6 +240,7 @@ "AILS": "AILS", "AK/SK mode: use AccessKey|SecretAccessKey|Region": "AK/SK mode: use AccessKey|SecretAccessKey|Region", "Ali": "Ali", + "Alipay": "Alipay", "All": "All", "All categories": "All categories", "All conditions must match before this tier is used.": "All conditions must match before this tier is used.", @@ -477,6 +479,7 @@ "Baidu V2": "Baidu V2", "Balance": "Balance", "Balance and top-up management": "Balance and top-up management", + "Balance depleted": "Balance depleted", "Balance is shown in quota units": "Balance is shown in quota units", "Balance queried successfully": "Balance queried successfully", "Balance updated successfully": "Balance updated successfully", @@ -888,6 +891,7 @@ "Console Area": "Console Area", "Console Content": "Console Content", "Consume": "Consume", + "Consumed in the last 24 hours": "Consumed in the last 24 hours", "Container": "Container", "Container name": "Container name", "Containers": "Containers", @@ -1897,6 +1901,7 @@ "Header Value (supports string or JSON mapping)": "Header Value (supports string or JSON mapping)", "header. Anthropic-formatted endpoints accept the": "header. Anthropic-formatted endpoints accept the", "Health": "Health", + "Healthy": "Healthy", "Hidden — verify to reveal": "Hidden — verify to reveal", "Hide": "Hide", "Hide API key": "Hide API key", @@ -2101,6 +2106,7 @@ "Language preference saved": "Language preference saved", "Language Preferences": "Language Preferences", "Language preferences sync across your signed-in devices and affect API error messages.": "Language preferences sync across your signed-in devices and affect API error messages.", + "Last 24h usage": "Last 24h usage", "Last 30 days uptime": "Last 30 days uptime", "Last check time": "Last check time", "Last detected addable models": "Last detected addable models", @@ -2143,6 +2149,7 @@ "Less": "Less", "Less than": "Less than", "Less Than": "Less Than", + "Less than 1 day left": "Less than 1 day left", "Less than or equal": "Less than or equal", "Less Than or Equal": "Less Than or Equal", "License": "License", @@ -2192,6 +2199,7 @@ "Logo": "Logo", "Logo URL": "Logo URL", "Logs": "Logs", + "Low balance": "Low balance", "Lowest median first-token latency": "Lowest median first-token latency", "m": "m", "Maintain a list of common questions for the dashboard help panel": "Maintain a list of common questions for the dashboard help panel", @@ -2371,6 +2379,7 @@ "MokaAI": "MokaAI", "Monitor": "Monitor", "Monitor balance, usage, and request volume": "Monitor balance, usage, and request volume", + "Monitored relay requests": "Monitored relay requests", "Monitoring & Alerts": "Monitoring & Alerts", "Month": "Month", "Month number": "Month number", @@ -2381,9 +2390,9 @@ "More": "More", "more mapping": "more mapping", "More templates...": "More templates...", + "More than 999 days left": "More than 999 days left", "More...": "More...", "Most-used models in the selected period and category": "Most-used models in the selected period and category", - "Monitored relay requests": "Monitored relay requests", "Move": "Move", "Move a request header": "Move a request header", "Move affiliate rewards to your main balance": "Move affiliate rewards to your main balance", @@ -2433,7 +2442,7 @@ "Name the channel, choose the provider, configure API access, and set credentials.": "Name the channel, choose the provider, configure API access, and set credentials.", "name@example.com": "name@example.com", "Native format": "Native format", - "Need a code?": "Need a code?", + "Need a redemption code?": "Need a redemption code?", "Needs API key": "Needs API key", "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.": "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.", "Nested JSON: source group →": "Nested JSON: source group →", @@ -2567,6 +2576,7 @@ "No providers available": "No providers available", "No Quota": "No Quota", "No ratio differences found": "No ratio differences found", + "No recent usage": "No recent usage", "No records found. Try adjusting your filters.": "No records found. Try adjusting your filters.", "No redemption codes available. Create your first redemption code to get started.": "No redemption codes available. Create your first redemption code to get started.", "No Redemption Codes Found": "No Redemption Codes Found", @@ -2851,6 +2861,7 @@ "Percentage:": "Percentage:", "Performance": "Performance", "Performance data is not yet available for this model.": "Performance data is not yet available for this model.", + "Performance health": "Performance health", "Performance metrics for the last 24 hours": "Performance metrics for the last 24 hours", "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.", "Performance Monitor": "Performance Monitor", @@ -2923,6 +2934,7 @@ "Please set Ollama API Base URL first": "Please set Ollama API Base URL first", "Please try again later.": "Please try again later.", "Please upload key file(s)": "Please upload key file(s)", + "Please wait a moment before trying again.": "Please wait a moment before trying again.", "Please wait a moment, human check is initializing...": "Please wait a moment, human check is initializing...", "Policy JSON": "Policy JSON", "Polling": "Polling", @@ -3061,8 +3073,8 @@ "Pull": "Pull", "Pull model": "Pull model", "Pulling...": "Pulling...", - "Purchase a plan to enjoy model benefits": "Purchase a plan to enjoy model benefits", - "Purchase here": "Purchase here", + "Subscribe to a plan for model access": "Subscribe to a plan for model access", + "Get one here": "Get one here", "Purchase Limit": "Purchase Limit", "Purchase limit reached": "Purchase limit reached", "Purchase Subscription": "Purchase Subscription", @@ -3356,6 +3368,7 @@ "Run GC": "Run GC", "Run tests for the selected models": "Run tests for the selected models", "Running": "Running", + "Runway": "Runway", "s": "s", "Safety Settings": "Safety Settings", "Same as Local": "Same as Local", @@ -3847,6 +3860,7 @@ "This action will permanently remove 2FA protection from your account.": "This action will permanently remove 2FA protection from your account.", "This channel is not an Ollama channel.": "This channel is not an Ollama channel.", "This channel type does not support fetching models": "This channel type does not support fetching models", + "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.", "This data may be unreliable, use with caution": "This data may be unreliable, use with caution", "This device does not support Passkey": "This device does not support Passkey", "This device does not support Passkey verification.": "This device does not support Passkey verification.", @@ -3955,6 +3969,7 @@ "Tokens since launch": "Tokens since launch", "Tokens-only mode will show raw quota values regardless of this toggle.": "Tokens-only mode will show raw quota values regardless of this toggle.", "Too many files. Some were not added.": "Too many files. Some were not added.", + "Too many requests": "Too many requests", "Tool / function declarations the model may call": "Tool / function declarations the model may call", "Tool identifier": "Tool identifier", "Tool price settings": "Tool price settings", @@ -3969,6 +3984,7 @@ "Top model": "Top model", "Top models": "Top models", "Top Models": "Top Models", + "Top models by traffic": "Top models by traffic", "Top up balance and view billing history.": "Top up balance and view billing history.", "Top Users": "Top Users", "Top vendors": "Top vendors", @@ -4023,6 +4039,7 @@ "Trim Suffix": "Trim Suffix", "Truncate embeddings to this many dimensions": "Truncate embeddings to this many dimensions", "Trusted": "Trusted", + "Try adjusting your search": "Try adjusting your search", "Try adjusting your search to locate a missing model.": "Try adjusting your search to locate a missing model.", "TTFT P50": "TTFT P50", "TTFT P95": "TTFT P95", @@ -4323,6 +4340,7 @@ "Website is under maintenance!": "Website is under maintenance!", "WeChat": "WeChat", "WeChat login QR code": "WeChat login QR code", + "WeChat Pay": "WeChat Pay", "WeChat QR code will be displayed here": "WeChat QR code will be displayed here", "WeChat sign in": "WeChat sign in", "Week": "Week", @@ -4398,15 +4416,9 @@ "Your setup guide is collapsed so usage stays in focus.": "Your setup guide is collapsed so usage stays in focus.", "Your system access token for API authentication. Keep it secure and don't share it with others.": "Your system access token for API authentication. Keep it secure and don't share it with others.", "Your Telegram Bot Token": "Your Telegram Bot Token", + "Your transaction history will appear here": "Your transaction history will appear here", "Your Turnstile secret key": "Your Turnstile secret key", "Your Turnstile site key": "Your Turnstile site key", - "Alipay": "Alipay", - "Please wait a moment before trying again.": "Please wait a moment before trying again.", - "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.", - "Too many requests": "Too many requests", - "Try adjusting your search": "Try adjusting your search", - "WeChat Pay": "WeChat Pay", - "Your transaction history will appear here": "Your transaction history will appear here", "Zero retention": "Zero retention", "Zhipu": "Zhipu", "Zhipu V4": "Zhipu V4", diff --git a/web/default/src/i18n/locales/fr.json b/web/default/src/i18n/locales/fr.json index 67ab1178..5944badb 100644 --- a/web/default/src/i18n/locales/fr.json +++ b/web/default/src/i18n/locales/fr.json @@ -100,6 +100,7 @@ "A billing multiplier. Lower ratios mean lower API call costs.": "Un multiplicateur de facturation. Plus le ratio est faible, plus le coût des appels API est bas.", "A focused home for keys, balance, routing, and service health.": "Un accueil dédié aux clés, au solde, au routage et à l'état du service.", "About": "À propos", + "About {{days}} days left": "Environ {{days}} jours restants", "Accept Unpriced Models": "Accepter les modèles non tarifés", "Accepts a JSON array of model identifiers that support the Imagine API.": "Accepte un tableau JSON d'identifiants de modèles qui prennent en charge l'API Imagine.", "Accepts comma-separated status codes and inclusive ranges.": "Accepte les codes de statut séparés par des virgules et les plages inclusives.", @@ -239,6 +240,7 @@ "AILS": "AILS", "AK/SK mode: use AccessKey|SecretAccessKey|Region": "Mode AK/SK : utiliser AccessKey|SecretAccessKey|Region", "Ali": "Ali", + "Alipay": "Alipay", "All": "Tout", "All categories": "Toutes catégories", "All conditions must match before this tier is used.": "Toutes les conditions doivent correspondre pour utiliser ce palier.", @@ -477,6 +479,7 @@ "Baidu V2": "Baidu V2", "Balance": "Solde", "Balance and top-up management": "Gestion du solde et des recharges", + "Balance depleted": "Solde épuisé", "Balance is shown in quota units": "Le solde est affiché en unités de quota", "Balance queried successfully": "Solde interrogé avec succès", "Balance updated successfully": "Solde mis à jour avec succès", @@ -888,6 +891,7 @@ "Console Area": "Zone console", "Console Content": "Contenu de la console", "Consume": "Consommation", + "Consumed in the last 24 hours": "Consommé dans les dernières 24 heures", "Container": "Conteneur", "Container name": "Nom du conteneur", "Containers": "Conteneurs", @@ -1897,6 +1901,7 @@ "Header Value (supports string or JSON mapping)": "Valeur de l'en-tête (chaîne ou mappage JSON)", "header. Anthropic-formatted endpoints accept the": ". Les points de terminaison au format Anthropic acceptent à la place", "Health": "Santé", + "Healthy": "Normal", "Hidden — verify to reveal": "Masqué — vérifiez pour révéler", "Hide": "Masquer", "Hide API key": "Masquer la clé API", @@ -2101,6 +2106,7 @@ "Language preference saved": "Préférence de langue enregistrée", "Language Preferences": "Préférences de langue", "Language preferences sync across your signed-in devices and affect API error messages.": "Les préférences de langue se synchronisent sur vos appareils connectés et affectent les messages d'erreur de l'API.", + "Last 24h usage": "Utilisation 24h", "Last 30 days uptime": "Disponibilité 30 derniers jours", "Last check time": "Dernière vérification", "Last detected addable models": "Derniers modèles ajoutables détectés", @@ -2143,6 +2149,7 @@ "Less": "Moins", "Less than": "Inférieur à", "Less Than": "Inférieur à", + "Less than 1 day left": "Moins d'un jour restant", "Less than or equal": "Inférieur ou égal", "Less Than or Equal": "Inférieur ou égal", "License": "Licence", @@ -2192,6 +2199,7 @@ "Logo": "Logo", "Logo URL": "URL du logo", "Logs": "Journaux", + "Low balance": "Solde faible", "Lowest median first-token latency": "Latence médiane de premier jeton la plus faible", "m": "m", "Maintain a list of common questions for the dashboard help panel": "Maintenir une liste de questions courantes pour le panneau d'aide du tableau de bord", @@ -2371,6 +2379,7 @@ "MokaAI": "MokaAI", "Monitor": "Surveiller", "Monitor balance, usage, and request volume": "Surveillez le solde, l'utilisation et le volume de requêtes", + "Monitored relay requests": "Requêtes relais surveillées", "Monitoring & Alerts": "Surveillance & Alertes", "Month": "Mois", "Month number": "Numéro du mois", @@ -2381,9 +2390,9 @@ "More": "Plus", "more mapping": "plus de mappage", "More templates...": "Autres modèles…", + "More than 999 days left": "Plus de 999 jours restants", "More...": "Plus...", "Most-used models in the selected period and category": "Modèles les plus utilisés dans la période et catégorie choisies", - "Monitored relay requests": "Requêtes relais surveillées", "Move": "Déplacer", "Move a request header": "Déplacer un en-tête de requête", "Move affiliate rewards to your main balance": "Transférer les récompenses d'affiliation vers votre solde principal", @@ -2433,7 +2442,7 @@ "Name the channel, choose the provider, configure API access, and set credentials.": "Nommez le canal, choisissez le fournisseur, configurez l’accès API et définissez les identifiants.", "name@example.com": "name@example.com", "Native format": "Format natif", - "Need a code?": "Besoin d'un code ?", + "Need a redemption code?": "Besoin d'un code d'échange ?", "Needs API key": "Clé API requise", "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.": "JSON imbriqué définissant des règles par groupe pour ajouter (+:), supprimer (-:), ou ajouter des groupes utilisables.", "Nested JSON: source group →": "JSON imbriqué : groupe source →", @@ -2567,6 +2576,7 @@ "No providers available": "Aucun fournisseur disponible", "No Quota": "Aucun quota", "No ratio differences found": "Aucune différence de ratio trouvée", + "No recent usage": "Aucune utilisation récente", "No records found. Try adjusting your filters.": "Aucun enregistrement trouvé. Essayez d'ajuster vos filtres.", "No redemption codes available. Create your first redemption code to get started.": "Aucun code d'échange disponible. Créez votre premier code d'échange pour commencer.", "No Redemption Codes Found": "Aucun code d'échange trouvé", @@ -2851,6 +2861,7 @@ "Percentage:": "Pourcentage :", "Performance": "Performances", "Performance data is not yet available for this model.": "Aucune donnée de performance n'est encore disponible pour ce modèle.", + "Performance health": "Santé des performances", "Performance metrics for the last 24 hours": "Indicateurs de performance des dernières 24 heures", "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Les indicateurs de performance présentés ici sont simulés à des fins de prévisualisation et seront remplacés par des données d'observabilité réelles une fois l'intégration du backend terminée.", "Performance Monitor": "Moniteur de performances", @@ -2923,6 +2934,7 @@ "Please set Ollama API Base URL first": "Veuillez d'abord définir l'URL de base de l'API Ollama", "Please try again later.": "Veuillez réessayer plus tard.", "Please upload key file(s)": "Veuillez télécharger le (s) fichier(s) clé (s)", + "Please wait a moment before trying again.": "Veuillez patienter un instant avant de réessayer.", "Please wait a moment, human check is initializing...": "Veuillez patienter un instant, la vérification humaine s'initialise...", "Policy JSON": "JSON de stratégie", "Polling": "Sondage", @@ -3061,8 +3073,8 @@ "Pull": "Télécharger", "Pull model": "Télécharger le modèle", "Pulling...": "Téléchargement en cours...", - "Purchase a plan to enjoy model benefits": "Souscrivez un plan pour bénéficier des avantages des modèles", - "Purchase here": "Acheter ici", + "Subscribe to a plan for model access": "Souscrivez à un plan pour accéder aux modèles", + "Get one here": "Obtenir ici", "Purchase Limit": "Limite d'achat", "Purchase limit reached": "Limite d'achat atteinte", "Purchase Subscription": "Acheter un abonnement", @@ -3356,6 +3368,7 @@ "Run GC": "Exécuter le GC", "Run tests for the selected models": "Exécuter les tests pour les modèles sélectionnés", "Running": "En cours", + "Runway": "Durée restante", "s": "s", "Safety Settings": "Paramètres de sécurité", "Same as Local": "Identique au local", @@ -3847,6 +3860,7 @@ "This action will permanently remove 2FA protection from your account.": "Cette action supprimera définitivement la protection 2FA de votre compte.", "This channel is not an Ollama channel.": "Ce canal n'est pas un canal Ollama.", "This channel type does not support fetching models": "Ce type de canal ne prend pas en charge la récupération de modèles", + "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "Ce réglage contrôle la limitation des requêtes de modèles. La limitation des routes Web/API se configure via les variables d'environnement et peut encore renvoyer 429.", "This data may be unreliable, use with caution": "Ces données peuvent être peu fiables, utilisez-les avec prudence", "This device does not support Passkey": "Cet appareil ne prend pas en charge Passkey", "This device does not support Passkey verification.": "Cet appareil ne prend pas en charge la vérification par clé d'accès.", @@ -3955,6 +3969,7 @@ "Tokens since launch": "Jetons depuis le lancement", "Tokens-only mode will show raw quota values regardless of this toggle.": "Le mode Tokens uniquement affichera les valeurs de quota brutes indépendamment de ce basculement.", "Too many files. Some were not added.": "Trop de fichiers. Certains n'ont pas été ajoutés.", + "Too many requests": "Trop de requêtes", "Tool / function declarations the model may call": "Déclarations d'outils / fonctions que le modèle peut appeler", "Tool identifier": "Identifiant d’outil", "Tool price settings": "Paramètres de prix des outils", @@ -3969,6 +3984,7 @@ "Top model": "Modèle principal", "Top models": "Top modèles", "Top Models": "Top Modèles", + "Top models by traffic": "Modèles les plus utilisés", "Top up balance and view billing history.": "Recharger le solde et consulter l'historique de facturation.", "Top Users": "Top utilisateurs", "Top vendors": "Top fournisseurs", @@ -4023,6 +4039,7 @@ "Trim Suffix": "Supprimer le suffixe", "Truncate embeddings to this many dimensions": "Tronquer les vecteurs à autant de dimensions", "Trusted": "Fiable", + "Try adjusting your search": "Essayez d'ajuster votre recherche", "Try adjusting your search to locate a missing model.": "Essayez d'ajuster votre recherche pour localiser un modèle manquant.", "TTFT P50": "TTFT P50", "TTFT P95": "TTFT P95", @@ -4323,6 +4340,7 @@ "Website is under maintenance!": "Le site web est en maintenance !", "WeChat": "WeChat", "WeChat login QR code": "Code QR de connexion WeChat", + "WeChat Pay": "WeChat Pay", "WeChat QR code will be displayed here": "Le code QR WeChat sera affiché ici", "WeChat sign in": "Connexion WeChat", "Week": "Semaine", @@ -4398,15 +4416,9 @@ "Your setup guide is collapsed so usage stays in focus.": "Le guide de configuration est réduit afin de garder l'utilisation au premier plan.", "Your system access token for API authentication. Keep it secure and don't share it with others.": "Votre jeton d'accès système pour l'authentification API. Gardez-le en sécurité et ne le partagez pas avec d'autres.", "Your Telegram Bot Token": "Votre Jeton de Bot Telegram", + "Your transaction history will appear here": "Votre historique de transactions apparaîtra ici", "Your Turnstile secret key": "Votre clé secrète Turnstile", "Your Turnstile site key": "Votre clé de site Turnstile", - "Alipay": "Alipay", - "Please wait a moment before trying again.": "Veuillez patienter un instant avant de réessayer.", - "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "Ce réglage contrôle la limitation des requêtes de modèles. La limitation des routes Web/API se configure via les variables d'environnement et peut encore renvoyer 429.", - "Too many requests": "Trop de requêtes", - "Try adjusting your search": "Essayez d'ajuster votre recherche", - "WeChat Pay": "WeChat Pay", - "Your transaction history will appear here": "Votre historique de transactions apparaîtra ici", "Zero retention": "Aucune rétention", "Zhipu": "Zhipu", "Zhipu V4": "Zhipu V4", diff --git a/web/default/src/i18n/locales/ja.json b/web/default/src/i18n/locales/ja.json index 6184b912..9ee353aa 100644 --- a/web/default/src/i18n/locales/ja.json +++ b/web/default/src/i18n/locales/ja.json @@ -100,6 +100,7 @@ "A billing multiplier. Lower ratios mean lower API call costs.": "課金倍率です。倍率が低いほど API 呼び出しコストは低くなります。", "A focused home for keys, balance, routing, and service health.": "キー、残高、ルーティング、サービス状態を集約したホームです。", "About": "このサービスについて", + "About {{days}} days left": "約 {{days}} 日分", "Accept Unpriced Models": "価格設定されていないモデルを許可", "Accepts a JSON array of model identifiers that support the Imagine API.": "Imagine APIをサポートするモデル識別子のJSON配列を受け入れます。", "Accepts comma-separated status codes and inclusive ranges.": "カンマ区切りのステータスコードと包含範囲を受け入れます。", @@ -239,6 +240,7 @@ "AILS": "AILS", "AK/SK mode: use AccessKey|SecretAccessKey|Region": "AK/SKモード: AccessKey | SecretAccessKey | Regionを使用", "Ali": "Ali", + "Alipay": "Alipay", "All": "すべて", "All categories": "すべてのカテゴリ", "All conditions must match before this tier is used.": "この階層を使用するには、すべての条件に一致する必要があります。", @@ -477,6 +479,7 @@ "Baidu V2": "Baidu V 2", "Balance": "残高", "Balance and top-up management": "残高とチャージ管理", + "Balance depleted": "残高なし", "Balance is shown in quota units": "残高はクォータ単位で表示されます", "Balance queried successfully": "残高の取得に成功しました", "Balance updated successfully": "残高が正常に更新されました", @@ -888,6 +891,7 @@ "Console Area": "コンソールエリア", "Console Content": "コンソールコンテンツ", "Consume": "消費", + "Consumed in the last 24 hours": "直近24時間の消費量", "Container": "コンテナ", "Container name": "コンテナ名", "Containers": "コンテナ", @@ -1897,6 +1901,7 @@ "Header Value (supports string or JSON mapping)": "ヘッダー値(文字列またはJSONマッピング対応)", "header. Anthropic-formatted endpoints accept the": " ヘッダーが必要です。Anthropic 形式のエンドポイントでは", "Health": "ヘルスケア", + "Healthy": "正常", "Hidden — verify to reveal": "非表示 — 確認して表示", "Hide": "非表示にする", "Hide API key": "APIキーを非表示", @@ -2101,6 +2106,7 @@ "Language preference saved": "言語設定を保存しました", "Language Preferences": "言語設定", "Language preferences sync across your signed-in devices and affect API error messages.": "言語設定はログイン中のすべてのデバイスで同期され、API のエラーメッセージ言語にも反映されます。", + "Last 24h usage": "直近24時間の使用量", "Last 30 days uptime": "直近 30 日の稼働率", "Last check time": "最終チェック時刻", "Last detected addable models": "最後に検出された追加可能モデル", @@ -2143,6 +2149,7 @@ "Less": "少ない", "Less than": "より小さい", "Less Than": "より小さい", + "Less than 1 day left": "残り1日未満", "Less than or equal": "以下", "Less Than or Equal": "以下", "License": "ライセンス", @@ -2192,6 +2199,7 @@ "Logo": "ロゴ", "Logo URL": "ロゴURL", "Logs": "ログ", + "Low balance": "残高不足", "Lowest median first-token latency": "最初のトークンまでの中央値レイテンシの最小値", "m": "m", "Maintain a list of common questions for the dashboard help panel": "ダッシュボードのヘルプパネル用のよくある質問のリストを維持する", @@ -2371,6 +2379,7 @@ "MokaAI": "MokaAI", "Monitor": "モニタリング", "Monitor balance, usage, and request volume": "残高、使用量、リクエスト数を監視", + "Monitored relay requests": "監視対象のリレーリクエスト", "Monitoring & Alerts": "監視とアラート", "Month": "月", "Month number": "月番号", @@ -2381,9 +2390,9 @@ "More": "もっと見る", "more mapping": "さらにマッピング", "More templates...": "ほかのテンプレート…", + "More than 999 days left": "999日以上", "More...": "その他...", "Most-used models in the selected period and category": "選択した期間とカテゴリで最も使われているモデル", - "Monitored relay requests": "監視対象のリレーリクエスト", "Move": "移動", "Move a request header": "リクエストヘッダーを移動", "Move affiliate rewards to your main balance": "アフィリエイト報酬をメイン残高に移動する", @@ -2433,7 +2442,7 @@ "Name the channel, choose the provider, configure API access, and set credentials.": "チャンネル名を設定し、プロバイダーを選択し、API アクセスと認証情報を設定します。", "name@example.com": "name@example.com", "Native format": "ネイティブ形式", - "Need a code?": "コードが必要ですか?", + "Need a redemption code?": "引き換えコードが必要ですか?", "Needs API key": "API キーが必要", "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.": "追加 (+:)、削除 (-:)、または使用可能なグループの追加を行うグループごとのルールを定義するネストされたJSON。", "Nested JSON: source group →": "ネストされたJSON: ソースグループ →", @@ -2567,6 +2576,7 @@ "No providers available": "利用可能なプロバイダーがありません", "No Quota": "クォータなし", "No ratio differences found": "比率の差異は見つかりませんでした", + "No recent usage": "最近の使用なし", "No records found. Try adjusting your filters.": "記録が見つかりません。フィルターを調整してみてください。", "No redemption codes available. Create your first redemption code to get started.": "利用可能な引き換えコードがありません。最初の引き換えコードを作成して開始してください。", "No Redemption Codes Found": "引き換えコードが見つかりません", @@ -2851,6 +2861,7 @@ "Percentage:": "パーセンテージ:", "Performance": "パフォーマンス", "Performance data is not yet available for this model.": "このモデルのパフォーマンスデータはまだ利用できません。", + "Performance health": "パフォーマンス状態", "Performance metrics for the last 24 hours": "直近24時間のパフォーマンス指標", "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "ここに表示されているパフォーマンス指標はプレビュー用のシミュレーションデータです。バックエンド連携の完了後、実データに置き換えられます。", "Performance Monitor": "パフォーマンス監視", @@ -2923,6 +2934,7 @@ "Please set Ollama API Base URL first": "最初にOllama APIベースURLを設定してください", "Please try again later.": "後でもう一度お試しください。", "Please upload key file(s)": "キーファイルをアップロードしてください", + "Please wait a moment before trying again.": "しばらく待ってからもう一度お試しください。", "Please wait a moment, human check is initializing...": "しばらくお待ちください、人間チェックを初期化中です...", "Policy JSON": "ポリシーJSON", "Polling": "ポーリング", @@ -3061,8 +3073,8 @@ "Pull": "プル", "Pull model": "モデルをプル", "Pulling...": "プル中...", - "Purchase a plan to enjoy model benefits": "プランを購入してモデルの特典を享受", - "Purchase here": "ここで購入", + "Subscribe to a plan for model access": "モデルアクセスのためにプランを登録", + "Get one here": "こちらから取得", "Purchase Limit": "購入上限", "Purchase limit reached": "購入上限に達しました", "Purchase Subscription": "サブスクリプションを購入", @@ -3356,6 +3368,7 @@ "Run GC": "GC 実行", "Run tests for the selected models": "選択したモデルのテストを実行", "Running": "実行中", + "Runway": "残り期間", "s": "s", "Safety Settings": "安全設定", "Same as Local": "ローカルと同じ", @@ -3847,6 +3860,7 @@ "This action will permanently remove 2FA protection from your account.": "この操作により、アカウントから2FA保護が完全に削除されます。", "This channel is not an Ollama channel.": "このチャンネルはOllamaチャンネルではありません。", "This channel type does not support fetching models": "このチャンネルタイプはモデルの取得をサポートしていません", + "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "これはモデルリクエストのレート制限を制御します。Web/API ルートのスロットリングは環境変数で設定され、引き続き 429 を返す場合があります。", "This data may be unreliable, use with caution": "このデータは信頼できない可能性があります。注意して使用してください", "This device does not support Passkey": "このデバイスはPasskeyをサポートしていません", "This device does not support Passkey verification.": "このデバイスはPasskey認証をサポートしていません。", @@ -3955,6 +3969,7 @@ "Tokens since launch": "リリース以降のトークン", "Tokens-only mode will show raw quota values regardless of this toggle.": "トークンのみモードでは、このトグルに関係なく生のクォータ値が表示されます。", "Too many files. Some were not added.": "ファイルが多すぎます。一部は追加されませんでした。", + "Too many requests": "リクエストが多すぎます", "Tool / function declarations the model may call": "モデルが呼び出せるツール / 関数の宣言", "Tool identifier": "ツールID", "Tool price settings": "ツール価格設定", @@ -3969,6 +3984,7 @@ "Top model": "トップモデル", "Top models": "人気モデル", "Top Models": "トップモデル", + "Top models by traffic": "トラフィック上位モデル", "Top up balance and view billing history.": "残高をチャージし、請求履歴を確認。", "Top Users": "上位ユーザー", "Top vendors": "人気ベンダー", @@ -4023,6 +4039,7 @@ "Trim Suffix": "サフィックス削除", "Truncate embeddings to this many dimensions": "指定した次元数にベクトルを切り詰めます", "Trusted": "信頼済み", + "Try adjusting your search": "検索条件を調整してみてください", "Try adjusting your search to locate a missing model.": "見つからないモデルを見つけるには、検索を調整してみてください。", "TTFT P50": "TTFT P50", "TTFT P95": "TTFT P95", @@ -4323,6 +4340,7 @@ "Website is under maintenance!": "ウェブサイトはメンテナンス中です!", "WeChat": "WeChat Pay", "WeChat login QR code": "WeChatログインQRコード", + "WeChat Pay": "WeChat Pay", "WeChat QR code will be displayed here": "WeChat QRコードがここに表示されます", "WeChat sign in": "WeChatでサインイン", "Week": "週", @@ -4398,15 +4416,9 @@ "Your setup guide is collapsed so usage stays in focus.": "利用状況に集中できるよう、セットアップガイドを折りたたみました。", "Your system access token for API authentication. Keep it secure and don't share it with others.": "API認証用のシステムアクセストークンです。安全に保管し、他者と共有しないでください。", "Your Telegram Bot Token": "あなたのTelegramボットトークン", + "Your transaction history will appear here": "取引履歴はここに表示されます", "Your Turnstile secret key": "あなたのTurnstileシークレットキー", "Your Turnstile site key": "あなたのTurnstileサイトキー", - "Alipay": "Alipay", - "Please wait a moment before trying again.": "しばらく待ってからもう一度お試しください。", - "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "これはモデルリクエストのレート制限を制御します。Web/API ルートのスロットリングは環境変数で設定され、引き続き 429 を返す場合があります。", - "Too many requests": "リクエストが多すぎます", - "Try adjusting your search": "検索条件を調整してみてください", - "WeChat Pay": "WeChat Pay", - "Your transaction history will appear here": "取引履歴はここに表示されます", "Zero retention": "データ保持なし", "Zhipu": "Zhipu", "Zhipu V4": "Zhipu V 4", diff --git a/web/default/src/i18n/locales/ru.json b/web/default/src/i18n/locales/ru.json index 5cf0e0aa..f6b24615 100644 --- a/web/default/src/i18n/locales/ru.json +++ b/web/default/src/i18n/locales/ru.json @@ -100,6 +100,7 @@ "A billing multiplier. Lower ratios mean lower API call costs.": "Множитель тарификации. Чем ниже коэффициент, тем ниже стоимость вызовов API.", "A focused home for keys, balance, routing, and service health.": "Единый экран для ключей, баланса, маршрутов и состояния сервиса.", "About": "О проекте", + "About {{days}} days left": "Примерно {{days}} дней", "Accept Unpriced Models": "Принимать модели без цены", "Accepts a JSON array of model identifiers that support the Imagine API.": "Принимает JSON-массив идентификаторов моделей, поддерживающих Imagine API.", "Accepts comma-separated status codes and inclusive ranges.": "Принимает коды статуса, разделенные запятыми, и включающие диапазоны.", @@ -239,6 +240,7 @@ "AILS": "AILS", "AK/SK mode: use AccessKey|SecretAccessKey|Region": "Режим AK/SK: используйте AccessKey|SecretAccessKey|Region", "Ali": "Ali", + "Alipay": "Alipay", "All": "Все", "All categories": "Все категории", "All conditions must match before this tier is used.": "All conditions must match before this tier is used.", @@ -477,6 +479,7 @@ "Baidu V2": "Baidu V2", "Balance": "Баланс", "Balance and top-up management": "Управление балансом и пополнением", + "Balance depleted": "Баланс исчерпан", "Balance is shown in quota units": "Баланс показан в единицах квоты", "Balance queried successfully": "Баланс успешно запрошен", "Balance updated successfully": "Баланс успешно обновлён", @@ -888,6 +891,7 @@ "Console Area": "Область консоли", "Console Content": "Содержимое консоли", "Consume": "Расход", + "Consumed in the last 24 hours": "Потреблено за последние 24 часа", "Container": "Контейнер", "Container name": "Имя контейнера", "Containers": "Контейнеры", @@ -1897,6 +1901,7 @@ "Header Value (supports string or JSON mapping)": "Значение заголовка (строка или JSON-маппинг)", "header. Anthropic-formatted endpoints accept the": ". Эндпоинты формата Anthropic вместо этого принимают", "Health": "Здоровье", + "Healthy": "В норме", "Hidden — verify to reveal": "Скрыто — подтвердите, чтобы показать", "Hide": "Скрыть", "Hide API key": "Скрыть API ключ", @@ -2101,6 +2106,7 @@ "Language preference saved": "Языковая настройка сохранена", "Language Preferences": "Языковые настройки", "Language preferences sync across your signed-in devices and affect API error messages.": "Языковые настройки синхронизируются на всех ваших устройствах после входа и влияют на язык сообщений об ошибках API.", + "Last 24h usage": "Расход за 24ч", "Last 30 days uptime": "Доступность за 30 дней", "Last check time": "Время последней проверки", "Last detected addable models": "Последние обнаруженные модели для добавления", @@ -2143,6 +2149,7 @@ "Less": "Меньше", "Less than": "Меньше", "Less Than": "Меньше", + "Less than 1 day left": "Менее 1 дня", "Less than or equal": "Меньше или равно", "Less Than or Equal": "Меньше или равно", "License": "Лицензия", @@ -2192,6 +2199,7 @@ "Logo": "Логотип", "Logo URL": "URL логотипа", "Logs": "Журналы", + "Low balance": "Низкий баланс", "Lowest median first-token latency": "Минимальная медианная задержка первого токена", "m": "m", "Maintain a list of common questions for the dashboard help panel": "Вести список часто задаваемых вопросов для панели помощи дашборда", @@ -2371,6 +2379,7 @@ "MokaAI": "MokaAI", "Monitor": "Мониторинг", "Monitor balance, usage, and request volume": "Отслеживайте баланс, расход и объем запросов", + "Monitored relay requests": "Отслеживаемые ретрансляционные запросы", "Monitoring & Alerts": "Мониторинг и оповещения", "Month": "Месяц", "Month number": "Номер месяца", @@ -2381,9 +2390,9 @@ "More": "Ещё", "more mapping": "больше сопоставлений", "More templates...": "Другие шаблоны…", + "More than 999 days left": "Более 999 дней", "More...": "Подробнее...", "Most-used models in the selected period and category": "Самые используемые модели в выбранном периоде и категории", - "Monitored relay requests": "Отслеживаемые ретрансляционные запросы", "Move": "Переместить", "Move a request header": "Переместить заголовок запроса", "Move affiliate rewards to your main balance": "Перевести партнерские вознаграждения на основной баланс", @@ -2433,7 +2442,7 @@ "Name the channel, choose the provider, configure API access, and set credentials.": "Задайте имя канала, выберите провайдера, настройте доступ к API и учетные данные.", "name@example.com": "name@example.com", "Native format": "Собственный формат", - "Need a code?": "Нужен код?", + "Need a redemption code?": "Нужен код активации?", "Needs API key": "Нужен API-ключ", "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.": "Вложенный JSON, определяющий правила для каждой группы для добавления (+:), удаления (-:) или добавления используемых групп.", "Nested JSON: source group →": "Вложенный JSON: исходная группа →", @@ -2567,6 +2576,7 @@ "No providers available": "Нет доступных провайдеров", "No Quota": "Нет квоты", "No ratio differences found": "Различия в коэффициентах не найдены", + "No recent usage": "Нет недавнего использования", "No records found. Try adjusting your filters.": "Записи не найдены. Попробуйте изменить фильтры.", "No redemption codes available. Create your first redemption code to get started.": "Нет доступных кодов активации. Создайте свой первый код активации, чтобы начать.", "No Redemption Codes Found": "Коды активации не найдены", @@ -2851,6 +2861,7 @@ "Percentage:": "Процент:", "Performance": "Производительность", "Performance data is not yet available for this model.": "Данные о производительности этой модели пока недоступны.", + "Performance health": "Состояние производительности", "Performance metrics for the last 24 hours": "Метрики производительности за последние 24 часа", "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Показанные метрики производительности сгенерированы для предпросмотра и будут заменены реальными данными наблюдаемости после интеграции бэкенда.", "Performance Monitor": "Монитор производительности", @@ -2923,6 +2934,7 @@ "Please set Ollama API Base URL first": "Сначала установите базовый URL-адрес API Ollama", "Please try again later.": "Пожалуйста, попробуйте еще раз позже.", "Please upload key file(s)": "Загрузите ключевой файл(ы)", + "Please wait a moment before trying again.": "Пожалуйста, подождите немного и попробуйте снова.", "Please wait a moment, human check is initializing...": "Пожалуйста, подождите немного, инициализация проверки человеком...", "Policy JSON": "JSON политики", "Polling": "Опрос", @@ -3061,8 +3073,8 @@ "Pull": "Загрузить", "Pull model": "Загрузить модель", "Pulling...": "Загрузка...", - "Purchase a plan to enjoy model benefits": "Приобретите план, чтобы воспользоваться преимуществами моделей", - "Purchase here": "Купить здесь", + "Subscribe to a plan for model access": "Подпишитесь на план для доступа к моделям", + "Get one here": "Получить здесь", "Purchase Limit": "Лимит покупок", "Purchase limit reached": "Достигнут лимит покупок", "Purchase Subscription": "Приобрести подписку", @@ -3356,6 +3368,7 @@ "Run GC": "Запустить GC", "Run tests for the selected models": "Запустить тесты для выбранных моделей", "Running": "Выполняется", + "Runway": "Запас", "s": "s", "Safety Settings": "Настройки безопасности", "Same as Local": "То же, что и локальный", @@ -3847,6 +3860,7 @@ "This action will permanently remove 2FA protection from your account.": "Это действие безвозвратно удалит защиту 2FA из вашей учетной записи.", "This channel is not an Ollama channel.": "Этот канал не является каналом Ollama.", "This channel type does not support fetching models": "Этот тип канала не поддерживает получение моделей", + "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "Этот параметр управляет ограничением частоты запросов к моделям. Ограничение маршрутов Web/API настраивается переменными окружения и всё ещё может возвращать 429.", "This data may be unreliable, use with caution": "Эти данные могут быть ненадежными, используйте с осторожностью", "This device does not support Passkey": "Это устройство не поддерживает Passkey", "This device does not support Passkey verification.": "Это устройство не поддерживает проверку с помощью Passkey.", @@ -3955,6 +3969,7 @@ "Tokens since launch": "Токенов с запуска", "Tokens-only mode will show raw quota values regardless of this toggle.": "Режим «только токены» будет показывать необработанные значения квот независимо от этого переключателя.", "Too many files. Some were not added.": "Слишком много файлов. Некоторые не были добавлены.", + "Too many requests": "Слишком много запросов", "Tool / function declarations the model may call": "Объявления инструментов и функций, которые модель может вызывать", "Tool identifier": "Идентификатор инструмента", "Tool price settings": "Настройки цен на инструменты", @@ -3969,6 +3984,7 @@ "Top model": "Лидирующая модель", "Top models": "Топ моделей", "Top Models": "Лучшие модели", + "Top models by traffic": "Популярные модели по трафику", "Top up balance and view billing history.": "Пополнить баланс и просмотреть историю платежей.", "Top Users": "Лучшие пользователи", "Top vendors": "Топ поставщиков", @@ -4023,6 +4039,7 @@ "Trim Suffix": "Обрезать суффикс", "Truncate embeddings to this many dimensions": "Усечь эмбеддинги до указанного числа измерений", "Trusted": "Доверенный", + "Try adjusting your search": "Попробуйте изменить условия поиска", "Try adjusting your search to locate a missing model.": "Попробуйте изменить параметры поиска, чтобы найти отсутствующую модель.", "TTFT P50": "TTFT P50", "TTFT P95": "TTFT P95", @@ -4323,6 +4340,7 @@ "Website is under maintenance!": "Сайт находится на техническом обслуживании!", "WeChat": "WeChat", "WeChat login QR code": "QR-код для входа в WeChat", + "WeChat Pay": "WeChat Pay", "WeChat QR code will be displayed here": "QR-код WeChat будет отображен здесь", "WeChat sign in": "Вход через WeChat", "Week": "Неделя", @@ -4398,15 +4416,9 @@ "Your setup guide is collapsed so usage stays in focus.": "Руководство свернуто, чтобы основные показатели оставались в фокусе.", "Your system access token for API authentication. Keep it secure and don't share it with others.": "Ваш системный токен доступа для аутентификации API. Храните его в безопасности и не делитесь им с другими.", "Your Telegram Bot Token": "Ваш токен Telegram-бота", + "Your transaction history will appear here": "Ваша история транзакций появится здесь", "Your Turnstile secret key": "Секретный ключ Turnstile", "Your Turnstile site key": "Ключ сайта Turnstile", - "Alipay": "Alipay", - "Please wait a moment before trying again.": "Пожалуйста, подождите немного и попробуйте снова.", - "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "Этот параметр управляет ограничением частоты запросов к моделям. Ограничение маршрутов Web/API настраивается переменными окружения и всё ещё может возвращать 429.", - "Too many requests": "Слишком много запросов", - "Try adjusting your search": "Попробуйте изменить условия поиска", - "WeChat Pay": "WeChat Pay", - "Your transaction history will appear here": "Ваша история транзакций появится здесь", "Zero retention": "Без хранения данных", "Zhipu": "Zhipu", "Zhipu V4": "Zhipu V4", diff --git a/web/default/src/i18n/locales/vi.json b/web/default/src/i18n/locales/vi.json index 4047a683..aafdc61c 100644 --- a/web/default/src/i18n/locales/vi.json +++ b/web/default/src/i18n/locales/vi.json @@ -100,6 +100,7 @@ "A billing multiplier. Lower ratios mean lower API call costs.": "Hệ số tính phí. Tỷ lệ càng thấp thì chi phí gọi API càng thấp.", "A focused home for keys, balance, routing, and service health.": "Trang tổng quan tập trung cho khóa, số dư, định tuyến và trạng thái dịch vụ.", "About": "Giới thiệu", + "About {{days}} days left": "Còn khoảng {{days}} ngày", "Accept Unpriced Models": "Chấp nhận các Mô hình chưa định giá", "Accepts a JSON array of model identifiers that support the Imagine API.": "Chấp nhận một mảng JSON gồm các mã định danh mô hình hỗ trợ API Imagine.", "Accepts comma-separated status codes and inclusive ranges.": "Chấp nhận mã trạng thái phân cách bằng dấu phẩy và phạm vi bao gồm.", @@ -239,6 +240,7 @@ "AILS": "AILS", "AK/SK mode: use AccessKey|SecretAccessKey|Region": "Chế độ AK/SK: sử dụng AccessKey|SecretAccessKey|Region", "Ali": "Ali", + "Alipay": "Alipay", "All": "All", "All categories": "Tất cả danh mục", "All conditions must match before this tier is used.": "All conditions must match before this tier is used.", @@ -477,6 +479,7 @@ "Baidu V2": "Baidu V2", "Balance": "Cân bằng", "Balance and top-up management": "Quản lý số dư và nạp tiền", + "Balance depleted": "Đã hết số dư", "Balance is shown in quota units": "Số dư được hiển thị theo đơn vị hạn mức", "Balance queried successfully": "Truy vấn số dư thành công", "Balance updated successfully": "Đã cập nhật số dư thành công", @@ -888,6 +891,7 @@ "Console Area": "Khu vực bảng điều khiển", "Console Content": "Nội dung bảng điều khiển", "Consume": "Tiêu thụ", + "Consumed in the last 24 hours": "Đã tiêu thụ trong 24 giờ qua", "Container": "Thùng chứa", "Container name": "Tên container", "Containers": "Các thùng chứa", @@ -1897,6 +1901,7 @@ "Header Value (supports string or JSON mapping)": "Giá trị header (hỗ trợ chuỗi hoặc ánh xạ JSON)", "header. Anthropic-formatted endpoints accept the": ". Các endpoint định dạng Anthropic chấp nhận header", "Health": "Sức khỏe", + "Healthy": "Bình thường", "Hidden — verify to reveal": "Ẩn — xác minh để hiển thị", "Hide": "Ẩn", "Hide API key": "Ẩn khóa API", @@ -2101,6 +2106,7 @@ "Language preference saved": "Đã lưu tùy chọn ngôn ngữ", "Language Preferences": "Tùy chọn ngôn ngữ", "Language preferences sync across your signed-in devices and affect API error messages.": "Tùy chọn ngôn ngữ sẽ đồng bộ trên các thiết bị đã đăng nhập và ảnh hưởng đến ngôn ngữ thông báo lỗi API.", + "Last 24h usage": "Sử dụng 24h qua", "Last 30 days uptime": "Uptime 30 ngày qua", "Last check time": "Thời gian kiểm tra gần nhất", "Last detected addable models": "Mô hình có thể thêm được phát hiện gần nhất", @@ -2143,6 +2149,7 @@ "Less": "Ít hơn", "Less than": "Nhỏ hơn", "Less Than": "Nhỏ hơn", + "Less than 1 day left": "Còn dưới 1 ngày", "Less than or equal": "Nhỏ hơn hoặc bằng", "Less Than or Equal": "Nhỏ hơn hoặc bằng", "License": "Giấy phép", @@ -2192,6 +2199,7 @@ "Logo": "Logo", "Logo URL": "URL Logo", "Logs": "Nhật ký", + "Low balance": "Số dư thấp", "Lowest median first-token latency": "Độ trễ trung vị token đầu tiên thấp nhất", "m": "m", "Maintain a list of common questions for the dashboard help panel": "Duy trì danh sách các câu hỏi thường gặp cho bảng trợ giúp của bảng điều khiển", @@ -2371,6 +2379,7 @@ "MokaAI": "MokaAI", "Monitor": "Giám sát", "Monitor balance, usage, and request volume": "Theo dõi số dư, mức dùng và số lượng yêu cầu", + "Monitored relay requests": "Yêu cầu relay được giám sát", "Monitoring & Alerts": "Giám sát & Cảnh báo", "Month": "Tháng", "Month number": "Số tháng", @@ -2381,9 +2390,9 @@ "More": "Thêm", "more mapping": "thêm lập bản đồ", "More templates...": "Thêm mẫu...", + "More than 999 days left": "Hơn 999 ngày", "More...": "Thêm...", "Most-used models in the selected period and category": "Mô hình được dùng nhiều nhất trong khoảng thời gian và danh mục đã chọn", - "Monitored relay requests": "Yêu cầu relay được giám sát", "Move": "Di chuyển", "Move a request header": "Di chuyển header yêu cầu", "Move affiliate rewards to your main balance": "Chuyển phần thưởng liên kết vào số dư chính của bạn", @@ -2433,7 +2442,7 @@ "Name the channel, choose the provider, configure API access, and set credentials.": "Đặt tên kênh, chọn nhà cung cấp, cấu hình truy cập API và thiết lập thông tin xác thực.", "name@example.com": "name@example.com", "Native format": "Định dạng gốc", - "Need a code?": "Cần mã không?", + "Need a redemption code?": "Cần mã đổi thưởng?", "Needs API key": "Cần khóa API", "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.": "JSON lồng nhau xác định quy tắc theo nhóm để thêm (+:), xóa (-:), hoặc nối các nhóm có thể sử dụng.", "Nested JSON: source group →": "JSON lồng nhau: nhóm nguồn →", @@ -2567,6 +2576,7 @@ "No providers available": "Không có nhà cung cấp khả dụng", "No Quota": "Không hạn ngạch", "No ratio differences found": "Không tìm thấy sự khác biệt tỷ lệ", + "No recent usage": "Chưa có sử dụng gần đây", "No records found. Try adjusting your filters.": "Không tìm thấy bản ghi nào. Hãy thử điều chỉnh bộ lọc của bạn.", "No redemption codes available. Create your first redemption code to get started.": "Hiện không có mã đổi thưởng nào. Hãy tạo mã đổi thưởng đầu tiên của bạn để bắt đầu.", "No Redemption Codes Found": "Không tìm thấy mã đổi thưởng", @@ -2851,6 +2861,7 @@ "Percentage:": "Phần trăm:", "Performance": "Hiệu suất", "Performance data is not yet available for this model.": "Chưa có dữ liệu hiệu năng cho mô hình này.", + "Performance health": "Tình trạng hiệu suất", "Performance metrics for the last 24 hours": "Chỉ số hiệu năng trong 24 giờ qua", "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "Các chỉ số hiệu năng hiển thị tại đây là dữ liệu mô phỏng để xem trước và sẽ được thay thế bằng dữ liệu thực sau khi tích hợp backend.", "Performance Monitor": "Giám sát hiệu suất", @@ -2923,6 +2934,7 @@ "Please set Ollama API Base URL first": "Vui lòng đặt URL cơ sở API Ollama trước", "Please try again later.": "Vui lòng thử lại sau.", "Please upload key file(s)": "Vui lòng tải lên (các) tệp khóa", + "Please wait a moment before trying again.": "Vui lòng chờ một lát rồi thử lại.", "Please wait a moment, human check is initializing...": "Vui lòng đợi một chút, kiểm tra con người đang khởi tạo...", "Policy JSON": "JSON chính sách", "Polling": "Thăm dò", @@ -3061,8 +3073,8 @@ "Pull": "Tải", "Pull model": "Tải mô hình", "Pulling...": "Đang tải...", - "Purchase a plan to enjoy model benefits": "Mua gói để tận hưởng quyền lợi mô hình", - "Purchase here": "Mua tại đây", + "Subscribe to a plan for model access": "Đăng ký gói để truy cập mô hình", + "Get one here": "Nhận tại đây", "Purchase Limit": "Giới hạn mua", "Purchase limit reached": "Đã đạt giới hạn mua", "Purchase Subscription": "Mua gói đăng ký", @@ -3356,6 +3368,7 @@ "Run GC": "Chạy GC", "Run tests for the selected models": "Chạy kiểm thử cho các mô hình đã chọn", "Running": "Đang chạy", + "Runway": "Thời gian còn lại", "s": "s", "Safety Settings": "Cài đặt an toàn", "Same as Local": "Giống như địa phương", @@ -3847,6 +3860,7 @@ "This action will permanently remove 2FA protection from your account.": "Hành động này sẽ vĩnh viễn gỡ bỏ tính năng bảo vệ", "This channel is not an Ollama channel.": "Kênh này không phải là kênh Ollama.", "This channel type does not support fetching models": "Loại kênh này không hỗ trợ lấy mô hình", + "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "Thiết lập này kiểm soát giới hạn tốc độ yêu cầu mô hình. Giới hạn tuyến Web/API được cấu hình bằng biến môi trường và vẫn có thể trả về 429.", "This data may be unreliable, use with caution": "Dữ liệu này có thể không đáng tin cậy, sử dụng thận trọng", "This device does not support Passkey": "Thiết bị này không hỗ trợ Passkey", "This device does not support Passkey verification.": "Thiết bị này không hỗ trợ xác minh Passkey.", @@ -3955,6 +3969,7 @@ "Tokens since launch": "Token kể từ khi ra mắt", "Tokens-only mode will show raw quota values regardless of this toggle.": "Chế độ Tokens-only sẽ hiển thị giá trị quota thô bất kể tùy chọn này.", "Too many files. Some were not added.": "Quá nhiều tệp. Một số không được thêm.", + "Too many requests": "Quá nhiều yêu cầu", "Tool / function declarations the model may call": "Khai báo công cụ / hàm mà model có thể gọi", "Tool identifier": "Định danh công cụ", "Tool price settings": "Cài đặt giá công cụ", @@ -3969,6 +3984,7 @@ "Top model": "Mô hình dẫn đầu", "Top models": "Mô hình hàng đầu", "Top Models": "Người mẫu hàng đầu", + "Top models by traffic": "Mô hình có lượng truy cập cao nhất", "Top up balance and view billing history.": "Nạp tiền vào tài khoản và xem lịch sử thanh toán.", "Top Users": "Người dùng hàng đầu", "Top vendors": "Nhà cung cấp hàng đầu", @@ -4023,6 +4039,7 @@ "Trim Suffix": "Cắt hậu tố", "Truncate embeddings to this many dimensions": "Cắt embedding xuống số chiều này", "Trusted": "Đáng tin cậy", + "Try adjusting your search": "Hãy thử điều chỉnh tìm kiếm", "Try adjusting your search to locate a missing model.": "Hãy thử điều chỉnh tìm kiếm của bạn để định vị một mô hình bị thiếu.", "TTFT P50": "TTFT P50", "TTFT P95": "TTFT P95", @@ -4323,6 +4340,7 @@ "Website is under maintenance!": "Website đang bảo trì!", "WeChat": "WeChat", "WeChat login QR code": "Mã QR đăng nhập WeChat", + "WeChat Pay": "WeChat Pay", "WeChat QR code will be displayed here": "Mã QR WeChat sẽ được hiển thị tại đây", "WeChat sign in": "Đăng nhập WeChat", "Week": "Tuần", @@ -4398,15 +4416,9 @@ "Your setup guide is collapsed so usage stays in focus.": "Hướng dẫn thiết lập đã thu gọn để giữ phần sử dụng ở vị trí nổi bật.", "Your system access token for API authentication. Keep it secure and don't share it with others.": "Mã truy cập hệ thống của bạn để xác thực API. Hãy giữ nó an toàn và đừng chia sẻ nó với người khác.", "Your Telegram Bot Token": "Mã thông báo bot Telegram của bạn", + "Your transaction history will appear here": "Lịch sử giao dịch của bạn sẽ xuất hiện ở đây", "Your Turnstile secret key": "Khóa bí mật Turnstile của bạn", "Your Turnstile site key": "Khóa site Turnstile của bạn", - "Alipay": "Alipay", - "Please wait a moment before trying again.": "Vui lòng chờ một lát rồi thử lại.", - "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "Thiết lập này kiểm soát giới hạn tốc độ yêu cầu mô hình. Giới hạn tuyến Web/API được cấu hình bằng biến môi trường và vẫn có thể trả về 429.", - "Too many requests": "Quá nhiều yêu cầu", - "Try adjusting your search": "Hãy thử điều chỉnh tìm kiếm", - "WeChat Pay": "WeChat Pay", - "Your transaction history will appear here": "Lịch sử giao dịch của bạn sẽ xuất hiện ở đây", "Zero retention": "Không lưu dữ liệu", "Zhipu": "Zhipu", "Zhipu V4": "Zhipu V4", diff --git a/web/default/src/i18n/locales/zh.json b/web/default/src/i18n/locales/zh.json index 949944d9..4d6bab3d 100644 --- a/web/default/src/i18n/locales/zh.json +++ b/web/default/src/i18n/locales/zh.json @@ -100,6 +100,7 @@ "A billing multiplier. Lower ratios mean lower API call costs.": "计费乘数,倍率越低,API 调用费用越低。", "A focused home for keys, balance, routing, and service health.": "集中展示密钥、余额、路由和服务健康状态。", "About": "关于", + "About {{days}} days left": "约剩 {{days}} 天", "Accept Unpriced Models": "接受未定价模型", "Accepts a JSON array of model identifiers that support the Imagine API.": "接受支持 Imagine API 的模型标识符的 JSON 数组。", "Accepts comma-separated status codes and inclusive ranges.": "接受逗号分隔的状态码和包含性范围。", @@ -239,6 +240,7 @@ "AILS": "AILS", "AK/SK mode: use AccessKey|SecretAccessKey|Region": "AK/SK 模式:使用 AccessKey|SecretAccessKey|Region", "Ali": "阿里", + "Alipay": "支付宝", "All": "全部", "All categories": "全部分类", "All conditions must match before this tier is used.": "所有条件都满足后才会使用该档位。", @@ -477,6 +479,7 @@ "Baidu V2": "百度 V2", "Balance": "余额", "Balance and top-up management": "余额充值管理", + "Balance depleted": "余额已耗尽", "Balance is shown in quota units": "余额以额度单位显示", "Balance queried successfully": "余额查询成功", "Balance updated successfully": "余额更新成功", @@ -888,6 +891,7 @@ "Console Area": "控制台区域", "Console Content": "控制台内容", "Consume": "消耗", + "Consumed in the last 24 hours": "近 24 小时消耗量", "Container": "容器", "Container name": "容器名称", "Containers": "容器", @@ -1897,6 +1901,7 @@ "Header Value (supports string or JSON mapping)": "请求头值(支持字符串或 JSON 映射)", "header. Anthropic-formatted endpoints accept the": " 请求头。Anthropic 格式的端点也接受", "Health": "健康", + "Healthy": "正常", "Hidden — verify to reveal": "隐藏 — 验证以显示", "Hide": "隐藏", "Hide API key": "隐藏 API 密钥", @@ -2101,6 +2106,7 @@ "Language preference saved": "语言偏好已保存", "Language Preferences": "语言偏好", "Language preferences sync across your signed-in devices and affect API error messages.": "语言偏好会同步到您登录的所有设备,并影响 API 错误消息语言。", + "Last 24h usage": "近 24 小时消耗", "Last 30 days uptime": "近 30 天可用率", "Last check time": "上次检测时间", "Last detected addable models": "上次检测到可加入模型", @@ -2143,6 +2149,7 @@ "Less": "更少", "Less than": "小于", "Less Than": "小于", + "Less than 1 day left": "剩余不足 1 天", "Less than or equal": "小于等于", "Less Than or Equal": "小于等于", "License": "许可证", @@ -2192,6 +2199,7 @@ "Logo": "徽标", "Logo URL": "徽标 URL", "Logs": "日志", + "Low balance": "余额偏低", "Lowest median first-token latency": "最低首 token 延迟中位数", "m": "分钟", "Maintain a list of common questions for the dashboard help panel": "维护仪表板帮助面板的常见问题列表", @@ -2371,6 +2379,7 @@ "MokaAI": "MokaAI", "Monitor": "监控", "Monitor balance, usage, and request volume": "监控余额、用量和请求量", + "Monitored relay requests": "已监控的中继请求", "Monitoring & Alerts": "监控与警报", "Month": "本月", "Month number": "月份", @@ -2381,9 +2390,9 @@ "More": "更多", "more mapping": "更多映射", "More templates...": "更多模板...", + "More than 999 days left": "剩余超过 999 天", "More...": "更多...", "Most-used models in the selected period and category": "所选时间范围与分类下使用率最高的模型", - "Monitored relay requests": "已监控的中继请求", "Move": "移动", "Move a request header": "移动请求头", "Move affiliate rewards to your main balance": "将推广奖励转移到您的主余额", @@ -2433,7 +2442,7 @@ "Name the channel, choose the provider, configure API access, and set credentials.": "命名渠道、选择供应商、配置 API 访问并设置凭据。", "name@example.com": "name@example.com", "Native format": "原生格式", - "Need a code?": "需要一个代码吗?", + "Need a redemption code?": "需要兑换码?", "Needs API key": "需要 API 密钥", "Nested JSON defining per-group rules for adding (+:), removing (-:), or appending usable groups.": "嵌套 JSON,定义按分组添加(+:)、移除(-:)或追加可用分组的规则。", "Nested JSON: source group →": "嵌套 JSON:源分组 →", @@ -2567,6 +2576,7 @@ "No providers available": "暂无可用提供商", "No Quota": "无余额", "No ratio differences found": "未发现比率差异", + "No recent usage": "暂无使用记录", "No records found. Try adjusting your filters.": "未找到记录。尝试调整您的筛选条件。", "No redemption codes available. Create your first redemption code to get started.": "没有可用的兑换码。创建您的第一个兑换码即可开始使用。", "No Redemption Codes Found": "未找到兑换码", @@ -2851,6 +2861,7 @@ "Percentage:": "百分比:", "Performance": "性能", "Performance data is not yet available for this model.": "该模型暂无性能数据。", + "Performance health": "性能健康", "Performance metrics for the last 24 hours": "最近 24 小时的性能指标", "Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.": "此处展示的性能指标为预览模拟数据,待后端对接完成后将替换为真实可观测数据。", "Performance Monitor": "性能监控", @@ -2923,6 +2934,7 @@ "Please set Ollama API Base URL first": "请先设置 Ollama API Base URL", "Please try again later.": "请稍后再试。", "Please upload key file(s)": "请上传密钥文件", + "Please wait a moment before trying again.": "请稍候再试。", "Please wait a moment, human check is initializing...": "请稍等,人机验证正在初始化...", "Policy JSON": "策略 JSON", "Polling": "轮询", @@ -3061,8 +3073,8 @@ "Pull": "拉取", "Pull model": "拉取模型", "Pulling...": "拉取中...", - "Purchase a plan to enjoy model benefits": "购买套餐后即可享受模型权益", - "Purchase here": "在此购买", + "Subscribe to a plan for model access": "订阅套餐以获取模型访问权限", + "Get one here": "点此获取", "Purchase Limit": "限购", "Purchase limit reached": "已达到购买上限", "Purchase Subscription": "购买订阅套餐", @@ -3356,6 +3368,7 @@ "Run GC": "执行 GC", "Run tests for the selected models": "运行所选模型的测试", "Running": "运行中", + "Runway": "可用时长", "s": "秒", "Safety Settings": "安全设置", "Same as Local": "与本地相同", @@ -3847,6 +3860,7 @@ "This action will permanently remove 2FA protection from your account.": "此操作将永久移除您账户的 2FA 保护。", "This channel is not an Ollama channel.": "该渠道不是 Ollama 渠道。", "This channel type does not support fetching models": "此通道类型不支持获取模型", + "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "此处仅控制模型请求速率限制。Web/API 路由限流由环境变量配置,仍可能返回 429。", "This data may be unreliable, use with caution": "此数据可能不可靠,请谨慎使用", "This device does not support Passkey": "此设备不支持 Passkey", "This device does not support Passkey verification.": "此设备不支持 Passkey 验证。", @@ -3955,6 +3969,7 @@ "Tokens since launch": "发布以来累计 Token", "Tokens-only mode will show raw quota values regardless of this toggle.": "Tokens-only 模式将无视此开关显示原始配额值。", "Too many files. Some were not added.": "文件过多。部分未添加。", + "Too many requests": "请求过于频繁", "Tool / function declarations the model may call": "模型可调用的工具 / 函数声明", "Tool identifier": "工具标识", "Tool price settings": "工具价格设置", @@ -3969,6 +3984,7 @@ "Top model": "领头模型", "Top models": "热门模型", "Top Models": "热门模型", + "Top models by traffic": "流量最高的模型", "Top up balance and view billing history.": "充值余额并查看账单历史。", "Top Users": "热门用户", "Top vendors": "热门厂商", @@ -4023,6 +4039,7 @@ "Trim Suffix": "裁剪后缀", "Truncate embeddings to this many dimensions": "将向量截断到指定维度", "Trusted": "受信任", + "Try adjusting your search": "请尝试调整搜索条件", "Try adjusting your search to locate a missing model.": "尝试调整您的搜索以找到缺失的模型。", "TTFT P50": "TTFT P50", "TTFT P95": "TTFT P95", @@ -4323,6 +4340,7 @@ "Website is under maintenance!": "网站正在维护中!", "WeChat": "微信", "WeChat login QR code": "微信登录二维码", + "WeChat Pay": "微信支付", "WeChat QR code will be displayed here": "微信二维码将显示在此处", "WeChat sign in": "微信登录", "Week": "本周", @@ -4398,15 +4416,9 @@ "Your setup guide is collapsed so usage stays in focus.": "设置引导已收起,让用量信息保持在焦点位置。", "Your system access token for API authentication. Keep it secure and don't share it with others.": "您的系统访问令牌,用于 API 认证。请妥善保管,不要与他人分享。", "Your Telegram Bot Token": "您的 Telegram 机器人令牌", + "Your transaction history will appear here": "您的交易历史会显示在这里", "Your Turnstile secret key": "您的 Turnstile 密钥", "Your Turnstile site key": "您的 Turnstile 站点密钥", - "Alipay": "支付宝", - "Please wait a moment before trying again.": "请稍候再试。", - "This controls model request rate limiting. Web/API route throttling is configured by environment variables and may still return 429.": "此处仅控制模型请求速率限制。Web/API 路由限流由环境变量配置,仍可能返回 429。", - "Too many requests": "请求过于频繁", - "Try adjusting your search": "请尝试调整搜索条件", - "WeChat Pay": "微信支付", - "Your transaction history will appear here": "您的交易历史会显示在这里", "Zero retention": "零数据保留", "Zhipu": "智谱", "Zhipu V4": "智谱 V4",