anylang
Version:
A translator's kit that uses the free APIs of Google Translate, Yandex, Bing, ChatGPT, and other LLMs
95 lines (93 loc) • 15 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { z } from 'zod';
export const getPrompt = (text, from, to) => {
// use full language name
const langFormatter = new Intl.DisplayNames(['en'], { type: 'language' });
const originLang = from == 'auto' ? 'auto' : langFormatter.of(from);
const targetLang = langFormatter.of(to);
return `You are a text translation service. I will provide an array of texts, and your task is to translate them from language ${originLang} to language ${targetLang}.
If I specify the source language as 'auto', you should automatically detect it and translate it into the target language I set.
The array in your response must be the same length as the one in the request. Do not add any explanations — translate strictly according to the content.
Be careful when creating an array; it must be syntactically correct and do not change quotation marks. Return an array of translated texts while preserving their order.
Here is the JSON array of texts: ${JSON.stringify(text)}`;
};
export class LLMTranslator {
constructor(llm, options) {
var _a, _b, _c, _d, _e, _f, _g;
this.llm = llm;
this.config = {
retryLimit: (_b = (_a = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _a === void 0 ? void 0 : _a.retryLimit) !== null && _b !== void 0 ? _b : 3,
retryTimeout: (_d = (_c = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _c === void 0 ? void 0 : _c.retryTimeout) !== null && _d !== void 0 ? _d : this.llm.getRequestsTimeout(),
maxRetryTimeout: (_e = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _e === void 0 ? void 0 : _e.maxRetryTimeout,
retryBackoffFactor: (_f = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _f === void 0 ? void 0 : _f.retryBackoffFactor,
getPrompt: (_g = options === null || options === void 0 ? void 0 : options.getPrompt) !== null && _g !== void 0 ? _g : getPrompt,
};
}
translate(text, from, to) {
return __awaiter(this, void 0, void 0, function* () {
const translated = yield this.translateBatch([text], from, to);
return translated[0];
});
}
translateBatch(text, from, to) {
return __awaiter(this, void 0, void 0, function* () {
let attempt = 0;
// Retry loop
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while (true) {
try {
// first request without delay
if (attempt > 0) {
yield this.waitRetryDelay(attempt);
}
const response = yield this.llm.fetch(this.config.getPrompt(text, from, to));
const validateResult = z
.string()
.array()
.length(text.length, {
message: 'The response must be the same length as the requested array',
})
.parse(JSON.parse(response));
return validateResult;
}
catch (error) {
attempt++;
if (attempt >= this.config.retryLimit)
throw error;
}
}
});
}
getLengthLimit() {
return this.llm.getLengthLimit();
}
getRequestsTimeout() {
return this.llm.getRequestsTimeout();
}
checkLimitExceeding(text) {
const plainText = Array.isArray(text) ? text.join('') : text;
const extra = plainText.length - this.getLengthLimit();
return extra > 0 ? extra : 0;
}
/**
* Calculates retry delays: starts with retryTimeout,
* then increases exponentially (retryTimeout * factor^n) up to maxRetryTimeout (default: 4000).
* Default retryBackoffFactor: 1.5
*/
waitRetryDelay(attempt) {
var _a, _b;
const maxTimeout = (_a = this.config.maxRetryTimeout) !== null && _a !== void 0 ? _a : 4000;
const factor = (_b = this.config.retryBackoffFactor) !== null && _b !== void 0 ? _b : 1.5;
const delay = Math.min(maxTimeout, this.config.retryTimeout * Math.pow(factor, (attempt - 1)));
return new Promise((r) => setTimeout(r, delay));
}
}
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRyYW5zbGF0b3JzL0xMTVRyYW5zbGF0b3JzL0xMTVRyYW5zbGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQThCeEIsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBYyxFQUFFLElBQVksRUFBRSxFQUFVLEVBQUUsRUFBRTtJQUNyRSx5QkFBeUI7SUFDekIsTUFBTSxhQUFhLEdBQUcsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUMxRSxNQUFNLFVBQVUsR0FBRyxJQUFJLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEUsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUV4QyxPQUFPLDBIQUEwSCxVQUFVLGdCQUFnQixVQUFVOzs7O21DQUluSSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7QUFDMUQsQ0FBQyxDQUFDO0FBRUYsTUFBTSxPQUFPLGFBQWE7SUFHekIsWUFDa0IsR0FBZSxFQUNoQyxPQUdDOztRQUpnQixRQUFHLEdBQUgsR0FBRyxDQUFZO1FBTWhDLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDYixVQUFVLEVBQUUsTUFBQSxNQUFBLE9BQU8sYUFBUCxPQUFPLHVCQUFQLE9BQU8sQ0FBRSxZQUFZLDBDQUFFLFVBQVUsbUNBQUksQ0FBQztZQUNsRCxZQUFZLEVBQ1gsTUFBQSxNQUFBLE9BQU8sYUFBUCxPQUFPLHVCQUFQLE9BQU8sQ0FBRSxZQUFZLDBDQUFFLFlBQVksbUNBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRTtZQUNyRSxlQUFlLEVB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QUFJLENBQUMsTUFBTSxDQUFDLFlBQVksR0FBRyxTQUFBLE1BQU0sRUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQSxDQUNsRCxDQUFDO1FBRUYsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ2pELENBQUM7Q0FDRCIsImZpbGUiOiJ0cmFuc2xhdG9ycy9MTE1UcmFuc2xhdG9ycy9MTE1UcmFuc2xhdG9yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5cbmltcG9ydCB7IFRyYW5zbGF0b3JJbnN0YW5jZU1lbWJlcnMgfSBmcm9tICcuLi9UcmFuc2xhdG9yJztcbmltcG9ydCB7IExMTUZldGNoZXIgfSBmcm9tICcuJztcblxuZXhwb3J0IHR5cGUgUHJvbXB0R2VuZXJhdG9yID0gKHRleHRzOiBzdHJpbmdbXSwgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKSA9PiBzdHJpbmc7XG5cbmV4cG9ydCB0eXBlIExMTVRyYW5zbGF0b3JSZXRyeU9wdGlvbnMgPSB7XG5cdC8qKlxuXHQgKiBNYXhpbXVtIG51bWJlciBvZiByZXRyeSBhdHRlbXB0cyBhZnRlciBhIGZhaWxlZCByZXF1ZXN0XG5cdCAqL1xuXHRyZXRyeUxpbWl0PzogbnVtYmVyO1xuXG5cdC8qKlxuXHQgKiBEZWxheSBiZWZvcmUgZmlyc3QgcmV0cnkgaW4gbXM7IGluY3JlYXNlcyBleHBvbmVudGlhbGx5IHVwIHRvIG1heFJldHJ5VGltZW91dFxuXHQgKi9cblx0cmV0cnlUaW1lb3V0PzogbnVtYmVyO1xuXG5cdC8qKlxuXHQgKiBNYXhpbXVtIGRlbGF5IGJlZm9yZSB0aGUgbmV4dCByZXRyeVxuXHQgKi9cblx0bWF4UmV0cnlUaW1lb3V0PzogbnVtYmVyO1xuXG5cdC8qKlxuXHQgKiBBbiBleHBvbmVudGlhbCBtdWx0aXBsaWVyIHVzZWQgdG8gaW5jcmVhc2UgdGhlIGRlbGF5IGJldHdlZW4gcmV0cnkgYXR0ZW1wdHMuXG5cdCAqIFdpdGggZWFjaCBhdHRlbXB0LCB0aGUgZGVsYXkgZ3Jvd3MgYmFzZWQgb24gdGhpcyBmYWN0b3IuXG5cdCAqL1xuXHRyZXRyeUJhY2tvZmZGYWN0b3I/OiBudW1iZXI7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0UHJvbXB0ID0gKHRleHQ6IHN0cmluZ1tdLCBmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcpID0+IHtcblx0Ly8gdXNlIGZ1bGwgbGFuZ3VhZ2UgbmFtZVxuXHRjb25zdCBsYW5nRm9ybWF0dGVyID0gbmV3IEludGwuRGlzcGxheU5hbWVzKFsnZW4nXSwgeyB0eXBlOiAnbGFuZ3VhZ2UnIH0pO1xuXHRjb25zdCBvcmlnaW5MYW5nID0gZnJvbSA9PSAnYXV0bycgPyAnYXV0bycgOiBsYW5nRm9ybWF0dGVyLm9mKGZyb20pO1xuXHRjb25zdCB0YXJnZXRMYW5nID0gbGFuZ0Zvcm1hdHRlci5vZih0byk7XG5cblx0cmV0dXJuIGBZb3UgYXJlIGEgdGV4dCB0cmFuc2xhdGlvbiBzZXJ2aWNlLiBJIHdpbGwgcHJvdmlkZSBhbiBhcnJheSBvZiB0ZXh0cywgYW5kIHlvdXIgdGFzayBpcyB0byB0cmFuc2xhdGUgdGhlbSBmcm9tIGxhbmd1YWdlICR7b3JpZ2luTGFuZ30gdG8gbGFuZ3VhZ2UgJHt0YXJnZXRMYW5nfS5cbklmIEkgc3BlY2lmeSB0aGUgc291cmNlIGxhbmd1YWdlIGFzICdhdXRvJywgeW91IHNob3VsZCBhdXRvbWF0aWNhbGx5IGRldGVjdCBpdCBhbmQgdHJhbnNsYXRlIGl0IGludG8gdGhlIHRhcmdldCBsYW5ndWFnZSBJIHNldC5cblRoZSBhcnJheSBpbiB5b3VyIHJlc3BvbnNlIG11c3QgYmUgdGhlIHNhbWUgbGVuZ3RoIGFzIHRoZSBvbmUgaW4gdGhlIHJlcXVlc3QuIERvIG5vdCBhZGQgYW55IGV4cGxhbmF0aW9ucyDigJQgdHJhbnNsYXRlIHN0cmljdGx5IGFjY29yZGluZyB0byB0aGUgY29udGVudC4gXG5CZSBjYXJlZnVsIHdoZW4gY3JlYXRpbmcgYW4gYXJyYXk7IGl0IG11c3QgYmUgc3ludGFjdGljYWxseSBjb3JyZWN0IGFuZCBkbyBub3QgY2hhbmdlIHF1b3RhdGlvbiBtYXJrcy4gUmV0dXJuIGFuIGFycmF5IG9mIHRyYW5zbGF0ZWQgdGV4dHMgd2hpbGUgcHJlc2VydmluZyB0aGVpciBvcmRlci5cbkhlcmUgaXMgdGhlIEpTT04gYXJyYXkgb2YgdGV4dHM6ICR7SlNPTi5zdHJpbmdpZnkodGV4dCl9YDtcbn07XG5cbmV4cG9ydCBjbGFzcyBMTE1UcmFuc2xhdG9yIGltcGxlbWVudHMgVHJhbnNsYXRvckluc3RhbmNlTWVtYmVycyB7XG5cdHByaXZhdGUgcmVhZG9ubHkgY29uZmlnO1xuXG5cdGNvbnN0cnVjdG9yKFxuXHRcdHByaXZhdGUgcmVhZG9ubHkgbGxtOiBMTE1GZXRjaGVyLFxuXHRcdG9wdGlvbnM/OiB7XG5cdFx0XHRnZXRQcm9tcHQ/OiBQcm9tcHRHZW5lcmF0b3I7XG5cdFx0XHRyZXRyeU9wdGlvbnM/OiBMTE1UcmFuc2xhdG9yUmV0cnlPcHRpb25zO1xuXHRcdH0sXG5cdCkge1xuXHRcdHRoaXMuY29uZmlnID0ge1xuXHRcdFx0cmV0cnlMaW1pdDogb3B0aW9ucz8ucmV0cnlPcHRpb25zPy5yZXRyeUxpbWl0ID8/IDMsXG5cdFx0XHRyZXRyeVRpbWVvdXQ6XG5cdFx0XHRcdG9wdGlvbnM/LnJldHJ5T3B0aW9ucz8ucmV0cnlUaW1lb3V0ID8/IHRoaXMubGxtLmdldFJlcXVlc3RzVGltZW91dCgpLFxuXHRcdFx0bWF4UmV0cnlUaW1lb3V0OiBvcHRpb25zPy5yZXRyeU9wdGlvbnM/Lm1heFJldHJ5VGltZW91dCxcblx0XHRcdHJldHJ5QmFja29mZkZhY3Rvcjogb3B0aW9ucz8ucmV0cnlPcHRpb25zPy5yZXRyeUJhY2tvZmZGYWN0b3IsXG5cdFx0XHRnZXRQcm9tcHQ6IG9wdGlvbnM/LmdldFByb21wdCA/PyBnZXRQcm9tcHQsXG5cdFx0fTtcblx0fVxuXG5cdHB1YmxpYyBhc3luYyB0cmFuc2xhdGUodGV4dDogc3RyaW5nLCBmcm9tOiBzdHJpbmcsIHRvOiBzdHJpbmcpIHtcblx0XHRjb25zdCB0cmFuc2xhdGVkID0gYXdhaXQgdGhpcy50cmFuc2xhdGVCYXRjaChbdGV4dF0sIGZyb20sIHRvKTtcblx0XHRyZXR1cm4gdHJhbnNsYXRlZFswXTtcblx0fVxuXG5cdHB1YmxpYyBhc3luYyB0cmFuc2xhdGVCYXRjaCh0ZXh0OiBzdHJpbmdbXSwgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKSB7XG5cdFx0bGV0IGF0dGVtcHQgPSAwO1xuXG5cdFx0Ly8gUmV0cnkgbG9vcFxuXHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5uZWNlc3NhcnktY29uZGl0aW9uXG5cdFx0d2hpbGUgKHRydWUpIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdC8vIGZpcnN0IHJlcXVlc3Qgd2l0aG91dCBkZWxheVxuXHRcdFx0XHRpZiAoYXR0ZW1wdCA+IDApIHtcblx0XHRcdFx0XHRhd2FpdCB0aGlzLndhaXRSZXRyeURlbGF5KGF0dGVtcHQpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmxsbS5mZXRjaChcblx0XHRcdFx0XHR0aGlzLmNvbmZpZy5nZXRQcm9tcHQodGV4dCwgZnJvbSwgdG8pLFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdGNvbnN0IHZhbGlkYXRlUmVzdWx0ID0gelxuXHRcdFx0XHRcdC5zdHJpbmcoKVxuXHRcdFx0XHRcdC5hcnJheSgpXG5cdFx0XHRcdFx0Lmxlbmd0aCh0ZXh0Lmxlbmd0aCwge1xuXHRcdFx0XHRcdFx0bWVzc2FnZTpcblx0XHRcdFx0XHRcdFx0J1RoZSByZXNwb25zZSBtdXN0IGJlIHRoZSBzYW1lIGxlbmd0aCBhcyB0aGUgcmVxdWVzdGVkIGFycmF5Jyxcblx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdC5wYXJzZShKU09OLnBhcnNlKHJlc3BvbnNlKSk7XG5cblx0XHRcdFx0cmV0dXJuIHZhbGlkYXRlUmVzdWx0O1xuXHRcdFx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRcdFx0YXR0ZW1wdCsrO1xuXHRcdFx0XHRpZiAoYXR0ZW1wdCA+PSB0aGlzLmNvbmZpZy5yZXRyeUxpbWl0KSB0aHJvdyBlcnJvcjtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRwdWJsaWMgZ2V0TGVuZ3RoTGltaXQoKSB7XG5cdFx0cmV0dXJuIHRoaXMubGxtLmdldExlbmd0aExpbWl0KCk7XG5cdH1cblxuXHRwdWJsaWMgZ2V0UmVxdWVzdHNUaW1lb3V0KCkge1xuXHRcdHJldHVybiB0aGlzLmxsbS5nZXRSZXF1ZXN0c1RpbWVvdXQoKTtcblx0fVxuXG5cdHB1YmxpYyBjaGVja0xpbWl0RXhjZWVkaW5nKHRleHQ6IHN0cmluZyB8IHN0cmluZ1tdKSB7XG5cdFx0Y29uc3QgcGxhaW5UZXh0ID0gQXJyYXkuaXNBcnJheSh0ZXh0KSA/IHRleHQuam9pbignJykgOiB0ZXh0O1xuXHRcdGNvbnN0IGV4dHJhID0gcGxhaW5UZXh0Lmxlbmd0aCAtIHRoaXMuZ2V0TGVuZ3RoTGltaXQoKTtcblx0XHRyZXR1cm4gZXh0cmEgPiAwID8gZXh0cmEgOiAwO1xuXHR9XG5cblx0LyoqXG5cdCAqIENhbGN1bGF0ZXMgcmV0cnkgZGVsYXlzOiBzdGFydHMgd2l0aCByZXRyeVRpbWVvdXQsXG5cdCAqIHRoZW4gaW5jcmVhc2VzIGV4cG9uZW50aWFsbHkgKHJldHJ5VGltZW91dCAqIGZhY3Rvcl5uKSB1cCB0byBtYXhSZXRyeVRpbWVvdXQgKGRlZmF1bHQ6IDQwMDApLlxuXHQgKiBEZWZhdWx0IHJldHJ5QmFja29mZkZhY3RvcjogMS41XG5cdCAqL1xuXHRwcml2YXRlIHdhaXRSZXRyeURlbGF5KGF0dGVtcHQ6IG51bWJlcikge1xuXHRcdGNvbnN0IG1heFRpbWVvdXQgPSB0aGlzLmNvbmZpZy5tYXhSZXRyeVRpbWVvdXQgPz8gNDAwMDtcblx0XHRjb25zdCBmYWN0b3IgPSB0aGlzLmNvbmZpZy5yZXRyeUJhY2tvZmZGYWN0b3IgPz8gMS41O1xuXHRcdGNvbnN0IGRlbGF5ID0gTWF0aC5taW4oXG5cdFx0XHRtYXhUaW1lb3V0LFxuXHRcdFx0dGhpcy5jb25maWcucmV0cnlUaW1lb3V0ICogZmFjdG9yICoqIChhdHRlbXB0IC0gMSksXG5cdFx0KTtcblxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSgocikgPT4gc2V0VGltZW91dChyLCBkZWxheSkpO1xuXHR9XG59XG4iXX0=