mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-27 16:26:16 +08:00
refactor(claude-desktop): simplify model mapping UX
- Remove "Import from Claude" button from main provider list (keep in empty state) - Remove "Desktop model" column from proxy mode mapping table; route names are now auto-generated - Rename "upstream model" label to "requested model" and equalize column widths - Rewrite model mapping hint and toggle description for end-user clarity - Update validation messages and remove dead i18n keys (routeModelLabel)
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
type CSSProperties,
|
||||
} from "react";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { AlertTriangle, Download, Search, X } from "lucide-react";
|
||||
import { AlertTriangle, Search, X } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
@@ -470,21 +470,6 @@ export function ProviderList({
|
||||
|
||||
return (
|
||||
<div className="mt-4 space-y-4">
|
||||
{appId === "claude-desktop" && (
|
||||
<div className="flex flex-wrap justify-end gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => importMutation.mutate()}
|
||||
disabled={importMutation.isPending}
|
||||
>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
{t("provider.importFromClaude", {
|
||||
defaultValue: "从 Claude 导入兼容供应商",
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{claudeDesktopStatusMessages.length > 0 && (
|
||||
<div className="rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-900 dark:text-amber-200">
|
||||
<div className="flex items-center gap-2 font-medium">
|
||||
|
||||
@@ -314,24 +314,24 @@ export function ClaudeDesktopProviderForm({
|
||||
}
|
||||
|
||||
const routeEntries = routes
|
||||
.map((route) => ({
|
||||
.map((route, index) => ({
|
||||
...route,
|
||||
route: route.route.trim(),
|
||||
route:
|
||||
route.route.trim() ||
|
||||
(mode === "proxy"
|
||||
? `claude-${route.model.trim().replace(/[/\\]/g, "-") || `model-${index + 1}`}`
|
||||
: ""),
|
||||
model: route.model.trim(),
|
||||
displayName: route.displayName.trim(),
|
||||
}))
|
||||
.filter((route) => route.route || route.model);
|
||||
|
||||
if (mode === "proxy") {
|
||||
const invalid = routeEntries.find(
|
||||
(route) =>
|
||||
!route.route || !route.model || !isClaudeSafeRoute(route.route),
|
||||
);
|
||||
if (invalid) {
|
||||
const missing = routeEntries.find((route) => !route.model);
|
||||
if (missing) {
|
||||
toast.error(
|
||||
t("claudeDesktop.routeInvalid", {
|
||||
defaultValue:
|
||||
"模型映射必须填写 claude-* / anthropic/claude-* 路由名和上游模型名",
|
||||
defaultValue: "请填写上游模型名",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
@@ -339,7 +339,7 @@ export function ClaudeDesktopProviderForm({
|
||||
if (routeEntries.length === 0) {
|
||||
toast.error(
|
||||
t("claudeDesktop.routesRequired", {
|
||||
defaultValue: "需要模型映射时至少填写一个模型路由",
|
||||
defaultValue: "至少填写一个上游模型",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
@@ -479,7 +479,7 @@ export function ClaudeDesktopProviderForm({
|
||||
{needsModelMapping
|
||||
? t("claudeDesktop.modelMappingOnHint", {
|
||||
defaultValue:
|
||||
"Claude Desktop 只看到 claude-* 路由名,CC Switch 本地路由会映射到真实上游模型;需要保持本地路由运行。",
|
||||
"Claude Desktop 目前对模型 ID 进行了限制,如果您的供应商提供的模型不是 Claude 系列模型,则需要打开本开关,并在使用过程中保持本地路由开启。",
|
||||
})
|
||||
: t("claudeDesktop.modelMappingOffHint", {
|
||||
defaultValue:
|
||||
@@ -552,26 +552,21 @@ export function ClaudeDesktopProviderForm({
|
||||
...current,
|
||||
nextRouteRow(current, defaultProxyRouteRows),
|
||||
]),
|
||||
t("claudeDesktop.addRoute", { defaultValue: "添加路由" }),
|
||||
t("claudeDesktop.addRoute", { defaultValue: "添加模型" }),
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs leading-relaxed text-muted-foreground">
|
||||
{t("claudeDesktop.routeMapHint", {
|
||||
defaultValue:
|
||||
"左侧是 Claude Desktop 看到的 claude-* 模型名,右侧是真实发送给供应商的上游模型名。",
|
||||
"填写供应商实际提供的模型名,显示名为在 Claude Desktop 模型列表中展示的名称。",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="hidden grid-cols-[1fr_1fr_140px_92px_36px] gap-2 px-1 text-xs font-medium text-muted-foreground md:grid">
|
||||
<span>
|
||||
{t("claudeDesktop.routeModelLabel", {
|
||||
defaultValue: "Desktop 模型",
|
||||
})}
|
||||
</span>
|
||||
<div className="hidden grid-cols-[1fr_1fr_92px_36px] gap-2 px-1 text-xs font-medium text-muted-foreground md:grid">
|
||||
<span>
|
||||
{t("claudeDesktop.upstreamModelLabel", {
|
||||
defaultValue: "上游模型",
|
||||
defaultValue: "实际请求模型",
|
||||
})}
|
||||
</span>
|
||||
<span>
|
||||
@@ -589,15 +584,8 @@ export function ClaudeDesktopProviderForm({
|
||||
{routes.map((route, index) => (
|
||||
<div
|
||||
key={`${route.route}-${index}`}
|
||||
className="grid grid-cols-1 gap-2 md:grid-cols-[1fr_1fr_140px_92px_36px]"
|
||||
className="grid grid-cols-1 gap-2 md:grid-cols-[1fr_1fr_92px_36px]"
|
||||
>
|
||||
<Input
|
||||
value={route.route}
|
||||
onChange={(event) =>
|
||||
updateRoute(index, { route: event.target.value })
|
||||
}
|
||||
placeholder="claude-sonnet-4-6"
|
||||
/>
|
||||
<div className="flex gap-1">
|
||||
<Input
|
||||
value={route.model}
|
||||
|
||||
@@ -179,11 +179,10 @@
|
||||
"modeProxy": "Model mapping",
|
||||
"modelMappingToggle": "Needs model mapping",
|
||||
"modelMappingOffHint": "Use this when the provider already exposes and accepts claude-* / anthropic/claude-* model IDs through Anthropic Messages. Claude Desktop connects to the provider directly.",
|
||||
"modelMappingOnHint": "Claude Desktop only sees claude-* route names. CC Switch local routing maps them to the real upstream models, so local routing must stay running.",
|
||||
"modelMappingOnHint": "Claude Desktop currently restricts model IDs. If your provider offers non-Claude models, enable this switch and keep local routing running while in use.",
|
||||
"routeMapTitle": "Model mapping",
|
||||
"routeMapHint": "The left side is the claude-* model ID shown to Claude Desktop; the right side is the real upstream model sent to the provider. Checking 1M appends [1M] to both model IDs.",
|
||||
"routeModelLabel": "Desktop model",
|
||||
"upstreamModelLabel": "Upstream model",
|
||||
"routeMapHint": "Enter the model name provided by your provider. The display name is shown in the Claude Desktop model list.",
|
||||
"upstreamModelLabel": "Requested model",
|
||||
"displayNameLabel": "Display name",
|
||||
"supports1mLabel": "1M",
|
||||
"directModelListTitle": "Manually specify Claude Desktop models (advanced, optional)",
|
||||
@@ -191,9 +190,9 @@
|
||||
"directModelListHint": "Only fill this when the provider's /v1/models is unavailable or does not return Claude Desktop-safe claude-* model IDs. Checking 1M writes the [1M] marker after the model ID.",
|
||||
"directModelInvalid": "Direct models must use claude-* / anthropic/claude-* model IDs",
|
||||
"addModel": "Add model",
|
||||
"addRoute": "Add route",
|
||||
"routeInvalid": "Model mapping requires a claude-* / anthropic/claude-* route name and an upstream model name",
|
||||
"routesRequired": "At least one model route is required when model mapping is enabled",
|
||||
"addRoute": "Add model",
|
||||
"routeInvalid": "Please enter the upstream model name",
|
||||
"routesRequired": "At least one upstream model is required",
|
||||
"statusTitle": "Claude Desktop configuration needs attention",
|
||||
"statusUnsupported": "This platform does not support writing Claude Desktop 3P configuration yet.",
|
||||
"statusStaleRawModels": "The Claude Desktop profile contains non-claude-* model IDs. Newer Claude Desktop versions may reject it; switch to the current provider again to repair it.",
|
||||
|
||||
@@ -179,11 +179,10 @@
|
||||
"modeProxy": "モデルマッピング",
|
||||
"modelMappingToggle": "モデルマッピングが必要",
|
||||
"modelMappingOffHint": "プロバイダーが Anthropic Messages で claude-* / anthropic/claude-* のモデル ID を公開し、そのまま受け付ける場合に使います。Claude Desktop はプロバイダーへ直接接続します。",
|
||||
"modelMappingOnHint": "Claude Desktop には claude-* のルート名だけを見せ、CC Switch のローカルルーティングが実際の上流モデルへマッピングします。ローカルルーティングを起動したままにしてください。",
|
||||
"modelMappingOnHint": "Claude Desktop は現在モデル ID を制限しています。お使いのプロバイダーが Claude 系列以外のモデルを提供する場合、このスイッチを有効にし、使用中はローカルルーティングを起動したままにしてください。",
|
||||
"routeMapTitle": "モデルマッピング",
|
||||
"routeMapHint": "左側は Claude Desktop に表示する claude-* モデル ID、右側はプロバイダーへ送る実際の上流モデルです。1M をオンにすると両方のモデル ID に [1M] を追加します。",
|
||||
"routeModelLabel": "Desktop モデル",
|
||||
"upstreamModelLabel": "上流モデル",
|
||||
"routeMapHint": "プロバイダーが実際に提供するモデル名を入力してください。表示名は Claude Desktop のモデルリストに表示される名前です。",
|
||||
"upstreamModelLabel": "リクエストモデル",
|
||||
"displayNameLabel": "表示名",
|
||||
"supports1mLabel": "1M",
|
||||
"directModelListTitle": "Claude Desktop モデルを手動指定(高度・任意)",
|
||||
@@ -191,9 +190,9 @@
|
||||
"directModelListHint": "プロバイダーの /v1/models が使えない、または Claude Desktop が認識できる claude-* モデル ID を返さない場合だけ入力してください。1M をオンにするとモデル ID の後ろに [1M] マーカーを書き込みます。",
|
||||
"directModelInvalid": "直結モデルは claude-* / anthropic/claude-* のモデル ID を使う必要があります",
|
||||
"addModel": "モデルを追加",
|
||||
"addRoute": "ルートを追加",
|
||||
"routeInvalid": "モデルマッピングには claude-* / anthropic/claude-* のルート名と上流モデル名が必要です",
|
||||
"routesRequired": "モデルマッピングを有効にする場合は、少なくとも 1 つのモデルルートが必要です",
|
||||
"addRoute": "モデルを追加",
|
||||
"routeInvalid": "上流モデル名を入力してください",
|
||||
"routesRequired": "少なくとも 1 つの上流モデルが必要です",
|
||||
"statusTitle": "Claude Desktop 設定の確認が必要です",
|
||||
"statusUnsupported": "このプラットフォームでは Claude Desktop 3P 設定の書き込みはまだサポートされていません。",
|
||||
"statusStaleRawModels": "Claude Desktop profile に claude-* ではないモデル ID が含まれています。新しい Claude Desktop では拒否される可能性があります。現在のプロバイダーへ再度切り替えると修復できます。",
|
||||
|
||||
@@ -179,11 +179,10 @@
|
||||
"modeProxy": "模型映射",
|
||||
"modelMappingToggle": "需要模型映射",
|
||||
"modelMappingOffHint": "适合供应商已经暴露并接受 claude-* / anthropic/claude-* 模型名的 Anthropic Messages API;请求会由 Claude Desktop 直连供应商。",
|
||||
"modelMappingOnHint": "Claude Desktop 只看到 claude-* 路由名,CC Switch 本地路由会映射到真实上游模型;需要保持本地路由运行。",
|
||||
"modelMappingOnHint": "Claude Desktop 目前对模型 ID 进行了限制,如果您的供应商提供的模型不是 Claude 系列模型,则需要打开本开关,并在使用过程中保持本地路由开启。",
|
||||
"routeMapTitle": "模型映射",
|
||||
"routeMapHint": "左侧是 Claude Desktop 看到的 claude-* 模型名,右侧是真实发送给供应商的上游模型名;勾选 1M 会在两侧模型名后追加 [1M]。",
|
||||
"routeModelLabel": "Desktop 模型",
|
||||
"upstreamModelLabel": "上游模型",
|
||||
"routeMapHint": "填写供应商实际提供的模型名,显示名为在 Claude Desktop 模型列表中展示的名称。",
|
||||
"upstreamModelLabel": "实际请求模型",
|
||||
"displayNameLabel": "显示名",
|
||||
"supports1mLabel": "1M",
|
||||
"directModelListTitle": "手动指定 Claude Desktop 模型列表(高级,可选)",
|
||||
@@ -191,9 +190,9 @@
|
||||
"directModelListHint": "仅当供应商的 /v1/models 不可用或没有返回 Claude Desktop 可识别的 claude-* 模型名时填写;勾选 1M 会在模型名后写入 [1M] 标记。",
|
||||
"directModelInvalid": "直连模型必须使用 claude-* / anthropic/claude-* 模型名",
|
||||
"addModel": "添加模型",
|
||||
"addRoute": "添加路由",
|
||||
"routeInvalid": "模型映射必须填写 claude-* / anthropic/claude-* 路由名和上游模型名",
|
||||
"routesRequired": "需要模型映射时至少填写一个模型路由",
|
||||
"addRoute": "添加模型",
|
||||
"routeInvalid": "请填写上游模型名",
|
||||
"routesRequired": "至少填写一个上游模型",
|
||||
"statusTitle": "Claude Desktop 配置需要检查",
|
||||
"statusUnsupported": "当前平台暂不支持 Claude Desktop 3P 配置写入。",
|
||||
"statusStaleRawModels": "Claude Desktop profile 中存在非 claude-* 模型名,新版 Claude Desktop 可能拒绝加载;重新切换当前供应商可修复。",
|
||||
|
||||
Reference in New Issue
Block a user