import { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { Button } from "@/components/ui/button"; import { toast } from "sonner"; import { Download, Loader2 } from "lucide-react"; import EndpointSpeedTest from "./EndpointSpeedTest"; import { ApiKeySection, EndpointField, ModelInputWithFetch } from "./shared"; import { fetchModelsForConfig, showFetchModelsError, type FetchedModel, } from "@/lib/api/model-fetch"; import type { ProviderCategory } from "@/types"; interface EndpointCandidate { url: string; } interface CodexFormFieldsProps { providerId?: string; // API Key codexApiKey: string; onApiKeyChange: (key: string) => void; category?: ProviderCategory; shouldShowApiKeyLink: boolean; websiteUrl: string; isPartner?: boolean; partnerPromotionKey?: string; // Base URL shouldShowSpeedTest: boolean; codexBaseUrl: string; onBaseUrlChange: (url: string) => void; isFullUrl: boolean; onFullUrlChange: (value: boolean) => void; isEndpointModalOpen: boolean; onEndpointModalToggle: (open: boolean) => void; onCustomEndpointsChange?: (endpoints: string[]) => void; autoSelect: boolean; onAutoSelectChange: (checked: boolean) => void; // Model Name shouldShowModelField?: boolean; modelName?: string; onModelNameChange?: (model: string) => void; // Speed Test Endpoints speedTestEndpoints: EndpointCandidate[]; } export function CodexFormFields({ providerId, codexApiKey, onApiKeyChange, category, shouldShowApiKeyLink, websiteUrl, isPartner, partnerPromotionKey, shouldShowSpeedTest, codexBaseUrl, onBaseUrlChange, isFullUrl, onFullUrlChange, isEndpointModalOpen, onEndpointModalToggle, onCustomEndpointsChange, autoSelect, onAutoSelectChange, shouldShowModelField = true, modelName = "", onModelNameChange, speedTestEndpoints, }: CodexFormFieldsProps) { const { t } = useTranslation(); const [fetchedModels, setFetchedModels] = useState([]); const [isFetchingModels, setIsFetchingModels] = useState(false); const handleFetchModels = useCallback(() => { if (!codexBaseUrl || !codexApiKey) { showFetchModelsError(null, t, { hasApiKey: !!codexApiKey, hasBaseUrl: !!codexBaseUrl, }); return; } setIsFetchingModels(true); fetchModelsForConfig(codexBaseUrl, codexApiKey, isFullUrl) .then((models) => { setFetchedModels(models); if (models.length === 0) { toast.info(t("providerForm.fetchModelsEmpty")); } else { toast.success( t("providerForm.fetchModelsSuccess", { count: models.length }), ); } }) .catch((err) => { console.warn("[ModelFetch] Failed:", err); showFetchModelsError(err, t); }) .finally(() => setIsFetchingModels(false)); }, [codexBaseUrl, codexApiKey, isFullUrl, t]); return ( <> {/* Codex API Key 输入框 */} {/* Codex Base URL 输入框 */} {shouldShowSpeedTest && ( onEndpointModalToggle(true)} /> )} {/* Codex Model Name 输入框 */} {shouldShowModelField && onModelNameChange && (
onModelNameChange!(v)} placeholder={t("codexConfig.modelNamePlaceholder", { defaultValue: "例如: gpt-5.4", })} fetchedModels={fetchedModels} isLoading={isFetchingModels} />

{modelName.trim() ? t("codexConfig.modelNameHint", { defaultValue: "指定使用的模型,将自动更新到 config.toml 中", }) : t("providerForm.modelHint", { defaultValue: "💡 留空将使用供应商的默认模型", })}

)} {/* 端点测速弹窗 - Codex */} {shouldShowSpeedTest && isEndpointModalOpen && ( onEndpointModalToggle(false)} autoSelect={autoSelect} onAutoSelectChange={onAutoSelectChange} onCustomEndpointsChange={onCustomEndpointsChange} /> )} ); }