diff --git a/src/components/providers/forms/CodexConfigEditor.tsx b/src/components/providers/forms/CodexConfigEditor.tsx index 4e11430..2501f96 100644 --- a/src/components/providers/forms/CodexConfigEditor.tsx +++ b/src/components/providers/forms/CodexConfigEditor.tsx @@ -1,6 +1,5 @@ import React, { useState, useEffect } from "react"; import { CodexAuthSection, CodexConfigSection } from "./CodexConfigSections"; -import { CodexQuickWizardModal } from "./CodexQuickWizardModal"; import { CodexCommonConfigModal } from "./CodexCommonConfigModal"; interface CodexConfigEditorProps { @@ -27,14 +26,6 @@ interface CodexConfigEditorProps { authError: string; configError: string; // config.toml 错误提示 - - onWebsiteUrlChange?: (url: string) => void; // 更新网址回调 - - isTemplateModalOpen?: boolean; // 模态框状态 - - setIsTemplateModalOpen?: (open: boolean) => void; // 设置模态框状态 - - onNameChange?: (name: string) => void; // 更新供应商名称回调 } const CodexConfigEditor: React.FC = ({ @@ -50,21 +41,9 @@ const CodexConfigEditor: React.FC = ({ commonConfigError, authError, configError, - onWebsiteUrlChange, - onNameChange, - isTemplateModalOpen: externalTemplateModalOpen, - setIsTemplateModalOpen: externalSetTemplateModalOpen, }) => { const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false); - // Use internal state or external state - const [internalTemplateModalOpen, setInternalTemplateModalOpen] = - useState(false); - const isTemplateModalOpen = - externalTemplateModalOpen ?? internalTemplateModalOpen; - const setIsTemplateModalOpen = - externalSetTemplateModalOpen ?? setInternalTemplateModalOpen; - // Auto-open common config modal if there's an error useEffect(() => { if (commonConfigError && !isCommonConfigModalOpen) { @@ -72,23 +51,6 @@ const CodexConfigEditor: React.FC = ({ } }, [commonConfigError, isCommonConfigModalOpen]); - const handleQuickWizardApply = ( - auth: string, - config: string, - extras: { websiteUrl?: string; displayName?: string }, - ) => { - onAuthChange(auth); - onConfigChange(config); - - if (onWebsiteUrlChange && extras.websiteUrl) { - onWebsiteUrlChange(extras.websiteUrl); - } - - if (onNameChange && extras.displayName) { - onNameChange(extras.displayName); - } - }; - return (
{/* Auth JSON Section */} @@ -110,13 +72,6 @@ const CodexConfigEditor: React.FC = ({ configError={configError} /> - {/* Quick Wizard Modal */} - setIsTemplateModalOpen(false)} - onApply={handleQuickWizardApply} - /> - {/* Common Config Modal */} void; - onApply: ( - auth: string, - config: string, - extras: { - websiteUrl?: string; - displayName?: string; - }, - ) => void; -} - -/** - * CodexQuickWizardModal - Codex quick configuration wizard - * Helps users quickly generate auth.json and config.toml - */ -export const CodexQuickWizardModal: React.FC = ({ - isOpen, - onClose, - onApply, -}) => { - const { t } = useTranslation(); - - const [templateApiKey, setTemplateApiKey] = useState(""); - const [templateProviderName, setTemplateProviderName] = useState(""); - const [templateBaseUrl, setTemplateBaseUrl] = useState(""); - const [templateWebsiteUrl, setTemplateWebsiteUrl] = useState(""); - const [templateModelName, setTemplateModelName] = useState("gpt-5-codex"); - const [templateDisplayName, setTemplateDisplayName] = useState(""); - - const apiKeyInputRef = useRef(null); - const baseUrlInputRef = useRef(null); - const modelNameInputRef = useRef(null); - const displayNameInputRef = useRef(null); - - const resetForm = () => { - setTemplateApiKey(""); - setTemplateProviderName(""); - setTemplateBaseUrl(""); - setTemplateWebsiteUrl(""); - setTemplateModelName("gpt-5-codex"); - setTemplateDisplayName(""); - }; - - const handleClose = () => { - resetForm(); - onClose(); - }; - - const applyTemplate = () => { - const requiredInputs = [ - displayNameInputRef.current, - apiKeyInputRef.current, - baseUrlInputRef.current, - modelNameInputRef.current, - ]; - - for (const input of requiredInputs) { - if (input && !input.checkValidity()) { - input.reportValidity(); - input.focus(); - return; - } - } - - const trimmedKey = templateApiKey.trim(); - const trimmedBaseUrl = templateBaseUrl.trim(); - const trimmedModel = templateModelName.trim(); - - const auth = generateThirdPartyAuth(trimmedKey); - const config = generateThirdPartyConfig( - templateProviderName || "custom", - trimmedBaseUrl, - trimmedModel, - ); - - onApply(JSON.stringify(auth, null, 2), config, { - websiteUrl: templateWebsiteUrl.trim(), - displayName: templateDisplayName.trim(), - }); - - resetForm(); - onClose(); - }; - - const handleInputKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - e.preventDefault(); - e.stopPropagation(); - applyTemplate(); - } - }; - - return ( - !open && handleClose()}> - - - {t("codexConfig.quickWizard")} - - -
-
-

- {t("codexConfig.wizardHint")} -

-
- -
- {/* API Key */} -
- - setTemplateApiKey(e.target.value)} - onKeyDown={handleInputKeyDown} - pattern=".*\S.*" - title={t("common.enterValidValue")} - placeholder={t("codexConfig.apiKeyPlaceholder")} - required - className="font-mono" - /> -
- - {/* Display Name */} -
- - setTemplateDisplayName(e.target.value)} - onKeyDown={handleInputKeyDown} - placeholder={t("codexConfig.supplierNamePlaceholder")} - required - pattern=".*\S.*" - title={t("common.enterValidValue")} - /> -

- {t("codexConfig.supplierNameHint")} -

-
- - {/* Provider Name */} -
- - setTemplateProviderName(e.target.value)} - onKeyDown={handleInputKeyDown} - placeholder={t("codexConfig.supplierCodePlaceholder")} - /> -

- {t("codexConfig.supplierCodeHint")} -

-
- - {/* Base URL */} -
- - setTemplateBaseUrl(e.target.value)} - onKeyDown={handleInputKeyDown} - placeholder={t("codexConfig.apiUrlPlaceholder")} - required - className="font-mono" - /> -
- - {/* Website URL */} -
- - setTemplateWebsiteUrl(e.target.value)} - onKeyDown={handleInputKeyDown} - placeholder={t("codexConfig.websitePlaceholder")} - /> -

- {t("codexConfig.websiteHint")} -

-
- - {/* Model Name */} -
- - setTemplateModelName(e.target.value)} - onKeyDown={handleInputKeyDown} - pattern=".*\S.*" - title={t("common.enterValidValue")} - placeholder={t("codexConfig.modelNamePlaceholder")} - required - /> -
-
- - {/* Preview */} - {(templateApiKey || templateProviderName || templateBaseUrl) && ( -
-

- {t("codexConfig.configPreview")} -

-
-
- -
-                    {JSON.stringify(
-                      generateThirdPartyAuth(templateApiKey),
-                      null,
-                      2,
-                    )}
-                  
-
-
- -
-                    {templateProviderName && templateBaseUrl
-                      ? generateThirdPartyConfig(
-                          templateProviderName,
-                          templateBaseUrl,
-                          templateModelName,
-                        )
-                      : ""}
-                  
-
-
-
- )} -
- - - - - -
-
- ); -}; diff --git a/src/components/providers/forms/ProviderForm.tsx b/src/components/providers/forms/ProviderForm.tsx index 45feff7..10ef138 100644 --- a/src/components/providers/forms/ProviderForm.tsx +++ b/src/components/providers/forms/ProviderForm.tsx @@ -220,9 +220,6 @@ export function ProviderForm({ [originalHandleCodexConfigChange, debouncedValidate], ); - const [isCodexTemplateModalOpen, setIsCodexTemplateModalOpen] = - useState(false); - useEffect(() => { form.reset(defaultValues); }, [defaultValues, form]); @@ -615,11 +612,6 @@ export function ProviderForm({ onPresetChange={handlePresetChange} category={category} appId={appId} - onOpenWizard={ - appId === "codex" - ? () => setIsCodexTemplateModalOpen(true) - : undefined - } /> )} @@ -739,10 +731,6 @@ export function ProviderForm({ commonConfigError={codexCommonConfigError} authError={codexAuthError} configError={codexConfigError} - onWebsiteUrlChange={(url) => form.setValue("websiteUrl", url)} - onNameChange={(name) => form.setValue("name", name)} - isTemplateModalOpen={isCodexTemplateModalOpen} - setIsTemplateModalOpen={setIsCodexTemplateModalOpen} /> {/* 配置验证错误显示 */} ; onPresetChange: (value: string) => void; - category?: ProviderCategory; // 新增:当前选中的分类 + category?: ProviderCategory; // 当前选中的分类 appId?: AppId; - onOpenWizard?: () => void; // Codex 专用:打开配置向导 } export function ProviderPresetSelector({ @@ -32,7 +31,6 @@ export function ProviderPresetSelector({ onPresetChange, category, appId, - onOpenWizard, }: ProviderPresetSelectorProps) { const { t } = useTranslation(); @@ -56,23 +54,6 @@ export function ProviderPresetSelector({ defaultValue: "💡 第三方供应商需要填写 API Key 和请求地址", }); case "custom": - // Codex 自定义:在此位置显示"手动配置…或者 使用配置向导" - if (appId === "codex" && onOpenWizard) { - return ( - <> - {t("providerForm.manualConfig")} - - - ); - } - // 其他情况沿用原提示 return t("providerForm.customApiKeyHint", { defaultValue: "💡 自定义配置需手动填写所有必要字段", }); diff --git a/src/config/codexProviderPresets.ts b/src/config/codexProviderPresets.ts index 51dc3ca..c82f55a 100644 --- a/src/config/codexProviderPresets.ts +++ b/src/config/codexProviderPresets.ts @@ -98,6 +98,52 @@ requires_openai_auth = true`, textColor: "#FFFFFF", }, }, + { + name: "Custom (Blank Template)", + websiteUrl: "https://docs.anthropic.com", + category: "third_party", + isCustomTemplate: true, + auth: generateThirdPartyAuth(""), + config: `# ======================================== +# Codex 自定义供应商配置模板 +# ======================================== +# 快速上手: +# 1. 在上方 auth.json 中设置 API Key +# 2. 将下方 'custom' 替换为供应商名称(小写、无空格) +# 3. 替换 base_url 为实际的 API 端点 +# 4. 根据需要调整模型名称 +# +# 文档: https://docs.anthropic.com +# ======================================== + +# ========== 模型配置 ========== +model_provider = "custom" # 供应商唯一标识 +model = "gpt-5-codex" # 模型名称 +model_reasoning_effort = "high" # 推理强度:low, medium, high +disable_response_storage = true # 隐私:不本地存储响应 + +# ========== 供应商设置 ========== +[model_providers.custom] +name = "custom" # 与上方 model_provider 保持一致 +base_url = "https://api.example.com/v1" # 👈 替换为实际端点 +wire_api = "responses" # API 响应格式 +requires_openai_auth = true # 使用 auth.json 中的 OPENAI_API_KEY + +# ========== 可选:自定义请求头 ========== +# 如果供应商需要自定义请求头,取消注释: +# [model_providers.custom.headers] +# X-Custom-Header = "value" + +# ========== 可选:模型覆盖 ========== +# 如果需要覆盖特定模型,取消注释: +# [model_overrides] +# "gpt-5-codex" = { model_provider = "custom", model = "your-model-name" }`, + theme: { + icon: "generic", + backgroundColor: "#6B7280", // gray-500 + textColor: "#FFFFFF", + }, + }, { name: "AiHubMix", websiteUrl: "https://aihubmix.com", diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 01dce0f..ef12d2d 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -239,9 +239,6 @@ "codexApiEndpointPlaceholder": "https://your-api-endpoint.com/v1", "manageAndTest": "Manage & Test", "configContent": "Config Content", - "useConfigWizard": "Use Configuration Wizard", - "openConfigWizard": "Open configuration wizard", - "manualConfig": "Manually configure provider, requires complete configuration, or", "officialNoApiKey": "Official login does not require API Key, save directly", "codexOfficialNoApiKey": "Official does not require API Key, save directly", "codexApiKeyAutoFill": "Just fill in here, auth.json below will be auto-filled", @@ -314,7 +311,6 @@ "testFailed": "Speed test failed: {{error}}" }, "codexConfig": { - "quickWizard": "Quick Configuration Wizard", "authJson": "auth.json (JSON) *", "authJsonPlaceholder": "{\n \"OPENAI_API_KEY\": \"sk-your-api-key-here\"\n}", "authJsonHint": "Codex auth.json configuration content", @@ -324,24 +320,7 @@ "editCommonConfig": "Edit Common Config", "editCommonConfigTitle": "Edit Codex Common Config Snippet", "commonConfigHint": "This snippet will be appended to the end of config.toml when 'Write Common Config' is checked", - "wizardHint": "Enter key parameters, the system will automatically generate standard auth.json and config.toml configuration.", - "apiKeyLabel": "API Key *", - "apiKeyPlaceholder": "sk-your-api-key-here", - "supplierNameLabel": "Provider Name *", - "supplierNamePlaceholder": "e.g., Codex Official", - "supplierNameHint": "Will be displayed in the provider list, can use Chinese", - "supplierCodeLabel": "Provider Code (English)", - "supplierCodePlaceholder": "custom (optional)", - "supplierCodeHint": "Will be used as identifier in config file, defaults to custom", - "apiUrlLabel": "API Request URL *", - "apiUrlPlaceholder": "https://your-api-endpoint.com/v1", - "websiteLabel": "Website URL", - "websitePlaceholder": "https://example.com", - "websiteHint": "Official website address (optional)", - "modelNameLabel": "Model Name *", - "modelNamePlaceholder": "gpt-5-codex", - "configPreview": "Configuration Preview", - "applyConfig": "Apply Configuration" + "apiUrlLabel": "API Request URL" }, "geminiConfig": { "envFile": "Environment Variables (.env)", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 1d9e74d..699e0c7 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -239,9 +239,6 @@ "codexApiEndpointPlaceholder": "https://your-api-endpoint.com/v1", "manageAndTest": "管理与测速", "configContent": "配置内容", - "useConfigWizard": "使用配置向导", - "openConfigWizard": "打开配置向导", - "manualConfig": "手动配置供应商,需要填写完整的配置信息,或者", "officialNoApiKey": "官方登录无需填写 API Key,直接保存即可", "codexOfficialNoApiKey": "官方无需填写 API Key,直接保存即可", "codexApiKeyAutoFill": "只需要填这里,下方 auth.json 会自动填充", @@ -314,7 +311,6 @@ "testFailed": "测速失败: {{error}}" }, "codexConfig": { - "quickWizard": "快速配置向导", "authJson": "auth.json (JSON) *", "authJsonPlaceholder": "{\n \"OPENAI_API_KEY\": \"sk-your-api-key-here\"\n}", "authJsonHint": "Codex auth.json 配置内容", @@ -324,24 +320,7 @@ "editCommonConfig": "编辑通用配置", "editCommonConfigTitle": "编辑 Codex 通用配置片段", "commonConfigHint": "该片段会在勾选'写入通用配置'时追加到 config.toml 末尾", - "wizardHint": "输入关键参数,系统将自动生成标准的 auth.json 和 config.toml 配置。", - "apiKeyLabel": "API 密钥 *", - "apiKeyPlaceholder": "sk-your-api-key-here", - "supplierNameLabel": "供应商名称 *", - "supplierNamePlaceholder": "例如:Codex 官方", - "supplierNameHint": "将显示在供应商列表中,可使用中文", - "supplierCodeLabel": "供应商代号(英文)", - "supplierCodePlaceholder": "custom(可选)", - "supplierCodeHint": "将用作配置文件中的标识符,默认为 custom", - "apiUrlLabel": "API 请求地址 *", - "apiUrlPlaceholder": "https://your-api-endpoint.com/v1", - "websiteLabel": "官网地址", - "websitePlaceholder": "https://example.com", - "websiteHint": "官方网站地址(可选)", - "modelNameLabel": "模型名称 *", - "modelNamePlaceholder": "gpt-5-codex", - "configPreview": "配置预览", - "applyConfig": "应用配置" + "apiUrlLabel": "API 请求地址" }, "geminiConfig": { "envFile": "环境变量 (.env)",