fluffychat/lib/pangea/analytics_data/level_up_analytics_service.dart
2025-12-23 14:35:41 -05:00

106 lines
3.2 KiB
Dart

import 'dart:async';
import 'package:matrix/matrix.dart';
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/constructs_model.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/constructs/construct_repo.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/widgets/matrix.dart';
class LevelUpAnalyticsService {
final Client client;
final Future<void> Function() ensureInitialized;
final AnalyticsDataService dataService;
const LevelUpAnalyticsService({
required this.client,
required this.ensureInitialized,
required this.dataService,
});
Future<ConstructSummary> getLevelUpAnalytics(
int lowerLevel,
int upperLevel,
DateTime? lastLevelUpTimestamp,
) async {
await ensureInitialized();
final uses = await dataService.getUses(since: lastLevelUpTimestamp);
final messages = await _buildMessageContext(uses);
final userController = MatrixState.pangeaController.userController;
final request = ConstructSummaryRequest(
constructs: uses,
messages: messages,
userL1: userController.userL1!.langCodeShort,
userL2: userController.userL2!.langCodeShort,
lowerLevel: lowerLevel,
upperLevel: upperLevel,
);
final response = await ConstructRepo.generateConstructSummary(request);
final summary = response.summary;
summary.levelVocabConstructs =
dataService.uniqueConstructsByType(ConstructTypeEnum.vocab);
summary.levelGrammarConstructs =
dataService.uniqueConstructsByType(ConstructTypeEnum.morph);
return summary;
}
Future<List<Map<String, dynamic>>> _buildMessageContext(
List<OneConstructUse> uses,
) async {
final Map<String, Set<String>> useEventIds = {};
for (final use in uses) {
final roomId = use.metadata.roomId;
final eventId = use.metadata.eventId;
if (roomId == null || eventId == null) continue;
useEventIds.putIfAbsent(roomId, () => {}).add(eventId);
}
final List<Map<String, dynamic>> messages = [];
for (final entry in useEventIds.entries) {
final room = client.getRoomById(entry.key);
if (room == null) continue;
final timeline = await room.getTimeline();
for (final eventId in entry.value) {
try {
final event = await room.getEventById(eventId);
if (event == null) continue;
final pangeaEvent = PangeaMessageEvent(
event: event,
timeline: timeline,
ownMessage: room.client.userID == event.senderId,
);
messages.add({
'sent': pangeaEvent.originalSent?.text ?? pangeaEvent.body,
'written': pangeaEvent.originalWrittenContent,
});
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {
'roomId': entry.key,
'eventId': eventId,
},
);
}
}
}
return messages;
}
}