UNPKG

@reverieit/reverie-client

Version:

Reverie's API access through node package manager

713 lines (612 loc) 23 kB
/*! * reverie-client * Copyright(c) 2025 Reverie Language Technologies * MIT Licensed */ 'use strict' function isEditable(element) { if (!element) return false; // Check if it's an input or textarea if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') { return true; } // Check if contenteditable is set to true if (element.isContentEditable) { return true; } return false; } function voiceText(event, callback, element, lang) { let stt_text = event.data; if (element) { if (isEditable(element)) { // Start voice recognition if (event.event === "FINAL_RESULT") { document.execCommand('insertText', false, stt_text); } else if (event.event === "PARTIAL_RESULTS") { if (["es-ES", "fr-FR", "ar-SA"].includes(lang)) { document.execCommand('insertText', false, stt_text); } } } } if (!element || isEditable(element)) { if (callback) { let stt_event = { ...event } callback({ stt_event }) } } } class ReverieClient { constructor(parameters) { this.apiKey = parameters.apiKey || 'REVERIE_API_KEY'; this.appId = parameters.appId || 'REVERIE_APP_ID'; this.baseUrl = parameters.baseUrl || 'https://revapi.reverieinc.com'; this.isListening = false; let script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/reverie-stt-sdk/dist/bundle.js'; document.body.appendChild(script); } async transliterate({ text, src_lang, tgt_lang, domain = 1 }) { try { if (!src_lang) { throw new Error('Source language is required'); return null; } if (!tgt_lang) { throw new Error('Target language is required'); return null; } if (!text) { throw new Error('Text to transliterate is required'); return null; } let resp = await fetch(this.baseUrl, { method: "POST", headers: { "Content-Type": "application/json", "REV-API-KEY": this.apiKey, "REV-APP-ID": this.appId, "src_lang": src_lang, "tgt_lang": tgt_lang, "domain": domain, "cnt_lang": "en", "REV-APPNAME": "transliteration", }, body: JSON.stringify({ data: [text], isBulk: false, ignoreTaggedEntities: false }) }); resp = await resp.json(); if (resp && resp.responseList && resp.responseList.length > 0) { return resp.responseList[0].outString[0]; } else { throw new Error("Failed to transliterate text"); return null; } } catch (error) { return error.message; } } async analyze_text({ text, src_lang, tgt_lang, translation_domain, moderation_types }) { try { if (!src_lang) { throw new Error('Content language is required'); } if (!text) { throw new Error('Text is required for text analysis'); } const url = `${this.baseUrl}/api/v2/text-analyse?translate=true&summary=true&sentiment=false&detect_entities=true&content_safety=true&pii_redaction=true`; const headers = { 'Content-Type': 'application/json', 'REV-API-KEY': this.apiKey, 'REV-APP-ID': this.appId, 'REV-APPNAME': 'text-analysis' }; const data = { "text": text, "language": src_lang, "pii_redaction": { "redact_pii_sub": "entity_name", "redact_pii_types": [] }, "summary": { "summary_model": "gemma2:2b", "summary_type": "gist" }, "entity_recognition": { "entity_types": [] }, "sentiment": { "level": "whole" }, "content_moderation": { "moderation_types": moderation_types || [ "hate_speech", "profanity" ] } }; if (tgt_lang) { data["traslation"] = { "target_language": tgt_lang, "translation_domain": translation_domain || "generic" } } let response = await fetch(url, { method: 'POST', headers: headers, body: JSON.stringify(data) }) response = await response.json(); if (response && response.results) { return response.results; } else { throw new Error("Failed to analyze text"); } } catch (error) { return error.message; } } async identify_language_by_text({ text }) { try { if (!text) { throw new Error('Text to identify is required'); } if (text.length > 512) { throw new Error('Text exceeds maximum length of 512 characters'); } let resp = await fetch(this.baseUrl, { method: "POST", headers: { "Content-Type": "application/json", "REV-API-KEY": this.apiKey, "REV-APP-ID": this.appId, "REV-APPNAME": "lang_id_text", }, body: JSON.stringify({ "text": text, "max_length": Math.pow(2, Math.floor(Math.sqrt(text.length)) + 1) }) }); resp = await resp.json(); if (resp) { return resp; } else { throw new Error("Failed to detect text"); } } catch (error) { return error.message; } } async translate({ text, src_lang, tgt_lang, domain }) { try { if (!src_lang) { throw new Error('Source language is required'); return null; } if (!tgt_lang) { throw new Error('Target language is required'); return null; } if (!text) { throw new Error('Text to translate is required'); return null; } let resp = await fetch(this.baseUrl, { method: "POST", headers: { "Content-Type": "application/json", "REV-API-KEY": this.apiKey, "REV-APP-ID": this.appId, "src_lang": src_lang, "tgt_lang": tgt_lang, 'domain': domain || 'generic', 'REV-APPNAME': 'localization', 'REV-APPVERSION': '3.0' }, body: JSON.stringify({ data: [text], "nmtMask": true, "nmtMaskTerms": {}, "enableNmt": true, "enableLookup": true }) }); resp = await resp.json(); if (resp && resp.responseList && resp.responseList.length > 0) { return resp.responseList[0].outString; } else { throw new Error("Failed to translate text"); return null; } } catch (error) { return error.message; } } async stt_file({ audioFile, src_lang, domain }) { try { if (!src_lang) { throw new Error('Source language is required'); return null; } if (!audioFile) { throw new Error('File to transcribe is required'); } const formData = new FormData(); formData.append("audio_file", audioFile); let resp = await fetch("https://revapi.reverieinc.com/", { method: "POST", headers: { "src_lang": src_lang, "domain": domain || "generic", "REV-APPNAME": "stt_file", "REV-API-KEY": this.apiKey, "REV-APP-ID": this.appId, }, body: formData }); resp = await resp.json(); if (resp && resp.display_text) { return resp.display_text; } else { throw new Error("Failed to transcribe text"); } } catch (error) { return error.message; } } async stt_batch({ audioFile, language, subtitles }) { return await this.transcribeAudio({ audioFile, language, subtitles }); } async text_to_speech({ text, speaker, speed, pitch, format = 'WAV' }) { try { if (!speaker) { throw new Error('Speaker is required for TTS'); } if (!text) { throw new Error('Text is required for TTS'); } if (!['WAV', 'MP3'].includes(format)) { throw new Error('Invalid audio format. Supported formats are wav and mp3'); } const requestData = { text, speed: parseFloat(speed), pitch: parseFloat(pitch), format: "WAV", speaker }; let resp = await fetch(this.baseUrl, { method: "POST", headers: { "Content-Type": "application/json", "REV-API-KEY": this.apiKey, "REV-APP-ID": this.appId, "REV-APPNAME": "tts", "speaker": speaker, }, body: JSON.stringify(requestData) }); let blob = await resp.blob(); if (resp) { return blob; } else { throw new Error("Failed to do tts for the text"); } } catch (error) { return error; } } async init_stt({ src_lang, domain, silence, continuous, logging, timeout, callback, element }) { if (!src_lang) { throw new Error('Source language is required for STT'); } if (!callback && !element) { throw new Error('Callback or element is required for STT'); } if (callback && typeof callback !== 'function') { throw new Error('Callback must be a function'); } if (element && typeof element !== 'object') { throw new Error('Element must be a DOM element'); } if (domain && typeof domain !== 'string') { throw new Error('Domain must be a string'); } if (silence && typeof silence !== 'number') { throw new Error('Silence must be a number'); } if (continuous && typeof continuous !== 'boolean') { throw new Error('Continuous must be a boolean'); } if (logging && typeof logging !== 'boolean') { throw new Error('Logging must be a boolean'); } if (timeout && typeof timeout !== 'number') { throw new Error('Timeout must be a number'); } try { await window.stt_stream.initSTT({ apikey: this.apiKey, appId: this.appId, language: src_lang, domain: domain || "generic", silence: silence || 1, continuous: continuous || 1, logging: logging && logging === false ? false : true, timeout: timeout || 180, eventHandler: (event) => voiceText(event, callback, element, src_lang), errorHandler: (error) => console.error('Error:', error), }); console.log('STT Streaming initialized successfully'); } catch (error) { console.error('STT Initialization failed:', error); } } async start_stt() { await window.stt_stream.startSTT(); this.isListening = true; } async stop_stt() { await window.stt_stream.stopSTT(); this.isListening = false; } async toggle_stt() { if (this.isListening) { await this.stop_stt(); } else { await this.start_stt(); } } async translateDocument({ sourceLanguage, targetLanguage, uploadedFile }) { try { const formData = new FormData(); formData.append('sourceLanguage', sourceLanguage || 'english'); formData.append('targetLanguage', targetLanguage || 'hindi'); formData.append('projectFiles', uploadedFile); const response = await fetch('https://revapi.reverieinc.com/translate_doc_import', { method: 'POST', headers: { 'REV-APP-ID': this.appId, 'REV-APPNAME': 'doc_translation', 'REV-API-KEY': this.apiKey }, body: formData }); const data = await response.json(); if (response.ok && data.projectId) { return this.checkStatus(data.projectId, targetLanguage); } else { throw new Error('Error in translation process'); } } catch (error) { throw new Error('Translation failed: ' + error.message); } } async translate_document({ sourceLanguage, targetLanguage, uploadedFile }) { return await this.translateDocument({ sourceLanguage, targetLanguage, uploadedFile }); } async checkStatus(docId, targetLanguage) { return new Promise((resolve, reject) => { const pollStatus = async () => { try { const response = await fetch(`https://revapi.reverieinc.com/translate_doc_status?doc_id=${docId}`, { headers: { 'REV-APP-ID': this.appId, 'REV-APPNAME': 'doc_translation', 'REV-API-KEY': this.apiKey } }); const statusData = await response.json(); if (statusData.success && statusData.message === 'completed') { resolve(this.downloadTranslatedFile(docId, targetLanguage)); } else { setTimeout(pollStatus, 2000); } } catch (error) { reject(new Error('Error checking status: ' + error.message)); } }; pollStatus(); }); } async check_status(docId, targetLanguage) { return await this.checkStatus(docId, targetLanguage); } async downloadTranslatedFile(docId, targetLanguage) { try { const response = await fetch('https://revapi.reverieinc.com/translate_doc_export', { method: 'POST', headers: { 'Content-Type': 'application/json', 'REV-APP-ID': this.appId, 'REV-APPNAME': 'doc_translation', 'REV-API-KEY': this.apiKey }, body: JSON.stringify({ unitId: docId, targetLanguages: [targetLanguage] }) }); const responseData = await response.json(); if (responseData.success) { Object.values(responseData.data.targetURLS).forEach(languages => { Object.values(languages).forEach(fileURL => { window.open(fileURL, '_blank'); }); }); return 'Translation complete! File is ready for download.'; } else { throw new Error('Error downloading translation'); } } catch (error) { throw new Error('Download failed: ' + error.message); } } async download_translated_file(docId, targetLanguage) { return await this.downloadTranslatedFile(docId, targetLanguage); } async uploadDocument({ file, file_type, languages, ocr_type }) { try { if (!file) { throw new Error('Please select a file'); } if (!file_type) { file_type = 'txt'; } if (!languages) { throw new Error("Languages parameter is required"); } if (!ocr_type || (ocr_type !== 'layout_ocr' && ocr_type !== 'only_ocr')) { throw new Error("Invalid ocr_type. Must be 'layout_ocr' or 'only_ocr'"); } if (file_type === 'img' && ocr_type === 'layout_ocr') { throw new Error('Layout OCR is not supported for images. Please select Only OCR.'); } const formData = new FormData(); formData.append('file', file); formData.append('file_type', file_type); formData.append('languages', languages); formData.append('ocr_type', ocr_type); let response = await fetch(this.baseUrl + '/process_doc', { method: 'POST', headers: { 'REV-APP-ID': this.appId, 'REV-API-KEY': this.apiKey, 'REV-APPNAME': 'ocr' }, body: formData }); if (ocr_type === 'layout_ocr') { return await response.blob(); } else { return await response.text(); } } catch (error) { return error.message; } } async upload_document({ file, file_type, languages, ocr_type }) { return await this.uploadDocument({ file, file_type, languages, ocr_type }); } async uploadAudio({ file }) { try { if (!file) throw new Error('Please select an audio file'); const formData = new FormData(); formData.append('audio_file', file); let response = await fetch(this.baseUrl + '/upload', { method: 'POST', headers: { 'REV-API-KEY': this.apiKey, 'REV-APP-ID': this.appId, 'REV-APPNAME': 'slid' }, body: formData }); let result = await response.json(); if (!result.success) throw new Error(result.cause); return { transcriptionId: result.id, language: result.language, confidence: result.confidence }; } catch (error) { throw error; } } async upload_audio({ file }) { return await this.uploadAudio({ file }); } async transcribeAudio({ language, subtitles, audioFile }) { if (!language || typeof subtitles === 'undefined' || !audioFile) { throw new Error('Missing required fields: language, domain, subtitles, or audioFile'); } try { const formData = new FormData(); formData.append('file', audioFile); const response = await fetch(`${this.baseUrl}/upload`, { method: 'POST', headers: { 'src_lang': language, 'domain': "generic", 'REV-API-KEY': this.apiKey, 'REV-APPNAME': 'stt_batch', 'REV-APP-ID': this.appId, 'subtitles': subtitles.toString() }, body: formData }); const data = await response.json(); if (response.ok && data.job_id) { return this.checkAudioStatus(data.job_id); } else { throw new Error('Upload failed or invalid response'); } } catch (error) { throw new Error('Transcription failed: ' + error.message); } } async checkAudioStatus(jobId) { return new Promise((resolve, reject) => { const poll = async () => { try { const response = await fetch(`${this.baseUrl}/status?job_id=${jobId}`, { headers: { 'REV-API-KEY': this.apiKey, 'REV-APPNAME': 'stt_batch', 'REV-APP-ID': this.appId } }); const status = await response.json(); if (status.status === 'completed') { resolve(this.getTranscript(jobId)); } else if (status.status === 'failed') { reject(new Error('Transcription failed on server')); } else { setTimeout(poll, 3000); } } catch (error) { reject(new Error('Error checking transcription status: ' + error.message)); } }; poll(); }); } async check_audio_status(jobId) { return await this.checkAudioStatus(jobId); } async getTranscript(jobId) { try { const response = await fetch(`${this.baseUrl}/transcript?job_id=${jobId}`, { headers: { 'REV-API-KEY': this.apiKey, 'REV-APPNAME': 'stt_batch', 'REV-APP-ID': this.appId } }); const data = await response.json(); if (response.ok && data.result) { return data.result; } else { throw new Error('Transcript not available'); } } catch (error) { throw new Error('Error fetching transcript: ' + error.message); } } async get_transcript(jobId) { return await this.getTranscript(jobId); } } module.exports = ReverieClient