From 12112e9d7d3841b6edbda8b598955dcadd353e04 Mon Sep 17 00:00:00 2001 From: Jason Date: Sun, 16 Nov 2025 13:23:53 +0800 Subject: [PATCH] refactor(codex): extract template to config with i18n support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Changes:** - Create src/config/codexTemplates.ts with getCodexCustomTemplate factory - Support both Chinese and English templates based on i18n.language - Remove 70 lines of duplicated template strings from ProviderForm.tsx - Update both useEffect and handlePresetChange to use template factory - Clean up unused "Custom (Blank Template)" preset entry **Benefits:** - ✅ Eliminates code duplication (35-line template repeated twice) - ✅ Adds internationalization support for English users - ✅ Follows project architecture (templates in config/ directory) - ✅ Improves maintainability (single source of truth) - ✅ Net reduction: 34 lines (81 additions, 115 deletions) **Technical Details:** - Template selection logic: (i18n.language || "zh").startsWith("zh") ? "zh" : "en" - Templates are identical except for comments language - Both auth and config are returned as a single CodexTemplate object Addresses DRY principle violation and architectural concerns identified in code review. --- .../providers/forms/ProviderForm.tsx | 18 +++- src/config/codexProviderPresets.ts | 46 --------- src/config/codexTemplates.ts | 95 +++++++++++++++++++ 3 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 src/config/codexTemplates.ts diff --git a/src/components/providers/forms/ProviderForm.tsx b/src/components/providers/forms/ProviderForm.tsx index 10ef138..3a47653 100644 --- a/src/components/providers/forms/ProviderForm.tsx +++ b/src/components/providers/forms/ProviderForm.tsx @@ -21,6 +21,7 @@ import { } from "@/config/geminiProviderPresets"; import { applyTemplateValues } from "@/utils/providerConfigUtils"; import { mergeProviderMeta } from "@/utils/providerMetaUtils"; +import { getCodexCustomTemplate } from "@/config/codexTemplates"; import CodexConfigEditor from "./CodexConfigEditor"; import { CommonConfigEditor } from "./CommonConfigEditor"; import GeminiConfigEditor from "./GeminiConfigEditor"; @@ -89,7 +90,7 @@ export function ProviderForm({ initialData, showButtons = true, }: ProviderFormProps) { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const isEditMode = Boolean(initialData); const [selectedPresetId, setSelectedPresetId] = useState( @@ -220,6 +221,15 @@ export function ProviderForm({ [originalHandleCodexConfigChange, debouncedValidate], ); + // Codex 新建模式:初始化时自动填充模板(支持国际化) + useEffect(() => { + if (appId === "codex" && !initialData && selectedPresetId === "custom") { + const locale = (i18n.language || "zh").startsWith("zh") ? "zh" : "en"; + const template = getCodexCustomTemplate(locale); + resetCodexConfig(template.auth, template.config); + } + }, [appId, initialData, selectedPresetId, resetCodexConfig, i18n.language]); + useEffect(() => { form.reset(defaultValues); }, [defaultValues, form]); @@ -525,9 +535,11 @@ export function ProviderForm({ setActivePreset(null); form.reset(defaultValues); - // Codex 自定义模式:重置为空配置 + // Codex 自定义模式:加载模板(支持国际化) if (appId === "codex") { - resetCodexConfig({}, ""); + const locale = (i18n.language || "zh").startsWith("zh") ? "zh" : "en"; + const template = getCodexCustomTemplate(locale); + resetCodexConfig(template.auth, template.config); } // Gemini 自定义模式:重置为空配置 if (appId === "gemini") { diff --git a/src/config/codexProviderPresets.ts b/src/config/codexProviderPresets.ts index c82f55a..51dc3ca 100644 --- a/src/config/codexProviderPresets.ts +++ b/src/config/codexProviderPresets.ts @@ -98,52 +98,6 @@ 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/config/codexTemplates.ts b/src/config/codexTemplates.ts new file mode 100644 index 0000000..1d1a9b0 --- /dev/null +++ b/src/config/codexTemplates.ts @@ -0,0 +1,95 @@ +/** + * Codex 配置模板 + * 用于新建自定义供应商时的默认配置 + */ + +export interface CodexTemplate { + auth: Record; + config: string; +} + +/** + * 获取 Codex 自定义模板 + * @param locale 语言环境 ('zh' | 'en') + * @returns Codex 模板配置 + */ +export function getCodexCustomTemplate( + locale: "zh" | "en" = "zh", +): CodexTemplate { + const templates = { + zh: `# ======================================== +# 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" }`, + + en: `# ======================================== +# Codex Custom Provider Configuration Template +# ======================================== +# Quick Start: +# 1. Set API Key in auth.json above +# 2. Replace 'custom' below with provider name (lowercase, no spaces) +# 3. Replace base_url with actual API endpoint +# 4. Adjust model name as needed +# +# Docs: https://docs.anthropic.com +# ======================================== + +# ========== Model Configuration ========== +model_provider = "custom" # Unique provider identifier +model = "gpt-5-codex" # Model name +model_reasoning_effort = "high" # Reasoning effort: low, medium, high +disable_response_storage = true # Privacy: do not store responses locally + +# ========== Provider Settings ========== +[model_providers.custom] +name = "custom" # Must match model_provider above +base_url = "https://api.example.com/v1" # 👈 Replace with actual endpoint +wire_api = "responses" # API response format +requires_openai_auth = true # Use OPENAI_API_KEY from auth.json + +# ========== Optional: Custom Headers ========== +# If provider requires custom headers, uncomment: +# [model_providers.custom.headers] +# X-Custom-Header = "value" + +# ========== Optional: Model Overrides ========== +# If you need to override specific models, uncomment: +# [model_overrides] +# "gpt-5-codex" = { model_provider = "custom", model = "your-model-name" }`, + }; + + return { + auth: { OPENAI_API_KEY: "" }, + config: templates[locale] || templates.zh, + }; +}