diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 5e6aa7362..830eaafec 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:async/async.dart' as async; import 'package:collection/collection.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; @@ -65,6 +66,10 @@ import 'package:fluffychat/pangea/learning_settings/language_mismatch_repo.dart' import 'package:fluffychat/pangea/learning_settings/p_language_dialog.dart'; import 'package:fluffychat/pangea/navigation/navigation_util.dart'; import 'package:fluffychat/pangea/spaces/load_participants_builder.dart'; +import 'package:fluffychat/pangea/speech_to_text/audio_encoding_enum.dart'; +import 'package:fluffychat/pangea/speech_to_text/speech_to_text_repo.dart'; +import 'package:fluffychat/pangea/speech_to_text/speech_to_text_request_model.dart'; +import 'package:fluffychat/pangea/speech_to_text/speech_to_text_response_model.dart'; import 'package:fluffychat/pangea/subscription/widgets/paywall_card.dart'; import 'package:fluffychat/pangea/token_info_feedback/show_token_feedback_dialog.dart'; import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_request.dart'; @@ -1207,7 +1212,11 @@ class ChatController extends State replyEvent.value = null; // Pangea# - room + // #Pangea + final transcriptFuture = _getVoiceMessageTranscript(file); + // room + final eventFuture = room + // Pangea# .sendFileEvent( file, // #Pangea @@ -1229,7 +1238,6 @@ class ChatController extends State }, // #Pangea ) - .then(_sendVoiceMessageAnalytics) .catchError((e, s) { ErrorHandler.logError( e: e, @@ -1247,6 +1255,39 @@ class ChatController extends State // ); // return null; // }); + + Future.wait([eventFuture, transcriptFuture]).then((results) async { + final eventId = results[0] as String?; + final transcript = results[1] as async.Result; + if (eventId == null) { + ErrorHandler.logError( + e: Exception('eventID null in voiceMessageAction'), + s: StackTrace.current, + data: {'roomId': roomId}, + ); + return; + } + + if (transcript.result == null) return; + final stt = transcript.result!; + final event = await room.getEventById(eventId); + if (event == null) { + ErrorHandler.logError( + e: Exception('Event not found after sending voice message'), + s: StackTrace.current, + data: {'roomId': roomId}, + ); + } else { + final messageEvent = PangeaMessageEvent( + event: event, + timeline: timeline!, + ownMessage: true, + ); + messageEvent.sendSttRepresentationEvent(stt); + } + + _sendVoiceMessageAnalytics(eventId, stt); + }); // Pangea# return; } @@ -2191,39 +2232,11 @@ class ChatController extends State } } - Future _sendVoiceMessageAnalytics(String? eventId) async { - if (eventId == null) { - ErrorHandler.logError( - e: Exception('eventID null in voiceMessageAction'), - s: StackTrace.current, - data: {'roomId': roomId}, - ); - return; - } - - final event = await room.getEventById(eventId); - if (event == null) { - ErrorHandler.logError( - e: Exception('Event not found after sending voice message'), - s: StackTrace.current, - data: {'roomId': roomId}, - ); - return; - } - + Future _sendVoiceMessageAnalytics( + String eventId, + SpeechToTextResponseModel stt, + ) async { try { - final messageEvent = PangeaMessageEvent( - event: event, - timeline: timeline!, - ownMessage: true, - ); - - final stt = await messageEvent.requestSpeechToText( - MatrixState.pangeaController.userController.userL1?.langCodeShort ?? - LanguageKeys.unknownLanguage, - MatrixState.pangeaController.userController.userL2?.langCodeShort ?? - LanguageKeys.unknownLanguage, - ); if (stt.transcript.sttTokens.isEmpty) return; final constructs = stt.constructs(roomId, eventId); if (constructs.isEmpty) return; @@ -2241,6 +2254,35 @@ class ChatController extends State } } + Future> _getVoiceMessageTranscript( + MatrixAudioFile file, + ) async { + return SpeechToTextRepo.get( + MatrixState.pangeaController.userController.accessToken, + SpeechToTextRequestModel( + audioContent: file.bytes, + config: SpeechToTextAudioConfigModel( + encoding: mimeTypeToAudioEncoding(file.mimeType), + sampleRateHertz: 22050, + userL1: + MatrixState + .pangeaController + .userController + .userL1 + ?.langCodeShort ?? + LanguageKeys.unknownLanguage, + userL2: + MatrixState + .pangeaController + .userController + .userL2 + ?.langCodeShort ?? + LanguageKeys.unknownLanguage, + ), + ), + ); + } + void showNextMatch() { MatrixState.pAnyState.closeOverlay(); final match = choreographer.igcController.openMatches.firstOrNull; diff --git a/lib/pangea/chat/widgets/pangea_chat_input_row.dart b/lib/pangea/chat/widgets/pangea_chat_input_row.dart index 7dcb3981f..c7559d1f4 100644 --- a/lib/pangea/chat/widgets/pangea_chat_input_row.dart +++ b/lib/pangea/chat/widgets/pangea_chat_input_row.dart @@ -327,17 +327,7 @@ class PangeaChatInputRow extends StatelessWidget { .value ? IconButton( tooltip: L10n.of(context).voiceMessage, - onPressed: () => ScaffoldMessenger.of(context) - .showSnackBar( - SnackBar( - content: Text( - L10n.of( - context, - ).longPressToRecordVoiceMessage, - ), - ), - ), - onLongPress: () => recordingViewModel + onPressed: () => recordingViewModel .startRecording(controller.room), style: IconButton.styleFrom( backgroundColor: theme.bubbleColor, diff --git a/lib/pangea/events/event_wrappers/pangea_message_event.dart b/lib/pangea/events/event_wrappers/pangea_message_event.dart index 6f930464f..fb925bf91 100644 --- a/lib/pangea/events/event_wrappers/pangea_message_event.dart +++ b/lib/pangea/events/event_wrappers/pangea_message_event.dart @@ -444,13 +444,13 @@ class PangeaMessageEvent { } if (sendEvent) { - _sendSttRepresentationEvent(result.result!); + sendSttRepresentationEvent(result.result!); } return result.result!; } - Future _sendSttRepresentationEvent( + Future sendSttRepresentationEvent( SpeechToTextResponseModel stt, ) async { final representation = PangeaRepresentation( @@ -486,7 +486,7 @@ class PangeaMessageEvent { SpeechToTextResponseModel? stt = rep?.content.speechToText; if (rep == null) { stt ??= await requestSpeechToText(l1Code, l2Code, sendEvent: false); - final repEvent = await _sendSttRepresentationEvent(stt); + final repEvent = await sendSttRepresentationEvent(stt); if (repEvent == null) { throw Exception("Failed to send representation event for STT"); }