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; };