source: main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/components/AudioUpload.vue@ 35407

Last change on this file since 35407 was 35407, checked in by cstephen, 3 years ago

Improve theme + update translations

File size: 6.8 KB
Line 
1<template>
2 <!-- Contains the file input, transcribe button and transcription progress indicator -->
3 <div class="audio-file-picker">
4 <div class="input-bar">
5 <!-- <button type="button" v-on:click="openFilePicker">
6 <span class="material-icons">&#xE2C6;</span> file_upload
7 <span>Upload Audio Files</span>
8 </button>-->
9
10 <div class="text-input-sl" style="cursor: pointer;" @click="openFilePicker">
11 <span class="text-placeholder material-icons" v-if="!anyFiles">&#xe226;</span> <!-- attach_file -->
12 <span class="text-placeholder" v-if="!anyFiles">{{ translations.get("AudioUpload_SelectFileText") }}</span>
13 <span v-if="anyFiles">{{ getFileNameList }}</span>
14 </div>
15
16 <input ref="audioFileInput" type="file" @input="onFilesChanged"
17 accept="audio/wav" multiple :disabled="isTranscribing" />
18
19 <button type="submit" :disabled="!anyFiles || isTranscribing" @click="doTranscription">
20 <span class="material-icons">&#xEA3E;</span> <!-- history_edu -->
21 <span>{{ translations.get("AudioUpload_TranscribeFiles") }}</span>
22 </button>
23 </div>
24
25 <progress v-if="isTranscribing" class="indeterminateLoadingBar" />
26
27 <ul class="list-view" v-if="failures.size > 0">
28 <li v-for="[id, failure] in failures" :key="failure.id" class="list-view__item transcription-error-container">
29 <div>
30 {{ translations.get("AudioUpload_TranscriptionFailed_Message") }} <i v-if="failure.fileName">{{ failure.fileName }}</i><br />
31 <span v-if="failure.message">{{ translations.get("AudioUpload_TranscriptionFailed_Reason") }}: {{ failure.message }}</span>
32 </div>
33
34 <button class="btn-fab theme-flat" @click="dismissFailure(id)">
35 <span class="material-icons">&#xE14C;</span> <!-- clear -->
36 </button>
37 </li>
38 </ul>
39 </div>
40</template>
41
42<!-- Add "scoped" attribute to limit CSS to this component only -->
43<style scoped lang="scss">
44.audio-file-picker {
45 display: flex;
46 gap: 0.5em;
47 flex-direction: column;
48
49 input {
50 display: none;
51 }
52
53 .text-container {
54 cursor: pointer;
55 }
56}
57
58.input-bar {
59 display: grid;
60 align-items: stretch;
61 gap: 0.5em;
62 grid-template-columns: 1fr auto;
63}
64
65.transcription-error-container {
66 display: grid;
67 gap: 0.5em;
68 grid-template-columns: 1fr auto;
69 align-items: center;
70
71 border-left: 3px solid red;
72}
73</style>
74
75<script>
76import { mapState } from "vuex";
77import TranscribeService from "../js/TranscribeModule";
78import Util from "../js/Util";
79import { TranscriptionViewModel } from "../main"
80
81class TranscriptionViewFailure {
82 /**
83 * @param {String} fileName The name of the file for which this failure occured.
84 * @param {String} message The reason for this failure.
85 */
86 constructor(fileName, message) {
87 /** @type {String} The UUID of this failure. */
88 this.id = Util.generateUuid();
89
90 /** @type {String | null} The name of the file for which this failure occured. */
91 this.fileName = fileName;
92
93 /** @type {String} The reason for the failure. */
94 this.message = message;
95 }
96}
97
98const transcribeService = new TranscribeService();
99
100export default {
101 name: "AudioUpload",
102 data() {
103 return {
104 /** @type {File[]} */
105 files: [],
106 /** @type {Map<String, TranscriptionViewFailure>} */
107 failures: new Map(),
108 canTranscribe: false,
109 isTranscribing: false
110 }
111 },
112 computed: mapState({
113 translations: state => state.translations,
114 anyFiles() {
115 return this.files?.length > 0;
116 },
117 getFileNameList() {
118 let fileNameList = "";
119
120 for (const file of this.files) {
121 fileNameList += file.name + ", ";
122 }
123
124 return fileNameList.slice(0, fileNameList.length - 2);
125 }
126 }),
127 emits: [ "newTranscription" ],
128 methods: {
129 openFilePicker() {
130 this.$refs.audioFileInput.click();
131 },
132 onFilesChanged() {
133 this.files = [];
134 const files = this.$refs.audioFileInput.files;
135
136 if (files?.length !== undefined && files?.length > 0) {
137 for (const file of files) {
138 this.files.push(file);
139 }
140 }
141 },
142 async doTranscription() {
143 this.isTranscribing = true;
144
145 await getTranscriptions(this.files, this.$store, this);
146
147 this.files = []; // Clear the file list, as there is no reason the user would want to transcribe the same file multiple times over
148 this.isTranscribing = false;
149 // TODO: Push files to queue. If currently transcribing, good to go; it'll pull off it.
150 // Else call getTranscriptions();
151 // Then, we don't have to worry about preventing the user from transcribing multiple items.
152 },
153 /**
154 * Dismisses a failure
155 * @param {String} id The UUID of the failure.
156 */
157 dismissFailure(id) {
158 this.failures.delete(id);
159 }
160 }
161}
162
163/**
164 * Gets the transcription of each submitted audio file.
165 *
166 * @param {File[]} files The files to transcribe.
167 */
168async function getTranscriptions(files, store, vm) {
169 await Util.delay(200); // TODO: Remove - UI testing purposes only
170
171 try {
172 for await (const batch of transcribeService.batchTranscribeFiles(files)) {
173 for (const t of batch) {
174 if (!t.success) {
175 const failure = new TranscriptionViewFailure(t.file_name, t.log);
176 vm.failures.set(failure.id, failure);
177 }
178 else {
179 const f = files.find(f => f.name === t.file_name);
180 if (f === undefined) {
181 throw new Error("File name mismatch");
182 }
183
184 // TODO: Hash file name and size instead. Good indicator that the user has uploaded a duplicate.
185 const tvm = new TranscriptionViewModel(t, f);
186 store.commit("transcriptionAdd", tvm);
187 // let model = new TranscriptionViewModel(t, f);
188 // model.words = getTranscriptionWords(t);
189
190 // TranscriptionsListVM.transcriptions.set(model.id, model);
191 }
192 }
193 }
194 }
195 catch (e) {
196 console.error("Failed to transcribe files");
197 console.error(e);
198
199 const failure = new TranscriptionViewFailure(e.fileName, e.message);
200 vm.failures.set(failure.id, failure);
201 }
202}
203</script>
Note: See TracBrowser for help on using the repository browser.