diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts index f24d66efe..fcd4af483 100644 --- a/packages/console/app/src/i18n/ar.ts +++ b/packages/console/app/src/i18n/ar.ts @@ -388,6 +388,9 @@ export const dict = { "zen.api.error.modelDisabled": "النموذج معطل", "zen.api.error.regionNotAllowed": "لا يتوفر أحدث إصدار من هذا النموذج إلا مستضافًا في الصين، ويتطلب تفعيلًا صريحًا: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "هذا النموذج غير متاح في بلدك.", + "zen.api.error.trainingNotAllowed": + "يجمع هذا النموذج بيانات تُستخدم لتحسين جودته، ويتطلب موافقتك الصريحة: {{consoleGoUrl}}", "zen.api.error.trialEnded": "انتهى العرض المجاني لـ {{model}}. يمكنك مواصلة استخدام النموذج بالاشتراك في OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts index 9d86e43b2..c7115b97f 100644 --- a/packages/console/app/src/i18n/br.ts +++ b/packages/console/app/src/i18n/br.ts @@ -397,6 +397,9 @@ export const dict = { "zen.api.error.modelDisabled": "O modelo está desabilitado", "zen.api.error.regionNotAllowed": "A versão mais recente deste modelo está disponível apenas com hospedagem na China e requer adesão explícita: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Este modelo não está disponível no seu país.", + "zen.api.error.trainingNotAllowed": + "Este modelo coleta dados usados para melhorar sua qualidade e exige seu consentimento explícito: {{consoleGoUrl}}", "zen.api.error.trialEnded": "A promoção gratuita do {{model}} terminou. Você pode continuar usando o modelo assinando o OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts index 530296296..ae324d581 100644 --- a/packages/console/app/src/i18n/da.ts +++ b/packages/console/app/src/i18n/da.ts @@ -394,6 +394,9 @@ export const dict = { "zen.api.error.modelDisabled": "Modellen er deaktiveret", "zen.api.error.regionNotAllowed": "Den nyeste version af denne model er kun tilgængelig som hostet i Kina og kræver, at du aktivt tilvælger den: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Denne model er ikke tilgængelig i dit land.", + "zen.api.error.trainingNotAllowed": + "Denne model indsamler data, der bruges til at forbedre dens kvalitet, og kræver, at du aktivt tilvælger den: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Den gratis kampagne for {{model}} er afsluttet. Du kan fortsætte med at bruge modellen ved at abonnere på OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts index 3468d5df1..9d4844469 100644 --- a/packages/console/app/src/i18n/de.ts +++ b/packages/console/app/src/i18n/de.ts @@ -396,6 +396,9 @@ export const dict = { "zen.api.error.modelDisabled": "Modell ist deaktiviert", "zen.api.error.regionNotAllowed": "Die neueste Version dieses Modells ist nur verfügbar, wenn sie in China gehostet wird, und muss ausdrücklich aktiviert werden: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Dieses Modell ist in deinem Land nicht verfügbar.", + "zen.api.error.trainingNotAllowed": + "Dieses Modell erfasst Daten, die zur Verbesserung seiner Qualität verwendet werden, und erfordert deine ausdrückliche Zustimmung: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Die kostenlose Aktion für {{model}} ist beendet. Du kannst das Modell weiterhin nutzen, indem du OpenCode Go abonnierst - {{link}}", diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 69179ec4b..739349f6b 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -393,7 +393,8 @@ export const dict = { "zen.api.error.modelDisabled": "Model is disabled", "zen.api.error.regionNotAllowed": "The latest version of this model is only available hosted in China and requires explicit opt in: {{consoleGoUrl}}", - "zen.api.error.nonZdrNotAllowed": + "zen.api.error.countryNotAllowed": "This model is not available in your country.", + "zen.api.error.trainingNotAllowed": "This model collects data used to improve its quality and requires explicit opt in: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Free promotion has ended for {{model}}. You can continue using the model by subscribing to OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts index db2f7346c..5ebff5a23 100644 --- a/packages/console/app/src/i18n/es.ts +++ b/packages/console/app/src/i18n/es.ts @@ -397,6 +397,9 @@ export const dict = { "zen.api.error.modelDisabled": "El modelo está deshabilitado", "zen.api.error.regionNotAllowed": "La versión más reciente de este modelo solo está disponible alojada en China y requiere una aceptación explícita: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Este modelo no está disponible en tu país.", + "zen.api.error.trainingNotAllowed": + "Este modelo recopila datos que se utilizan para mejorar su calidad y requiere tu consentimiento explícito: {{consoleGoUrl}}", "zen.api.error.trialEnded": "La promoción gratuita de {{model}} ha finalizado. Puedes seguir usando el modelo suscribiéndote a OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts index 6ba904245..174ed7057 100644 --- a/packages/console/app/src/i18n/fr.ts +++ b/packages/console/app/src/i18n/fr.ts @@ -398,6 +398,9 @@ export const dict = { "zen.api.error.modelDisabled": "Le modèle est désactivé", "zen.api.error.regionNotAllowed": "La dernière version de ce modèle est uniquement disponible avec un hébergement en Chine et nécessite votre consentement explicite : {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Ce modèle n’est pas disponible dans votre pays.", + "zen.api.error.trainingNotAllowed": + "Ce modèle collecte des données utilisées pour améliorer sa qualité et nécessite votre consentement explicite : {{consoleGoUrl}}", "zen.api.error.trialEnded": "La promotion gratuite de {{model}} est terminée. Vous pouvez continuer à utiliser le modèle en vous abonnant à OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts index 56238b837..cf4c0d772 100644 --- a/packages/console/app/src/i18n/it.ts +++ b/packages/console/app/src/i18n/it.ts @@ -393,6 +393,9 @@ export const dict = { "zen.api.error.modelDisabled": "Il modello è disabilitato", "zen.api.error.regionNotAllowed": "La versione più recente di questo modello è disponibile solo con hosting in Cina e richiede un consenso esplicito: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Questo modello non è disponibile nel tuo paese.", + "zen.api.error.trainingNotAllowed": + "Questo modello raccoglie dati utilizzati per migliorarne la qualità e richiede il tuo consenso esplicito: {{consoleGoUrl}}", "zen.api.error.trialEnded": "La promozione gratuita di {{model}} è terminata. Puoi continuare a usare il modello abbonandoti a OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts index 117731413..1ed9df750 100644 --- a/packages/console/app/src/i18n/ja.ts +++ b/packages/console/app/src/i18n/ja.ts @@ -392,6 +392,9 @@ export const dict = { "zen.api.error.modelDisabled": "モデルが無効です", "zen.api.error.regionNotAllowed": "このモデルの最新バージョンは中国でのみホスト提供されており、利用するには明示的なオプトインが必要です: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "このモデルはお住まいの国では利用できません。", + "zen.api.error.trainingNotAllowed": + "このモデルは品質向上のためのデータを収集します。利用するには明示的な同意が必要です: {{consoleGoUrl}}", "zen.api.error.trialEnded": "{{model}} の無料プロモーションは終了しました。OpenCode Go を購読するとモデルを引き続き使用できます - {{link}}", diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts index 581072cf7..946b5c089 100644 --- a/packages/console/app/src/i18n/ko.ts +++ b/packages/console/app/src/i18n/ko.ts @@ -386,6 +386,9 @@ export const dict = { "zen.api.error.modelDisabled": "모델이 비활성화되었습니다", "zen.api.error.regionNotAllowed": "이 모델의 최신 버전은 중국에서 호스팅되는 경우에만 사용할 수 있으며, 명시적으로 사용에 동의해야 합니다: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "이 모델은 거주 국가에서 사용할 수 없습니다.", + "zen.api.error.trainingNotAllowed": + "이 모델은 품질 개선에 사용되는 데이터를 수집하며, 사용하려면 명시적으로 동의해야 합니다: {{consoleGoUrl}}", "zen.api.error.trialEnded": "{{model}}의 무료 프로모션이 종료되었습니다. OpenCode Go를 구독하면 모델을 계속 사용할 수 있습니다 - {{link}}", diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts index 493039837..ce0ae2121 100644 --- a/packages/console/app/src/i18n/no.ts +++ b/packages/console/app/src/i18n/no.ts @@ -395,6 +395,9 @@ export const dict = { "zen.api.error.modelDisabled": "Modellen er deaktivert", "zen.api.error.regionNotAllowed": "Den nyeste versjonen av denne modellen er bare tilgjengelig som en tjeneste driftet i Kina og krever at du uttrykkelig samtykker: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Denne modellen er ikke tilgjengelig i landet ditt.", + "zen.api.error.trainingNotAllowed": + "Denne modellen samler inn data som brukes til å forbedre modellens kvalitet, og krever at du uttrykkelig samtykker: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Den gratis kampanjen for {{model}} er avsluttet. Du kan fortsette å bruke modellen ved å abonnere på OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts index 44040f6ea..4aa76126b 100644 --- a/packages/console/app/src/i18n/pl.ts +++ b/packages/console/app/src/i18n/pl.ts @@ -395,6 +395,9 @@ export const dict = { "zen.api.error.modelDisabled": "Model jest wyłączony", "zen.api.error.regionNotAllowed": "Najnowsza wersja tego modelu jest dostępna wyłącznie jako usługa hostowana w Chinach i wymaga jawnej zgody użytkownika: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Ten model nie jest dostępny w Twoim kraju.", + "zen.api.error.trainingNotAllowed": + "Ten model zbiera dane wykorzystywane do poprawy jego jakości i wymaga wyraźnej zgody użytkownika: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Bezpłatna promocja {{model}} dobiegła końca. Możesz dalej korzystać z modelu, subskrybując OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts index 9fda0e095..8fe362c2e 100644 --- a/packages/console/app/src/i18n/ru.ts +++ b/packages/console/app/src/i18n/ru.ts @@ -400,6 +400,9 @@ export const dict = { "zen.api.error.modelDisabled": "Модель отключена", "zen.api.error.regionNotAllowed": "Последняя версия этой модели размещена только в Китае. Чтобы использовать её, необходимо явно подтвердить согласие: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Эта модель недоступна в вашей стране.", + "zen.api.error.trainingNotAllowed": + "Эта модель собирает данные, которые используются для улучшения её качества, и требует явного согласия: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Бесплатная акция для {{model}} завершена. Вы можете продолжить использование модели, подписавшись на OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts index 82aff9deb..4ad94a44e 100644 --- a/packages/console/app/src/i18n/th.ts +++ b/packages/console/app/src/i18n/th.ts @@ -390,6 +390,9 @@ export const dict = { "zen.api.error.modelDisabled": "โมเดลถูกปิดใช้งาน", "zen.api.error.regionNotAllowed": "โมเดลเวอร์ชันล่าสุดนี้ให้บริการเฉพาะผ่านระบบที่โฮสต์ในประเทศจีน และต้องให้ความยินยอมอย่างชัดแจ้งก่อนใช้งาน: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "โมเดลนี้ไม่พร้อมให้บริการในประเทศของคุณ", + "zen.api.error.trainingNotAllowed": + "โมเดลนี้เก็บรวบรวมข้อมูลที่ใช้เพื่อปรับปรุงคุณภาพของโมเดล และต้องได้รับความยินยอมอย่างชัดแจ้งก่อนใช้งาน: {{consoleGoUrl}}", "zen.api.error.trialEnded": "โปรโมชันฟรีสำหรับ {{model}} สิ้นสุดแล้ว คุณสามารถใช้โมเดลต่อได้โดยสมัครสมาชิก OpenCode Go - {{link}}", diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts index a2b9e5aef..2b2a0182f 100644 --- a/packages/console/app/src/i18n/tr.ts +++ b/packages/console/app/src/i18n/tr.ts @@ -398,6 +398,9 @@ export const dict = { "zen.api.error.modelDisabled": "Model devre dışı", "zen.api.error.regionNotAllowed": "Bu modelin en son sürümü yalnızca Çin'de barındırılıyor ve kullanabilmek için açıkça onay vermeniz gerekiyor: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Bu model ülkenizde kullanılamıyor.", + "zen.api.error.trainingNotAllowed": + "Bu model, kalitesini artırmak için kullanılan verileri toplar. Modeli kullanabilmek için açıkça onay vermeniz gerekir: {{consoleGoUrl}}", "zen.api.error.trialEnded": "{{model}} için ücretsiz promosyon sona erdi. OpenCode Go'ya abone olarak modeli kullanmaya devam edebilirsiniz - {{link}}", diff --git a/packages/console/app/src/i18n/uk.ts b/packages/console/app/src/i18n/uk.ts index c85154244..c625a0165 100644 --- a/packages/console/app/src/i18n/uk.ts +++ b/packages/console/app/src/i18n/uk.ts @@ -394,6 +394,9 @@ export const dict = { "zen.api.error.modelDisabled": "Модель вимкнено", "zen.api.error.regionNotAllowed": "Остання версія цієї моделі доступна лише на серверах у Китаї, і для її використання потрібно надати явну згоду: {{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "Ця модель недоступна у вашій країні.", + "zen.api.error.trainingNotAllowed": + "Ця модель збирає дані, які використовуються для покращення її якості; для її використання потрібна ваша явна згода: {{consoleGoUrl}}", "zen.api.error.trialEnded": "Безкоштовна акція для {{model}} закінчилася. Ви можете продовжити використання, підписавшись на OpenCode Go — {{link}}", diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts index a0c8d5cad..a4ab294ae 100644 --- a/packages/console/app/src/i18n/zh.ts +++ b/packages/console/app/src/i18n/zh.ts @@ -370,6 +370,8 @@ export const dict = { "zen.api.error.userMonthlyLimitReached": "您已达到每月支出限额 ${{amount}}。请在此处管理您的限额:{{membersUrl}}", "zen.api.error.modelDisabled": "模型已禁用", "zen.api.error.regionNotAllowed": "该模型的最新版本仅在中国提供托管服务,需明确选择启用:{{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "该模型在你所在的国家或地区不可用。", + "zen.api.error.trainingNotAllowed": "该模型会收集用于提升其质量的数据,使用前需要你明确同意:{{consoleGoUrl}}", "zen.api.error.trialEnded": "{{model}} 的限免活动已结束。您可以订阅 OpenCode Go 继续使用该模型 - {{link}}", "black.meta.title": "OpenCode Black | 访问全球顶尖编程模型", diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts index 148cbcccb..b8fa4df5b 100644 --- a/packages/console/app/src/i18n/zht.ts +++ b/packages/console/app/src/i18n/zht.ts @@ -370,6 +370,8 @@ export const dict = { "zen.api.error.userMonthlyLimitReached": "你已達到每月支出限額 ${{amount}}。請在此處管理你的限額:{{membersUrl}}", "zen.api.error.modelDisabled": "模型已停用", "zen.api.error.regionNotAllowed": "此模型的最新版本僅於中國託管,且需明確選擇啟用:{{consoleGoUrl}}", + "zen.api.error.countryNotAllowed": "此模型無法在你所在的國家或地區使用。", + "zen.api.error.trainingNotAllowed": "此模型會收集用於提升其品質的資料,使用前須經你明確同意:{{consoleGoUrl}}", "zen.api.error.trialEnded": "{{model}} 的限免活动已結束。您可以訂閱 OpenCode Go 繼續使用該模型 - {{link}}", "black.meta.title": "OpenCode Black | 存取全球最佳編碼模型", diff --git a/packages/console/app/src/lib/request-country.ts b/packages/console/app/src/lib/request-country.ts index a4e39eb60..0eb16722a 100644 --- a/packages/console/app/src/lib/request-country.ts +++ b/packages/console/app/src/lib/request-country.ts @@ -1,5 +1,74 @@ +const MUSE_SPARK_BLOCKED_COUNTRIES = new Set([ + "AD", + "AF", + "AT", + "AU", + "BE", + "BG", + "BR", + "BY", + "CA", + "CH", + "CN", + "CU", + "CY", + "CZ", + "DE", + "DK", + "EE", + "EH", + "ER", + "ES", + "ET", + "FI", + "FR", + "GB", + "GR", + "HK", + "HR", + "HT", + "HU", + "IE", + "IQ", + "IR", + "IS", + "IT", + "KH", + "KP", + "KR", + "LI", + "LT", + "LU", + "LV", + "LY", + "MC", + "MM", + "MO", + "MT", + "NI", + "NL", + "NO", + "PK", + "PL", + "PT", + "RO", + "RU", + "SE", + "SI", + "SK", + "SM", + "SO", + "SY", + "VA", + "VE", +]) + export function countryFromRequest(request: Request | undefined) { if (!request) return undefined const cloudflareRequest = request as Request & { cf?: { country?: string } } return cloudflareRequest.cf?.country ?? request.headers.get("cf-ipcountry") ?? undefined } + +export function isModelCountryRestricted(model: string, country: string | undefined) { + return model === "muse-spark-1.2" && country !== undefined && MUSE_SPARK_BLOCKED_COUNTRIES.has(country.toUpperCase()) +} diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 699a00c48..d6b1dba6d 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -52,7 +52,7 @@ import { createModelTpsLimiter } from "./modelTpsLimiter" import { createProviderBudgetTracker } from "./providerBudgetTracker" import { accumulateUsage, HOT_WORKSPACES } from "./usageBatcher" import { Workspace } from "@opencode-ai/console-core/workspace.js" -import { countryFromRequest } from "~/lib/request-country" +import { countryFromRequest, isModelCountryRestricted } from "~/lib/request-country" type ZenData = Awaited> type RetryOptions = { @@ -122,6 +122,8 @@ export async function handler( }) const zenData = ZenData.list(opts.modelList) const modelInfo = validateModel(zenData, model) + const country = countryFromRequest(input.request) + if (isModelCountryRestricted(modelInfo.id, country)) throw new RegionError(t("zen.api.error.countryNotAllowed")) const trialLimiter = createTrialLimiter(modelInfo.trialProvider, ip) const trialProviders = await trialLimiter?.check() const rateLimiter = modelInfo.allowAnonymous @@ -131,7 +133,7 @@ export async function handler( const authInfo = await authenticate(modelInfo, zenApiKey) if (authInfo && opts.modelList === "lite" && modelInfo.id === "muse-spark-1.2" && !authInfo.allowTraining) throw new DataPolicyError( - t("zen.api.error.nonZdrNotAllowed", { + t("zen.api.error.trainingNotAllowed", { consoleGoUrl: `https://opencode.ai/workspace/${authInfo.workspaceID}/go`, }), ) @@ -140,7 +142,7 @@ export async function handler( : await (async () => { if (!authInfo) return return Actor.provide("system", { workspaceID: authInfo.workspaceID }, () => - Workspace.setDefaultRegion({ country: countryFromRequest(input.request) }), + Workspace.setDefaultRegion({ country }), ) })() if (