fix: centralize activity constructs type in ActivityTypeEnum, skip over invalid morph uses (#5767)

This commit is contained in:
ggurdin 2026-02-23 11:05:07 -05:00 committed by GitHub
parent 859cb78339
commit c1b88c6dbd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 47 additions and 30 deletions

View file

@ -273,7 +273,7 @@ class AnalyticsDataService {
final Map<ConstructIdentifier, DateTime?> cappedLastUseCache = {};
for (final use in uses) {
if (blocked.contains(use.identifier)) continue;
if (use.category == 'other') continue;
if (use.identifier.isInvalid) continue;
if (!cappedLastUseCache.containsKey(use.identifier)) {
final constructs = await getConstructUse(use.identifier, language);

View file

@ -23,8 +23,7 @@ class ConstructMergeTable {
) {
for (final use in uses) {
final id = use.identifier;
if (exclude.contains(id)) continue;
if (id.category == 'other') continue;
if (exclude.contains(id) || id.isInvalid) continue;
final composite = id.compositeKey;
(lemmaTypeGroups[composite] ??= {}).add(id);
@ -32,8 +31,7 @@ class ConstructMergeTable {
for (final use in uses) {
final id = use.identifier;
if (exclude.contains(id)) continue;
if (id.category == 'other') continue;
if (exclude.contains(id) || id.isInvalid) continue;
final group = lemmaTypeGroups[id.compositeKey];
if (group == null) continue;
@ -71,7 +69,7 @@ class ConstructMergeTable {
Set<ConstructIdentifier> exclude,
) {
final keys = <ConstructIdentifier>[];
if (exclude.contains(id) || id.category == 'other') {
if (exclude.contains(id) || id.isInvalid) {
return keys;
}

View file

@ -1,9 +1,7 @@
import 'package:fluffychat/pangea/analytics_data/analytics_data_service.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/practice_activities/practice_target.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -24,21 +22,26 @@ class AnalyticsPracticeAnalyticsController {
) => analyticsService.updateService.addAnalytics(targetId, uses, language);
Future<void> addSkippedActivityAnalytics(
PangeaToken token,
ConstructTypeEnum type,
PracticeTarget target,
String language,
) async {
final use = OneConstructUse(
useType: ConstructUseTypeEnum.ignPA,
constructType: type,
metadata: ConstructUseMetaData(roomId: null, timeStamp: DateTime.now()),
category: token.pos,
lemma: token.lemma.text,
form: token.lemma.text,
xp: 0,
);
await analyticsService.updateService.addAnalytics(null, [use], language);
final uses = target.tokens
.map(
(t) => OneConstructUse(
useType: ConstructUseTypeEnum.ignPA,
constructType: target.activityType.constructUsesType,
metadata: ConstructUseMetaData(
roomId: null,
timeStamp: DateTime.now(),
),
category: t.pos,
lemma: t.lemma.text,
form: t.lemma.text,
xp: 0,
),
)
.toList();
await analyticsService.updateService.addAnalytics(null, uses, language);
}
Future<void> addSessionAnalytics(

View file

@ -314,8 +314,7 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
// Record a 0 XP use so that activity isn't chosen again soon
_sessionController.skipActivity();
await _analyticsController.addSkippedActivityAnalytics(
request.target.tokens.first,
widget.type,
request.target,
_l2!.langCodeShort,
);
}

View file

@ -37,7 +37,6 @@ class ConstructIdentifier {
if (type == ConstructTypeEnum.morph &&
MorphFeaturesEnumExtension.fromString(category) ==
MorphFeaturesEnum.Unknown) {
debugger(when: kDebugMode);
ErrorHandler.logError(
e: Exception("Morph feature not found"),
data: {"category": category, "lemma": lemma, "type": type},
@ -97,8 +96,8 @@ class ConstructIdentifier {
other.lemma == lemma &&
other.type == type &&
(category == other.category ||
category.toLowerCase() == "other" ||
other.category.toLowerCase() == "other");
category.toLowerCase() == 'other' ||
other.category.toLowerCase() == 'other');
}
@override
@ -190,4 +189,10 @@ class ConstructIdentifier {
(isContentWord
? AnalyticsConstants.contentWordMultiplier
: AnalyticsConstants.functionWordMultiplier);
bool get isInvalid =>
(type == ConstructTypeEnum.morph &&
MorphFeaturesEnumExtension.fromString(category) ==
MorphFeaturesEnum.Unknown) ||
category == 'other';
}

View file

@ -252,4 +252,17 @@ enum ActivityTypeEnum {
return _grammarPracticeTypes;
}
}
/// The type of construct uses that these activities produce.
/// NOTE: Grammar error activities create vocab uses, assosiated with the tokens in the
/// targeted error span NOT morph uses.
ConstructTypeEnum get constructUsesType {
switch (this) {
case ActivityTypeEnum.grammarCategory:
case ActivityTypeEnum.morphId:
return ConstructTypeEnum.morph;
default:
return ConstructTypeEnum.vocab;
}
}
}

View file

@ -1,6 +1,5 @@
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_practice/analytics_practice_session_model.dart';
@ -241,7 +240,7 @@ sealed class MultipleChoicePracticeActivityModel extends PracticeActivityModel {
.map(
(token) => OneConstructUse(
useType: useType,
constructType: ConstructTypeEnum.vocab,
constructType: activityType.constructUsesType,
metadata: ConstructUseMetaData(
roomId: null,
timeStamp: DateTime.now(),
@ -310,7 +309,7 @@ sealed class MorphPracticeActivityModel
.map(
(token) => OneConstructUse(
useType: useType,
constructType: ConstructTypeEnum.morph,
constructType: activityType.constructUsesType,
metadata: ConstructUseMetaData(
roomId: null,
timeStamp: DateTime.now(),
@ -390,7 +389,7 @@ class VocabAudioPracticeActivityModel
return [
OneConstructUse(
useType: useType,
constructType: ConstructTypeEnum.vocab,
constructType: activityType.constructUsesType,
metadata: ConstructUseMetaData(roomId: null, timeStamp: DateTime.now()),
category: matchingToken.pos,
lemma: matchingToken.lemma.text,