Skip to content

Commit

Permalink
feat(subtitles): Don't show delayed final
Browse files Browse the repository at this point in the history
If a non final transcript was displayed and then hidden and then we receive a final transcript we remove the part that has already been shown before. If the final transcript is the same as the non final that was already displayed we don't show the final.
  • Loading branch information
hristoterezov committed Nov 19, 2024
1 parent 50e9413 commit beb6f81
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 9 deletions.
11 changes: 11 additions & 0 deletions react/features/subtitles/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@
*/
export const REMOVE_TRANSCRIPT_MESSAGE = 'REMOVE_TRANSCRIPT_MESSAGE';

/**
* The type of (redux) action which indicates that an cached transcript
* has to be removed from the state.
*
* {
* type: REMOVE_CACHED_TRANSCRIPT_MESSAGE,
* transciptMessageID: string,
* }
*/
export const REMOVE_CACHED_TRANSCRIPT_MESSAGE = 'REMOVE_CACHED_TRANSCRIPT_MESSAGE';

/**
* The type of (redux) action which indicates that a transcript with an
* given message_id to be added or updated is received.
Expand Down
17 changes: 17 additions & 0 deletions react/features/subtitles/actions.any.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DEFAULT_LANGUAGE } from '../base/i18n/i18next';

import {
REMOVE_CACHED_TRANSCRIPT_MESSAGE,
REMOVE_TRANSCRIPT_MESSAGE,
SET_REQUESTING_SUBTITLES,
TOGGLE_REQUESTING_SUBTITLES,
Expand All @@ -23,6 +24,22 @@ export function removeTranscriptMessage(transcriptMessageID: string) {
};
}

/**
* Signals that a cached transcript has to be removed from the state.
*
* @param {string} transcriptMessageID - The message_id to be removed.
* @returns {{
* type: REMOVE_CACHED_TRANSCRIPT_MESSAGE,
* transcriptMessageID: string,
* }}
*/
export function removeCachedTranscriptMessage(transcriptMessageID: string) {
return {
type: REMOVE_CACHED_TRANSCRIPT_MESSAGE,
transcriptMessageID
};
}

/**
* Signals that a transcript with the given message_id to be added or updated
* is received.
Expand Down
40 changes: 31 additions & 9 deletions react/features/subtitles/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
TOGGLE_REQUESTING_SUBTITLES
} from './actionTypes';
import {
removeCachedTranscriptMessage,
removeTranscriptMessage,
setRequestingSubtitles,
updateTranscriptMessage
Expand Down Expand Up @@ -134,18 +135,16 @@ function _endpointMessageReceived(store: IStore, next: Function, action: AnyActi
name
};

let newTranscriptMessage: ITranscriptMessage | undefined;

if (json.type === JSON_TYPE_TRANSLATION_RESULT && json.language === language) {
// Displays final results in the target language if translation is
// enabled.

const newTranscriptMessage = {
newTranscriptMessage = {
clearTimeOut: undefined,
final: json.text,
final: json.text?.trim(),
participant
};

_setClearerOnTranscriptMessage(dispatch, transcriptMessageID, newTranscriptMessage);
dispatch(updateTranscriptMessage(transcriptMessageID, newTranscriptMessage));
} else if (json.type === JSON_TYPE_TRANSCRIPTION_RESULT) {
// Displays interim and final results without any translation if
// translations are disabled.
Expand Down Expand Up @@ -209,13 +208,12 @@ function _endpointMessageReceived(store: IStore, next: Function, action: AnyActi
// message ID or adds a new transcript message if it does not
// exist in the map.
const existingMessage = state['features/subtitles']._transcriptMessages.get(transcriptMessageID);
const newTranscriptMessage: ITranscriptMessage = {

newTranscriptMessage = {
clearTimeOut: existingMessage?.clearTimeOut,
participant
};

_setClearerOnTranscriptMessage(dispatch, transcriptMessageID, newTranscriptMessage);

// If this is final result, update the state as a final result
// and start a count down to remove the subtitle from the state
if (!json.is_interim) {
Expand All @@ -231,7 +229,31 @@ function _endpointMessageReceived(store: IStore, next: Function, action: AnyActi
// after the stable part.
newTranscriptMessage.unstable = text;
}
}

if (newTranscriptMessage) {
if (newTranscriptMessage.final) {
const cachedTranscriptMessage
= state['features/subtitles']._cachedTranscriptMessages?.get(transcriptMessageID);

if (cachedTranscriptMessage) {
const cachedText = (cachedTranscriptMessage.stable || cachedTranscriptMessage.unstable)?.trim();
const newText = newTranscriptMessage.final;

if (cachedText && cachedText.length > 0 && newText && newText.length > 0
&& newText.toLowerCase().startsWith(cachedText.toLowerCase())) {
newTranscriptMessage.final = newText.slice(cachedText.length)?.trim();
}
dispatch(removeCachedTranscriptMessage(transcriptMessageID));

if (!newTranscriptMessage.final || newTranscriptMessage.final.length === 0) {
return next(action);
}
}
}


_setClearerOnTranscriptMessage(dispatch, transcriptMessageID, newTranscriptMessage);
dispatch(updateTranscriptMessage(transcriptMessageID, newTranscriptMessage));
}

Expand Down
38 changes: 38 additions & 0 deletions react/features/subtitles/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ReducerRegistry from '../base/redux/ReducerRegistry';
import { TRANSCRIBER_LEFT } from '../transcribing/actionTypes';

import {
REMOVE_CACHED_TRANSCRIPT_MESSAGE,
REMOVE_TRANSCRIPT_MESSAGE,
SET_REQUESTING_SUBTITLES,
TOGGLE_REQUESTING_SUBTITLES,
Expand All @@ -13,13 +14,15 @@ import { ITranscriptMessage } from './types';
* Default State for 'features/transcription' feature.
*/
const defaultState = {
_cachedTranscriptMessages: new Map(),
_displaySubtitles: false,
_transcriptMessages: new Map(),
_requestingSubtitles: false,
_language: null
};

export interface ISubtitlesState {
_cachedTranscriptMessages: Map<string, ITranscriptMessage>;
_displaySubtitles: boolean;
_language: string | null;
_requestingSubtitles: boolean;
Expand All @@ -35,6 +38,8 @@ ReducerRegistry.register<ISubtitlesState>('features/subtitles', (
switch (action.type) {
case REMOVE_TRANSCRIPT_MESSAGE:
return _removeTranscriptMessage(state, action);
case REMOVE_CACHED_TRANSCRIPT_MESSAGE:
return _removeCachedTranscriptMessage(state, action);
case UPDATE_TRANSCRIPT_MESSAGE:
return _updateTranscriptMessage(state, action);
case SET_REQUESTING_SUBTITLES:
Expand Down Expand Up @@ -70,16 +75,45 @@ ReducerRegistry.register<ISubtitlesState>('features/subtitles', (
*/
function _removeTranscriptMessage(state: ISubtitlesState, { transcriptMessageID }: { transcriptMessageID: string; }) {
const newTranscriptMessages = new Map(state._transcriptMessages);
const message = newTranscriptMessages.get(transcriptMessageID);
let { _cachedTranscriptMessages } = state;

if (message && !message.final) {
_cachedTranscriptMessages = new Map(_cachedTranscriptMessages);
state._cachedTranscriptMessages.set(transcriptMessageID, message);
}

// Deletes the key from Map once a final message arrives.
newTranscriptMessages.delete(transcriptMessageID);

return {
...state,
_cachedTranscriptMessages,
_transcriptMessages: newTranscriptMessages
};
}


/**
* Reduces a specific Redux action REMOVE_CACHED_TRANSCRIPT_MESSAGE of the feature transcription.
*
* @param {Object} state - The Redux state of the feature transcription.
* @param {Action} action -The Redux action REMOVE_CACHED_TRANSCRIPT_MESSAGE to reduce.
* @returns {Object} The new state of the feature transcription after the reduction of the specified action.
*/
function _removeCachedTranscriptMessage(state: ISubtitlesState,
{ transcriptMessageID }: { transcriptMessageID: string; }) {
const newCachedTranscriptMessages = new Map(state._cachedTranscriptMessages);

// Deletes the key from Map once a final message arrives.
newCachedTranscriptMessages.delete(transcriptMessageID);

return {
...state,
_cachedTranscriptMessages: newCachedTranscriptMessages
};
}

/**
* Reduces a specific Redux action UPDATE_TRANSCRIPT_MESSAGE of the feature
* transcription.
Expand All @@ -92,12 +126,16 @@ function _removeTranscriptMessage(state: ISubtitlesState, { transcriptMessageID
function _updateTranscriptMessage(state: ISubtitlesState, { transcriptMessageID, newTranscriptMessage }:
{ newTranscriptMessage: ITranscriptMessage; transcriptMessageID: string; }) {
const newTranscriptMessages = new Map(state._transcriptMessages);
const _cachedTranscriptMessages = new Map(state._cachedTranscriptMessages);

_cachedTranscriptMessages.delete(transcriptMessageID);

// Updates the new message for the given key in the Map.
newTranscriptMessages.set(transcriptMessageID, newTranscriptMessage);

return {
...state,
_cachedTranscriptMessages,
_transcriptMessages: newTranscriptMessages
};
}

0 comments on commit beb6f81

Please sign in to comment.