sonix-speech-recognition
Version:
A library that produces audio transcriptions and translations using the Sonix.AI service.
185 lines (184 loc) • 8.3 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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SonixSpeechRecognitionService = void 0;
const axios_1 = require("axios");
const fs = require("fs");
const FormData = require("form-data");
const constants_1 = require("./constants");
class SonixSpeechRecognitionService {
constructor(authKey) {
this.authKey = authKey;
}
uploadFileForTranscription({ audioUrl, audioFilePath, fileName, language, }) {
return __awaiter(this, void 0, void 0, function* () {
if (!audioUrl && !audioFilePath) {
throw new Error('Either audioUrl or audioFilePath must be provided');
}
const form = new FormData();
if (audioUrl) {
form.append('file_url', audioUrl);
}
if (audioFilePath) {
const fileStream = fs.createReadStream(audioFilePath);
form.append('file', fileStream, fileName);
}
form.append('language', language);
if (fileName) {
form.append('name', fileName);
}
const response = yield axios_1.default.post(constants_1.SPEECH_BASE_URL, form, {
headers: {
Authorization: `Bearer ${this.authKey}`,
},
});
return response.data;
});
}
getTranscriptionStatus(uploadAudioResponse) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield axios_1.default.request({
method: 'get',
maxBodyLength: Infinity,
url: `${constants_1.SPEECH_BASE_URL}/${uploadAudioResponse.id}`,
headers: {
Authorization: `Bearer ${this.authKey}`,
},
});
return response.data;
});
}
getTranscriptionResult(transcriptionId, language) {
return __awaiter(this, void 0, void 0, function* () {
const form = new FormData();
form.append('language', language);
const response = yield axios_1.default.get(`${constants_1.SPEECH_BASE_URL}/${transcriptionId}/transcript`, {
headers: {
Authorization: `Bearer ${this.authKey}`,
},
data: form,
});
return response.data;
});
}
queueTranslation({ transcriptionJobId, language, }) {
return __awaiter(this, void 0, void 0, function* () {
const form = new FormData();
form.append('language', language);
const response = yield axios_1.default.post(`${constants_1.SPEECH_BASE_URL}/${transcriptionJobId}/translations`, form, {
headers: {
Authorization: `Bearer ${this.authKey}`,
},
});
return response.data;
});
}
getTranslationStatus({ transcriptionJobId, language, }) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield axios_1.default.request({
method: 'get',
maxBodyLength: Infinity,
url: `${constants_1.SPEECH_BASE_URL}/${transcriptionJobId}/translations/${language}`,
headers: {
Authorization: `Bearer ${this.authKey}`,
},
});
return response.data;
});
}
delay(ms) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => setTimeout(resolve, ms));
});
}
speechToText({ audioUrl, fileName, language, audioFilePath, }) {
return __awaiter(this, void 0, void 0, function* () {
let jobId = '';
try {
const fileUploadResponse = yield this.uploadFileForTranscription({
audioUrl,
fileName,
language,
audioFilePath,
});
jobId = fileUploadResponse.id;
const startTime = Date.now();
let transcriptionStatus = yield this.getTranscriptionStatus(fileUploadResponse);
while (transcriptionStatus.status !== 'completed') {
if (Date.now() - startTime > constants_1.MAX_WAIT_TIME) {
throw new Error('Transcription timeout');
}
yield this.delay(constants_1.RECOGNITION_POLLING_DELAY);
transcriptionStatus = yield this.getTranscriptionStatus(fileUploadResponse);
if (transcriptionStatus.status === 'duplicate') {
if (!transcriptionStatus.duplicate_media_id) {
throw new Error('Sonix returned failed status and duplicate media id is not provided. Please check portal https://my.sonix.ai/ for more details');
}
const duplicateMediaId = transcriptionStatus.duplicate_media_id;
transcriptionStatus = Object.assign(Object.assign({}, transcriptionStatus), { id: duplicateMediaId });
break;
}
if (transcriptionStatus.status === 'failed') {
throw new Error('Sonix returned failed status. Please check portal https://my.sonix.ai/ for more details');
}
}
const transcription = yield this.getTranscriptionResult(transcriptionStatus.id, language);
return {
jobId: transcriptionStatus.id,
text: transcription,
status: 'completed',
};
}
catch (error) {
return {
jobId,
text: '',
status: 'failed',
error: error.message,
};
}
});
}
translateTranscription(request) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield this.queueTranslation(request);
const startTime = Date.now();
let translationStatus = yield this.getTranslationStatus(request);
while (translationStatus.status !== 'completed') {
if (Date.now() - startTime > constants_1.MAX_WAIT_TIME) {
throw new Error('Transcription timeout');
}
yield this.delay(constants_1.RECOGNITION_POLLING_DELAY);
translationStatus = yield this.getTranslationStatus(request);
if (translationStatus.status === 'failed') {
throw new Error('Sonix returned failed status. Please check portal https://my.sonix.ai/ for more details');
}
}
const transcriptionEnglish = yield this.getTranscriptionResult(request.transcriptionJobId, request.language);
return {
jobId: request.transcriptionJobId,
text: transcriptionEnglish,
status: 'completed',
};
}
catch (error) {
return {
jobId: request.transcriptionJobId,
text: '',
status: 'failed',
error: error.message,
};
}
});
}
}
exports.SonixSpeechRecognitionService = SonixSpeechRecognitionService;