Changeset 35301


Ignore:
Timestamp:
2021-08-17T11:08:33+12:00 (3 years ago)
Author:
davidb
Message:

Fix incorrect audio being loaded when duplicate filenames are present

Location:
main/trunk/model-interfaces-dev/atea
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/model-interfaces-dev/atea/js/asr/TranscribeModule.js

    r35297 r35301  
    5050     * @param {Number | undefined} statusCode The HTTP status code of the error.
    5151     * @param {String | undefined} message The status message.
    52      * @param {String | null} file The file on which the transcription failed.
    53      */
    54     constructor(message = undefined, file = null, statusCode = -1)
     52     * @param {String | null} fileName The file on which the transcription failed.
     53     */
     54    constructor(message = undefined, fileName = null, statusCode = -1)
    5555    {
    5656        super(message);
    57         //this.message = message;
    58 
    59         this.file = file;
     57
     58        /** @type {String | null} The name of the file that the transcription error occured on. */
     59        this.fileName = fileName;
     60
     61        /** @type {Number | undefined} The status code returned by the API when the erro was generated. */
    6062        this.statusCode = statusCode;
    6163    }
     
    8587     * A maximum of 5 MiB before chunking.
    8688     *
    87      * @param {FileList} files The files to upload
     89     * @param {FileList | File[]} files The files to upload
    8890     * @returns {AsyncGenerator<TranscriptionModel[]>} The transcribed audio files.
    8991     * @throws {TranscriptionError} When the transcription request fails to complete.
  • main/trunk/model-interfaces-dev/atea/js/asr/asr-controller.js

    r35297 r35301  
    1414const TRANSCRIPTION_AUDIO_SOURCE_ELEMENT = document.getElementById("transcriptionAudioSource");
    1515
    16 let cachedAudioFileList = new Map();
     16class TranscriptionViewModel {
     17    /**
     18     * Initialises a new instance of the {@link TranscriptionViewModel} class.
     19     *
     20     * @param {TranscriptionModel} transcription
     21     * @param {File} file The file from which the transcription was generated.
     22     */
     23    constructor(transcription, file) {
     24        /** @type {String} The UUID of this transcription. */
     25        this.id = UUID.generate();
     26
     27        /** @type {String} The transcription. */
     28        this.transcription = transcription.transcription;
     29
     30        /** @type {String} The name of the file from which the transcription was generated. */
     31        this.fileName = transcription.file_name;
     32
     33        /** @type {TranscriptionMetadata[]} The transcription metadata. */
     34        this.metadata = transcription.metadata;
     35
     36        /** @type {File} The file from which the transcription was generated. */
     37        this.file = file;
     38    }
     39}
     40
    1741var transcribeService = new TranscribeService();
    1842
     
    93117
    94118                if (audioFileInput.files?.length != undefined && audioFileInput.files?.length > 0) {
    95                     this.files = audioFileInput?.files
     119                   
     120                    for (const f of audioFileInput.files) {
     121                        this.files.push(f);
     122                    }
    96123                }
    97124                else {
     
    103130                // Else call getTranscriptions();
    104131                // Then, we don't have to worry about preventing the user from transcribing multiple items.
    105                 await getTranscriptions();
     132                await getTranscriptions(this.files);
    106133            }
    107134        }
     
    110137const AudioUploadVM = AudioUploadComponent.mount("#audioUploadContainer");
    111138
    112 /**
    113  * @typedef TranscriptionViewModel
    114  * @property {String} id
    115  * @property {String} transcription
    116  * @property {String} fileName
    117  * @property {TranscriptionMetadata} metadata
    118  * @property {File} file
    119  */
    120 
    121139// @ts-ignore
    122140const TranscriptionsListComponent = Vue.createApp(
     
    125143    {
    126144        return {
    127             /** @type {Map<String, TranscriptionModel>} */
     145            /** @type {Map<String, TranscriptionViewModel>} */
    128146            transcriptions: new Map(),
    129147            /** @type {Map<String, TranscriptionError>} */
    130148            failures: new Map(),
    131149            showCharDisplay: false,
    132             showWordList: false
    133         }
    134     },
    135     computed:
    136     {
    137         getTranscriptions()
    138         {
    139             let converted = [];
    140 
    141             for (const [key, value] of this.transcriptions)
    142             {
    143                 converted.push(
    144                 {
    145                     id: key,
    146                     transcription: value.transcription,
    147                     fileName: value.file_name,
    148                     metadata: value.metadata
    149                 });
    150             }
    151 
    152             return converted;
     150            showWordList: false,
     151            /** @type {{id: String, url: String} | null} Gets the ID of the transcription for which the audio is currently loaded */
     152            currentlyLoadedAudio: null
    153153        }
    154154    },
    155155    methods:
    156156    {
    157         playAudioFile(fileName, startTime = 0) // TODO: Convert to ID
     157        playAudioFile(transcriptionId, startTime = 0) // TODO: Convert to ID
    158158        {
    159159            if (startTime < 0)
     
    169169            }
    170170           
    171             console.log("Starting at " + startTime + " seconds");
    172             loadAudioFile(fileName);
    173             this.currentAudioTime = startTime;
     171            this.currentlyLoadedAudio = loadTranscriptionAudio(transcriptionId, this.currentlyLoadedAudio);
     172
    174173            TRANSCRIPTION_AUDIO_ELEMENT.currentTime = startTime;
    175174            TRANSCRIPTION_AUDIO_ELEMENT.play();
     
    267266/**
    268267 * Gets the transcription of each submitted audio file.
     268 *
     269 * @param {File[]} files The files to transcribe.
    269270 */
    270 async function getTranscriptions()
     271async function getTranscriptions(files)
    271272{
    272273    AudioUploadVM.isTranscribing = true;
    273 
    274     /** @type {FileList} */
    275     const files = AudioUploadVM.files;
    276274   
    277     await delay(200); // TODO: Remove - UI testing purposes only
    278 
    279     // Cache the file list so that we can playback audio in the future
    280     for (const file of files) {
    281         cachedAudioFileList.set(file.name, file)
    282     }
     275    // await delay(200); // TODO: Remove - UI testing purposes only
    283276   
    284277    // Transcribe each audio file in batches.
     
    293286                }
    294287                else {
    295                     TranscriptionsListVM.transcriptions.set(UUID.generate(), t);
     288                    let f = files.find(f => f.name == t.file_name);
     289                    if (f == undefined)
     290                        throw new Error("File name mismatch");
     291
     292                    let model = new TranscriptionViewModel(t, f);
     293
     294                    TranscriptionsListVM.transcriptions.set(model.id, model);
    296295                }
    297296            }
     
    302301        console.error("Failed to transcribe files");
    303302        console.error(e);
    304         TranscriptionsListVM.failures.push(e);
     303        TranscriptionsListVM.failures.set(UUID.generate(), e);
    305304    }
    306305   
     
    371370/**
    372371 * Loads an audio file.
    373  * @param {String} requestedAudioFile The name of the requested audio file.
     372 * @param {String} transcriptionId The name of the requested audio file.
     373 * @param {{id: String, url: String} | null} current The currently loaded audio.
     374 * @returns {{id: String, url: String}} If a new audio file was loaded, a new audio tracking object, else the current one.
    374375 */
    375 function loadAudioFile(requestedAudioFile)
    376 {
    377     const currentAudioFile = TRANSCRIPTION_AUDIO_SOURCE_ELEMENT.dataset.fileName;
    378 
    379     // Load the appropiate audio if necessary.
    380     if (currentAudioFile != requestedAudioFile)
    381     {
    382         // If an audio file is already loaded we can revoke it.
    383         if (currentAudioFile) {
    384             URL.revokeObjectURL(currentAudioFile);
    385         }
    386 
    387         const urlObject = URL.createObjectURL(cachedAudioFileList.get(requestedAudioFile));
     376function loadTranscriptionAudio(transcriptionId, current)
     377{
     378    if (current == null || current.id != transcriptionId)
     379    {
     380        // TODO: Need to profile on some larger tracks; this may not be worth it? Better to cache a URL object instead?
     381        if (current != null) {
     382            URL.revokeObjectURL(current.url);
     383        }
     384
     385        const urlObject = URL.createObjectURL(TranscriptionsListVM.transcriptions.get(transcriptionId).file);
    388386        TRANSCRIPTION_AUDIO_SOURCE_ELEMENT.src = urlObject;
    389         TRANSCRIPTION_AUDIO_SOURCE_ELEMENT.dataset.fileName = requestedAudioFile;
    390387        TRANSCRIPTION_AUDIO_ELEMENT.load();
    391     }
     388
     389        return { id: transcriptionId, url: urlObject };
     390    }
     391
     392    return current;
    392393}
    393394
  • main/trunk/model-interfaces-dev/atea/transform/pages/asr.xsl

    r35297 r35301  
    8484                        <div class="transcription__error-container card">
    8585                            <div>
    86                                 Failed to transcribe <i v-if="value.file">{{ value.file }}</i><br/>
     86                                Failed to transcribe <i v-if="value.file">{{ value.fileName }}</i><br/>
    8787                                <span v-if="value.message">Reason: {{ value.message }}</span>
    8888                            </div>
     
    9595
    9696                    <!-- Displays each transcription -->
    97                     <li v-for="transcription in getTranscriptions">
     97                    <li v-for="[id, transcription] in transcriptions">
    9898                        <div class="transcription__container card">
    9999                            <!-- Header containing info and actions for the transcription -->
     
    101101                                <span>File: {{ transcription.fileName }}</span>
    102102
    103                                 <button class="theme-error" v-on:click="removeTranscription(transcription.id)" type="button">
     103                                <button class="theme-error" v-on:click="removeTranscription(id)" type="button">
    104104                                    <span class="material-icons">delete</span>
    105105                                    <span>Remove</span>
     
    113113                            <div class="transcription__word-list" v-if="showWordList">
    114114                                <div class="transcription__word-list__controls">
    115                                     <button class="btn-fab" v-on:click="playAudioFile(transcription.fileName)" type="button">
     115                                    <button class="btn-fab" v-on:click="playAudioFile(id)" type="button">
    116116                                        <span class="material-icons">play_arrow</span>
    117117                                    </button>
     
    123123                                    <li v-if="!showCharDisplay">
    124124                                        <span v-for="word in getWords(transcription.id)" class="transcription__word"
    125                                               v-on:click="playAudioFile(transcription.fileName, word.startTime)">
     125                                              v-on:click="playAudioFile(id, word.startTime)">
    126126                                            {{ word.word }}
    127127                                        </span>
     
    129129                                    <li v-if="showCharDisplay">
    130130                                        <span v-for="char in getChars(transcription.id)" class="transcription__word"
    131                                               v-on:click="playAudioFile(transcription.fileName, char.startTime)">
     131                                              v-on:click="playAudioFile(id, char.startTime)">
    132132                                            {{ char.char }}
    133133                                        </span>
Note: See TracChangeset for help on using the changeset viewer.