Updating translation endpoint so its reachable
Homelab Main / deploy (push) Successful in 1m24s
Details
Homelab Main / deploy (push) Successful in 1m24s
Details
This commit is contained in:
parent
4f65136e74
commit
6e78988a6a
|
|
@ -38,6 +38,8 @@ RUN usermod -u 1000 apache && \
|
|||
chown -R apache:apache /run/apache2 /var/log/apache2 /tmp/website-lang /var/www/localhost/htdocs/db
|
||||
|
||||
ENV WEBSITE_LANG_WRITE_DIR=/var/www/localhost/htdocs/db/lang
|
||||
ENV OLLAMA_HOST=http://192.168.100.68:11434
|
||||
ENV OLLAMA_MODEL=llama3.2:3b
|
||||
|
||||
USER apache
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@
|
|||
</div>
|
||||
|
||||
<script>
|
||||
const OLLAMA_HOST = 'http://192.168.100.68:11434';
|
||||
const OLLAMA_MODEL = 'llama3.2:3b';
|
||||
const TRANSLATE_URL = '/translate.php';
|
||||
const SAVE_URL = '/save_lang.php';
|
||||
const CURRENT_LANG = '<?php echo $lang; ?>';
|
||||
const STATIC_LANGS = <?php echo json_encode(array_values($availableLangs)); ?>;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
function translate_response(int $status, array $body): never {
|
||||
http_response_code($status);
|
||||
echo json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function clean_translate_text(string $value, int $maxLength = 4000): string {
|
||||
$value = strip_tags($value);
|
||||
$value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $value) ?? '';
|
||||
$value = trim($value);
|
||||
if (strlen($value) > $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);
|
||||
|
|
@ -19,6 +19,7 @@ const prompt = document.getElementById('translate-prompt');
|
|||
const btn = document.getElementById('translate-btn');
|
||||
const actionSpan = document.getElementById('translate-action');
|
||||
const detectedSpan = document.getElementById('detected-lang-name');
|
||||
let lastTranslationModel = 'Ollama';
|
||||
|
||||
function showBadge(msg) {
|
||||
if (badge) {
|
||||
|
|
@ -33,31 +34,25 @@ function hidePrompt() {
|
|||
|
||||
async function translateBatch(texts, targetLang) {
|
||||
const name = LANG_NAMES[targetLang] || targetLang;
|
||||
const prompt = `Translate each item to ${name}.
|
||||
Return ONLY a valid JSON array of translated strings in the same order, no explanations, no markdown.
|
||||
Example input: ["Hello", "How are you"]
|
||||
Example output: ["Bonjour", "Comment allez-vous"]
|
||||
|
||||
Input: ${JSON.stringify(texts)}`;
|
||||
|
||||
const response = await fetch(`${OLLAMA_HOST}/api/generate`, {
|
||||
const response = await fetch(TRANSLATE_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
model: OLLAMA_MODEL,
|
||||
prompt,
|
||||
stream: false
|
||||
targetLang,
|
||||
targetName: name,
|
||||
texts
|
||||
}),
|
||||
signal: AbortSignal.timeout(120000)
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
const data = await response.json();
|
||||
const raw = data.response.trim().replace(/```json|```/g, '').trim();
|
||||
const result = JSON.parse(raw);
|
||||
const data = await response.json();
|
||||
const result = data.translations;
|
||||
if (data.model) lastTranslationModel = `Ollama / ${data.model}`;
|
||||
|
||||
if (!Array.isArray(result) || result.length !== texts.length) {
|
||||
throw new Error(`Unexpected response: got ${result.length}, expected ${texts.length}`);
|
||||
const resultCount = Array.isArray(result) ? result.length : 0;
|
||||
if (!Array.isArray(result) || resultCount !== texts.length) {
|
||||
throw new Error(`Unexpected response: got ${resultCount}, expected ${texts.length}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -142,7 +137,7 @@ async function doTranslation() {
|
|||
}
|
||||
|
||||
await saveLang(browserLang, allTranslations);
|
||||
showBadge(`Translated by Ollama / ${OLLAMA_MODEL}`);
|
||||
showBadge(`Translated by ${lastTranslationModel}`);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ spec:
|
|||
value: /var/www/localhost/htdocs/db/lang
|
||||
- name: WEBSITE_IDEAS_WRITE_DIR
|
||||
value: /var/www/localhost/htdocs/db/ideas
|
||||
- name: OLLAMA_HOST
|
||||
value: http://192.168.100.68:11434
|
||||
- name: OLLAMA_MODEL
|
||||
value: llama3.2:3b
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
|
|
|
|||
Loading…
Reference in New Issue