Files
imgPub/server/src/services/glmClient.js
2025-11-21 01:21:37 +03:00

166 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const GLM_API_KEY = process.env.ZAI_GLM_API_KEY || process.env.ANTHROPIC_API_KEY;
const GLM_MODEL = process.env.ANTHROPIC_MODEL || process.env.ZAI_GLM_MODEL || 'glm-4.6';
const resolveEndpoint = () => {
const base =
process.env.ANTHROPIC_BASE_URL || process.env.ZAI_GLM_API_URL || 'https://api.z.ai/api/anthropic';
const normalized = base.replace(/\/$/, '');
if (/\/messages$/.test(normalized)) {
return normalized;
}
if (/\/v\d+$/.test(normalized)) {
return `${normalized}/messages`;
}
if (/\/v\d+\/.+/.test(normalized)) {
return normalized;
}
return `${normalized}/v1/messages`;
};
const GLM_API_URL = resolveEndpoint();
const IS_ANTHROPIC_STYLE = /anthropic/.test(GLM_API_URL);
const SYSTEM_PROMPT =
'You are a professional localization editor. Translate any given English or mixed-language text into fluent, publication-ready Turkish. Keep the original meaning, respect formatting, and avoid adding explanations.';
const extractContent = (payload) => {
if (!payload) return '';
if (Array.isArray(payload.content)) {
return payload.content
.map((item) => {
if (!item) return '';
if (typeof item === 'string') return item;
if (Array.isArray(item.text)) {
return item.text.map((inner) => inner?.text || inner || '').join('');
}
if (typeof item.text === 'string') return item.text;
if (Array.isArray(item.content)) {
return item.content
.map((inner) => (typeof inner === 'string' ? inner : inner?.text || ''))
.join('');
}
return '';
})
.filter(Boolean)
.join('\n')
.trim();
}
if (Array.isArray(payload.output)) {
return payload.output
.map((item) => item.content || item.text || '')
.filter(Boolean)
.join('')
.trim();
}
if (Array.isArray(payload.choices) && payload.choices.length > 0) {
const choice = payload.choices[0];
if (choice.message?.content) {
if (Array.isArray(choice.message.content)) {
return choice.message.content
.map((c) => (typeof c === 'string' ? c : c.text || ''))
.join('')
.trim();
}
return `${choice.message.content}`.trim();
}
if (choice.text) {
return `${choice.text}`.trim();
}
}
if (payload.data?.output_text?.length) {
return payload.data.output_text.join('\n').trim();
}
if (typeof payload.content === 'string') {
return payload.content.trim();
}
if (typeof payload.text === 'string') {
return payload.text.trim();
}
return '';
};
export const isGlmConfigured = () => Boolean(GLM_API_KEY);
export const translateWithGlm = async (text) => {
if (!isGlmConfigured()) {
throw new Error('ZAI_GLM_API_KEY veya ANTHROPIC_API_KEY tanımlı değil.');
}
const prompt =
`Aşağıdaki metni Türkçe'ye çevir. Yalnızca çeviriyi döndür:\n\n"""${text}"""`;
let body;
if (IS_ANTHROPIC_STYLE) {
body = {
model: GLM_MODEL,
max_tokens: 1024,
temperature: 0.1,
system: SYSTEM_PROMPT,
messages: [
{
role: 'user',
content: [{ type: 'text', text: prompt }],
},
],
};
} else {
body = {
model: GLM_MODEL,
max_tokens: 1024,
temperature: 0.1,
messages: [
{ role: 'system', content: SYSTEM_PROMPT },
{ role: 'user', content: prompt },
],
};
}
console.log('[GLM] İstek hazırlanıyor', {
endpoint: GLM_API_URL,
model: GLM_MODEL,
snippet: text.slice(0, 80),
});
const response = await fetch(GLM_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${GLM_API_KEY}`,
...(IS_ANTHROPIC_STYLE && {
'x-api-key': GLM_API_KEY,
'anthropic-version': process.env.ANTHROPIC_VERSION || '2023-06-01',
}),
},
body: JSON.stringify(body),
});
let payload = {};
try {
payload = await response.json();
} catch (error) {
console.error('[GLM] JSON parse başarısız', error);
}
console.log('[GLM] Yanıt alındı', {
status: response.status,
ok: response.ok,
hasOutput: Boolean(payload?.output || payload?.choices || payload?.content),
error: payload?.error,
});
if (!response.ok) {
const message =
payload?.error?.message ||
payload?.msg ||
`GLM isteği başarısız oldu (status: ${response.status})`;
throw new Error(message);
}
const translated = extractContent(payload);
if (!translated) {
console.error('[GLM] Boş içerik döndü', payload);
throw new Error('GLM çıktısı boş döndü.');
}
console.log('[GLM] Çeviri tamamlandı');
return translated;
};