Merge branch 'main' into revert-space-view

pull/1428/head
ggurdin 1 year ago committed by GitHub
commit 4cf0b372da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -5,13 +5,10 @@ import 'dart:developer';
import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/pangea/config/environment.dart';
import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/enum/activity_type_enum.dart';
import 'package:fluffychat/pangea/enum/construct_type_enum.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/practice_activity_event.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/practice_activity_event.dart';
import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart';
import 'package:fluffychat/pangea/models/practice_activities.dart/multiple_choice_activity_model.dart';
import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart';
import 'package:fluffychat/pangea/network/requests.dart'; import 'package:fluffychat/pangea/network/requests.dart';
import 'package:fluffychat/pangea/network/urls.dart'; import 'package:fluffychat/pangea/network/urls.dart';
@ -22,11 +19,11 @@ import 'package:matrix/matrix.dart';
/// Represents an item in the completion cache. /// Represents an item in the completion cache.
class _RequestCacheItem { class _RequestCacheItem {
MessageActivityRequest req; MessageActivityRequest req;
PracticeActivityModel? practiceActivityEvent; PracticeActivityModel? practiceActivity;
_RequestCacheItem({ _RequestCacheItem({
required this.req, required this.req,
required this.practiceActivityEvent, required this.practiceActivity,
}); });
} }
@ -109,64 +106,46 @@ class PracticeGenerationController {
final int cacheKey = req.hashCode; final int cacheKey = req.hashCode;
if (_cache.containsKey(cacheKey)) { if (_cache.containsKey(cacheKey)) {
return _cache[cacheKey]!.practiceActivityEvent; return _cache[cacheKey]!.practiceActivity;
} else { }
//TODO - send request to server/bot, either via API or via event of type pangeaActivityReq
// for now, just make and send the event from the client
final MessageActivityResponse res = await _fetch(
accessToken: _pangeaController.userController.accessToken,
requestModel: req,
);
if (res.finished) { final MessageActivityResponse res = await _fetch(
debugPrint('Activity generation finished'); accessToken: _pangeaController.userController.accessToken,
return null; requestModel: req,
} );
// if the server points to an existing event, return that event if (res.finished) {
if (res.existingActivityEventId != null) { debugPrint('Activity generation finished');
final Event? existingEvent = return null;
await event.room.getEventById(res.existingActivityEventId!); }
debugPrint( // if the server points to an existing event, return that event
'Existing activity event found: ${existingEvent?.content}', if (res.existingActivityEventId != null) {
); final Event? existingEvent =
if (existingEvent != null) { await event.room.getEventById(res.existingActivityEventId!);
return PracticeActivityEvent(
event: existingEvent,
timeline: event.timeline,
).practiceActivity;
}
}
if (res.activity == null) { debugPrint(
debugPrint('No activity generated'); 'Existing activity event found: ${existingEvent?.content}',
return null; );
if (existingEvent != null) {
return PracticeActivityEvent(
event: existingEvent,
timeline: event.timeline,
).practiceActivity;
} }
}
if (res.activity == null) {
debugPrint('No activity generated');
return null;
}
debugPrint('Activity generated: ${res.activity!.toJson()}'); debugPrint('Activity generated: ${res.activity!.toJson()}');
_sendAndPackageEvent(res.activity!, event); _sendAndPackageEvent(res.activity!, event);
_cache[cacheKey] = _cache[cacheKey] =
_RequestCacheItem(req: req, practiceActivityEvent: res.activity!); _RequestCacheItem(req: req, practiceActivity: res.activity!);
return _cache[cacheKey]!.practiceActivityEvent; return _cache[cacheKey]!.practiceActivity;
}
} }
PracticeActivityModel _dummyModel(PangeaMessageEvent event) =>
PracticeActivityModel(
tgtConstructs: [
ConstructIdentifier(lemma: "be", type: ConstructTypeEnum.vocab),
],
activityType: ActivityTypeEnum.multipleChoice,
langCode: event.messageDisplayLangCode,
msgId: event.eventId,
content: ActivityContent(
question: "What is a synonym for 'happy'?",
choices: ["sad", "angry", "joyful", "tired"],
answer: "joyful",
spanDisplayDetails: null,
),
);
} }

@ -1,22 +1,10 @@
enum ActivityTypeEnum { enum ActivityTypeEnum { multipleChoice, wordFocusListening }
multipleChoice,
freeResponse,
listening,
speaking,
wordFocusListening
}
extension ActivityTypeExtension on ActivityTypeEnum { extension ActivityTypeExtension on ActivityTypeEnum {
String get string { String get string {
switch (this) { switch (this) {
case ActivityTypeEnum.multipleChoice: case ActivityTypeEnum.multipleChoice:
return 'multiple_choice'; return 'multiple_choice';
case ActivityTypeEnum.freeResponse:
return 'free_response';
case ActivityTypeEnum.listening:
return 'listening';
case ActivityTypeEnum.speaking:
return 'speaking';
case ActivityTypeEnum.wordFocusListening: case ActivityTypeEnum.wordFocusListening:
return 'word_focus_listening'; return 'word_focus_listening';
} }

@ -45,18 +45,24 @@ extension PangeaEvent on Event {
Future<PangeaAudioFile?> getPangeaAudioFile() async { Future<PangeaAudioFile?> getPangeaAudioFile() async {
if (type != EventTypes.Message || messageType != MessageTypes.Audio) { if (type != EventTypes.Message || messageType != MessageTypes.Audio) {
ErrorHandler.logError( ErrorHandler.logError(
e: "Event $eventId is not an audio message", e: "Event is not an audio message",
data: {
"event": toJson(),
},
); );
return null; return null;
} }
// @ggurdin what are cases where these would be null?
// if it would be unexpected, we should log an error with details to investigate
final transcription = final transcription =
content.tryGetMap<String, dynamic>(ModelKey.transcription); content.tryGetMap<String, dynamic>(ModelKey.transcription);
final audioContent = final audioContent =
content.tryGetMap<String, dynamic>('org.matrix.msc1767.audio'); content.tryGetMap<String, dynamic>('org.matrix.msc1767.audio');
if (transcription == null || audioContent == null) return null; if (transcription == null || audioContent == null) {
ErrorHandler.logError(
e: "Called getPangeaAudioFile on an audio message without transcription or audio content",
);
return null;
}
final matrixFile = await downloadAndDecryptAttachment(); final matrixFile = await downloadAndDecryptAttachment();
final duration = audioContent.tryGet<int>('duration'); final duration = audioContent.tryGet<int>('duration');

@ -603,6 +603,7 @@ class PangeaMessageEvent {
event: event, event: event,
), ),
); );
final content = practiceEvents.last.practiceActivity;
} catch (e, s) { } catch (e, s) {
ErrorHandler.logError(e: e, s: s, data: event.toJson()); ErrorHandler.logError(e: e, s: s, data: event.toJson());
} }
@ -625,22 +626,10 @@ class PangeaMessageEvent {
List<PracticeActivityEvent> practiceActivitiesByLangCode( List<PracticeActivityEvent> practiceActivitiesByLangCode(
String langCode, { String langCode, {
bool debug = false, bool debug = false,
}) { }) =>
try { _practiceActivityEvents
debugger(when: debug); .where((event) => event.practiceActivity.langCode == langCode)
final List<PracticeActivityEvent> activities = []; .toList();
for (final event in _practiceActivityEvents) {
if (event.practiceActivity.langCode == langCode) {
activities.add(event);
}
}
return activities;
} catch (e, s) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: e, s: s, data: event.toJson());
return [];
}
}
/// Returns a list of [PracticeActivityEvent] for the user's active l2. /// Returns a list of [PracticeActivityEvent] for the user's active l2.
List<PracticeActivityEvent> get practiceActivities => List<PracticeActivityEvent> get practiceActivities =>

@ -41,7 +41,6 @@ class PracticeActivityEvent {
return _content!; return _content!;
} catch (e, s) { } catch (e, s) {
final contentMap = event.content; final contentMap = event.content;
debugger(when: kDebugMode);
rethrow; rethrow;
} }
} }

@ -242,6 +242,11 @@ class MessageActivityRequest {
'existing_activities': existingActivities.map((e) => e.toJson()).toList(), 'existing_activities': existingActivities.map((e) => e.toJson()).toList(),
'activity_quality_feedback': activityQualityFeedback?.toJson(), 'activity_quality_feedback': activityQualityFeedback?.toJson(),
'iso_8601_time_of_req': DateTime.now().toIso8601String(), 'iso_8601_time_of_req': DateTime.now().toIso8601String(),
// this is a list of activity types that the client can handle
// the server will only return activities of these types
// this for backwards compatibility with old clients
'client_version_compatible_activity_types':
ActivityTypeEnum.values.map((e) => e.string).toList(),
}; };
} }

@ -56,12 +56,6 @@ class MessageAudioCardState extends State<MessageAudioCard> {
@override @override
void didUpdateWidget(covariant oldWidget) { void didUpdateWidget(covariant oldWidget) {
// @ggurdin did you find a case of needing to reinitialize TTS because of a language change?
// if (widget.messageEvent.messageDisplayLangCode !=
// oldWidget.messageEvent.messageDisplayLangCode) {
// initializeTTS();
// }
if (oldWidget.selection != widget.selection) { if (oldWidget.selection != widget.selection) {
debugPrint('selection changed'); debugPrint('selection changed');
setSectionStartAndEndFromSelection(); setSectionStartAndEndFromSelection();

@ -14,7 +14,6 @@ class TtsController {
List<String> availableLangCodes = []; List<String> availableLangCodes = [];
final flutter_tts.FlutterTts tts = flutter_tts.FlutterTts(); final flutter_tts.FlutterTts tts = flutter_tts.FlutterTts();
// if targetLanguage isn't set here, it needs to be set later
TtsController() { TtsController() {
setupTTS(); setupTTS();
} }
@ -26,8 +25,6 @@ class TtsController {
debugger(when: kDebugMode && targetLanguage == null); debugger(when: kDebugMode && targetLanguage == null);
debugPrint('setupTTS targetLanguage: $targetLanguage');
tts.setLanguage( tts.setLanguage(
targetLanguage ?? "en", targetLanguage ?? "en",
); );
@ -35,21 +32,21 @@ class TtsController {
await tts.awaitSpeakCompletion(true); await tts.awaitSpeakCompletion(true);
final voices = await tts.getVoices; final voices = await tts.getVoices;
debugPrint("voices: $voices");
availableLangCodes = (voices as List) availableLangCodes = (voices as List)
.map((v) { .map((v) {
// debugPrint('v: $v'); // on iOS / web, the codes are in 'locale', but on Android, they are in 'name'
final nameCode = v['name']?.split("-").first;
//@ggurdin i changed this from name to locale final localeCode = v['locale']?.split("-").first;
//in my testing, that's where the language code is stored return nameCode.length == 2 ? nameCode : localeCode;
// maybe it's different for different devices? was it different in your android testing?
// return v['name']?.split("-").first;
return v['locale']?.split("-").first;
}) })
.toSet() .toSet()
.cast<String>() .cast<String>()
.toList(); .toList();
debugPrint("lang supported? $isLanguageFullySupported"); debugPrint("availableLangCodes: $availableLangCodes");
debugger(when: kDebugMode && !isLanguageFullySupported);
} catch (e, s) { } catch (e, s) {
debugger(when: kDebugMode); debugger(when: kDebugMode);
ErrorHandler.logError(e: e, s: s); ErrorHandler.logError(e: e, s: s);
@ -67,7 +64,6 @@ class TtsController {
bool get isLanguageFullySupported => bool get isLanguageFullySupported =>
availableLangCodes.contains(targetLanguage); availableLangCodes.contains(targetLanguage);
// @ggurdin
Widget get missingVoiceButton => targetLanguage != null && Widget get missingVoiceButton => targetLanguage != null &&
(kIsWeb || isLanguageFullySupported || !PlatformInfos.isAndroid) (kIsWeb || isLanguageFullySupported || !PlatformInfos.isAndroid)
? const SizedBox.shrink() ? const SizedBox.shrink()

Loading…
Cancel
Save