From 48f089cdc7504ab179c5ea7b7781ecdf2f4215b7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Jul 2026 08:53:33 +0800 Subject: [PATCH] fix(ai): normalize OpenAI-compatible API base to /v1 Accept gateway root URLs like https://llm.example.com and auto-append /v1 so NewAPI-style providers work; update Extension AI help text accordingly. --- .../src/pages/extensions/ExtensionAI.vue | 7 ++-- inc/classes/class-aksrt-ai.php | 33 +++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/assets/admin/src/pages/extensions/ExtensionAI.vue b/assets/admin/src/pages/extensions/ExtensionAI.vue index 11434b2e..7205b031 100644 --- a/assets/admin/src/pages/extensions/ExtensionAI.vue +++ b/assets/admin/src/pages/extensions/ExtensionAI.vue @@ -47,7 +47,7 @@

主题 Provider 配置(回退链路)

-

当站点已配置 WordPress AI Connectors 时,生成会优先走核心客户端;以下配置作为兼容回退。

+

已配置主题 Provider 时优先走下方接口;未配置时才尝试 WordPress AI Connectors。NewAPI/兼容网关请填到 /v1(也可只填域名,保存时会自动补全)。

- + +

示例:https://api.openai.com/v1 或 https://你的网关/v1(不要填到 /chat/completions)

@@ -117,7 +118,7 @@

重要说明

  • AI 输出仅作为建议,不会自动写库;需用户点「更新/提交」才保存
  • -
  • 优先使用 WordPress AI Connectors;主题 API Key 为兼容回退
  • +
  • 主题 API Key 已配置时优先使用;否则回退 WordPress AI Connectors
  • 生成接口要求登录与编辑/投稿权限;配置接口仍需管理员
diff --git a/inc/classes/class-aksrt-ai.php b/inc/classes/class-aksrt-ai.php index 7906a0fd..e1c5e6cc 100644 --- a/inc/classes/class-aksrt-ai.php +++ b/inc/classes/class-aksrt-ai.php @@ -62,7 +62,7 @@ class AKSRT_AI { $merged['enabled'] = !empty($merged['enabled']); $merged['provider'] = sanitize_key((string) ($merged['provider'] ?? self::PROVIDER_NONE)); $merged['api_key'] = (string) ($merged['api_key'] ?? ''); - $merged['api_base'] = esc_url_raw((string) ($merged['api_base'] ?? 'https://api.openai.com/v1')); + $merged['api_base'] = $this->normalize_api_base((string) ($merged['api_base'] ?? 'https://api.openai.com/v1')); $merged['model'] = sanitize_text_field((string) ($merged['model'] ?? 'gpt-3.5-turbo')); $merged['max_tokens'] = max(100, min(4000, (int) ($merged['max_tokens'] ?? 1000))); $merged['rate_limit'] = max(1, min(100, (int) ($merged['rate_limit'] ?? 10))); @@ -294,11 +294,40 @@ class AKSRT_AI { } } + /** + * Normalize OpenAI-compatible base URL. + * + * Accepts gateway root (https://host), /v1, trailing slash, or full + * .../chat/completions and returns a base that can append /chat/completions. + */ + public function normalize_api_base(string $api_base): string { + $api_base = trim($api_base); + if ($api_base === '') { + return 'https://api.openai.com/v1'; + } + + $api_base = esc_url_raw($api_base); + $api_base = rtrim($api_base, '/'); + + // If user pasted the full chat endpoint, strip the leaf. + if (preg_match('#/chat/completions$#i', $api_base)) { + $api_base = (string) preg_replace('#/chat/completions$#i', '', $api_base); + $api_base = rtrim($api_base, '/'); + } + + // Common gateways (NewAPI etc.): root host needs /v1. + if (!preg_match('#/(v1|openai/v1)$#i', $api_base)) { + $api_base .= '/v1'; + } + + return rtrim($api_base, '/'); + } + private function generate_via_theme(string $prompt, string $system, array $options): array { $config = $this->get_config(); $max_tokens = (int) ($options['max_tokens'] ?? $config['max_tokens']); $temperature = (float) ($options['temperature'] ?? 0.7); - $api_base = rtrim((string) $config['api_base'], '/'); + $api_base = $this->normalize_api_base((string) $config['api_base']); $response = wp_remote_post($api_base . '/chat/completions', [ 'headers' => [