source: main/trunk/model-interfaces-dev/atea/js/asr/TranscribeService.js@ 35259

Last change on this file since 35259 was 35259, checked in by davidb, 3 years ago

Implement support for switching between audio files

File size: 5.6 KB
Line 
1/**
2 * @file Defines components that are used to interact with the transcription proxy servlet.
3 * @author Carl Stephens
4 */
5
6/**
7 * The transcription object returned from our transcription endpoint.
8 *
9 * @typedef {Object} TranscriptionModel
10 * @property {String} file_name The name of the file that was transcribed.
11 * @property {String} log A note of how the transcription was processed.
12 * @property {{char: String, confidence: Number, start_time: Number}[]} metadata The character metadata.
13 * @property {boolean} success A value indicating if the transcription was successful or not.
14 * @property {String} transcription The transcription.
15 */
16
17class TranscribeError
18{
19 /**
20 * Initialises a new instance of the {@link TranscribeError} object.
21 *
22 * @param {Number | undefined} statusCode The status code of the error.
23 * @param {String | undefined} statusMessage The status message.
24 */
25 constructor(statusCode, statusMessage)
26 {
27 this.statusCode = statusCode;
28 this.statusMessage = statusMessage;
29 }
30}
31
32/**
33 * A service that uploads audio files in a multipart request to the Korero Maori API Interface servlet, and interprets the result.
34 */
35class TranscribeService
36{
37 constructor()
38 {
39 /** @type {String} The URL to which query POST requests should be made. */
40 this.queryUrl = "/gs3-koreromaori/transcribe";
41
42 /** @type {Number} The maximum number of files which can be transcribed in one request to the API. */
43 this.MAX_BATCH_COUNT = 3;
44
45 /** @type {Number} The soft upper limit on how many bytes can be submitted in one request. */
46 this.BATCH_BYTE_LIMIT = 5242880; // 5 MiB
47 }
48
49 /**
50 * Performs chunked queries to transcribe the given audio files, returning the data in iterations.
51 * Data is chunked according to which ever occurs first:
52 * A maximum of three files per request, or;
53 * A maximum of 5 MiB before chunking.
54 *
55 * @param {FileList} files The files to upload
56 * @returns {AsyncGenerator<TranscriptionModel[]>} The transcribed audio files.
57 */
58 async* batchTranscribeFiles(files)
59 {
60 let filesToSubmit = [];
61 let fileCounter = 0;
62 let byteCounter = 0;
63
64 for (let file of files)
65 {
66 if (fileCounter == this.MAX_BATCH_COUNT || byteCounter > this.BATCH_BYTE_LIMIT) // 5 MiB
67 {
68 yield await this.transcribeFiles(filesToSubmit);
69 filesToSubmit = [];
70 byteCounter = 0;
71 fileCounter = 0;
72 }
73
74 filesToSubmit[fileCounter++] = file;
75 byteCounter += file.size;
76 }
77
78 if (filesToSubmit.length > 0) {
79 yield await this.transcribeFiles(filesToSubmit);
80 }
81 }
82
83 /**
84 * Performs a query to transcribe the given audio files.
85 *
86 * @param {FileList | File[]} files The files to upload.
87 * @returns {Promise<TranscriptionModel[]>} The transcribed audio file.
88 */
89 async transcribeFiles(files)
90 {
91 const that = this;
92 const formData = new FormData();
93
94 let audioFileKeys = "";
95 for (let i = 0; i < files.length; i++)
96 {
97 const f = files[i];
98 const key = "audioFile" + i;
99
100 formData.append(key, f, f.name);
101 audioFileKeys += key + "|";
102 }
103 formData.append("audioFileKeys", audioFileKeys);
104
105 let response;
106 try
107 {
108 response = await fetch
109 (
110 that.queryUrl,
111 {
112 method: "POST",
113 body: formData
114 }
115 );
116 }
117 catch (e)
118 {
119 console.error(`Transcription failed with reason ${e}`);
120 throw new TranscribeError(undefined, undefined);
121 }
122
123 if (!response.ok)
124 {
125 console.error(`Transcription API failed with status ${response.status} and message ${response.statusText}`);
126 throw new TranscribeError(response.status, response.statusText);
127 }
128
129 return await response.json();
130 }
131
132 // OBSOLETE. Kept for reference purposes on XMLHttpRequest usage. See doFetchUpload instead.
133 //
134 // Based on https://stackoverflow.com/questions/2320069/jquery-ajax-file-upload
135 // doUpload(files, resultCallback, progressCallback)
136 // {
137 // let that = this;
138 // let formData = new FormData();
139
140 // let audioFileKeys = "";
141 // for (let f of files)
142 // {
143 // formData.append(f.name, f, f.name);
144 // audioFileKeys += f.name + "|";
145 // }
146 // formData.append("audioFileKeys", audioFileKeys);
147
148 // $.ajax({
149 // type: "POST",
150 // url: this.queryUrl,
151 // xhr: function ()
152 // {
153 // var myXhr = $.ajaxSettings.xhr();
154 // if (myXhr.upload && progressCallback != undefined)
155 // {
156 // myXhr.upload.addEventListener("progress", progressCallback, false);
157 // }
158 // return myXhr;
159 // },
160 // success: function (data)
161 // {
162 // resultCallback(data);
163 // },
164 // error: function (error)
165 // {
166 // console.error("Failed to upload file via AJAX POST: " + error);
167 // },
168 // async: true,
169 // data: formData,
170 // cache: false,
171 // contentType: false,
172 // processData: false,
173 // timeout: 60000 // TODO: Consider if we need a longer timeout.
174 // });
175 // }
176}
Note: See TracBrowser for help on using the repository browser.