Clear placeholder values for model input fields to avoid suggesting specific model names that may not be applicable to all providers. This prevents user confusion when configuring different Claude providers.
265 lines
8.0 KiB
TypeScript
265 lines
8.0 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { FormLabel } from "@/components/ui/form";
|
|
import { Input } from "@/components/ui/input";
|
|
import EndpointSpeedTest from "./EndpointSpeedTest";
|
|
import { ApiKeySection, EndpointField } from "./shared";
|
|
import type { ProviderCategory } from "@/types";
|
|
import type { TemplateValueConfig } from "@/config/claudeProviderPresets";
|
|
|
|
interface EndpointCandidate {
|
|
url: string;
|
|
}
|
|
|
|
interface ClaudeFormFieldsProps {
|
|
providerId?: string;
|
|
// API Key
|
|
shouldShowApiKey: boolean;
|
|
apiKey: string;
|
|
onApiKeyChange: (key: string) => void;
|
|
category?: ProviderCategory;
|
|
shouldShowApiKeyLink: boolean;
|
|
websiteUrl: string;
|
|
isPartner?: boolean;
|
|
partnerPromotionKey?: string;
|
|
|
|
// Template Values
|
|
templateValueEntries: Array<[string, TemplateValueConfig]>;
|
|
templateValues: Record<string, TemplateValueConfig>;
|
|
templatePresetName: string;
|
|
onTemplateValueChange: (key: string, value: string) => void;
|
|
|
|
// Base URL
|
|
shouldShowSpeedTest: boolean;
|
|
baseUrl: string;
|
|
onBaseUrlChange: (url: string) => void;
|
|
isEndpointModalOpen: boolean;
|
|
onEndpointModalToggle: (open: boolean) => void;
|
|
onCustomEndpointsChange: (endpoints: string[]) => void;
|
|
|
|
// Model Selector
|
|
shouldShowModelSelector: boolean;
|
|
claudeModel: string;
|
|
defaultHaikuModel: string;
|
|
defaultSonnetModel: string;
|
|
defaultOpusModel: string;
|
|
onModelChange: (
|
|
field:
|
|
| "ANTHROPIC_MODEL"
|
|
| "ANTHROPIC_DEFAULT_HAIKU_MODEL"
|
|
| "ANTHROPIC_DEFAULT_SONNET_MODEL"
|
|
| "ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
value: string,
|
|
) => void;
|
|
|
|
// Speed Test Endpoints
|
|
speedTestEndpoints: EndpointCandidate[];
|
|
}
|
|
|
|
export function ClaudeFormFields({
|
|
providerId,
|
|
shouldShowApiKey,
|
|
apiKey,
|
|
onApiKeyChange,
|
|
category,
|
|
shouldShowApiKeyLink,
|
|
websiteUrl,
|
|
isPartner,
|
|
partnerPromotionKey,
|
|
templateValueEntries,
|
|
templateValues,
|
|
templatePresetName,
|
|
onTemplateValueChange,
|
|
shouldShowSpeedTest,
|
|
baseUrl,
|
|
onBaseUrlChange,
|
|
isEndpointModalOpen,
|
|
onEndpointModalToggle,
|
|
onCustomEndpointsChange,
|
|
shouldShowModelSelector,
|
|
claudeModel,
|
|
defaultHaikuModel,
|
|
defaultSonnetModel,
|
|
defaultOpusModel,
|
|
onModelChange,
|
|
speedTestEndpoints,
|
|
}: ClaudeFormFieldsProps) {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<>
|
|
{/* API Key 输入框 */}
|
|
{shouldShowApiKey && (
|
|
<ApiKeySection
|
|
value={apiKey}
|
|
onChange={onApiKeyChange}
|
|
category={category}
|
|
shouldShowLink={shouldShowApiKeyLink}
|
|
websiteUrl={websiteUrl}
|
|
isPartner={isPartner}
|
|
partnerPromotionKey={partnerPromotionKey}
|
|
/>
|
|
)}
|
|
|
|
{/* 模板变量输入 */}
|
|
{templateValueEntries.length > 0 && (
|
|
<div className="space-y-3">
|
|
<FormLabel>
|
|
{t("providerForm.parameterConfig", {
|
|
name: templatePresetName,
|
|
defaultValue: `${templatePresetName} 参数配置`,
|
|
})}
|
|
</FormLabel>
|
|
<div className="space-y-4">
|
|
{templateValueEntries.map(([key, config]) => (
|
|
<div key={key} className="space-y-2">
|
|
<FormLabel htmlFor={`template-${key}`}>
|
|
{config.label}
|
|
</FormLabel>
|
|
<Input
|
|
id={`template-${key}`}
|
|
type="text"
|
|
required
|
|
value={
|
|
templateValues[key]?.editorValue ??
|
|
config.editorValue ??
|
|
config.defaultValue ??
|
|
""
|
|
}
|
|
onChange={(e) => onTemplateValueChange(key, e.target.value)}
|
|
placeholder={config.placeholder || config.label}
|
|
autoComplete="off"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Base URL 输入框 */}
|
|
{shouldShowSpeedTest && (
|
|
<EndpointField
|
|
id="baseUrl"
|
|
label={t("providerForm.apiEndpoint")}
|
|
value={baseUrl}
|
|
onChange={onBaseUrlChange}
|
|
placeholder={t("providerForm.apiEndpointPlaceholder")}
|
|
hint={t("providerForm.apiHint")}
|
|
onManageClick={() => onEndpointModalToggle(true)}
|
|
/>
|
|
)}
|
|
|
|
{/* 端点测速弹窗 */}
|
|
{shouldShowSpeedTest && isEndpointModalOpen && (
|
|
<EndpointSpeedTest
|
|
appId="claude"
|
|
providerId={providerId}
|
|
value={baseUrl}
|
|
onChange={onBaseUrlChange}
|
|
initialEndpoints={speedTestEndpoints}
|
|
visible={isEndpointModalOpen}
|
|
onClose={() => onEndpointModalToggle(false)}
|
|
onCustomEndpointsChange={onCustomEndpointsChange}
|
|
/>
|
|
)}
|
|
|
|
{/* 模型选择器 */}
|
|
{shouldShowModelSelector && (
|
|
<div className="space-y-3">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{/* 主模型 */}
|
|
<div className="space-y-2">
|
|
<FormLabel htmlFor="claudeModel">
|
|
{t("providerForm.anthropicModel", { defaultValue: "主模型" })}
|
|
</FormLabel>
|
|
<Input
|
|
id="claudeModel"
|
|
type="text"
|
|
value={claudeModel}
|
|
onChange={(e) =>
|
|
onModelChange("ANTHROPIC_MODEL", e.target.value)
|
|
}
|
|
placeholder={t("providerForm.modelPlaceholder", {
|
|
defaultValue: "",
|
|
})}
|
|
autoComplete="off"
|
|
/>
|
|
</div>
|
|
|
|
{/* 默认 Haiku */}
|
|
<div className="space-y-2">
|
|
<FormLabel htmlFor="claudeDefaultHaikuModel">
|
|
{t("providerForm.anthropicDefaultHaikuModel", {
|
|
defaultValue: "Haiku 默认模型",
|
|
})}
|
|
</FormLabel>
|
|
<Input
|
|
id="claudeDefaultHaikuModel"
|
|
type="text"
|
|
value={defaultHaikuModel}
|
|
onChange={(e) =>
|
|
onModelChange("ANTHROPIC_DEFAULT_HAIKU_MODEL", e.target.value)
|
|
}
|
|
placeholder={t("providerForm.haikuModelPlaceholder", {
|
|
defaultValue: "",
|
|
})}
|
|
autoComplete="off"
|
|
/>
|
|
</div>
|
|
|
|
{/* 默认 Sonnet */}
|
|
<div className="space-y-2">
|
|
<FormLabel htmlFor="claudeDefaultSonnetModel">
|
|
{t("providerForm.anthropicDefaultSonnetModel", {
|
|
defaultValue: "Sonnet 默认模型",
|
|
})}
|
|
</FormLabel>
|
|
<Input
|
|
id="claudeDefaultSonnetModel"
|
|
type="text"
|
|
value={defaultSonnetModel}
|
|
onChange={(e) =>
|
|
onModelChange(
|
|
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
e.target.value,
|
|
)
|
|
}
|
|
placeholder={t("providerForm.modelPlaceholder", {
|
|
defaultValue: "",
|
|
})}
|
|
autoComplete="off"
|
|
/>
|
|
</div>
|
|
|
|
{/* 默认 Opus */}
|
|
<div className="space-y-2">
|
|
<FormLabel htmlFor="claudeDefaultOpusModel">
|
|
{t("providerForm.anthropicDefaultOpusModel", {
|
|
defaultValue: "Opus 默认模型",
|
|
})}
|
|
</FormLabel>
|
|
<Input
|
|
id="claudeDefaultOpusModel"
|
|
type="text"
|
|
value={defaultOpusModel}
|
|
onChange={(e) =>
|
|
onModelChange("ANTHROPIC_DEFAULT_OPUS_MODEL", e.target.value)
|
|
}
|
|
placeholder={t("providerForm.modelPlaceholder", {
|
|
defaultValue: "",
|
|
})}
|
|
autoComplete="off"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground">
|
|
{t("providerForm.modelHelper", {
|
|
defaultValue:
|
|
"可选:指定默认使用的 Claude 模型,留空则使用系统默认。",
|
|
})}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|