$maxLength) { $value = substr($value, 0, $maxLength); } return $value; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { translate_response(405, ['error' => 'Method not allowed']); } if ((int) ($_SERVER['CONTENT_LENGTH'] ?? 0) > 131072) { translate_response(413, ['error' => 'Request too large']); } $body = json_decode(file_get_contents('php://input'), true); if (!is_array($body) || !isset($body['targetLang'], $body['texts']) || !is_array($body['texts'])) { translate_response(400, ['error' => 'Missing target language or texts']); } $targetLang = preg_replace('/[^a-z]/', '', strtolower((string) $body['targetLang'])); if (strlen($targetLang) < 2 || strlen($targetLang) > 5) { translate_response(400, ['error' => 'Invalid target language']); } $targetName = clean_translate_text((string) ($body['targetName'] ?? strtoupper($targetLang)), 80); $texts = []; $totalLength = 0; foreach ($body['texts'] as $text) { if (!is_string($text) && !is_numeric($text)) { continue; } $cleanText = clean_translate_text((string) $text); $totalLength += strlen($cleanText); $texts[] = $cleanText; } if (!$texts || count($texts) > 240 || $totalLength > 80000) { translate_response(400, ['error' => 'Invalid translation batch']); } $prompt = "Translate each item to {$targetName}.\n" . "Return ONLY a valid JSON array of translated strings in the same order, no explanations, no markdown.\n" . "Example input: [\"Hello\", \"How are you\"]\n" . "Example output: [\"Bonjour\", \"Comment allez-vous\"]\n\n" . 'Input: ' . json_encode($texts, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); $ollamaHost = rtrim(getenv('OLLAMA_HOST') ?: 'http://192.168.100.68:11434', '/'); $ollamaModel = getenv('OLLAMA_MODEL') ?: 'llama3.2:3b'; $ollamaPayload = json_encode([ 'model' => $ollamaModel, 'prompt' => $prompt, 'stream' => false, ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($ollamaPayload === false) { translate_response(500, ['error' => 'Could not encode Ollama request']); } $curl = curl_init($ollamaHost . '/api/generate'); curl_setopt_array($curl, [ CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => $ollamaPayload, CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 130, ]); $rawResponse = curl_exec($curl); $curlError = curl_error($curl); $statusCode = (int) curl_getinfo($curl, CURLINFO_RESPONSE_CODE); curl_close($curl); if ($rawResponse === false || $statusCode < 200 || $statusCode >= 300) { translate_response(502, ['error' => 'Ollama request failed', 'status' => $statusCode, 'detail' => $curlError]); } $ollamaResponse = json_decode($rawResponse, true); if (!is_array($ollamaResponse) || !isset($ollamaResponse['response']) || !is_string($ollamaResponse['response'])) { translate_response(502, ['error' => 'Invalid Ollama response']); } $translationJson = trim(str_replace(['```json', '```'], '', $ollamaResponse['response'])); $translations = json_decode($translationJson, true); if (!is_array($translations) || count($translations) !== count($texts)) { translate_response(502, ['error' => 'Unexpected translation response']); } $cleanTranslations = []; foreach ($translations as $translation) { if (!is_string($translation) && !is_numeric($translation)) { translate_response(502, ['error' => 'Unexpected translation item']); } $cleanTranslations[] = clean_translate_text((string) $translation); } echo json_encode([ 'translations' => $cleanTranslations, 'model' => $ollamaModel, ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);