saving of tokens, changing of top language calculation, documentation
This commit is contained in:
parent
2526331706
commit
c6d3f36805
16 changed files with 96 additions and 108 deletions
|
|
@ -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 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
|
||||
// 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: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 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.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…
Add table
Reference in a new issue