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

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

Implement auto-chunking of transcription requests, and display more error information to the user.

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