From b37074459ea57c91aefbcf2d3e7f747941ebf0e6 Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Tue, 12 Nov 2024 16:33:59 -0500 Subject: [PATCH 1/6] guess grammar category when missing, saving form when available --- assets/l10n/intl_en.arb | 4 +- .../morph_categories_and_labels.dart | 167 ++++++++++++++++++ .../controllers/put_analytics_controller.dart | 1 + .../models/analytics/constructs_model.dart | 96 ++++++---- .../practice_activity_record_model.dart | 2 + .../models/representation_content_model.dart | 3 + .../utils/{ => grammar}/get_grammar_copy.dart | 2 +- .../analytics_popup/analytics_xp_tile.dart | 2 +- 8 files changed, 240 insertions(+), 37 deletions(-) create mode 100644 lib/pangea/constants/morph_categories_and_labels.dart rename lib/pangea/utils/{ => grammar}/get_grammar_copy.dart (99%) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 2d0a3c823..e4290abd3 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4158,7 +4158,9 @@ "goToSpace": "Go to space: {space}", "@goToSpace": { "type": "text", - "space": {} + "placeholders": { + "space": {} + } }, "markAsUnread": "Mark as unread", "userLevel": "{level} - User", diff --git a/lib/pangea/constants/morph_categories_and_labels.dart b/lib/pangea/constants/morph_categories_and_labels.dart new file mode 100644 index 000000000..6eb056a53 --- /dev/null +++ b/lib/pangea/constants/morph_categories_and_labels.dart @@ -0,0 +1,167 @@ +const Map> morphCategoriesAndLabels = { + "Pos": [ + "ADJ", + "ADP", + "ADV", + "AFFIX", + "AUX", + "CCONJ", + "DET", + "INTJ", + "NOUN", + "NUM", + "PART", + "PRON", + "PROPN", + "PUNCT", + "SCONJ", + "SPACE", + "SYM", + "VERB", + "X", + ], + "AdvType": ["Adverbial", "Tim"], + "Aspect": [ + "Imp", + "Perf", + "Prog", + "Hab", + ], + "Case": [ + "Nom", + "Acc", + "Dat", + "Gen", + "Voc", + "Abl", + "Loc", + "All", + "Ins", + "Ess", + "Tra", + "Com", + "Par", + "Adv", + "Ref", + "Rel", + "Equ", + "Dis", + "Abs", + "Erg", + "Cau", + "Ben", + "Sub", + "Sup", + "Tem", + "Obl", + "Acc,Dat", + "Acc,Nom", + "Pre", + ], + "ConjType": ["Coord", "Sub", "Cmp"], + "Definite": ["Def", "Ind", "Cons"], + "Degree": [ + "Pos", + "Cmp", + "Sup", + "Abs", + ], + "Evident": ["Fh", "Nfh"], + "Foreign": ["Yes"], + "Gender": ["Masc", "Fem", "Neut", "Com"], + "Mood": [ + "Ind", + "Imp", + "Sub", + "Cnd", + "Opt", + "Jus", + "Adm", + "Des", + "Nec", + "Pot", + "Prp", + "Qot", + "Int", + ], + "NounType": ["Prop", "Comm", "Not_proper"], + "NumForm": [ + "Digit", + "Word", + "Roman", + "Letter", + ], + "NumType": [ + "Card", + "Ord", + "Mult", + "Frac", + "Sets", + "Range", + "Dist", + ], + "Number": [ + "Sing", + "Plur", + "Dual", + "Tri", + "Pauc", + "Grpa", + "Grpl", + "Inv", + ], + "Number[psor]": ["Sing", "Plur", "Dual"], + "Person": [ + "0", + "1", + "2", + "3", + "4", + ], + "Polarity": ["Pos", "Neg"], + "Polite": ["Infm", "Form", "Elev", "Humb"], + "Poss": ["Yes"], + "PrepCase": ["Npr"], + "PronType": [ + "Prs", + "Int", + "Rel", + "Dem", + "Tot", + "Neg", + "Art", + "Emp", + "Exc", + "Ind", + "Rcp", + "Int,Rel", + ], + "PunctSide": ["Ini", "Fin"], + "PunctType": [ + "Brck", + "Dash", + "Excl", + "Peri", + "Qest", + "Quot", + "Semi", + "Colo", + "Comm", + ], + "Reflex": ["Yes"], + "Tense": ["Pres", "Past", "Fut", "Imp", "Pqp", "Aor", "Eps", "Prosp"], + "VerbForm": [ + "Fin", + "Inf", + "Sup", + "Part", + "Conv", + "Vnoun", + "Ger", + "Adn", + "Lng", + ], + "VerbType": ["Mod", "Caus"], + "Voice": ["Act", "Mid", "Pass", "Antip", "Cau", "Dir", "Inv", "Rcp", "Caus"], + "X": ["X"], +}; diff --git a/lib/pangea/controllers/put_analytics_controller.dart b/lib/pangea/controllers/put_analytics_controller.dart index f484520e8..26e0507a4 100644 --- a/lib/pangea/controllers/put_analytics_controller.dart +++ b/lib/pangea/controllers/put_analytics_controller.dart @@ -189,6 +189,7 @@ class PutAnalyticsController extends BaseController { OneConstructUse( useType: useType, lemma: entry.value, + form: token.text.content, category: entry.key, constructType: ConstructTypeEnum.morph, metadata: metadata, diff --git a/lib/pangea/models/analytics/constructs_model.dart b/lib/pangea/models/analytics/constructs_model.dart index b6b13399b..22fee9ee5 100644 --- a/lib/pangea/models/analytics/constructs_model.dart +++ b/lib/pangea/models/analytics/constructs_model.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:fluffychat/pangea/constants/morph_categories_and_labels.dart'; import 'package:fluffychat/pangea/enum/construct_use_type_enum.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; @@ -49,12 +50,15 @@ class ConstructAnalyticsModel { } class OneConstructUse { - String? lemma; + String lemma; + + // practice activities do not currently include form in the target_construct info + // for that, this is nullable String? form; /// For vocab constructs, this is the POS. For morph /// constructs, this is the morphological category. - String? category; + String category; ConstructTypeEnum constructType; ConstructUseTypeEnum useType; @@ -70,8 +74,8 @@ class OneConstructUse { required this.lemma, required this.constructType, required this.metadata, - this.category, - this.form, + required this.category, + required this.form, this.id, }); @@ -80,27 +84,20 @@ class OneConstructUse { DateTime get timeStamp => metadata.timeStamp; factory OneConstructUse.fromJson(Map json) { - final constructType = json['constructType'] != null - ? ConstructTypeUtil.fromString(json['constructType']) - : null; - debugger(when: kDebugMode && constructType == null); + debugger(when: kDebugMode && json['constructType'] == null); - final categoryEntry = json['cat'] ?? json['categories']; - String? category; - if (categoryEntry != null) { - if ((categoryEntry is List) && categoryEntry.isNotEmpty) { - category = categoryEntry.first; - } else if (categoryEntry is String) { - category = categoryEntry; - } - } + final ConstructTypeEnum constructType = json['constructType'] != null + ? ConstructTypeUtil.fromString(json['constructType']) + : ConstructTypeEnum.vocab; return OneConstructUse( useType: ConstructUseTypeUtil.fromString(json['useType']), lemma: json['lemma'], form: json['form'], - category: category, - constructType: constructType ?? ConstructTypeEnum.vocab, + category: constructType == ConstructTypeEnum.morph + ? getCategory(json) + : "Other", + constructType: constructType, id: json['id'], metadata: ConstructUseMetaData( eventId: json['msgId'], @@ -110,21 +107,52 @@ class OneConstructUse { ); } - Map toJson() { - final Map data = { - 'useType': useType.string, - 'chatId': metadata.roomId, - 'timeStamp': metadata.timeStamp.toIso8601String(), - 'form': form, - 'msgId': metadata.eventId, - }; + Map toJson() => { + 'useType': useType.string, + 'chatId': metadata.roomId, + 'timeStamp': metadata.timeStamp.toIso8601String(), + 'form': form, + 'msgId': metadata.eventId, + 'lemma': lemma, + 'constructType': constructType.string, + 'categories': category, + 'id': id, + }; + + static String getCategory(Map json) { + final categoryEntry = json['cat'] ?? json['categories']; - data['lemma'] = lemma!; - data['constructType'] = constructType.string; + if (categoryEntry == null) { + return _guessGrammarCategory(json["lemma"]); + } - if (id != null) data['id'] = id; - data['categories'] = category; - return data; + if ((categoryEntry is List)) { + if (categoryEntry.isEmpty) { + return _guessGrammarCategory(json["lemma"]); + } + return categoryEntry.first; + } else if (categoryEntry is String) { + return categoryEntry; + } + + debugPrint( + "Category entry is not a list or string -${json['cat'] ?? json['categories']}-", + ); + return _guessGrammarCategory(json["lemma"]); + } + + static String _guessGrammarCategory(String morphLemma) { + for (final String category in morphCategoriesAndLabels.keys) { + if (morphCategoriesAndLabels[category]!.contains(morphLemma)) { + debugPrint( + "found missing construct category for $morphLemma: $category"); + return category; + } + } + ErrorHandler.logError( + m: "Morph construct lemma $morphLemma not found in morph categories and labels", + ); + return "Other"; } Room? getRoom(Client client) { @@ -140,9 +168,9 @@ class OneConstructUse { int get pointValue => useType.pointValue; ConstructIdentifier get identifier => ConstructIdentifier( - lemma: lemma!, + lemma: lemma, type: constructType, - category: category ?? "", + category: category, ); } diff --git a/lib/pangea/models/practice_activities.dart/practice_activity_record_model.dart b/lib/pangea/models/practice_activities.dart/practice_activity_record_model.dart index ffa6fd30b..74f2d0d64 100644 --- a/lib/pangea/models/practice_activities.dart/practice_activity_record_model.dart +++ b/lib/pangea/models/practice_activities.dart/practice_activity_record_model.dart @@ -143,6 +143,8 @@ class ActivityRecordResponse { .map( (construct) => OneConstructUse( lemma: construct.lemma, + // TODO - add form to practiceActivity target_construct data somehow + form: null, constructType: construct.type, useType: useType, metadata: metadata, diff --git a/lib/pangea/models/representation_content_model.dart b/lib/pangea/models/representation_content_model.dart index c3f649069..3d21d7ff6 100644 --- a/lib/pangea/models/representation_content_model.dart +++ b/lib/pangea/models/representation_content_model.dart @@ -159,6 +159,7 @@ class PangeaRepresentation { OneConstructUse( useType: useType, lemma: entry.value, + form: token.text.content, category: entry.key, constructType: ConstructTypeEnum.morph, metadata: metadata, @@ -210,6 +211,7 @@ class PangeaRepresentation { OneConstructUse( useType: ConstructUseTypeEnum.ga, lemma: entry.value, + form: token.text.content, category: entry.key, constructType: ConstructTypeEnum.morph, metadata: metadata, @@ -227,6 +229,7 @@ class PangeaRepresentation { OneConstructUse( useType: ConstructUseTypeEnum.wa, lemma: entry.value, + form: token.text.content, category: entry.key, constructType: ConstructTypeEnum.morph, metadata: metadata, diff --git a/lib/pangea/utils/get_grammar_copy.dart b/lib/pangea/utils/grammar/get_grammar_copy.dart similarity index 99% rename from lib/pangea/utils/get_grammar_copy.dart rename to lib/pangea/utils/grammar/get_grammar_copy.dart index fa7178cf9..193995b80 100644 --- a/lib/pangea/utils/get_grammar_copy.dart +++ b/lib/pangea/utils/grammar/get_grammar_copy.dart @@ -458,6 +458,6 @@ String? getGrammarCopy({ 'context': context, }, ); - return key; // Fallback to the key itself if no match is found + return lemma; // Fallback to the lemma itself if no match is found } } diff --git a/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_xp_tile.dart b/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_xp_tile.dart index b297418f7..1d89ecafd 100644 --- a/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_xp_tile.dart +++ b/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_xp_tile.dart @@ -2,7 +2,7 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; import 'package:fluffychat/pangea/enum/progress_indicators_enum.dart'; import 'package:fluffychat/pangea/models/analytics/construct_list_model.dart'; -import 'package:fluffychat/pangea/utils/get_grammar_copy.dart'; +import 'package:fluffychat/pangea/utils/grammar/get_grammar_copy.dart'; import 'package:flutter/material.dart'; class ConstructUsesXPTile extends StatelessWidget { From 6e3795fe482ace76f4105b1ff87343114a7b3c5b Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Tue, 12 Nov 2024 16:49:31 -0500 Subject: [PATCH 2/6] removed redundant category from label copy --- assets/l10n/intl_en.arb | 182 +++++++++--------- lib/main.dart | 2 +- .../practice_activity_card.dart | 121 ++++++------ 3 files changed, 152 insertions(+), 153 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index e4290abd3..3b8d9860e 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4247,7 +4247,7 @@ "grammarCopyPUNCTTYPEqest": "Question", "grammarCopyASPECTperf": "Perfect", "grammarCopyCASEaccnom": "Accusative, Nominative", - "grammarCopyCASEobl": "Oblique Case", + "grammarCopyCASEobl": "Oblique", "grammarCopyVOICEact": "Active", "grammarCopyPUNCTTYPEbrck": "Bracket", "grammarCopyNOUNTYPEart": "Article", @@ -4290,7 +4290,7 @@ "grammarCopyPRONTYPErel": "Relative", "grammarCopyVERBFORMfinalEnding": "Final Ending", "grammarCopyPRONTYPEdem": "Demonstrative", - "grammarCopyPREPCASEpre": "Preposition", + "grammarCopyPREPCASEpre": "Prepositional", "grammarCopyVERBFORMfin": "Finite", "grammarCopyDEGREEpos": "Positive", "grammarCopyPUNCTTYPEquot": "Quotation", @@ -4306,36 +4306,36 @@ "grammarCopyCASEloc": "Locative", "grammarCopyMOODind": "Indicative", "grammarCopyDEGREEcmp": "Comparative", - "grammarCopyCASErelativeCase": "Relative Case", + "grammarCopyCASErelativeCase": "Relative", "grammarCopyPUNCTTYPEexcl": "Exclamative", "grammarCopyPERSON1": "First Person", "grammarCopyPUNCTSIDEini": "Initial", "grammarCopyGENDERperson": "Person", "grammarCopyFOREIGNyes": "Foreign", "grammarCopyVOICEvoice": "Voice", - "grammarCopyVERBTYPEverbType": "Verb Type", + "grammarCopyVERBTYPEverbType": "Verb", "grammarCopyPOSSpass": "Possessive", - "grammarCopyPREPCASEprepCase": "Prepositional Case", - "grammarCopyNUMTYPEnumType": "Numeral Type", - "grammarCopyNOUNTYPEnounType": "Noun Type", + "grammarCopyPREPCASEprepCase": "Prepositional", + "grammarCopyNUMTYPEnumType": "Numeral", + "grammarCopyNOUNTYPEnounType": "Noun", "grammarCopyREFLEXreflex": "Reflexive", - "grammarCopyPRONTYPEpronType": "Pronoun Type", + "grammarCopyPRONTYPEpronType": "Pronoun", "grammarCopyPUNCTSIDEpunctSide": "Punctuation Side", - "grammarCopyVERBFORMverbForm": "Verb Form", + "grammarCopyVERBFORMverbForm": "Verb", "grammarCopyGENDERgender": "Gender", "grammarCopyMOODmood": "Mood", "grammarCopyASPECTaspect": "Aspect", - "grammarCopyPUNCTTYPEpunctType": "Punctuation Type", + "grammarCopyPUNCTTYPEpunctType": "Punctuation", "grammarCopyTENSEtense": "Tense", "grammarCopyDEGREEdegree": "Degree", "grammarCopyPOLITEpolite": "Politeness", - "grammarCopyADVTYPEadvType": "Adverb Type", + "grammarCopyADVTYPEadvType": "Adverb", "grammarCopyNUMFORMnumber": "Number", - "grammarCopyCONJTYPEconjType": "Conjunction Type", + "grammarCopyCONJTYPEconjType": "Conjunction", "grammarCopyPOLARITYpolarity": "Polarity", "grammarCopyCASEcase": "Case", "grammarCopyDEFINITEdefinite": "Definiteness", - "grammarCopyNUMFORMnumForm": "Numeral Form", + "grammarCopyNUMFORMnumForm": "Numeral", "grammarCopyPRONTYPEadn": "Adnominal", "grammarCopyVOCvoc": "Vocative", "grammarCopyCMPLcmpl": "Complementizer", @@ -4346,74 +4346,74 @@ "grammarCopyPARTTYPEpar": "Partitive", "grammarCopySPCspc": "Specific", "grammarCopyTENSEpqp": "Pluperfect", - "grammarCopyREFLEXref": "Reflexive Case", + "grammarCopyREFLEXref": "Reflexive", "grammarCopyPUNCTTYPEnshrt": "Short", "grammarCopyNUMBERdual": "Dual", "grammarCopyNUMFORMlng": "Long", - "grammarCopyVOICEmid": "Middle Voice", + "grammarCopyVOICEmid": "Middle", "grammarCopyINTRELintRel": "Interrogative, Relative", "grammarCopyINTint": "Interrogative", - "grammarCopyVOICEcaus": "Causative Voice", + "grammarCopyVOICEcaus": "Causative", "grammarCopyUnknown": "Unknown", "grammarCopyEVIDENTevident": "Evidentiality", "grammarCopyNUMFORMnumberPsor": "Possessor's Number", "grammarCopyASPECThab": "Habitual", - "grammarCopyCASEabl": "Ablative Case", - "grammarCopyCASEall": "Allative Case", - "grammarCopyCASEess": "Essive Case", - "grammarCopyCASEtra": "Translative Case", - "grammarCopyCASEequ": "Equative Case", - "grammarCopyCASEdis": "Distributive Case", - "grammarCopyCASEabs": "Absolutive Case", - "grammarCopyCASEerg": "Ergative Case", - "grammarCopyCASEcau": "Causal Case", - "grammarCopyCASEben": "Benefactive Case", - "grammarCopyCASEtem": "Temporal Case", - "grammarCopyCONJTYPEcoord": "Coordinating Conjunction", + "grammarCopyCASEabl": "Ablative", + "grammarCopyCASEall": "Allative", + "grammarCopyCASEess": "Essive", + "grammarCopyCASEtra": "Translative", + "grammarCopyCASEequ": "Equative", + "grammarCopyCASEdis": "Distributive", + "grammarCopyCASEabs": "Absolutive", + "grammarCopyCASEerg": "Ergative", + "grammarCopyCASEcau": "Causal", + "grammarCopyCASEben": "Benefactive", + "grammarCopyCASEtem": "Temporal", + "grammarCopyCONJTYPEcoord": "Coordinating", "grammarCopyDEFINITEcons": "Construct State", "grammarCopyDEGREEabs": "Absolute Degree", "grammarCopyEVIDENTfh": "Factual Evidentiality", "grammarCopyEVIDENTnfh": "Non-factual Evidentiality", - "grammarCopyMOODopt": "Optative Mood", - "grammarCopyMOODadm": "Admirative Mood", - "grammarCopyMOODdes": "Desiderative Mood", - "grammarCopyMOODnec": "Necessitative Mood", - "grammarCopyMOODpot": "Potential Mood", - "grammarCopyMOODprp": "Propositive Mood", - "grammarCopyMOODqot": "Quotative Mood", + "grammarCopyMOODopt": "Optative", + "grammarCopyMOODadm": "Admirative", + "grammarCopyMOODdes": "Desiderative", + "grammarCopyMOODnec": "Necessitative", + "grammarCopyMOODpot": "Potential", + "grammarCopyMOODprp": "Propositive", + "grammarCopyMOODqot": "Quotative", "grammarCopyNUMFORMword": "Word Form", "grammarCopyNUMFORMroman": "Roman Numeral", "grammarCopyNUMFORMletter": "Letter Form", - "grammarCopyNUMTYPEmult": "Multiplicative Numeral", - "grammarCopyNUMTYPEfrac": "Fractional Numeral", - "grammarCopyNUMTYPEsets": "Set Numeral", - "grammarCopyNUMTYPErange": "Range Numeral", - "grammarCopyNUMTYPEdist": "Distributive Numeral", - "grammarCopyNUMBERtri": "Trial Number", - "grammarCopyNUMBERpauc": "Paucal Number", - "grammarCopyNUMBERgrpa": "Greater Paucal Number", - "grammarCopyNUMBERgrpl": "Greater Plural Number", - "grammarCopyNUMBERinv": "Inverse Number", - "grammarCopyPERSON0": "Zero Person", - "grammarCopyPERSON4": "Fourth Person", - "grammarCopyPOLITEform": "Formal Politeness", - "grammarCopyPOLITEelev": "Elevated Politeness", - "grammarCopyPOLITEhumb": "Humble Politeness", - "grammarCopyPRONTYPEemp": "Emphatic Pronoun", - "grammarCopyPRONTYPEexc": "Exclamative Pronoun", - "grammarCopyPRONTYPErcp": "Reciprocal Pronoun", - "grammarCopyPRONTYPEintRelPronType": "Interrogative-Relative Pronoun", - "grammarCopyTENSEaor": "Aorist Tense", - "grammarCopyTENSEeps": "Epistemic Tense", - "grammarCopyTENSEprosp": "Prospective Tense", - "grammarCopyVERBFORMpart": "Participle Form", - "grammarCopyVERBFORMconv": "Converb Form", + "grammarCopyNUMTYPEmult": "Multiplicative", + "grammarCopyNUMTYPEfrac": "Fractional", + "grammarCopyNUMTYPEsets": "Set", + "grammarCopyNUMTYPErange": "Range", + "grammarCopyNUMTYPEdist": "Distributive", + "grammarCopyNUMBERtri": "Trial", + "grammarCopyNUMBERpauc": "Paucal", + "grammarCopyNUMBERgrpa": "Greater Paucal", + "grammarCopyNUMBERgrpl": "Greater Plural", + "grammarCopyNUMBERinv": "Inverse", + "grammarCopyPERSON0": "Zero", + "grammarCopyPERSON4": "Fourth", + "grammarCopyPOLITEform": "Formal", + "grammarCopyPOLITEelev": "Elevated", + "grammarCopyPOLITEhumb": "Humble", + "grammarCopyPRONTYPEemp": "Emphatic", + "grammarCopyPRONTYPEexc": "Exclamative", + "grammarCopyPRONTYPErcp": "Reciprocal", + "grammarCopyPRONTYPEintRelPronType": "Interrogative-Relative", + "grammarCopyTENSEaor": "Aorist", + "grammarCopyTENSEeps": "Epistemic", + "grammarCopyTENSEprosp": "Prospective", + "grammarCopyVERBFORMpart": "Participle", + "grammarCopyVERBFORMconv": "Converb", "grammarCopyVERBFORMvnoun": "Verbal Noun", - "grammarCopyVOICEantip": "Antipassive Voice", - "grammarCopyVOICEcauVoice": "Causative Voice", - "grammarCopyVOICedir": "Direct Voice", - "grammarCopyVOICEinvVoice": "Inverse Voice", - "grammarCopyVOICErcpVoice": "Reciprocal Voice", + "grammarCopyVOICEantip": "Antipassive", + "grammarCopyVOICEcauVoice": "Causative", + "grammarCopyVOICedir": "Direct", + "grammarCopyVOICEinvVoice": "Inverse", + "grammarCopyVOICErcpVoice": "Reciprocal", "grammarCopyPOS": "Part of Speech", "grammarCopyGENDER": "Gender", "grammarCopyPERSON": "Person", @@ -4449,18 +4449,18 @@ "grammarCopyNUMBERPSOR": "Possessor's Number", "grammarCopyPOSS": "Possessive", "grammarCopyASPECTimp": "Imperfective Aspect", - "grammarCopyCASEvoc": "Vocative Case", - "grammarCopyCASEcom": "Comitative Case", - "grammarCopyCASEpar": "Partitive Case", - "grammarCopyCASEadv": "Adverbial Case", - "grammarCopyCASEref": "Referential Case", - "grammarCopyCASErel": "Relative Case", - "grammarCopyCASEsub": "Subessive Case", - "grammarCopyCASEsup": "Superessive Case", - "grammarCopyCASEaccdat": "Accusative-Dative Case", - "grammarCopyCASEpre": "Prepositional Case", - "grammarCopyCONJTYPEsub": "Subordinating Conjunction", - "grammarCopyCONJTYPEcmp": "Comparative Conjunction", + "grammarCopyCASEvoc": "Vocative", + "grammarCopyCASEcom": "Comitative", + "grammarCopyCASEpar": "Partitive", + "grammarCopyCASEadv": "Adverbial", + "grammarCopyCASEref": "Referential", + "grammarCopyCASErel": "Relative", + "grammarCopyCASEsub": "Subessive", + "grammarCopyCASEsup": "Superessive", + "grammarCopyCASEaccdat": "Accusative-Dative", + "grammarCopyCASEpre": "Prepositional", + "grammarCopyCONJTYPEsub": "Subordinating", + "grammarCopyCONJTYPEcmp": "Comparative", "grammarCopyDEFINITEind": "Indefinite", "grammarCopyMOODint": "Interrogative Mood", "grammarCopyNOUNTYPEcomm": "Common Noun", @@ -4470,25 +4470,25 @@ "grammarCopyPOLARITYpos": "Positive Polarity", "grammarCopyPOSSyes": "Possessive", "grammarCopyPREPCASEnpr": "Non-prepositional", - "grammarCopyPRONTYPEprs": "Personal Pronoun", - "grammarCopyPRONTYPEint": "Interrogative Pronoun", - "grammarCopyPRONTYPEtot": "Total Pronoun", - "grammarCopyPRONTYPEneg": "Negative Pronoun", - "grammarCopyPRONTYPEart": "Article Pronoun", - "grammarCopyPRONTYPEind": "Indefinite Pronoun", - "grammarCopyPRONTYPEintrel": "Interrogative-Relative Pronoun", + "grammarCopyPRONTYPEprs": "Personal", + "grammarCopyPRONTYPEint": "Interrogative", + "grammarCopyPRONTYPEtot": "Total", + "grammarCopyPRONTYPEneg": "Negative", + "grammarCopyPRONTYPEart": "Article", + "grammarCopyPRONTYPEind": "Indefinite", + "grammarCopyPRONTYPEintrel": "Interrogative-Relative", "grammarCopyPUNCTSIDEfin": "Final Punctuation", "grammarCopyPUNCTTYPEperi": "Period", "grammarCopyREFLEXyes": "Reflexive", - "grammarCopyTENSEimp": "Imperfect Tense", - "grammarCopyVERBFORMsup": "Supine Form", - "grammarCopyVERBFORMadn": "Adnominal Form", - "grammarCopyVERBFORMlng": "Long Form", + "grammarCopyTENSEimp": "Imperfect", + "grammarCopyVERBFORMsup": "Supine", + "grammarCopyVERBFORMadn": "Adnominal", + "grammarCopyVERBFORMlng": "Long", "grammarCopyVERBTYPEcaus": "Causative Verb", - "grammarCopyVOICEcau": "Causative Voice", - "grammarCopyVOICEdir": "Direct Voice", - "grammarCopyVOICEinv": "Inverse Voice", - "grammarCopyVOICErcp": "Reciprocal Voice", + "grammarCopyVOICEcau": "Causative", + "grammarCopyVOICEdir": "Direct", + "grammarCopyVOICEinv": "Inverse", + "grammarCopyVOICErcp": "Reciprocal", "enterPrompt": "Please enter a system prompt", "selectBotLanguage": "Select bot language", "chooseVoice": "Choose a voice", diff --git a/lib/main.dart b/lib/main.dart index 9f5e656bd..847b012b2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,7 +23,7 @@ void main() async { // #Pangea try { - await dotenv.load(fileName: ".env"); + await dotenv.load(fileName: ".env.local_choreo"); } catch (e) { Logs().e('Failed to load .env file', e); } diff --git a/lib/pangea/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/widgets/practice_activity/practice_activity_card.dart index 8b64c4d2a..ea6c27251 100644 --- a/lib/pangea/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/widgets/practice_activity/practice_activity_card.dart @@ -103,79 +103,78 @@ class PracticeActivityCardState extends State { Future _fetchNewActivity([ ActivityQualityFeedback? activityFeedback, ]) async { - try { - debugPrint('Fetching new activity'); - - _updateFetchingActivity(true); - - // target tokens can be empty if activities have been completed for each - // it's set on initialization and then removed when each activity is completed - if (!pangeaController.languageController.languagesSet) { - debugger(when: kDebugMode); - _updateFetchingActivity(false); - return null; - } + // try { + debugPrint('Fetching new activity'); - if (!mounted) { - debugger(when: kDebugMode); - _updateFetchingActivity(false); - return null; - } + _updateFetchingActivity(true); - if (widget.pangeaMessageEvent.messageDisplayRepresentation == null) { - debugger(when: kDebugMode); - _updateFetchingActivity(false); - ErrorHandler.logError( - e: Exception('No original message found in _fetchNewActivity'), - data: { - 'event': widget.pangeaMessageEvent.event.toJson(), - }, - ); - return null; - } - - final PracticeActivityModelResponse? activityResponse = - await pangeaController.practiceGenerationController - .getPracticeActivity( - MessageActivityRequest( - userL1: pangeaController.languageController.userL1!.langCode, - userL2: pangeaController.languageController.userL2!.langCode, - messageText: widget.pangeaMessageEvent.messageDisplayText, - tokensWithXP: await widget.targetTokensController.targetTokens( - widget.pangeaMessageEvent, - ), - messageId: widget.pangeaMessageEvent.eventId, - existingActivities: practiceActivities - .map((activity) => activity.activityRequestMetaData) - .toList(), - activityQualityFeedback: activityFeedback, - clientCompatibleActivities: widget - .ttsController.isLanguageFullySupported - ? ActivityTypeEnum.values - : ActivityTypeEnum.values - .where((type) => type != ActivityTypeEnum.wordFocusListening) - .toList(), - ), - widget.pangeaMessageEvent, - ); + // target tokens can be empty if activities have been completed for each + // it's set on initialization and then removed when each activity is completed + if (!pangeaController.languageController.languagesSet) { + debugger(when: kDebugMode); + _updateFetchingActivity(false); + return null; + } - currentActivityCompleter = activityResponse?.eventCompleter; + if (!mounted) { + debugger(when: kDebugMode); _updateFetchingActivity(false); + return null; + } - return activityResponse?.activity; - } catch (e, s) { + if (widget.pangeaMessageEvent.messageDisplayRepresentation == null) { debugger(when: kDebugMode); + _updateFetchingActivity(false); ErrorHandler.logError( - e: e, - s: s, - m: 'Failed to get new activity', + e: Exception('No original message found in _fetchNewActivity'), data: { - 'activity': currentActivity, - 'record': currentCompletionRecord, + 'event': widget.pangeaMessageEvent.event.toJson(), }, ); return null; } + + final PracticeActivityModelResponse? activityResponse = + await pangeaController.practiceGenerationController.getPracticeActivity( + MessageActivityRequest( + userL1: pangeaController.languageController.userL1!.langCode, + userL2: pangeaController.languageController.userL2!.langCode, + messageText: widget.pangeaMessageEvent.messageDisplayText, + tokensWithXP: await widget.targetTokensController.targetTokens( + widget.pangeaMessageEvent, + ), + messageId: widget.pangeaMessageEvent.eventId, + existingActivities: practiceActivities + .map((activity) => activity.activityRequestMetaData) + .toList(), + activityQualityFeedback: activityFeedback, + clientCompatibleActivities: widget + .ttsController.isLanguageFullySupported + ? ActivityTypeEnum.values + : ActivityTypeEnum.values + .where((type) => type != ActivityTypeEnum.wordFocusListening) + .toList(), + ), + widget.pangeaMessageEvent, + ); + + currentActivityCompleter = activityResponse?.eventCompleter; + _updateFetchingActivity(false); + + return activityResponse?.activity; + // } catch (e, s) { + // debugger(when: kDebugMode); + // ErrorHandler.logError( + // e: e, + // s: s, + // m: 'Failed to get new activity', + // data: { + // 'activity': currentActivity, + // 'record': currentCompletionRecord, + // }, + // ); + // return null; + // } } ConstructUseMetaData get metadata => ConstructUseMetaData( From 159a25022baba846372a5541b5455f0bfea9201f Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Tue, 12 Nov 2024 16:58:11 -0500 Subject: [PATCH 3/6] added some missing copy --- assets/l10n/intl_en.arb | 3 ++- lib/pangea/utils/grammar/get_grammar_copy.dart | 4 ++++ .../analytics_summary/analytics_popup/analytics_popup.dart | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 3b8d9860e..58db298d0 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4477,11 +4477,12 @@ "grammarCopyPRONTYPEart": "Article", "grammarCopyPRONTYPEind": "Indefinite", "grammarCopyPRONTYPEintrel": "Interrogative-Relative", + "grammarCopyPRONTYPEint": "Interrogative", "grammarCopyPUNCTSIDEfin": "Final Punctuation", "grammarCopyPUNCTTYPEperi": "Period", "grammarCopyREFLEXyes": "Reflexive", "grammarCopyTENSEimp": "Imperfect", - "grammarCopyVERBFORMsup": "Supine", + "grammarCopyVERBFORMsup": "SuApine", "grammarCopyVERBFORMadn": "Adnominal", "grammarCopyVERBFORMlng": "Long", "grammarCopyVERBTYPEcaus": "Causative Verb", diff --git a/lib/pangea/utils/grammar/get_grammar_copy.dart b/lib/pangea/utils/grammar/get_grammar_copy.dart index 193995b80..b8e406faf 100644 --- a/lib/pangea/utils/grammar/get_grammar_copy.dart +++ b/lib/pangea/utils/grammar/get_grammar_copy.dart @@ -411,6 +411,8 @@ String? getGrammarCopy({ return L10n.of(context)!.grammarCopyPRONTYPEexc; case 'grammarCopyPRONTYPErcp': return L10n.of(context)!.grammarCopyPRONTYPErcp; + case 'grammarCopyPRONTYPEint': + return L10n.of(context)!.grammarCopyPRONTYPEint; case 'grammarCopyPRONTYPEintrel': return L10n.of(context)!.grammarCopyPRONTYPEintrel; case 'grammarCopyPRONTYPEintRelPronType': @@ -439,6 +441,8 @@ String? getGrammarCopy({ return L10n.of(context)!.grammarCopyVOICEinvVoice; case 'grammarCopyVOICErcpVoice': return L10n.of(context)!.grammarCopyVOICErcpVoice; + case "grammarCopyCASEaccdat": + return L10n.of(context)!.grammarCopyCASEaccdat; // Handle empty tag case '': ErrorHandler.logError( diff --git a/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart b/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart index ef8f456ce..764475a2c 100644 --- a/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart +++ b/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart @@ -155,6 +155,8 @@ class ConstructsTileList extends StatelessWidget { @override Widget build(BuildContext context) { + // sort list by xp + constructs.sort((a, b) => b.points.compareTo(a.points)); return ListView.builder( itemCount: constructs.length, itemBuilder: (context, index) => ConstructUsesXPTile(constructs[index]), From 5ffe5a2d73202c2c7895f28a86a9e84512d94b07 Mon Sep 17 00:00:00 2001 From: wcjord <32568597+wcjord@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:20:36 -0500 Subject: [PATCH 4/6] Update main.dart --- lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 847b012b2..9f5e656bd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,7 +23,7 @@ void main() async { // #Pangea try { - await dotenv.load(fileName: ".env.local_choreo"); + await dotenv.load(fileName: ".env"); } catch (e) { Logs().e('Failed to load .env file', e); } From 7dc9fa8a359e1b5f7a0343fbe03a7ac71afc35e3 Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Tue, 12 Nov 2024 17:22:28 -0500 Subject: [PATCH 5/6] turning try-catch back on practice fetch activity --- .../practice_activity_card.dart | 121 +++++++++--------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/lib/pangea/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/widgets/practice_activity/practice_activity_card.dart index ea6c27251..8b64c4d2a 100644 --- a/lib/pangea/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/widgets/practice_activity/practice_activity_card.dart @@ -103,78 +103,79 @@ class PracticeActivityCardState extends State { Future _fetchNewActivity([ ActivityQualityFeedback? activityFeedback, ]) async { - // try { - debugPrint('Fetching new activity'); + try { + debugPrint('Fetching new activity'); - _updateFetchingActivity(true); + _updateFetchingActivity(true); - // target tokens can be empty if activities have been completed for each - // it's set on initialization and then removed when each activity is completed - if (!pangeaController.languageController.languagesSet) { - debugger(when: kDebugMode); - _updateFetchingActivity(false); - return null; - } + // target tokens can be empty if activities have been completed for each + // it's set on initialization and then removed when each activity is completed + if (!pangeaController.languageController.languagesSet) { + debugger(when: kDebugMode); + _updateFetchingActivity(false); + return null; + } - if (!mounted) { - debugger(when: kDebugMode); + if (!mounted) { + debugger(when: kDebugMode); + _updateFetchingActivity(false); + return null; + } + + if (widget.pangeaMessageEvent.messageDisplayRepresentation == null) { + debugger(when: kDebugMode); + _updateFetchingActivity(false); + ErrorHandler.logError( + e: Exception('No original message found in _fetchNewActivity'), + data: { + 'event': widget.pangeaMessageEvent.event.toJson(), + }, + ); + return null; + } + + final PracticeActivityModelResponse? activityResponse = + await pangeaController.practiceGenerationController + .getPracticeActivity( + MessageActivityRequest( + userL1: pangeaController.languageController.userL1!.langCode, + userL2: pangeaController.languageController.userL2!.langCode, + messageText: widget.pangeaMessageEvent.messageDisplayText, + tokensWithXP: await widget.targetTokensController.targetTokens( + widget.pangeaMessageEvent, + ), + messageId: widget.pangeaMessageEvent.eventId, + existingActivities: practiceActivities + .map((activity) => activity.activityRequestMetaData) + .toList(), + activityQualityFeedback: activityFeedback, + clientCompatibleActivities: widget + .ttsController.isLanguageFullySupported + ? ActivityTypeEnum.values + : ActivityTypeEnum.values + .where((type) => type != ActivityTypeEnum.wordFocusListening) + .toList(), + ), + widget.pangeaMessageEvent, + ); + + currentActivityCompleter = activityResponse?.eventCompleter; _updateFetchingActivity(false); - return null; - } - if (widget.pangeaMessageEvent.messageDisplayRepresentation == null) { + return activityResponse?.activity; + } catch (e, s) { debugger(when: kDebugMode); - _updateFetchingActivity(false); ErrorHandler.logError( - e: Exception('No original message found in _fetchNewActivity'), + e: e, + s: s, + m: 'Failed to get new activity', data: { - 'event': widget.pangeaMessageEvent.event.toJson(), + 'activity': currentActivity, + 'record': currentCompletionRecord, }, ); return null; } - - final PracticeActivityModelResponse? activityResponse = - await pangeaController.practiceGenerationController.getPracticeActivity( - MessageActivityRequest( - userL1: pangeaController.languageController.userL1!.langCode, - userL2: pangeaController.languageController.userL2!.langCode, - messageText: widget.pangeaMessageEvent.messageDisplayText, - tokensWithXP: await widget.targetTokensController.targetTokens( - widget.pangeaMessageEvent, - ), - messageId: widget.pangeaMessageEvent.eventId, - existingActivities: practiceActivities - .map((activity) => activity.activityRequestMetaData) - .toList(), - activityQualityFeedback: activityFeedback, - clientCompatibleActivities: widget - .ttsController.isLanguageFullySupported - ? ActivityTypeEnum.values - : ActivityTypeEnum.values - .where((type) => type != ActivityTypeEnum.wordFocusListening) - .toList(), - ), - widget.pangeaMessageEvent, - ); - - currentActivityCompleter = activityResponse?.eventCompleter; - _updateFetchingActivity(false); - - return activityResponse?.activity; - // } catch (e, s) { - // debugger(when: kDebugMode); - // ErrorHandler.logError( - // e: e, - // s: s, - // m: 'Failed to get new activity', - // data: { - // 'activity': currentActivity, - // 'record': currentCompletionRecord, - // }, - // ); - // return null; - // } } ConstructUseMetaData get metadata => ConstructUseMetaData( From 4a518e053b53b0c13f23c3ad249f051ba81e44d2 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 13 Nov 2024 09:40:23 -0500 Subject: [PATCH 6/6] sort construct list on construct list update, don't repeat sort operation --- .../models/analytics/construct_list_model.dart | 15 ++++++++------- .../analytics_popup/analytics_popup.dart | 9 +-------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/pangea/models/analytics/construct_list_model.dart b/lib/pangea/models/analytics/construct_list_model.dart index bc82855f6..eeb3696bb 100644 --- a/lib/pangea/models/analytics/construct_list_model.dart +++ b/lib/pangea/models/analytics/construct_list_model.dart @@ -52,16 +52,21 @@ class ConstructListModel { _updateMetrics(); } + int _sortConstructs(ConstructUses a, ConstructUses b) { + final comp = b.points.compareTo(a.points); + if (comp != 0) return comp; + return a.lemma.compareTo(b.lemma); + } + /// A map of lemmas to ConstructUses, each of which contains a lemma /// key = lemmma + constructType.string, value = ConstructUses void _updateConstructMap(final List newUses) { for (final use in newUses) { - if (use.lemma == null) continue; final currentUses = _constructMap[use.identifier.string] ?? ConstructUses( uses: [], constructType: use.constructType, - lemma: use.lemma!, + lemma: use.lemma, category: use.category, ); currentUses.uses.add(use); @@ -75,11 +80,7 @@ class ConstructListModel { void _updateConstructList() { // TODO check how expensive this is _constructList = _constructMap.values.toList(); - _constructList.sort((a, b) { - final comp = b.uses.length.compareTo(a.uses.length); - if (comp != 0) return comp; - return a.lemma.compareTo(b.lemma); - }); + _constructList.sort(_sortConstructs); } void _updateCategoriesToUses() { diff --git a/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart b/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart index 8e78bdffc..4fae8c71c 100644 --- a/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart +++ b/lib/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart @@ -1,4 +1,3 @@ -import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; import 'package:fluffychat/pangea/enum/progress_indicators_enum.dart'; import 'package:fluffychat/pangea/models/analytics/construct_list_model.dart'; @@ -94,11 +93,7 @@ class AnalyticsPopupState extends State { dialogContent = Center(child: Text(L10n.of(context)!.noDataFound)); } else if (hasNoCategories || !widget.showGroups) { dialogContent = ConstructsTileList( - _constructsModel.constructList(type: widget.type).sorted((a, b) { - final comp = b.points.compareTo(a.points); - if (comp != 0) return comp; - return a.lemma.compareTo(b.lemma); - }), + _constructsModel.constructList(type: widget.type), ); } else { dialogContent = ListView.builder( @@ -156,8 +151,6 @@ class ConstructsTileList extends StatelessWidget { @override Widget build(BuildContext context) { - // sort list by xp - constructs.sort((a, b) => b.points.compareTo(a.points)); return ListView.builder( itemCount: constructs.length, itemBuilder: (context, index) => ConstructUsesXPTile(constructs[index]),