yandex-cloud-translate
Version:
Translate text with Yandex Cloud AI API
117 lines (97 loc) • 3.86 kB
text/typescript
import { fetch } from './fetch'
interface Config {
YC_OAUTH_TOKEN?: string; // https://cloud.yandex.com/en-ru/docs/iam/concepts/authorization/oauth-token
YC_FOLDER_ID?: string; // https://cloud.yandex.com/en-ru/docs/resource-manager/operations/folder/get-id
YC_API_ADDRESS?: string;
}
interface ITranslateConfig {
texts: string | string[]; // if a string - result will be a string, if array of strings - array of strings
from?: string | null; // ISO ru, en, fr ... etc
to: string; // ISO ru, en, fr ... etc
format?: 'text' | 'html';
}
interface IBody {
folderId: string;
texts: string[];
targetLanguageCode: string;
sourceLanguageCode?: string | null;
format: 'PLAIN_TEXT' | 'HTML';
}
export class Yandex {
private YC_OAUTH_TOKEN: string;
private YC_FOLDER_ID: string;
private IAM_TOKEN: string;
private IAM_TOKEN_EXPIRES: number;
private YC_API_ADDRESS: string;
constructor(config: Config = {}) {
const { YC_OAUTH_TOKEN, YC_FOLDER_ID, YC_API_ADDRESS } = config;
this.YC_OAUTH_TOKEN = YC_OAUTH_TOKEN || process.env.YC_OAUTH_TOKEN || '';
this.YC_FOLDER_ID = YC_FOLDER_ID || process.env.YC_FOLDER_ID || '';
this.YC_API_ADDRESS =
YC_API_ADDRESS ||
process.env.YC_API_ADDRESS ||
'https://translate.api.cloud.yandex.net/translate/v2/translate';
this.IAM_TOKEN = '';
this.IAM_TOKEN_EXPIRES = Date.now();
if (!this.YC_OAUTH_TOKEN) {
throw new Error('invalid YC_OAUTH_TOKEN (add to .env YC_OAUTH_TOKEN)');
}
if (!this.YC_FOLDER_ID) {
throw new Error('invalid YC_FOLDER_ID (add to .env YC_FOLDER_ID)');
}
}
async setIamToken() {
let hour = 60 * 60 * 1000;
if (this.IAM_TOKEN && (this.IAM_TOKEN_EXPIRES - Date.now()) / hour > 11) {
return;
}
const iAm = await fetch('https://iam.api.cloud.yandex.net/iam/v1/tokens', {
method: 'POST',
body: JSON.stringify({
yandexPassportOauthToken: this.YC_OAUTH_TOKEN,
}),
})
.then(async (data) => await data.json())
.then((json) => {
return json;
});
this.IAM_TOKEN = iAm.iamToken;
this.IAM_TOKEN_EXPIRES = new Date(iAm.expiresAt).getTime();
}
async translate({ texts, to, from = null, format = 'text' }: ITranslateConfig): Promise<typeof texts> {
await this.setIamToken();
if (!this.IAM_TOKEN) {
throw new Error('invalid IAM_TOKEN');
}
if (!texts) {
throw new Error('invalid {texts} in Config');
}
if (!to) {
throw new Error('invalid {to} in Config');
}
let body: IBody;
body = {
folderId: this.YC_FOLDER_ID,
texts: typeof texts === 'string' ? [texts] : texts,
targetLanguageCode: to,
sourceLanguageCode: from,
format: format === 'html' ? 'HTML' : 'PLAIN_TEXT',
};
const json = await fetch(this.YC_API_ADDRESS, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.IAM_TOKEN}`,
},
body: JSON.stringify(body),
})
.then(async (data) => await data.json())
.then((json) => json);
if (!json.translations && json.message) {
throw new Error(`Translation error: ${json.message}`);
}
return typeof texts === 'string'
? json.translations[0].text
: json.translations.map((tr: { text: string }) => tr.text);
}
}