Plugin Directory

Changeset 3451583


Ignore:
Timestamp:
02/01/2026 08:20:52 PM (3 weeks ago)
Author:
gkanters
Message:

Version 2.2.4

Location:
ai-translate
Files:
7 edited
42 copied

Legend:

Unmodified
Added
Removed
  • ai-translate/tags/2.2.4/README.md

    r3451503 r3451583  
    11=== AI Translate ===
    22Contributors: gkanters 
    3 Tags: translation, multilingual, woocommerce, seo, artificial intelligence, ai
     3Tags: translation, multilingual, woocommerce, seo, artificial intelligence 
    44Requires at least: 5.0 
    55Tested up to: 6.9 
    6 Stable tag: 2.2.3
     6Stable tag: 2.2.4
    77Requires PHP: 8.0
    88License: GPLv2 or later 
     
    184184## Changelog
    185185
    186 ### 2.2.3
     186### 2.2.4
    187187
    188188- Added cache warming for pages to admin.
  • ai-translate/tags/2.2.4/ai-translate.php

    r3451123 r3451583  
    66 * Author: NetCare
    77 * Author URI: https://netcare.nl/
    8  * Version: 2.2.3
     8 * Version: 2.2.4
    99 * Requires at least: 5.0
    1010 * Tested up to: 6.9
  • ai-translate/tags/2.2.4/docs/readme-ja_JP.po

    r3451499 r3451583  
    2626msgstr "35言語で自動ウェブサイト翻訳を可能にするAI搭載プラグイン。トラフィックを増やし、SEOを改善します。"
    2727
    28 #. Short Description
    29 msgid "AI-powered translation for WordPress & WooCommerce. Automatically translate your site in 35+ languages with your brand's unique tone of voice. Fast caching, SEO-friendly, and cost-effective."
    30 msgstr "WordPress & WooCommerce向けのAI翻訳。35以上の言語でサイトを自動翻訳し、ブランドの独自のトーンで表現。高速キャッシュ、SEO対応、コスト効率に優れています。"
    31 
    3228#. Description
    3329msgid "AI Translate automatically makes your WordPress website available in 35+ languages. Increase your reach and improve your SEO without manual work."
  • ai-translate/tags/2.2.4/docs/readme-pt_PT.po

    r3451499 r3451583  
    2626msgstr "Plugin alimentado por IA para tradução automática de sites em 35 idiomas. Aumenta o tráfego e melhora o seu SEO."
    2727
    28 #. Short Description
    29 msgid "AI-powered translation for WordPress & WooCommerce. Automatically translate your site in 35+ languages with your brand's unique tone of voice. Fast caching, SEO-friendly, and cost-effective."
    30 msgstr "Tradução com IA para WordPress e WooCommerce. Traduza automaticamente o seu site em mais de 35 idiomas com o tom de voz único da sua marca. Cache rápido, otimizado para SEO e económico."
    31 
    3228#. Description
    3329msgid "AI Translate automatically makes your WordPress website available in 35+ languages. Increase your reach and improve your SEO without manual work."
  • ai-translate/tags/2.2.4/includes/admin-page.php

    r3451503 r3451583  
    23892389    // OpenRouter requires Referer header
    23902390    if ($provider_key === 'openrouter' || ($provider_key === 'custom' && strpos($api_url, 'openrouter.ai') !== false)) {
    2391         $headers['Referer'] = home_url();
    2392         $headers['X-Title'] = get_bloginfo('name');
     2391        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
     2392        $headers['X-Title'] = 'AI Translate';
    23932393    }
    23942394    $response = wp_remote_get($endpoint, [
     
    24202420    }, $data['data']);
    24212421    $models = array_filter($models);
    2422     // Block only o1/o3 (no reasoning_effort support); gpt-5 models allowed
    2423     $models = array_filter($models, function($model) {
     2422    // o1/o3 reasoning models don't support temperature; block from selection to avoid API errors
     2423    $models = array_filter($models, function ($model) {
    24242424        return !preg_match('/^(o1-|o3-)/i', $model);
    24252425    });
  • ai-translate/tags/2.2.4/includes/class-ai-batch.php

    r3451123 r3451583  
    1010    /**
    1111     * Translate a plan's segments using configured provider.
    12      * GPT-5 models use reasoning_effort=minimal for fast translations.
    13      * Blocked: o1, o3 (no reasoning_effort parameter support).
    1412     *
    1513     * @param array $plan
     
    2523
    2624        $timeLimit = (int) ini_get('max_execution_time');
    27         $elapsed = microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true));
     25        $requestTime = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(true);
     26        $elapsed = microtime(true) - $requestTime;
    2827        $remaining = $timeLimit > 0 ? ($timeLimit - $elapsed) : 60;
    2928        if ($remaining < 15) {
     
    3736        $apiKeys = isset($settings['api_keys']) && is_array($settings['api_keys']) ? $settings['api_keys'] : [];
    3837        $apiKey = $provider !== '' ? ($apiKeys[$provider] ?? '') : '';
    39 
    40         // Block o1/o3 reasoning models: they don't support reasoning_effort parameter
    41         if ($model !== '' && preg_match('/^(o1-|o3-)/i', $model)) {
    42             return ['segments' => [], 'map' => []];
    43         }
    4438
    4539        if (empty($segments)) {
     
    204198                        ],
    205199                    ];
    206                     // Newer models (gpt-5.x, o1-series, o3-series) and DeepSeek v3.2 use max_completion_tokens instead of max_tokens
    207                     // These models also don't support temperature != 1, so we omit it
    208                     if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    209                         $body['max_completion_tokens'] = 4096;
    210                         // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    211                         if (str_starts_with($model, 'gpt-5')) {
    212                             $body['reasoning_effort'] = 'minimal';
    213                         }
    214                     } else {
    215                         $body['max_tokens'] = 4096;
    216                         $body['temperature'] = 0;
    217                     }
     200                    $body['temperature'] = 0;
    218201                    $headers = [ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json' ];
    219202                    // OpenRouter requires Referer header (WordPress adds HTTP- prefix automatically)
     
    245228                        foreach ($batchesSingle as $i => $batchSegs2) {
    246229                            $userPayload = self::buildUserPayload($batchSegs2);
    247                             $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $system], ['role' => 'user', 'content' => $userPayload] ] ];
    248                             if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    249                                 $body['max_completion_tokens'] = 4096;
    250                                 // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    251                                 if (str_starts_with($model, 'gpt-5')) {
    252                                     $body['reasoning_effort'] = 'minimal';
    253                                 }
    254                             } else {
    255                                 $body['max_tokens'] = 4096;
    256                                 $body['temperature'] = 0;
    257                             }
     230                            $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $system], ['role' => 'user', 'content' => $userPayload] ] ];                            $body['temperature'] = 0;
    258231                            $fallbackHeaders = [ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json' ];
    259232                            if ($provider === 'custom' && isset($settings['custom_api_url']) && strpos($settings['custom_api_url'], 'openrouter.ai') !== false) {
     
    460433                    foreach ($retryChunks as $rc) {
    461434                        $userPayload = self::buildUserPayload($rc);
    462                         $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $strictSystem], ['role' => 'user', 'content' => $userPayload] ] ];
    463                         if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    464                             $body['max_completion_tokens'] = 4096;
    465                             // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    466                             if (str_starts_with($model, 'gpt-5')) {
    467                                 $body['reasoning_effort'] = 'minimal';
    468                             }
    469                         } else {
    470                             $body['max_tokens'] = 4096;
    471                             $body['temperature'] = 0;
    472                         }
     435                        $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $strictSystem], ['role' => 'user', 'content' => $userPayload] ] ];                       
     436                        $body['temperature'] = 0;
    473437                        $retryHeaders = [ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json' ];
    474438                        if ($provider === 'custom' && isset($settings['custom_api_url']) && strpos($settings['custom_api_url'], 'openrouter.ai') !== false) {
     
    556520                ],
    557521            ];
    558             // Newer models (gpt-5.x, o1-series, o3-series) use max_completion_tokens instead of max_tokens
    559             // DeepSeek v3.2 also uses max_completion_tokens
    560             // These models also don't support temperature != 1, so we omit it
    561             if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    562                 $body['max_completion_tokens'] = 4096;
    563                 // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    564                 if (str_starts_with($model, 'gpt-5')) {
    565                     $body['reasoning_effort'] = 'minimal';
    566                 }
    567             } else {
    568                 $body['max_tokens'] = 4096;
     522            if (!preg_match('/^(o1-|o3-)/i', $model)) {
    569523                $body['temperature'] = 0;
    570524            }
     
    576530            do {
    577531                $attempts++;
    578                 $timeRemaining = $timeLimit > 0 ? ($timeLimit - (microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true)))) : 60;
     532                $requestTime = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(true);
     533                $timeRemaining = $timeLimit > 0 ? ($timeLimit - (microtime(true) - $requestTime)) : 60;
    579534                $safeTimeout = min($timeoutSeconds, max(10, (int)($timeRemaining - 10)));
    580535               
     
    723678                    $userPayload = self::buildUserPayload($rc);
    724679                    $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $strictSystem], ['role' => 'user', 'content' => $userPayload] ] ];
    725                     if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    726                         $body['max_completion_tokens'] = 4096;
    727                         // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    728                         if (str_starts_with($model, 'gpt-5')) {
    729                             $body['reasoning_effort'] = 'minimal';
    730                         }
    731                     } else {
    732                         $body['max_tokens'] = 4096;
     680                    if (!preg_match('/^(o1-|o3-)/i', $model)) {
    733681                        $body['temperature'] = 0;
    734682                    }
  • ai-translate/tags/2.2.4/includes/class-ai-translate-core.php

    r3451499 r3451583  
    104104        // OpenRouter requires Referer header
    105105        if ($provider_key === 'custom' && strpos($custom_api_url, 'openrouter.ai') !== false) {
    106             $headers['Referer'] = home_url();
    107             $headers['X-Title'] = get_bloginfo('name');
     106            $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
     107            $headers['X-Title'] = 'AI Translate';
    108108        }
    109109        $resp = wp_remote_get($endpoint, [
     
    153153            // OpenRouter requires Referer header
    154154            if ($provider_key === 'custom' && strpos($custom_api_url, 'openrouter.ai') !== false) {
    155                 $chatHeaders['Referer'] = home_url();
    156                 $chatHeaders['X-Title'] = get_bloginfo('name');
     155                $chatHeaders['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
     156                $chatHeaders['X-Title'] = 'AI Translate';
    157157            }
    158158            $chatBody = [
     
    162162                ],
    163163            ];
    164             // Chat test: ruime limiet voor alle models inclusief reasoning models
    165             $chatBody['max_completion_tokens'] = 10000;
    166164            $chatResp = wp_remote_post($chatEndpoint, [
    167165                'headers' => $chatHeaders,
     
    856854                       
    857855                        if (!empty($content)) {
    858                             if (defined('WP_DEBUG') && WP_DEBUG) {
    859                                 error_log('AI Translate: Fetched content from domain ' . $domain . ' (length: ' . mb_strlen($content) . ')');
    860                             }
    861856                            return $content;
    862857                        }
     
    877872        $content = '';
    878873        $home_id = (int) get_option('page_on_front');
    879         $site_name = (string) get_bloginfo('name');
     874        $site_name = (string) 'AI Translate';
    880875       
    881876        if ($home_id > 0) {
     
    989984            }
    990985        } else {
    991             $site_name = (string) get_bloginfo('name');
     986            $site_name = (string) 'AI Translate';
    992987        }
    993988
     
    10131008                    ],
    10141009                ];
    1015 
    1016                 // Token limits - ruime limiet voor alle models (je betaalt alleen wat je gebruikt)
    1017                 $body['max_completion_tokens'] = 16000;
     1010                if ($provider === 'openrouter' || ($provider === 'custom' && strpos($baseUrl, 'openrouter.ai') !== false)) {
     1011                    $body['user'] = !empty($domain) ? $domain : parse_url(home_url(), PHP_URL_HOST);
     1012                }
    10181013
    10191014                $headers = [
     
    10291024                            $protocol = sanitize_text_field(wp_unslash($_SERVER['REQUEST_SCHEME']));
    10301025                        }
    1031                         $headers['Referer'] = $protocol . '://' . $domain . '/';
     1026                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    10321027                    } else {
    1033                         $headers['Referer'] = home_url();
     1028                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    10341029                    }
    1035                     $headers['X-Title'] = $site_name;
     1030                    $headers['X-Title'] = 'AI Translate';
    10361031                }
    10371032
     
    11251120                $site_name = strtok($domain, ':');
    11261121            }
    1127            
    1128             if (defined('WP_DEBUG') && WP_DEBUG) {
    1129                 error_log('AI Translate: Using domain-specific site name for ' . $domain . ': ' . $site_name);
    1130             }
    11311122        } else {
    1132             $site_name = (string) get_bloginfo('name');
     1123            $site_name = (string) 'AI Translate';
    11331124        }
    11341125       
     
    11591150                          "Website Content:\n" . $content . $context_section;
    11601151
     1152                $metaModel = (stripos($model, 'gpt-5') !== false) ? 'gpt-4.1-mini' : $model;
    11611153                $body = [
    1162                     'model' => $model,
     1154                    'model' => $metaModel,
    11631155                    'messages' => [
    11641156                        ['role' => 'system', 'content' => 'You are an expert SEO copywriter specializing in writing compelling, keyword-rich meta descriptions that drive click-through rates. You understand that generic descriptions hurt SEO performance.'],
     
    11661158                    ],
    11671159                ];
    1168 
    1169                 // Token limits - ruime limiet voor alle models (je betaalt alleen wat je gebruikt)
    1170                 $body['max_completion_tokens'] = 16000;
     1160                $m = strtolower((string) $model);
     1161                if ($m !== '' && strpos($m, 'gpt-5') === false) {
     1162                    if (strpos($m, 'o1-') === 0 || strpos($m, 'o3-') === 0) {
     1163                        $body['thinking'] = false;
     1164                    } elseif (strpos($m, 'deepseek-r1') !== false || strpos($m, 'deepseek-reasoner') !== false) {
     1165                        $body['thinking'] = array('type' => 'disabled');
     1166                    }
     1167                }
     1168                if ($provider === 'openrouter' || ($provider === 'custom' && strpos($baseUrl, 'openrouter.ai') !== false)) {
     1169                    $body['user'] = !empty($domain) ? $domain : parse_url(home_url(), PHP_URL_HOST);
     1170                }
    11711171
    11721172                $headers = [
     
    11821182                            $protocol = sanitize_text_field(wp_unslash($_SERVER['REQUEST_SCHEME']));
    11831183                        }
    1184                         $headers['Referer'] = $protocol . '://' . $domain . '/';
     1184                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    11851185                    } else {
    1186                         $headers['Referer'] = home_url();
     1186                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    11871187                    }
    1188                     $headers['X-Title'] = $site_name;
    1189                 }
    1190 
     1188                    $headers['X-Title'] = 'AI Translate';
     1189                }
     1190
     1191                // Shorter timeout for meta descriptions (simple task; reasoning minimized above).
    11911192                $response = wp_remote_post($endpoint, [
    11921193                    'headers' => $headers,
    1193                     'timeout' => 45,
     1194                    'timeout' => 60,
    11941195                    'sslverify' => true,
    11951196                    'body' => wp_json_encode($body),
  • ai-translate/trunk/README.md

    r3451503 r3451583  
    11=== AI Translate ===
    22Contributors: gkanters 
    3 Tags: translation, multilingual, woocommerce, seo, artificial intelligence, ai
     3Tags: translation, multilingual, woocommerce, seo, artificial intelligence 
    44Requires at least: 5.0 
    55Tested up to: 6.9 
    6 Stable tag: 2.2.3
     6Stable tag: 2.2.4
    77Requires PHP: 8.0
    88License: GPLv2 or later 
     
    184184## Changelog
    185185
    186 ### 2.2.3
     186### 2.2.4
    187187
    188188- Added cache warming for pages to admin.
  • ai-translate/trunk/ai-translate.php

    r3451123 r3451583  
    66 * Author: NetCare
    77 * Author URI: https://netcare.nl/
    8  * Version: 2.2.3
     8 * Version: 2.2.4
    99 * Requires at least: 5.0
    1010 * Tested up to: 6.9
  • ai-translate/trunk/docs/readme-ja_JP.po

    r3451499 r3451583  
    2626msgstr "35言語で自動ウェブサイト翻訳を可能にするAI搭載プラグイン。トラフィックを増やし、SEOを改善します。"
    2727
    28 #. Short Description
    29 msgid "AI-powered translation for WordPress & WooCommerce. Automatically translate your site in 35+ languages with your brand's unique tone of voice. Fast caching, SEO-friendly, and cost-effective."
    30 msgstr "WordPress & WooCommerce向けのAI翻訳。35以上の言語でサイトを自動翻訳し、ブランドの独自のトーンで表現。高速キャッシュ、SEO対応、コスト効率に優れています。"
    31 
    3228#. Description
    3329msgid "AI Translate automatically makes your WordPress website available in 35+ languages. Increase your reach and improve your SEO without manual work."
  • ai-translate/trunk/docs/readme-pt_PT.po

    r3451499 r3451583  
    2626msgstr "Plugin alimentado por IA para tradução automática de sites em 35 idiomas. Aumenta o tráfego e melhora o seu SEO."
    2727
    28 #. Short Description
    29 msgid "AI-powered translation for WordPress & WooCommerce. Automatically translate your site in 35+ languages with your brand's unique tone of voice. Fast caching, SEO-friendly, and cost-effective."
    30 msgstr "Tradução com IA para WordPress e WooCommerce. Traduza automaticamente o seu site em mais de 35 idiomas com o tom de voz único da sua marca. Cache rápido, otimizado para SEO e económico."
    31 
    3228#. Description
    3329msgid "AI Translate automatically makes your WordPress website available in 35+ languages. Increase your reach and improve your SEO without manual work."
  • ai-translate/trunk/includes/admin-page.php

    r3451503 r3451583  
    23892389    // OpenRouter requires Referer header
    23902390    if ($provider_key === 'openrouter' || ($provider_key === 'custom' && strpos($api_url, 'openrouter.ai') !== false)) {
    2391         $headers['Referer'] = home_url();
    2392         $headers['X-Title'] = get_bloginfo('name');
     2391        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
     2392        $headers['X-Title'] = 'AI Translate';
    23932393    }
    23942394    $response = wp_remote_get($endpoint, [
     
    24202420    }, $data['data']);
    24212421    $models = array_filter($models);
    2422     // Block only o1/o3 (no reasoning_effort support); gpt-5 models allowed
    2423     $models = array_filter($models, function($model) {
     2422    // o1/o3 reasoning models don't support temperature; block from selection to avoid API errors
     2423    $models = array_filter($models, function ($model) {
    24242424        return !preg_match('/^(o1-|o3-)/i', $model);
    24252425    });
  • ai-translate/trunk/includes/class-ai-batch.php

    r3451123 r3451583  
    1010    /**
    1111     * Translate a plan's segments using configured provider.
    12      * GPT-5 models use reasoning_effort=minimal for fast translations.
    13      * Blocked: o1, o3 (no reasoning_effort parameter support).
    1412     *
    1513     * @param array $plan
     
    2523
    2624        $timeLimit = (int) ini_get('max_execution_time');
    27         $elapsed = microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true));
     25        $requestTime = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(true);
     26        $elapsed = microtime(true) - $requestTime;
    2827        $remaining = $timeLimit > 0 ? ($timeLimit - $elapsed) : 60;
    2928        if ($remaining < 15) {
     
    3736        $apiKeys = isset($settings['api_keys']) && is_array($settings['api_keys']) ? $settings['api_keys'] : [];
    3837        $apiKey = $provider !== '' ? ($apiKeys[$provider] ?? '') : '';
    39 
    40         // Block o1/o3 reasoning models: they don't support reasoning_effort parameter
    41         if ($model !== '' && preg_match('/^(o1-|o3-)/i', $model)) {
    42             return ['segments' => [], 'map' => []];
    43         }
    4438
    4539        if (empty($segments)) {
     
    204198                        ],
    205199                    ];
    206                     // Newer models (gpt-5.x, o1-series, o3-series) and DeepSeek v3.2 use max_completion_tokens instead of max_tokens
    207                     // These models also don't support temperature != 1, so we omit it
    208                     if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    209                         $body['max_completion_tokens'] = 4096;
    210                         // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    211                         if (str_starts_with($model, 'gpt-5')) {
    212                             $body['reasoning_effort'] = 'minimal';
    213                         }
    214                     } else {
    215                         $body['max_tokens'] = 4096;
    216                         $body['temperature'] = 0;
    217                     }
     200                    $body['temperature'] = 0;
    218201                    $headers = [ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json' ];
    219202                    // OpenRouter requires Referer header (WordPress adds HTTP- prefix automatically)
     
    245228                        foreach ($batchesSingle as $i => $batchSegs2) {
    246229                            $userPayload = self::buildUserPayload($batchSegs2);
    247                             $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $system], ['role' => 'user', 'content' => $userPayload] ] ];
    248                             if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    249                                 $body['max_completion_tokens'] = 4096;
    250                                 // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    251                                 if (str_starts_with($model, 'gpt-5')) {
    252                                     $body['reasoning_effort'] = 'minimal';
    253                                 }
    254                             } else {
    255                                 $body['max_tokens'] = 4096;
    256                                 $body['temperature'] = 0;
    257                             }
     230                            $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $system], ['role' => 'user', 'content' => $userPayload] ] ];                            $body['temperature'] = 0;
    258231                            $fallbackHeaders = [ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json' ];
    259232                            if ($provider === 'custom' && isset($settings['custom_api_url']) && strpos($settings['custom_api_url'], 'openrouter.ai') !== false) {
     
    460433                    foreach ($retryChunks as $rc) {
    461434                        $userPayload = self::buildUserPayload($rc);
    462                         $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $strictSystem], ['role' => 'user', 'content' => $userPayload] ] ];
    463                         if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    464                             $body['max_completion_tokens'] = 4096;
    465                             // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    466                             if (str_starts_with($model, 'gpt-5')) {
    467                                 $body['reasoning_effort'] = 'minimal';
    468                             }
    469                         } else {
    470                             $body['max_tokens'] = 4096;
    471                             $body['temperature'] = 0;
    472                         }
     435                        $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $strictSystem], ['role' => 'user', 'content' => $userPayload] ] ];                       
     436                        $body['temperature'] = 0;
    473437                        $retryHeaders = [ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json' ];
    474438                        if ($provider === 'custom' && isset($settings['custom_api_url']) && strpos($settings['custom_api_url'], 'openrouter.ai') !== false) {
     
    556520                ],
    557521            ];
    558             // Newer models (gpt-5.x, o1-series, o3-series) use max_completion_tokens instead of max_tokens
    559             // DeepSeek v3.2 also uses max_completion_tokens
    560             // These models also don't support temperature != 1, so we omit it
    561             if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    562                 $body['max_completion_tokens'] = 4096;
    563                 // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    564                 if (str_starts_with($model, 'gpt-5')) {
    565                     $body['reasoning_effort'] = 'minimal';
    566                 }
    567             } else {
    568                 $body['max_tokens'] = 4096;
     522            if (!preg_match('/^(o1-|o3-)/i', $model)) {
    569523                $body['temperature'] = 0;
    570524            }
     
    576530            do {
    577531                $attempts++;
    578                 $timeRemaining = $timeLimit > 0 ? ($timeLimit - (microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true)))) : 60;
     532                $requestTime = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(true);
     533                $timeRemaining = $timeLimit > 0 ? ($timeLimit - (microtime(true) - $requestTime)) : 60;
    579534                $safeTimeout = min($timeoutSeconds, max(10, (int)($timeRemaining - 10)));
    580535               
     
    723678                    $userPayload = self::buildUserPayload($rc);
    724679                    $body = [ 'model' => $model, 'messages' => [ ['role' => 'system', 'content' => $strictSystem], ['role' => 'user', 'content' => $userPayload] ] ];
    725                     if (str_starts_with($model, 'gpt-5') || str_starts_with($model, 'o1-') || str_starts_with($model, 'o3-') || str_starts_with($model, 'deepseek/deepseek-v3')) {
    726                         $body['max_completion_tokens'] = 4096;
    727                         // GPT-5 models: use minimal reasoning for translations (fast, no extended thinking)
    728                         if (str_starts_with($model, 'gpt-5')) {
    729                             $body['reasoning_effort'] = 'minimal';
    730                         }
    731                     } else {
    732                         $body['max_tokens'] = 4096;
     680                    if (!preg_match('/^(o1-|o3-)/i', $model)) {
    733681                        $body['temperature'] = 0;
    734682                    }
  • ai-translate/trunk/includes/class-ai-translate-core.php

    r3451499 r3451583  
    104104        // OpenRouter requires Referer header
    105105        if ($provider_key === 'custom' && strpos($custom_api_url, 'openrouter.ai') !== false) {
    106             $headers['Referer'] = home_url();
    107             $headers['X-Title'] = get_bloginfo('name');
     106            $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
     107            $headers['X-Title'] = 'AI Translate';
    108108        }
    109109        $resp = wp_remote_get($endpoint, [
     
    153153            // OpenRouter requires Referer header
    154154            if ($provider_key === 'custom' && strpos($custom_api_url, 'openrouter.ai') !== false) {
    155                 $chatHeaders['Referer'] = home_url();
    156                 $chatHeaders['X-Title'] = get_bloginfo('name');
     155                $chatHeaders['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
     156                $chatHeaders['X-Title'] = 'AI Translate';
    157157            }
    158158            $chatBody = [
     
    162162                ],
    163163            ];
    164             // Chat test: ruime limiet voor alle models inclusief reasoning models
    165             $chatBody['max_completion_tokens'] = 10000;
    166164            $chatResp = wp_remote_post($chatEndpoint, [
    167165                'headers' => $chatHeaders,
     
    856854                       
    857855                        if (!empty($content)) {
    858                             if (defined('WP_DEBUG') && WP_DEBUG) {
    859                                 error_log('AI Translate: Fetched content from domain ' . $domain . ' (length: ' . mb_strlen($content) . ')');
    860                             }
    861856                            return $content;
    862857                        }
     
    877872        $content = '';
    878873        $home_id = (int) get_option('page_on_front');
    879         $site_name = (string) get_bloginfo('name');
     874        $site_name = (string) 'AI Translate';
    880875       
    881876        if ($home_id > 0) {
     
    989984            }
    990985        } else {
    991             $site_name = (string) get_bloginfo('name');
     986            $site_name = (string) 'AI Translate';
    992987        }
    993988
     
    10131008                    ],
    10141009                ];
    1015 
    1016                 // Token limits - ruime limiet voor alle models (je betaalt alleen wat je gebruikt)
    1017                 $body['max_completion_tokens'] = 16000;
     1010                if ($provider === 'openrouter' || ($provider === 'custom' && strpos($baseUrl, 'openrouter.ai') !== false)) {
     1011                    $body['user'] = !empty($domain) ? $domain : parse_url(home_url(), PHP_URL_HOST);
     1012                }
    10181013
    10191014                $headers = [
     
    10291024                            $protocol = sanitize_text_field(wp_unslash($_SERVER['REQUEST_SCHEME']));
    10301025                        }
    1031                         $headers['Referer'] = $protocol . '://' . $domain . '/';
     1026                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    10321027                    } else {
    1033                         $headers['Referer'] = home_url();
     1028                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    10341029                    }
    1035                     $headers['X-Title'] = $site_name;
     1030                    $headers['X-Title'] = 'AI Translate';
    10361031                }
    10371032
     
    11251120                $site_name = strtok($domain, ':');
    11261121            }
    1127            
    1128             if (defined('WP_DEBUG') && WP_DEBUG) {
    1129                 error_log('AI Translate: Using domain-specific site name for ' . $domain . ': ' . $site_name);
    1130             }
    11311122        } else {
    1132             $site_name = (string) get_bloginfo('name');
     1123            $site_name = (string) 'AI Translate';
    11331124        }
    11341125       
     
    11591150                          "Website Content:\n" . $content . $context_section;
    11601151
     1152                $metaModel = (stripos($model, 'gpt-5') !== false) ? 'gpt-4.1-mini' : $model;
    11611153                $body = [
    1162                     'model' => $model,
     1154                    'model' => $metaModel,
    11631155                    'messages' => [
    11641156                        ['role' => 'system', 'content' => 'You are an expert SEO copywriter specializing in writing compelling, keyword-rich meta descriptions that drive click-through rates. You understand that generic descriptions hurt SEO performance.'],
     
    11661158                    ],
    11671159                ];
    1168 
    1169                 // Token limits - ruime limiet voor alle models (je betaalt alleen wat je gebruikt)
    1170                 $body['max_completion_tokens'] = 16000;
     1160                $m = strtolower((string) $model);
     1161                if ($m !== '' && strpos($m, 'gpt-5') === false) {
     1162                    if (strpos($m, 'o1-') === 0 || strpos($m, 'o3-') === 0) {
     1163                        $body['thinking'] = false;
     1164                    } elseif (strpos($m, 'deepseek-r1') !== false || strpos($m, 'deepseek-reasoner') !== false) {
     1165                        $body['thinking'] = array('type' => 'disabled');
     1166                    }
     1167                }
     1168                if ($provider === 'openrouter' || ($provider === 'custom' && strpos($baseUrl, 'openrouter.ai') !== false)) {
     1169                    $body['user'] = !empty($domain) ? $domain : parse_url(home_url(), PHP_URL_HOST);
     1170                }
    11711171
    11721172                $headers = [
     
    11821182                            $protocol = sanitize_text_field(wp_unslash($_SERVER['REQUEST_SCHEME']));
    11831183                        }
    1184                         $headers['Referer'] = $protocol . '://' . $domain . '/';
     1184                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    11851185                    } else {
    1186                         $headers['Referer'] = home_url();
     1186                        $headers['HTTP-Referer'] = 'https://github.com/gerard-kanters/ai-translate';
    11871187                    }
    1188                     $headers['X-Title'] = $site_name;
    1189                 }
    1190 
     1188                    $headers['X-Title'] = 'AI Translate';
     1189                }
     1190
     1191                // Shorter timeout for meta descriptions (simple task; reasoning minimized above).
    11911192                $response = wp_remote_post($endpoint, [
    11921193                    'headers' => $headers,
    1193                     'timeout' => 45,
     1194                    'timeout' => 60,
    11941195                    'sslverify' => true,
    11951196                    'body' => wp_json_encode($body),
Note: See TracChangeset for help on using the changeset viewer.