saving of tokens, changing of top language calculation, documentation

pull/1384/head
William Jordan-Cooley 1 year ago
parent 2526331706
commit c6d3f36805

@ -16,7 +16,6 @@ import 'package:fluffychat/pages/chat/recording_dialog.dart';
import 'package:fluffychat/pages/chat_details/chat_details.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/enum/use_type.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/models/choreo_record.dart';
@ -586,7 +585,6 @@ class ChatController extends State<ChatPageWithRoom>
PangeaMessageTokens? tokensSent,
PangeaMessageTokens? tokensWritten,
ChoreoRecord? choreo,
UseType? useType,
}) async {
// Pangea#
if (sendController.text.trim().isEmpty) return;
@ -630,7 +628,6 @@ class ChatController extends State<ChatPageWithRoom>
tokensSent: tokensSent,
tokensWritten: tokensWritten,
choreo: choreo,
useType: useType,
)
.then(
(String? msgEventId) async {
@ -644,7 +641,6 @@ class ChatController extends State<ChatPageWithRoom>
GoogleAnalytics.sendMessage(
room.id,
room.classCode,
useType ?? UseType.un,
);
if (msgEventId == null) {

@ -470,7 +470,7 @@ class Message extends StatelessWidget {
?.showUseType ??
false) ...[
pangeaMessageEvent!
.useType
.msgUseType
.iconView(
context,
textColor

@ -24,7 +24,6 @@ import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import '../../../widgets/matrix.dart';
import '../../enum/use_type.dart';
import '../../models/choreo_record.dart';
import '../../models/language_model.dart';
import '../../models/pangea_match_model.dart';
@ -108,27 +107,16 @@ class Choreographer {
originalSent: false,
)
: null;
//TODO - confirm that IT is indeed making sure the message is in the user's L1
// if the message has not been processed to determine its language
// then run it through the language detection endpoint. If the detection
// confidence is high enough, use that language code as the message's language
// to save that pangea representation
// TODO - move this to somewhere such that the message can be cleared from the input field
// before the language detection is complete. Otherwise, user is going to be waiting
// in cases of slow internet or slow language detection
final String? originalSentLangCode = igc.igcTextData?.detectedLanguage;
// TODO - why does both it and igc need to be enabled for choreo to be applicable?
final ChoreoRecord? applicableChoreo =
isITandIGCEnabled && igc.igcTextData != null ? choreoRecord : null;
final UseType useType = useTypeCalculator(applicableChoreo);
// if tokens or language detection are not available, get them
// note that we probably need to move this to after we clear the input field
// or the user could experience some lag here. note that this call is being
// made after we've determined if we have an applicable choreo in order to
// final ChoreoRecord? applicableChoreo =
// isITandIGCEnabled && igc.igcTextData != null ? choreoRecord : null;
// if tokens or language detection are not available, we should get them
// notes
// 1) we probably need to move this to after we clear the input field
// or the user could experience some lag here.
// 2) that this call is being made after we've determined if we have an applicable choreo in order to
// say whether correction was run on the message. we may eventually want
// to edit the useType after
if (igc.igcTextData?.tokens == null ||
@ -137,26 +125,24 @@ class Choreographer {
}
final PangeaRepresentation originalSent = PangeaRepresentation(
langCode: originalSentLangCode ?? LanguageKeys.unknownLanguage,
langCode:
igc.igcTextData?.detectedLanguage ?? LanguageKeys.unknownLanguage,
text: currentText,
originalSent: true,
originalWritten: originalWritten == null,
);
debugger(when: kDebugMode);
final PangeaMessageTokens? tokensSent = igc.igcTextData?.tokens != null
? PangeaMessageTokens(tokens: igc.igcTextData!.tokens)
: null;
chatController.send(
// PTODO - turn this back on in conjunction with saving tokens
// we need to save those tokens as well, in order for exchanges to work
// properly. in an exchange, the other user will want
// originalWritten: originalWritten,
originalSent: originalSent,
tokensSent: igc.igcTextData?.tokens != null
? PangeaMessageTokens(tokens: igc.igcTextData!.tokens)
: null,
tokensSent: tokensSent,
//TODO - save originalwritten tokens
choreo: applicableChoreo,
useType: useType,
// choreo: applicableChoreo,
choreo: choreoRecord,
);
clear();

@ -66,7 +66,6 @@ class ModelKey {
static const String tokensSent = "tokens_sent";
static const String tokensWritten = "tokens_written";
static const String choreoRecord = "choreo_record";
static const String useType = "use_type";
static const String baseDefinition = "base_definition";
static const String targetDefinition = "target_definition";

@ -76,15 +76,20 @@ class LanguageDetectionResponse {
};
}
LanguageDetection get _bestDetection {
/// Return the highest confidence detection.
/// If there are no detections, the unknown language detection is returned.
LanguageDetection get highestConfidenceDetection {
detections.sort((a, b) => b.confidence.compareTo(a.confidence));
return detections.firstOrNull ?? unknownLanguageDetection;
}
LanguageDetection bestDetection({double? threshold}) =>
_bestDetection.confidence >=
/// Returns the highest validated detection based on the confidence threshold.
/// If the highest confidence detection is below the threshold, the unknown language
/// detection is returned.
LanguageDetection highestValidatedDetection({double? threshold}) =>
highestConfidenceDetection.confidence >=
(threshold ?? languageDetectionConfidenceThreshold)
? _bestDetection
? highestConfidenceDetection
: unknownLanguageDetection;
}

@ -216,8 +216,6 @@ class MyAnalyticsController {
.where((room) => !room.isSpace && !room.isAnalyticsRoom)
.toList();
final DateTime now = DateTime.now();
// get the recent message events and activity records for each chat
final List<Future<List<Event>>> recentMsgFutures = [];
final List<Future<List<Event>>> recentActivityFutures = [];
@ -309,10 +307,13 @@ class MyAnalyticsController {
recentConstructUses.addAll(constructLists.expand((e) => e));
//TODO - confirm that this is the correct construct content
debugger(
when: kDebugMode &&
(recentPangeaMessageEvents.isNotEmpty ||
recentActivityRecords.isNotEmpty));
// debugger(
// when: kDebugMode,
// );
// ; debugger(
// when: kDebugMode &&
// (allRecentMessages.isNotEmpty || recentActivityRecords.isNotEmpty),
// );
await analyticsRoom.sendConstructsEvent(
recentConstructUses,

@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../models/choreo_record.dart';
import '../utils/bot_style.dart';
enum UseType { wa, ta, ga, un }
@ -93,17 +91,3 @@ extension UseTypeMethods on UseType {
}
}
}
UseType useTypeCalculator(
ChoreoRecord? choreoRecord,
) {
if (choreoRecord == null) {
return UseType.un;
} else if (choreoRecord.includedIT) {
return UseType.ta;
} else if (choreoRecord.hasAcceptedMatches) {
return UseType.ga;
} else {
return UseType.wa;
}
}

@ -229,7 +229,6 @@ extension EventsRoomExtension on Room {
PangeaMessageTokens? tokensSent,
PangeaMessageTokens? tokensWritten,
ChoreoRecord? choreo,
UseType? useType,
}) {
// if (parseCommands) {
// return client.parseAndRunCommand(this, message,
@ -247,7 +246,6 @@ extension EventsRoomExtension on Room {
ModelKey.originalWritten: originalWritten?.toJson(),
ModelKey.tokensSent: tokensSent?.toJson(),
ModelKey.tokensWritten: tokensWritten?.toJson(),
ModelKey.useType: useType?.string,
};
if (parseMarkdown) {
final html = markdown(
@ -347,7 +345,7 @@ extension EventsRoomExtension on Room {
RecentMessageRecord(
eventId: event.eventId,
chatId: id,
useType: pMsgEvent.useType,
useType: pMsgEvent.msgUseType,
time: event.originServerTs,
),
);

@ -34,7 +34,6 @@ import 'package:sentry_flutter/sentry_flutter.dart';
import '../../../config/app_config.dart';
import '../../constants/pangea_event_types.dart';
import '../../enum/use_type.dart';
import '../../models/choreo_record.dart';
import '../../models/representation_content_model.dart';
import '../client_extension/client_extension.dart';
@ -181,7 +180,6 @@ extension PangeaRoom on Room {
PangeaMessageTokens? tokensSent,
PangeaMessageTokens? tokensWritten,
ChoreoRecord? choreo,
UseType? useType,
}) =>
_pangeaSendTextEvent(
message,
@ -198,7 +196,6 @@ extension PangeaRoom on Room {
tokensSent: tokensSent,
tokensWritten: tokensWritten,
choreo: choreo,
useType: useType,
);
Future<String> updateStateEvent(Event stateEvent) =>

@ -37,7 +37,6 @@ class PangeaMessageEvent {
late Event _event;
final Timeline timeline;
final bool ownMessage;
bool _isValidPangeaMessageEvent = true;
PangeaMessageEvent({
required Event event,
@ -45,7 +44,7 @@ class PangeaMessageEvent {
required this.ownMessage,
}) {
if (event.type != EventTypes.Message) {
_isValidPangeaMessageEvent = false;
debugger(when: kDebugMode);
ErrorHandler.logError(
m: "${event.type} should not be used to make a PangeaMessageEvent",
);
@ -548,7 +547,18 @@ class PangeaMessageEvent {
originalWritten: false,
);
UseType get useType => useTypeCalculator(originalSent?.choreo);
UseType get msgUseType {
final ChoreoRecord? choreoRecord = originalSent?.choreo;
if (choreoRecord == null) {
return UseType.un;
} else if (choreoRecord.includedIT) {
return UseType.ta;
} else if (choreoRecord.hasAcceptedMatches) {
return UseType.ga;
} else {
return UseType.wa;
}
}
bool get showUseType =>
!ownMessage &&
@ -662,30 +672,7 @@ class PangeaMessageEvent {
/// all construct uses for the message, including vocab and grammar
List<OneConstructUse> get allConstructUses =>
[..._grammarConstructUses, ..._vocabUses];
/// get construct uses of type vocab for the message
List<OneConstructUse> get _vocabUses {
final List<OneConstructUse> uses = [];
// missing vital info so return. should not happen
if (event.roomId == null) {
debugger(when: kDebugMode);
return uses;
}
// for each token, record whether selected in ga, ta, or wa
if (originalSent?.tokens != null) {
for (final token in originalSent!.tokens!) {
uses.addAll(_getVocabUseForToken(token));
}
}
// add construct uses related to IT use
uses.addAll(_itStepsToConstructUses);
return uses;
}
[..._grammarConstructUses, ..._vocabUses, ..._itStepsToConstructUses];
/// Returns a list of [OneConstructUse] from itSteps for which the continuance
/// was selected or ignored. Correct selections are considered in the tokens
@ -696,6 +683,8 @@ class PangeaMessageEvent {
/// are actually in the final message.
List<OneConstructUse> get _itStepsToConstructUses {
final List<OneConstructUse> uses = [];
if (originalSent?.choreo == null) return uses;
for (final itStep in originalSent!.choreo!.itSteps) {
for (final continuance in itStep.continuances) {
// this seems to always be false for continuances right now
@ -728,6 +717,24 @@ class PangeaMessageEvent {
return uses;
}
/// get construct uses of type vocab for the message
List<OneConstructUse> get _vocabUses {
final List<OneConstructUse> uses = [];
// missing vital info so return
if (event.roomId == null || originalSent?.tokens == null) {
debugger(when: kDebugMode);
return uses;
}
// for each token, record whether selected in ga, ta, or wa
for (final token in originalSent!.tokens!) {
uses.addAll(_getVocabUseForToken(token));
}
return uses;
}
/// Returns a list of [OneConstructUse] objects for the given [token]
/// If there is no [originalSent] or [originalSent.choreo], the [token] is
/// considered to be a [ConstructUseTypeEnum.wa] as long as it matches the target language.

@ -50,7 +50,7 @@ class SummaryAnalyticsModel extends AnalyticsModel {
(msg) => RecentMessageRecord(
eventId: msg.eventId,
chatId: msg.room.id,
useType: msg.useType,
useType: msg.msgUseType,
time: msg.originServerTs,
),
)

@ -51,7 +51,8 @@ class IGCTextData {
"full_text": json["original_input"],
})
: LanguageDetectionResponse.fromJson(
json[_detectionsKey] as Map<String, dynamic>);
json[_detectionsKey] as Map<String, dynamic>,
);
return IGCTextData(
tokens: (json[_tokensKey] as Iterable)
@ -96,7 +97,17 @@ class IGCTextData {
"enable_igc": enableIGC,
};
String get detectedLanguage => detections.bestDetection().langCode;
/// if we haven't run IGC or IT or there are no matches, we use the highest validated detection
/// from [LanguageDetectionResponse.highestValidatedDetection]
/// if we have run igc/it and there are no matches, we can relax the threshold
/// and use the highest confidence detection
String get detectedLanguage {
if (!(enableIGC && enableIT) || matches.isNotEmpty) {
return detections.highestValidatedDetection().langCode;
} else {
return detections.highestConfidenceDetection.langCode;
}
}
// reconstruct fullText based on accepted match
//update offsets in existing matches to reflect the change

@ -1,6 +1,13 @@
/// Represents a lemma object
class Lemma {
/// [text] ex "ir" - text of the lemma of the word
final String text;
/// [form] ex "vamos" - conjugated form of the lemma and as it appeared in some original text
final String form;
/// [saveVocab] true - whether to save the lemma to the user's vocabulary
/// vocab that are not saved: emails, urls, numbers, punctuation, etc.
final bool saveVocab;
Lemma({required this.text, required this.saveVocab, required this.form});

@ -4,7 +4,6 @@ import 'package:fluffychat/pangea/controllers/subscription_controller.dart';
import 'package:flutter/widgets.dart';
import '../../config/firebase_options.dart';
import '../enum/use_type.dart';
// PageRoute import
@ -90,13 +89,12 @@ class GoogleAnalytics {
logEvent('join_group', parameters: {'group_id': classCode});
}
static sendMessage(String chatRoomId, String classCode, UseType useType) {
static sendMessage(String chatRoomId, String classCode) {
logEvent(
'sent_message',
parameters: {
"chat_id": chatRoomId,
'group_id': classCode,
"message_type": useType.toString(),
},
);
}

@ -166,7 +166,7 @@ class OverlayMessage extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
if (pangeaMessageEvent.showUseType) ...[
pangeaMessageEvent.useType.iconView(
pangeaMessageEvent.msgUseType.iconView(
context,
textColor.withAlpha(164),
),

@ -1,9 +1,8 @@
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../models/chat_topic_model.dart';
import '../../models/lemma.dart';
import '../../repo/topic_data_repo.dart';
@ -76,7 +75,7 @@ class ChatVocabularyList extends StatelessWidget {
for (final word in topic.vocab)
Chip(
labelStyle: Theme.of(context).textTheme.bodyMedium,
label: Text(word.form),
label: Text(word.text),
onDeleted: () {
onChanged(topic.vocab..remove(word));
},
@ -464,7 +463,7 @@ class PromptsFieldState extends State<PromptsField> {
// button to call API
ElevatedButton.icon(
icon: BotFace(
icon: const BotFace(
width: 50.0,
expression: BotExpression.idle,
),

Loading…
Cancel
Save