import { readSettings } from "./settings-store"; type ReplicateOutput = string | string[] | { translation?: string; translated_text?: string; output?: string }; export async function replicateTranslate( text: string, targetLanguage: string ): Promise { const settings = readSettings(); if (!settings.replicateApiToken) { throw new Error("Replicate API token not configured"); } if (!settings.jigsawApiKey) { throw new Error("JigsawStack API key not configured"); } const body = { version: settings.modelVersion, input: { text, api_key: settings.jigsawApiKey, target_language: targetLanguage } }; const response = await fetch("https://api.replicate.com/v1/predictions", { method: "POST", headers: { "Authorization": `Bearer ${settings.replicateApiToken}`, "Content-Type": "application/json", "Prefer": "wait" }, body: JSON.stringify(body) }); if (!response.ok) { const err = await response.text(); throw new Error(`Replicate API error: ${response.status} ${err}`); } const data = await response.json(); if (data.error) { throw new Error(`Replicate model error: ${data.error}`); } // Extract translated text from various output formats const output: ReplicateOutput = data.output; if (typeof output === "string") return output; if (Array.isArray(output)) return output.join(""); if (output && typeof output === "object") { return output.translation ?? output.translated_text ?? output.output ?? String(output); } throw new Error("Unexpected output format from Replicate"); } // Batch translate using separator trick to minimize API calls const SEPARATOR = "\n{{SEP}}\n"; export async function replicateTranslateBatch( texts: string[], targetLanguage: string ): Promise { if (texts.length === 0) return []; if (texts.length === 1) { return [await replicateTranslate(texts[0], targetLanguage)]; } const joined = texts.join(SEPARATOR); const translated = await replicateTranslate(joined, targetLanguage); // Try to split on the separator; fall back to individual calls if it got translated const parts = translated.split(SEPARATOR); if (parts.length === texts.length) { return parts; } // Fallback: translate individually return Promise.all(texts.map(t => replicateTranslate(t, targetLanguage))); }