forked from krille-chan/fluffychat
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathconstructs_model.dart
208 lines (174 loc) · 5.56 KB
/
constructs_model.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart';
import 'package:fluffychat/pangea/morphs/morph_models.dart';
import 'construct_type_enum.dart';
class ConstructAnalyticsModel {
List<OneConstructUse> uses;
ConstructAnalyticsModel({
this.uses = const [],
});
static const _usesKey = "uses";
factory ConstructAnalyticsModel.fromJson(Map<String, dynamic> json) {
final List<OneConstructUse> uses = [];
if (json[_usesKey] is List) {
// This is the new format
for (final useJson in json[_usesKey]) {
// grammar construct uses are deprecated so but some are saved
// here we're filtering from data
if (["grammar", "g"].contains(useJson['constructType'])) {
continue;
} else {
try {
uses.add(OneConstructUse.fromJson(useJson));
} catch (err, s) {
ErrorHandler.logError(
e: err,
s: s,
data: {
"useJson": useJson,
},
);
continue;
}
}
}
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(
m: "Analytics room with non-list uses",
data: {
"usesKey": _usesKey,
},
);
}
return ConstructAnalyticsModel(
uses: uses,
);
}
Map<String, dynamic> toJson() {
return {
_usesKey: uses.map((use) => use.toJson()).toList(),
};
}
}
class OneConstructUse {
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;
ConstructTypeEnum constructType;
ConstructUseTypeEnum useType;
/// Used to unqiuely identify the construct use. Useful in the case
/// that a users makes the same type of mistake multiple times in a
/// message, and those uses need to be disinguished.
String? id;
ConstructUseMetaData metadata;
OneConstructUse({
required this.useType,
required this.lemma,
required this.constructType,
required this.metadata,
required category,
required this.form,
this.id,
}) : _category = category ?? "other";
String get chatId => metadata.roomId;
String get msgId => metadata.eventId!;
DateTime get timeStamp => metadata.timeStamp;
factory OneConstructUse.fromJson(Map<String, dynamic> json) {
debugger(when: kDebugMode && json['constructType'] == null);
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: getCategory(json, constructType),
constructType: constructType,
id: json['id'],
metadata: ConstructUseMetaData(
eventId: json['msgId'],
roomId: json['chatId'],
timeStamp: DateTime.parse(json['timeStamp']),
),
);
}
Map<String, dynamic> 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,
};
String get category {
if (_category.isEmpty) return "other";
return _category.toLowerCase();
}
static String getCategory(
Map<String, dynamic> json,
ConstructTypeEnum constructType,
) {
final categoryEntry = json['cat'] ?? json['categories'];
if (constructType == ConstructTypeEnum.vocab) {
final String? category = categoryEntry is String
? categoryEntry
: categoryEntry is List && categoryEntry.isNotEmpty
? categoryEntry.first
: null;
return category ?? "Other";
}
final MorphFeaturesAndTags morphs = defaultMorphMapping;
if (categoryEntry == null) {
return morphs.guessMorphCategory(json["lemma"]);
}
if ((categoryEntry is List)) {
if (categoryEntry.isEmpty) {
return morphs.guessMorphCategory(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 morphs.guessMorphCategory(json["lemma"]);
}
Room? getRoom(Client client) {
return client.getRoomById(metadata.roomId);
}
Future<Event?> getEvent(Client client) async {
final Room? room = getRoom(client);
if (room == null || metadata.eventId == null) return null;
return room.getEventById(metadata.eventId!);
}
int get pointValue => useType.pointValue;
ConstructIdentifier get identifier => ConstructIdentifier(
lemma: lemma,
type: constructType,
category: category,
);
}
class ConstructUseMetaData {
String? eventId;
String roomId;
DateTime timeStamp;
ConstructUseMetaData({
required this.roomId,
required this.timeStamp,
this.eventId,
});
}