feat: fetch new tokens for messages without originalsent representations (#1853)
This commit is contained in:
parent
21b9b7e720
commit
32d314c026
9 changed files with 242 additions and 38 deletions
|
|
@ -10,7 +10,7 @@ import 'package:fluffychat/pangea/choreographer/models/language_detection_model.
|
|||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/span_card_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/span_data.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/language_detection_request.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/language_detection_repo.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
|
|
@ -21,7 +21,7 @@ import '../../common/constants/model_keys.dart';
|
|||
// import 'package:language_tool/language_tool.dart';
|
||||
|
||||
class IGCTextData {
|
||||
LanguageDetectionRequest detections;
|
||||
LanguageDetectionResponse detections;
|
||||
String originalInput;
|
||||
String? fullTextCorrection;
|
||||
List<PangeaToken> tokens;
|
||||
|
|
@ -47,14 +47,15 @@ class IGCTextData {
|
|||
factory IGCTextData.fromJson(Map<String, dynamic> json) {
|
||||
// changing this to allow for use of the LanguageDetectionResponse methods
|
||||
// TODO - change API after we're sure all clients are updated. not urgent.
|
||||
final LanguageDetectionRequest detections = json[_detectionsKey] is Iterable
|
||||
? LanguageDetectionRequest.fromJson({
|
||||
"detections": json[_detectionsKey],
|
||||
"full_text": json["original_input"],
|
||||
})
|
||||
: LanguageDetectionRequest.fromJson(
|
||||
json[_detectionsKey] as Map<String, dynamic>,
|
||||
);
|
||||
final LanguageDetectionResponse detections =
|
||||
json[_detectionsKey] is Iterable
|
||||
? LanguageDetectionResponse.fromJson({
|
||||
"detections": json[_detectionsKey],
|
||||
"full_text": json["original_input"],
|
||||
})
|
||||
: LanguageDetectionResponse.fromJson(
|
||||
json[_detectionsKey] as Map<String, dynamic>,
|
||||
);
|
||||
|
||||
return IGCTextData(
|
||||
tokens: (json[_tokensKey] as Iterable)
|
||||
|
|
@ -102,7 +103,7 @@ class IGCTextData {
|
|||
}
|
||||
|
||||
return IGCTextData(
|
||||
detections: LanguageDetectionRequest(
|
||||
detections: LanguageDetectionResponse(
|
||||
detections: [
|
||||
LanguageDetection(langCode: content.langCode, confidence: 1),
|
||||
],
|
||||
|
|
@ -136,7 +137,7 @@ class IGCTextData {
|
|||
};
|
||||
|
||||
/// if we haven't run IGC or IT or there are no matches, we use the highest validated detection
|
||||
/// from [LanguageDetectionRequest.highestValidatedDetection]
|
||||
/// 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 {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import 'package:http/http.dart';
|
|||
|
||||
import 'package:fluffychat/pangea/choreographer/models/language_detection_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/language_detection_request.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/language_detection_repo.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/span_data_repo.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
|
|
@ -41,7 +41,7 @@ class IgcRepo {
|
|||
await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
final IGCTextData igcTextData = IGCTextData(
|
||||
detections: LanguageDetectionRequest(
|
||||
detections: LanguageDetectionResponse(
|
||||
detections: [LanguageDetection(langCode: "en", confidence: 0.99)],
|
||||
fullText: "This be a sample text",
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,17 +1,68 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/models/language_detection_model.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/common/network/urls.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
|
||||
class LanguageDetectionRepo {
|
||||
static Future<LanguageDetectionResponse> get(
|
||||
String? accessToken, {
|
||||
required LanguageDetectionRequest request,
|
||||
}) async {
|
||||
final Requests req = Requests(
|
||||
accessToken: accessToken,
|
||||
choreoApiKey: Environment.choreoApiKey,
|
||||
);
|
||||
final Response res = await req.post(
|
||||
url: PApiUrls.languageDetection,
|
||||
body: request.toJson(),
|
||||
);
|
||||
|
||||
final Map<String, dynamic> json =
|
||||
jsonDecode(utf8.decode(res.bodyBytes).toString());
|
||||
|
||||
final LanguageDetectionResponse response =
|
||||
LanguageDetectionResponse.fromJson(json);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
class LanguageDetectionRequest {
|
||||
final String text;
|
||||
final String? senderl1;
|
||||
final String? senderl2;
|
||||
|
||||
LanguageDetectionRequest({
|
||||
required this.text,
|
||||
this.senderl1,
|
||||
this.senderl2,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'full_text': text,
|
||||
'sender_l1': senderl1,
|
||||
'sender_l2': senderl2,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class LanguageDetectionResponse {
|
||||
List<LanguageDetection> detections;
|
||||
String fullText;
|
||||
|
||||
LanguageDetectionRequest({
|
||||
LanguageDetectionResponse({
|
||||
required this.detections,
|
||||
required this.fullText,
|
||||
});
|
||||
|
||||
factory LanguageDetectionRequest.fromJson(Map<String, dynamic> json) {
|
||||
return LanguageDetectionRequest(
|
||||
factory LanguageDetectionResponse.fromJson(Map<String, dynamic> json) {
|
||||
return LanguageDetectionResponse(
|
||||
detections: List<LanguageDetection>.from(
|
||||
(json['detections'] as Iterable).map(
|
||||
(e) => LanguageDetection.fromJson(e),
|
||||
|
|
@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
|
|||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/common/network/urls.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/representation_content_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart';
|
||||
|
|
@ -184,4 +185,70 @@ class MessageDataController extends BaseController {
|
|||
|
||||
return rep;
|
||||
}
|
||||
|
||||
Future<String?> getPangeaRepresentationEvent({
|
||||
required FullTextTranslationRequestModel req,
|
||||
required PangeaMessageEvent messageEvent,
|
||||
bool originalSent = false,
|
||||
}) async {
|
||||
final FullTextTranslationResponseModel res =
|
||||
await FullTextTranslationRepo.translate(
|
||||
accessToken: _pangeaController.userController.accessToken,
|
||||
request: req,
|
||||
);
|
||||
|
||||
if (originalSent && messageEvent.originalSent != null) {
|
||||
originalSent = false;
|
||||
}
|
||||
|
||||
final rep = PangeaRepresentation(
|
||||
langCode: req.tgtLang,
|
||||
text: res.bestTranslation,
|
||||
originalSent: originalSent,
|
||||
originalWritten: false,
|
||||
);
|
||||
|
||||
try {
|
||||
final repEvent = await messageEvent.room.sendPangeaEvent(
|
||||
content: rep.toJson(),
|
||||
parentEventId: messageEvent.eventId,
|
||||
type: PangeaEventTypes.representation,
|
||||
);
|
||||
return repEvent?.eventId;
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
m: "error in _getPangeaRepresentation.sendPangeaEvent",
|
||||
e: e,
|
||||
s: s,
|
||||
data: req.toJson(),
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendTokensEvent({
|
||||
required String repEventId,
|
||||
required TokensRequestModel req,
|
||||
required Room room,
|
||||
}) async {
|
||||
final TokensResponseModel res = await _fetchTokens(
|
||||
_pangeaController.userController.accessToken,
|
||||
req,
|
||||
);
|
||||
|
||||
try {
|
||||
await room.sendPangeaEvent(
|
||||
content: PangeaMessageTokens(tokens: res.tokens).toJson(),
|
||||
parentEventId: repEventId,
|
||||
type: PangeaEventTypes.tokens,
|
||||
);
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
m: "error in _getTokens.sendPangeaEvent",
|
||||
e: e,
|
||||
s: s,
|
||||
data: req.toJson(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import 'package:sentry_flutter/sentry_flutter.dart';
|
|||
import 'package:fluffychat/pangea/choreographer/models/choreo_record.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/language_detection_repo.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
|
||||
import 'package:fluffychat/pangea/events/extensions/pangea_event_extension.dart';
|
||||
|
|
@ -508,6 +509,39 @@ class PangeaMessageEvent {
|
|||
);
|
||||
}
|
||||
|
||||
Future<String?> representationByDetectedLanguage() async {
|
||||
final resp = await LanguageDetectionRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
request: LanguageDetectionRequest(
|
||||
text: _latestEdit.body,
|
||||
senderl1: l1Code,
|
||||
senderl2: l2Code,
|
||||
),
|
||||
);
|
||||
|
||||
final langCode = resp.detections.firstOrNull?.langCode;
|
||||
if (langCode == null) return null;
|
||||
if (langCode == originalSent?.langCode) {
|
||||
return originalSent?.event?.eventId;
|
||||
}
|
||||
|
||||
// clear representations cache so the new representation event can be added when next requested
|
||||
_representations = null;
|
||||
|
||||
return MatrixState.pangeaController.messageData
|
||||
.getPangeaRepresentationEvent(
|
||||
req: FullTextTranslationRequestModel(
|
||||
text: originalSent?.content.text ?? _latestEdit.body,
|
||||
srcLang: originalSent?.langCode,
|
||||
tgtLang: langCode,
|
||||
userL2: l2Code ?? LanguageKeys.unknownLanguage,
|
||||
userL1: l1Code ?? LanguageKeys.unknownLanguage,
|
||||
),
|
||||
messageEvent: this,
|
||||
originalSent: true,
|
||||
);
|
||||
}
|
||||
|
||||
RepresentationEvent? get originalSent => representations
|
||||
.firstWhereOrNull((element) => element.content.originalSent);
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,33 @@ class RepresentationEvent {
|
|||
return res;
|
||||
}
|
||||
|
||||
Future<void> sendTokensEvent(
|
||||
String repEventID,
|
||||
Room room,
|
||||
String userl1,
|
||||
String userl2,
|
||||
) async {
|
||||
if (tokens != null) return;
|
||||
if (_event == null) {
|
||||
ErrorHandler.logError(
|
||||
e: "Called getTokensEvent with no _event",
|
||||
data: {},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await MatrixState.pangeaController.messageData.sendTokensEvent(
|
||||
repEventId: repEventID,
|
||||
room: room,
|
||||
req: TokensRequestModel(
|
||||
fullText: text,
|
||||
langCode: langCode,
|
||||
senderL1: userl1,
|
||||
senderL2: userl2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ChoreoRecord? get choreo {
|
||||
if (_choreo != null) return _choreo;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import 'package:fluffychat/pages/chat/chat.dart';
|
|||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/controllers/text_to_speech_controller.dart';
|
||||
|
|
@ -52,8 +53,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
MessageMode toolbarMode = MessageMode.noneSelected;
|
||||
PangeaTokenText? _selectedSpan;
|
||||
List<PangeaTokenText>? _highlightedTokens;
|
||||
|
||||
List<PangeaToken>? tokens;
|
||||
bool initialized = false;
|
||||
|
||||
PangeaMessageEvent? get pangeaMessageEvent => PangeaMessageEvent(
|
||||
|
|
@ -143,20 +142,43 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
}
|
||||
|
||||
MessageAnalyticsEntry? get messageAnalyticsEntry =>
|
||||
pangeaMessageEvent != null && tokens != null
|
||||
pangeaMessageEvent?.messageDisplayRepresentation?.tokens != null
|
||||
? MatrixState.pangeaController.getAnalytics.perMessage.get(
|
||||
tokens!,
|
||||
pangeaMessageEvent!.messageDisplayRepresentation!.tokens!,
|
||||
pangeaMessageEvent!,
|
||||
)
|
||||
: null;
|
||||
|
||||
Future<RepresentationEvent?> _fetchNewRepEvent() async {
|
||||
final RepresentationEvent? repEvent =
|
||||
pangeaMessageEvent?.messageDisplayRepresentation;
|
||||
|
||||
if (repEvent != null) return repEvent;
|
||||
final eventID =
|
||||
await pangeaMessageEvent?.representationByDetectedLanguage();
|
||||
|
||||
if (eventID == null) return null;
|
||||
final event = await widget._event.room.getEventById(eventID);
|
||||
if (event == null) return null;
|
||||
return RepresentationEvent(
|
||||
timeline: pangeaMessageEvent!.timeline,
|
||||
parentMessageEvent: pangeaMessageEvent!.event,
|
||||
event: event,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initializeTokensAndMode() async {
|
||||
try {
|
||||
final repEvent = pangeaMessageEvent?.messageDisplayRepresentation;
|
||||
if (repEvent != null) {
|
||||
tokens = await repEvent.tokensGlobal(
|
||||
pangeaMessageEvent!.senderId,
|
||||
pangeaMessageEvent!.originServerTs,
|
||||
RepresentationEvent? repEvent =
|
||||
pangeaMessageEvent?.messageDisplayRepresentation;
|
||||
repEvent ??= await _fetchNewRepEvent();
|
||||
|
||||
if (repEvent?.event != null) {
|
||||
await repEvent!.sendTokensEvent(
|
||||
repEvent.event!.eventId,
|
||||
widget._event.room,
|
||||
MatrixState.pangeaController.languageController.userL1!.langCode,
|
||||
MatrixState.pangeaController.languageController.userL2!.langCode,
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
|
|
@ -331,7 +353,9 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
);
|
||||
}
|
||||
|
||||
PangeaToken? get selectedToken => tokens?.firstWhereOrNull(isTokenSelected);
|
||||
PangeaToken? get selectedToken =>
|
||||
pangeaMessageEvent?.messageDisplayRepresentation?.tokens
|
||||
?.firstWhereOrNull(isTokenSelected);
|
||||
|
||||
/// Whether the overlay is currently displaying a selection
|
||||
bool get isSelection => _selectedSpan != null || _highlightedTokens != null;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@ import 'package:fluffychat/widgets/matrix.dart';
|
|||
/// Need to test.
|
||||
class MessageTokenText extends StatelessWidget {
|
||||
final PangeaMessageEvent _pangeaMessageEvent;
|
||||
|
||||
final List<PangeaToken>? _tokens;
|
||||
|
||||
final TextStyle _style;
|
||||
|
||||
final bool Function(PangeaToken)? _isSelected;
|
||||
|
|
@ -34,9 +31,11 @@ class MessageTokenText extends StatelessWidget {
|
|||
}) : _onClick = onClick,
|
||||
_isSelected = isSelected,
|
||||
_style = style,
|
||||
_tokens = tokens,
|
||||
_pangeaMessageEvent = pangeaMessageEvent;
|
||||
|
||||
List<PangeaToken>? get _tokens =>
|
||||
_pangeaMessageEvent.messageDisplayRepresentation?.tokens;
|
||||
|
||||
MessageAnalyticsEntry? get messageAnalyticsEntry => _tokens != null
|
||||
? MatrixState.pangeaController.getAnalytics.perMessage.get(
|
||||
_tokens!,
|
||||
|
|
@ -44,6 +43,12 @@ class MessageTokenText extends StatelessWidget {
|
|||
)
|
||||
: null;
|
||||
|
||||
void callOnClick(TokenPosition tokenPosition) {
|
||||
_onClick != null && tokenPosition.token != null
|
||||
? _onClick!(tokenPosition.token!)
|
||||
: null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_tokens == null) {
|
||||
|
|
@ -53,12 +58,6 @@ class MessageTokenText extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
void callOnClick(TokenPosition tokenPosition) {
|
||||
_onClick != null && tokenPosition.token != null
|
||||
? _onClick!(tokenPosition.token!)
|
||||
: null;
|
||||
}
|
||||
|
||||
return MessageTextWidget(
|
||||
pangeaMessageEvent: _pangeaMessageEvent,
|
||||
style: _style,
|
||||
|
|
|
|||
|
|
@ -200,7 +200,8 @@ class PracticeActivityCardState extends State<PracticeActivityCard> {
|
|||
userL1: MatrixState.pangeaController.languageController.userL1!.langCode,
|
||||
userL2: MatrixState.pangeaController.languageController.userL2!.langCode,
|
||||
messageText: widget.pangeaMessageEvent.messageDisplayText,
|
||||
messageTokens: widget.overlayController.tokens!,
|
||||
messageTokens:
|
||||
widget.pangeaMessageEvent.messageDisplayRepresentation?.tokens ?? [],
|
||||
activityQualityFeedback: activityFeedback,
|
||||
targetTokens: tokens,
|
||||
targetType: type,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue