refactor: remove unused files in choreo folder, remove request and response models into their own files

This commit is contained in:
ggurdin 2025-10-24 14:27:09 -04:00
parent cdd34a7f7c
commit 2637308891
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
46 changed files with 729 additions and 1475 deletions

View file

@ -42,10 +42,10 @@ import 'package:fluffychat/pangea/chat/widgets/event_too_large_dialog.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
import 'package:fluffychat/pangea/choreographer/models/choreo_record.dart';
import 'package:fluffychat/pangea/choreographer/utils/language_mismatch_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/language_mismatch_repo.dart';
import 'package:fluffychat/pangea/choreographer/utils/pangea_text_controller.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/language_mismatch_popup.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/message_analytics_feedback.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/pangea_text_controller.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';

View file

@ -8,7 +8,7 @@ import 'package:matrix/matrix.dart';
import 'package:slugify/slugify.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/pangea_text_controller.dart';
import 'package:fluffychat/pangea/choreographer/utils/pangea_text_controller.dart';
import 'package:fluffychat/pangea/toolbar/utils/shrinkable_text.dart';
import 'package:fluffychat/utils/markdown_context_builder.dart';
import 'package:fluffychat/widgets/mxc_image.dart';

View file

@ -2,9 +2,6 @@ import 'package:flutter/material.dart';
class ChoreoConstants {
static const numberOfITChoices = 4;
// static const millisecondsToDisplayFeedback = 2500;
static const millisecondsToDisplayFeedback = 0;
static const commonalityThreshold = 0.9;
static const levelThresholdForGreen = 1;
static const levelThresholdForYellow = 2;
static const levelThresholdForRed = 3;

View file

@ -14,7 +14,7 @@ import 'package:fluffychat/pangea/choreographer/models/choreo_record.dart';
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
import 'package:fluffychat/pangea/choreographer/utils/input_paste_listener.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/pangea_text_controller.dart';
import 'package:fluffychat/pangea/choreographer/utils/pangea_text_controller.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/paywall_card.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/any_state_holder.dart';

View file

@ -1,152 +0,0 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:collection/collection.dart';
import 'package:http/http.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import '../../common/constants/model_keys.dart';
import '../../common/controllers/pangea_controller.dart';
import '../../common/network/requests.dart';
import '../../common/network/urls.dart';
class ContextualDefinitionController {
late PangeaController _pangeaController;
final List<_ContextualDefinitionCacheItem> _definitions = [];
ContextualDefinitionController(PangeaController pangeaController) {
_pangeaController = pangeaController;
}
_ContextualDefinitionCacheItem? _getLocal(
ContextualDefinitionRequestModel req,
) =>
_definitions.firstWhereOrNull(
(e) => e.word == req.word && e.fullText == req.fullText,
);
Future<ContextualDefinitionResponseModel?> get(
ContextualDefinitionRequestModel req,
) {
final _ContextualDefinitionCacheItem? localItem = _getLocal(req);
if (localItem != null) return localItem.data;
_definitions.add(
_ContextualDefinitionCacheItem(
word: req.word,
fullText: req.fullText,
data: _define(req),
),
);
return _definitions.last.data;
}
Future<ContextualDefinitionResponseModel?> _define(
ContextualDefinitionRequestModel request,
) async {
try {
final ContextualDefinitionResponseModel res =
await _ContextualDefinitionRepo.define(
_pangeaController.userController.accessToken,
request,
);
return res;
} catch (err, stack) {
debugPrint(
"error getting contextual definition for ${request.word} in '${request.fullText}'",
);
ErrorHandler.logError(e: err, s: stack, data: request.toJson());
return null;
}
}
}
class _ContextualDefinitionCacheItem {
String word;
String fullText;
Future<ContextualDefinitionResponseModel?> data;
_ContextualDefinitionCacheItem({
required this.word,
required this.fullText,
required this.data,
});
}
class _ContextualDefinitionRepo {
static Future<ContextualDefinitionResponseModel> define(
String accessToken,
ContextualDefinitionRequestModel request,
) async {
final Requests req = Requests(
choreoApiKey: Environment.choreoApiKey,
accessToken: accessToken,
);
final Response res = await req.post(
url: PApiUrls.contextualDefinition,
body: request.toJson(),
);
final ContextualDefinitionResponseModel response =
ContextualDefinitionResponseModel.fromJson(
jsonDecode(
utf8.decode(res.bodyBytes).toString(),
),
);
if (response.text.isEmpty) {
ErrorHandler.logError(
e: Exception(
"empty text in contextual definition response",
),
data: {
"request": request.toJson(),
"accessToken": accessToken,
},
);
}
return response;
}
}
class ContextualDefinitionRequestModel {
final String fullText;
final String word;
final String feedbackLang;
final String fullTextLang;
final String wordLang;
ContextualDefinitionRequestModel({
required this.fullText,
required this.word,
required this.feedbackLang,
required this.fullTextLang,
required this.wordLang,
});
Map<String, dynamic> toJson() => {
ModelKey.fullText: fullText,
ModelKey.word: word,
ModelKey.lang: feedbackLang,
ModelKey.fullTextLang: fullTextLang,
ModelKey.wordLang: wordLang,
};
}
class ContextualDefinitionResponseModel {
String text;
ContextualDefinitionResponseModel({required this.text});
factory ContextualDefinitionResponseModel.fromJson(
Map<String, dynamic> json,
) =>
ContextualDefinitionResponseModel(text: json["response"]);
}

View file

@ -13,6 +13,7 @@ import 'package:fluffychat/pangea/choreographer/controllers/span_data_controller
import 'package:fluffychat/pangea/choreographer/models/igc_text_data_model.dart';
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/igc_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/igc_request_model.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/span_card.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -48,8 +49,6 @@ class _IgnoredMatchCacheItem {
class IgcController {
Choreographer choreographer;
IGCTextData? igcTextData;
Object? igcError;
Completer<IGCTextData> igcCompleter = Completer();
late SpanDataController spanDataController;
// cache for IGC data and prev message
@ -77,7 +76,7 @@ class IgcController {
if (choreographer.currentText.isEmpty) return clear();
debugPrint('getIGCTextData called with ${choreographer.currentText}');
final IGCRequestBody reqBody = IGCRequestBody(
final IGCRequestModel reqBody = IGCRequestModel(
fullText: choreographer.currentText,
userId: choreographer.pangeaController.userController.userId!,
userL1: choreographer.l1LangCode!,

View file

@ -11,10 +11,10 @@ import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../models/custom_input_translation_model.dart';
import '../models/it_response_model.dart';
import '../models/it_step.dart';
import '../repo/custom_input_request_model.dart';
import '../repo/interactive_translation_repo.dart';
import '../repo/it_response_model.dart';
import 'choreographer.dart';
class ITController {
@ -23,7 +23,6 @@ class ITController {
bool _isOpen = false;
bool _willOpen = false;
bool _isEditingSourceText = false;
bool showChoiceFeedback = false;
bool dismissed = false;
ITStartData? _itStartData;
@ -41,7 +40,6 @@ class ITController {
_willOpen = false;
MatrixState.pAnyState.closeOverlay("it_feedback_card");
showChoiceFeedback = false;
_isEditingSourceText = false;
dismissed = false;
@ -309,19 +307,6 @@ class ITController {
final itStep = ITStep(currentITStep!.continuances, chosen: chosenIndex);
completedITSteps.add(itStep);
showChoiceFeedback = true;
Future.delayed(
const Duration(
milliseconds: ChoreoConstants.millisecondsToDisplayFeedback,
),
() {
showChoiceFeedback = false;
choreographer.setState();
},
);
choreographer.onITChoiceSelect(itStep);
choreographer.setState();
}

View file

@ -1,42 +0,0 @@
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class ITFeedbackRequestModel {
final String sourceText;
final String currentText;
final String bestContinuance;
final String chosenContinuance;
final String feedbackLang;
final String sourceTextLang;
final String targetLang;
ITFeedbackRequestModel({
required this.sourceText,
required this.currentText,
required this.bestContinuance,
required this.chosenContinuance,
required this.feedbackLang,
required this.sourceTextLang,
required this.targetLang,
});
Map<String, dynamic> toJson() => {
ModelKey.sourceText: sourceText,
ModelKey.currentText: currentText,
ModelKey.bestContinuance: bestContinuance,
ModelKey.chosenContinuance: chosenContinuance,
ModelKey.feedbackLang: feedbackLang,
ModelKey.srcLang: sourceTextLang,
ModelKey.tgtLang: targetLang,
};
}
class ITFeedbackResponseModel {
String text;
ITFeedbackResponseModel({required this.text});
factory ITFeedbackResponseModel.fromJson(
Map<String, dynamic> json,
) =>
ITFeedbackResponseModel(text: json[ModelKey.text]);
}

View file

@ -8,7 +8,7 @@ import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pangea/choreographer/models/span_data.dart';
import 'package:fluffychat/pangea/choreographer/repo/span_data_repo.dart';
import 'package:fluffychat/pangea/choreographer/utils/normalize_text.dart';
import 'package:fluffychat/pangea/choreographer/utils/text_normalization_util.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
class _SpanDetailsCacheItem {
@ -70,7 +70,8 @@ class SpanDataController {
);
return correctChoice != null &&
normalizeString(correctChoice) == normalizeString(errorSpan);
TextNormalizationUtil.normalizeString(correctChoice) ==
TextNormalizationUtil.normalizeString(errorSpan);
}
Future<void> getSpanDetails(

View file

@ -1,92 +0,0 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/l10n/l10n.dart';
import '../../bot/utils/bot_style.dart';
enum UseType { wa, ta, ga, un }
extension UseTypeMethods on UseType {
String get string => toString().split(".").last;
String tooltipString(BuildContext context) {
final l10n = L10n.of(context);
switch (this) {
case UseType.ga:
return l10n.gaTooltip;
case UseType.ta:
return l10n.taTooltip;
case UseType.wa:
return l10n.waTooltip;
default:
return l10n.unTooltip;
}
}
IconData get iconData {
switch (this) {
case UseType.ga:
return Icons.spellcheck_outlined;
case UseType.ta:
return Icons.translate;
case UseType.wa:
return Icons.thumb_up;
default:
return Icons.question_mark_outlined;
}
}
Widget iconView(BuildContext context, Color color, [int size = 14]) =>
Tooltip(
message: tooltipString(context),
child: Icon(
iconData,
color: color,
size: size.toDouble(),
),
);
Widget iconButtonView(BuildContext context, Color color, [int size = 14]) =>
Tooltip(
message: tooltipString(context),
child: Icon(
iconData,
color: color,
size: size.toDouble(),
),
);
Widget textView(BuildContext context, [TextStyle? existingStyle]) => Tooltip(
message: tooltipString(context),
child: Text(
string,
style: BotStyle.text(
context,
existingStyle: existingStyle,
italics: true,
),
textAlign: TextAlign.end,
),
);
static bool isDarkMode(BuildContext context) =>
Theme.of(context).brightness == Brightness.dark;
Color color(BuildContext context) {
switch (this) {
case UseType.ga:
return isDarkMode(context)
? const Color.fromARGB(255, 157, 234, 172)
: const Color.fromARGB(255, 31, 146, 54);
case UseType.ta:
return isDarkMode(context)
? const Color.fromARGB(255, 169, 183, 237)
: const Color.fromARGB(255, 38, 59, 141);
case UseType.wa:
return isDarkMode(context)
? const Color.fromARGB(255, 212, 144, 216)
: const Color.fromARGB(255, 163, 39, 169);
default:
return Theme.of(context).textTheme.bodyLarge!.color ?? Colors.blueGrey;
}
}
}

View file

@ -37,27 +37,4 @@ class ChoreoEvent {
return null;
}
}
// bool get hasAcceptedMatches =>
// content?.steps.any(
// (element) =>
// element.acceptedOrIgnoredMatch?.status ==
// PangeaMatchStatus.accepted,
// ) ??
// false;
// bool get hasIgnoredMatches =>
// content?.steps.any(
// (element) =>
// element.acceptedOrIgnoredMatch?.status == PangeaMatchStatus.ignored,
// ) ??
// false;
// bool get includedIT =>
// content?.steps.any((step) {
// return step.acceptedOrIgnoredMatch?.status ==
// PangeaMatchStatus.accepted &&
// (step.acceptedOrIgnoredMatch?.isITStart ?? false);
// }) ??
// false;
}

View file

@ -1,172 +0,0 @@
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
class ITResponseModel {
String fullTextTranslation;
List<Continuance> continuances;
List<Continuance>? goldContinuances;
bool isFinal;
String? translationId;
int payloadId;
ITResponseModel({
required this.fullTextTranslation,
required this.continuances,
required this.translationId,
required this.goldContinuances,
required this.isFinal,
required this.payloadId,
});
factory ITResponseModel.fromJson(Map<String, dynamic> json) {
//PTODO - is continuances a variable type? can we change that?
if (json['continuances'].runtimeType == String) {
debugPrint("continuances was string - ${json['continuances']}");
json['continuances'] = [];
json['finished'] = true;
}
final List<Continuance> interimCont = (json['continuances'] as List)
.mapIndexed((index, e) {
e["index"] = index;
return Continuance.fromJson(e);
})
.toList()
.take(ChoreoConstants.numberOfITChoices)
.toList()
.cast<Continuance>()
//can't do this on the backend because step translation can't filter them out
.where((element) => element.inDictionary)
.toList();
interimCont.shuffle();
return ITResponseModel(
fullTextTranslation: json["full_text_translation"] ?? json["translation"],
continuances: interimCont,
translationId: json['translation_id'],
payloadId: json['payload_id'] ?? 0,
isFinal: json['finished'] ?? false,
goldContinuances: json['gold_continuances'] != null
? (json['gold_continuances'] as Iterable).map((e) {
e["gold"] = true;
return Continuance.fromJson(e);
}).toList()
: null,
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['full_text_translation'] = fullTextTranslation;
data['continuances'] = continuances.map((v) => v.toJson()).toList();
if (translationId != null) {
data['translation_id'] = translationId;
}
data['payload_id'] = payloadId;
data["finished"] = isFinal;
return data;
}
}
class Continuance {
/// only saving this top set in a condensed json form
double probability;
int level;
String text;
// List<PangeaToken> tokens;
/// saving this in a full json form
String description;
int? indexSavedByServer;
bool wasClicked;
bool inDictionary;
bool hasInfo;
bool gold;
Continuance({
required this.probability,
required this.level,
required this.text,
required this.description,
required this.indexSavedByServer,
required this.wasClicked,
required this.inDictionary,
required this.hasInfo,
required this.gold,
// required this.tokens,
});
factory Continuance.fromJson(Map<String, dynamic> json) {
// final List<PangeaToken> tokensInternal = (json[ModelKey.tokens] != null)
// ? (json[ModelKey.tokens] as Iterable)
// .map<PangeaToken>(
// (e) => PangeaToken.fromJson(e as Map<String, dynamic>),
// )
// .toList()
// .cast<PangeaToken>()
// : [];
return Continuance(
probability: json['probability'].toDouble(),
level: json['level'],
text: json['text'],
description: json['description'] ?? "",
indexSavedByServer: json["index"],
inDictionary: json['in_dictionary'] ?? true,
wasClicked: json['clkd'] ?? false,
hasInfo: json['has_info'] ?? false,
gold: json['gold'] ?? false,
// tokens: tokensInternal,
);
}
Map<String, dynamic> toJson([bool condensed = false]) {
final Map<String, dynamic> data = <String, dynamic>{};
data['probability'] = probability;
data['level'] = level;
data['text'] = text;
data['clkd'] = wasClicked;
// data[ModelKey.tokens] = tokens.map((e) => e.toJson()).toList();
if (!condensed) {
data['description'] = description;
data['in_dictionary'] = inDictionary;
data['has_info'] = hasInfo;
data["index"] = indexSavedByServer;
data['gold'] = gold;
}
return data;
}
Color? get color {
if (!wasClicked) return null;
switch (level) {
case ChoreoConstants.levelThresholdForGreen:
return ChoreoConstants.green;
case ChoreoConstants.levelThresholdForYellow:
return ChoreoConstants.yellow;
case ChoreoConstants.levelThresholdForRed:
return ChoreoConstants.red;
default:
return null;
}
}
String? feedbackText(BuildContext context) {
final L10n l10n = L10n.of(context);
switch (level) {
case ChoreoConstants.levelThresholdForGreen:
return l10n.greenFeedback;
case ChoreoConstants.levelThresholdForYellow:
return l10n.yellowFeedback;
case ChoreoConstants.levelThresholdForRed:
return l10n.redFeedback;
default:
return null;
}
}
}

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/l10n/l10n.dart';
import '../constants/choreo_constants.dart';
import 'it_response_model.dart';
class ITStep {
List<Continuance> continuances;
@ -68,3 +68,101 @@ class ITStep {
);
}
}
class Continuance {
/// only saving this top set in a condensed json form
double probability;
int level;
String text;
// List<PangeaToken> tokens;
/// saving this in a full json form
String description;
int? indexSavedByServer;
bool wasClicked;
bool inDictionary;
bool hasInfo;
bool gold;
Continuance({
required this.probability,
required this.level,
required this.text,
required this.description,
required this.indexSavedByServer,
required this.wasClicked,
required this.inDictionary,
required this.hasInfo,
required this.gold,
// required this.tokens,
});
factory Continuance.fromJson(Map<String, dynamic> json) {
// final List<PangeaToken> tokensInternal = (json[ModelKey.tokens] != null)
// ? (json[ModelKey.tokens] as Iterable)
// .map<PangeaToken>(
// (e) => PangeaToken.fromJson(e as Map<String, dynamic>),
// )
// .toList()
// .cast<PangeaToken>()
// : [];
return Continuance(
probability: json['probability'].toDouble(),
level: json['level'],
text: json['text'],
description: json['description'] ?? "",
indexSavedByServer: json["index"],
inDictionary: json['in_dictionary'] ?? true,
wasClicked: json['clkd'] ?? false,
hasInfo: json['has_info'] ?? false,
gold: json['gold'] ?? false,
// tokens: tokensInternal,
);
}
Map<String, dynamic> toJson([bool condensed = false]) {
final Map<String, dynamic> data = <String, dynamic>{};
data['probability'] = probability;
data['level'] = level;
data['text'] = text;
data['clkd'] = wasClicked;
// data[ModelKey.tokens] = tokens.map((e) => e.toJson()).toList();
if (!condensed) {
data['description'] = description;
data['in_dictionary'] = inDictionary;
data['has_info'] = hasInfo;
data["index"] = indexSavedByServer;
data['gold'] = gold;
}
return data;
}
Color? get color {
if (!wasClicked) return null;
switch (level) {
case ChoreoConstants.levelThresholdForGreen:
return ChoreoConstants.green;
case ChoreoConstants.levelThresholdForYellow:
return ChoreoConstants.yellow;
case ChoreoConstants.levelThresholdForRed:
return ChoreoConstants.red;
default:
return null;
}
}
String? feedbackText(BuildContext context) {
final L10n l10n = L10n.of(context);
switch (level) {
case ChoreoConstants.levelThresholdForGreen:
return l10n.greenFeedback;
case ChoreoConstants.levelThresholdForYellow:
return l10n.yellowFeedback;
case ChoreoConstants.levelThresholdForRed:
return l10n.redFeedback;
default:
return null;
}
}
}

View file

@ -1,202 +0,0 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/word_data_card.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class WordData {
final String word;
final String fullText;
final String? userL1;
final String? userL2;
// final List<LanguageSense> languageSenses;
final String targetPartOfSpeech;
final String basePartOfSpeech;
final String partOfSpeech;
final String targetDefinition;
final String baseDefinition;
final String targetWord;
final String baseWord;
final String baseExampleSentence;
final String targetExampleSentence;
WordData({
// required this.languageSenses,
required this.fullText,
required this.word,
required this.userL1,
required this.userL2,
required this.baseDefinition,
required this.targetDefinition,
required this.basePartOfSpeech,
required this.targetPartOfSpeech,
required this.partOfSpeech,
required this.baseWord,
required this.targetWord,
required this.baseExampleSentence,
required this.targetExampleSentence,
});
// static const String _languageSensesKey = 'sense_responses';
static const String _dataFullKey = 'data_full';
Map<String, dynamic> toJson() => {
// _languageSensesKey: languageSenses.map((e) => e.toJson()).toList(),
ModelKey.word: word,
ModelKey.userL1: userL1,
ModelKey.userL2: userL2,
ModelKey.baseDefinition: baseDefinition,
ModelKey.targetDefinition: targetDefinition,
ModelKey.basePartOfSpeech: basePartOfSpeech,
ModelKey.targetPartOfSpeech: targetPartOfSpeech,
ModelKey.partOfSpeech: partOfSpeech,
ModelKey.baseWord: baseWord,
ModelKey.targetWord: targetWord,
ModelKey.baseExampleSentence: baseExampleSentence,
ModelKey.targetExampleSentence: targetExampleSentence,
};
factory WordData.fromJson(
Map<String, dynamic> json, {
required String word,
required String fullText,
required String userL1,
required String userL2,
}) {
try {
return WordData(
// languageSenses: (json[_languageSensesKey] as List<dynamic>)
// .map<LanguageSense>(
// (e) => LanguageSense.fromJson(e as Map<String, dynamic>),
// )
// .toList()
// .cast<LanguageSense>(),
baseDefinition: json[_dataFullKey][ModelKey.baseDefinition],
targetDefinition: json[_dataFullKey][ModelKey.targetDefinition],
basePartOfSpeech: json[_dataFullKey][ModelKey.basePartOfSpeech],
targetPartOfSpeech: json[_dataFullKey][ModelKey.targetPartOfSpeech],
partOfSpeech: json[_dataFullKey][ModelKey.partOfSpeech],
baseWord: json[_dataFullKey][ModelKey.baseWord],
targetWord: json[_dataFullKey][ModelKey.targetWord],
baseExampleSentence: json[_dataFullKey][ModelKey.baseExampleSentence],
targetExampleSentence: json[_dataFullKey]
[ModelKey.targetExampleSentence],
word: word,
userL1: userL1,
userL2: userL2,
fullText: fullText,
);
} catch (err) {
debugger(when: kDebugMode);
return [] as WordData;
}
}
bool isMatch({
required String w,
required String f,
required String? l1,
required String? l2,
}) =>
word == w && userL1 == l1 && userL2 == l2 && fullText == f;
String? formattedPartOfSpeech(LanguageType languageType) {
final String pos = languageType == LanguageType.base
? basePartOfSpeech
: targetPartOfSpeech;
if (pos.isEmpty) return null;
return pos[0].toUpperCase() + pos.substring(1);
}
// List<LanguageSense> sensesForLanguage(String code) =>
// languageSenses.where((langSense) => langSense.langCode == code).toList();
}
// class LanguageSense {
// List<Sense> senses;
// String langCode;
// LanguageSense({
// required this.senses,
// required this.langCode,
// });
// static const String _sensesKey = "senses";
// static const String _langCodeKey = "lang_code";
// Map<String, dynamic> toJson() => {
// _sensesKey: senses.map((e) => e.toJson()).toList(),
// _langCodeKey: langCode,
// };
// factory LanguageSense.fromJson(Map<String, dynamic> json) => LanguageSense(
// senses: (json[_sensesKey] as List<dynamic>)
// .map<Sense>(
// (e) => Sense.fromJson(e as Map<String, dynamic>),
// )
// .toList()
// .cast<Sense>(),
// langCode: json[_langCodeKey],
// );
// List<String> get partsOfSpeech =>
// senses.map((sense) => sense.partOfSpeech).toSet().toList();
// List<String> definitionsForPartOfSpeech(String partOfSpeech) {
// final List<String> definitions = [];
// for (final Sense sense in senses) {
// if (sense.partOfSpeech == partOfSpeech &&
// sense.definition != null &&
// sense.definition!.isNotEmpty) {
// definitions.add(sense.definition!);
// }
// }
// return definitions;
// }
// // List<String> partOfSpeechSense(partOfSpeech) {
// // return senses
// // .where((sense) => sense.partOfSpeech == partOfSpeech)
// // .map((sense) => sense.lemmas.join(', '))
// // .toSet()
// // .toList();
// // }
// // Map<String, List<String>> get partOfSpeechSenses {
// // final Map<String, List<String>> senses = {};
// // for (final partOfSpeech in partsOfSpeech) {
// // senses[partOfSpeech] = partOfSpeechSense(partOfSpeech);
// // }
// // return senses;
// // }
// }
// class Sense {
// String partOfSpeech;
// List<String> lemmas;
// String? definition;
// Sense({
// required this.partOfSpeech,
// required this.lemmas,
// required this.definition,
// });
// static const String _posKey = "pos";
// static const String _lemmasKey = "lemmas";
// static const String _definitionKey = "definition";
// Map<String, dynamic> toJson() => {
// _posKey: partOfSpeech,
// _lemmasKey: lemmas.toString(),
// _definitionKey: definition
// };
// factory Sense.fromJson(Map<String, dynamic> json) => Sense(
// partOfSpeech: json[_posKey],
// lemmas: (json[_lemmasKey] as List<dynamic>).cast<String>(),
// definition: json[_definitionKey],
// );
// }

View file

@ -0,0 +1,109 @@
import 'dart:convert';
import 'package:async/async.dart';
import 'package:http/http.dart';
import 'package:fluffychat/pangea/choreographer/repo/contextual_definition_request_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/contextual_definition_response_model.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import '../../common/network/requests.dart';
import '../../common/network/urls.dart';
class ContextualDefinitionRepo {
static final Map<String, Future<ContextualDefinitionResponseModel>> _cache =
{};
static Future<Result<ContextualDefinitionResponseModel>> get(
String accessToken,
ContextualDefinitionRequestModel request,
) async {
final cached = _getCached(request);
if (cached != null) {
try {
return Result.value(await cached);
} catch (e, s) {
_cache.remove(request.hashCode.toString());
ErrorHandler.logError(
e: e,
s: s,
data: request.toJson(),
);
return Result.error(e);
}
}
final future = _fetch(accessToken, request);
_setCached(request, future);
return _getResult(request, future);
}
static Future<ContextualDefinitionResponseModel> _fetch(
String accessToken,
ContextualDefinitionRequestModel request,
) async {
final Requests req = Requests(
choreoApiKey: Environment.choreoApiKey,
accessToken: accessToken,
);
final Response res = await req.post(
url: PApiUrls.contextualDefinition,
body: request.toJson(),
);
if (res.statusCode != 200) {
throw res;
}
final ContextualDefinitionResponseModel response =
ContextualDefinitionResponseModel.fromJson(
jsonDecode(
utf8.decode(res.bodyBytes).toString(),
),
);
if (response.text.isEmpty) {
ErrorHandler.logError(
e: Exception(
"empty text in contextual definition response",
),
data: {
"request": request.toJson(),
"accessToken": accessToken,
},
);
}
return response;
}
static Future<Result<ContextualDefinitionResponseModel>> _getResult(
ContextualDefinitionRequestModel request,
Future<ContextualDefinitionResponseModel> future,
) async {
try {
final res = await future;
return Result.value(res);
} catch (e, s) {
_cache.remove(request.hashCode.toString());
ErrorHandler.logError(
e: e,
s: s,
data: request.toJson(),
);
return Result.error(e);
}
}
static Future<ContextualDefinitionResponseModel>? _getCached(
ContextualDefinitionRequestModel request,
) =>
_cache[request.hashCode.toString()];
static void _setCached(
ContextualDefinitionRequestModel request,
Future<ContextualDefinitionResponseModel> response,
) =>
_cache[request.hashCode.toString()] = response;
}

View file

@ -0,0 +1,44 @@
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class ContextualDefinitionRequestModel {
final String fullText;
final String word;
final String feedbackLang;
final String fullTextLang;
final String wordLang;
ContextualDefinitionRequestModel({
required this.fullText,
required this.word,
required this.feedbackLang,
required this.fullTextLang,
required this.wordLang,
});
Map<String, dynamic> toJson() => {
ModelKey.fullText: fullText,
ModelKey.word: word,
ModelKey.lang: feedbackLang,
ModelKey.fullTextLang: fullTextLang,
ModelKey.wordLang: wordLang,
};
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ContextualDefinitionRequestModel &&
runtimeType == other.runtimeType &&
fullText == other.fullText &&
word == other.word &&
feedbackLang == other.feedbackLang &&
fullTextLang == other.fullTextLang &&
wordLang == other.wordLang;
@override
int get hashCode =>
fullText.hashCode ^
word.hashCode ^
feedbackLang.hashCode ^
fullTextLang.hashCode ^
wordLang.hashCode;
}

View file

@ -0,0 +1,10 @@
class ContextualDefinitionResponseModel {
String text;
ContextualDefinitionResponseModel({required this.text});
factory ContextualDefinitionResponseModel.fromJson(
Map<String, dynamic> json,
) =>
ContextualDefinitionResponseModel(text: json["response"]);
}

View file

@ -1,4 +1,4 @@
import 'package:fluffychat/pangea/choreographer/models/it_response_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/it_response_model.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class CustomInputRequestModel {

View file

@ -5,8 +5,9 @@ import 'dart:convert';
import 'package:http/http.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_request_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_response_model.dart';
import '../../common/config/environment.dart';
import '../../common/constants/model_keys.dart';
import '../../common/network/requests.dart';
import '../../common/network/urls.dart';
@ -87,95 +88,3 @@ class FullTextTranslationRepo {
return responseModel;
}
}
class FullTextTranslationRequestModel {
String text;
String? srcLang;
String tgtLang;
String userL1;
String userL2;
bool? deepL;
int? offset;
int? length;
FullTextTranslationRequestModel({
required this.text,
this.srcLang,
required this.tgtLang,
required this.userL2,
required this.userL1,
this.deepL = false,
this.offset,
this.length,
});
//PTODO throw error for null
Map<String, dynamic> toJson() => {
"text": text,
ModelKey.srcLang: srcLang,
ModelKey.tgtLang: tgtLang,
ModelKey.userL2: userL2,
ModelKey.userL1: userL1,
ModelKey.deepL: deepL,
ModelKey.offset: offset,
ModelKey.length: length,
};
// override equals and hashcode
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is FullTextTranslationRequestModel &&
other.text == text &&
other.srcLang == srcLang &&
other.tgtLang == tgtLang &&
other.userL2 == userL2 &&
other.userL1 == userL1 &&
other.deepL == deepL &&
other.offset == offset &&
other.length == length;
}
@override
int get hashCode =>
text.hashCode ^
srcLang.hashCode ^
tgtLang.hashCode ^
userL2.hashCode ^
userL1.hashCode ^
deepL.hashCode ^
offset.hashCode ^
length.hashCode;
}
class FullTextTranslationResponseModel {
List<String> translations;
/// detected source
/// PTODO -
String source;
String? deepL;
FullTextTranslationResponseModel({
required this.translations,
required this.source,
required this.deepL,
});
factory FullTextTranslationResponseModel.fromJson(Map<String, dynamic> json) {
return FullTextTranslationResponseModel(
translations: (json["translations"] as Iterable)
.map<String>(
(e) => e,
)
.toList()
.cast<String>(),
source: json[ModelKey.srcLang],
deepL: json['deepl_res'],
);
}
String get bestTranslation => deepL ?? translations.first;
}

View file

@ -0,0 +1,63 @@
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class FullTextTranslationRequestModel {
String text;
String? srcLang;
String tgtLang;
String userL1;
String userL2;
bool? deepL;
int? offset;
int? length;
FullTextTranslationRequestModel({
required this.text,
this.srcLang,
required this.tgtLang,
required this.userL2,
required this.userL1,
this.deepL = false,
this.offset,
this.length,
});
//PTODO throw error for null
Map<String, dynamic> toJson() => {
"text": text,
ModelKey.srcLang: srcLang,
ModelKey.tgtLang: tgtLang,
ModelKey.userL2: userL2,
ModelKey.userL1: userL1,
ModelKey.deepL: deepL,
ModelKey.offset: offset,
ModelKey.length: length,
};
// override equals and hashcode
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is FullTextTranslationRequestModel &&
other.text == text &&
other.srcLang == srcLang &&
other.tgtLang == tgtLang &&
other.userL2 == userL2 &&
other.userL1 == userL1 &&
other.deepL == deepL &&
other.offset == offset &&
other.length == length;
}
@override
int get hashCode =>
text.hashCode ^
srcLang.hashCode ^
tgtLang.hashCode ^
userL2.hashCode ^
userL1.hashCode ^
deepL.hashCode ^
offset.hashCode ^
length.hashCode;
}

View file

@ -0,0 +1,31 @@
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class FullTextTranslationResponseModel {
List<String> translations;
/// detected source
/// PTODO -
String source;
String? deepL;
FullTextTranslationResponseModel({
required this.translations,
required this.source,
required this.deepL,
});
factory FullTextTranslationResponseModel.fromJson(Map<String, dynamic> json) {
return FullTextTranslationResponseModel(
translations: (json["translations"] as Iterable)
.map<String>(
(e) => e,
)
.toList()
.cast<String>(),
source: json[ModelKey.srcLang],
deepL: json['deepl_res'],
);
}
String get bestTranslation => deepL ?? translations.first;
}

View file

@ -2,10 +2,8 @@ import 'dart:convert';
import 'package:http/http.dart';
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/span_data_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/igc_request_model.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import '../../common/constants/model_keys.dart';
import '../../common/network/requests.dart';
import '../../common/network/urls.dart';
import '../models/igc_text_data_model.dart';
@ -13,7 +11,7 @@ import '../models/igc_text_data_model.dart';
class IgcRepo {
static Future<IGCTextData> getIGC(
String? accessToken, {
required IGCRequestBody igcRequest,
required IGCRequestModel igcRequest,
}) async {
final Requests req = Requests(
accessToken: accessToken,
@ -31,130 +29,4 @@ class IgcRepo {
return response;
}
static Future<IGCTextData> getMockData() async {
await Future.delayed(const Duration(seconds: 2));
final IGCTextData igcTextData = IGCTextData(
matches: [
PangeaMatch(
match: spanDataRepomockSpan,
status: PangeaMatchStatus.open,
),
],
originalInput: "This be a sample text",
fullTextCorrection: "This is a sample text",
userL1: "es",
userL2: "en",
enableIT: true,
enableIGC: true,
);
return igcTextData;
}
}
/// Previous text/audio message sent in chat
/// Contain message content, sender, and timestamp
class PreviousMessage {
String content;
String sender;
DateTime timestamp;
PreviousMessage({
required this.content,
required this.sender,
required this.timestamp,
});
factory PreviousMessage.fromJson(Map<String, dynamic> json) =>
PreviousMessage(
content: json[ModelKey.prevContent] ?? "",
sender: json[ModelKey.prevSender] ?? "",
timestamp: json[ModelKey.prevTimestamp] == null
? DateTime.now()
: DateTime.parse(json[ModelKey.prevTimestamp]),
);
Map<String, dynamic> toJson() => {
ModelKey.prevContent: content,
ModelKey.prevSender: sender,
ModelKey.prevTimestamp: timestamp.toIso8601String(),
};
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! PreviousMessage) return false;
return content == other.content &&
sender == other.sender &&
timestamp == other.timestamp;
}
@override
int get hashCode {
return Object.hash(
content,
sender,
timestamp,
);
}
}
class IGCRequestBody {
String fullText;
String userL1;
String userL2;
bool enableIT;
bool enableIGC;
String userId;
List<PreviousMessage> prevMessages;
IGCRequestBody({
required this.fullText,
required this.userL1,
required this.userL2,
required this.enableIGC,
required this.enableIT,
required this.userId,
required this.prevMessages,
});
Map<String, dynamic> toJson() => {
ModelKey.fullText: fullText,
ModelKey.userL1: userL1,
ModelKey.userL2: userL2,
"enable_it": enableIT,
"enable_igc": enableIGC,
ModelKey.userId: userId,
ModelKey.prevMessages:
jsonEncode(prevMessages.map((x) => x.toJson()).toList()),
};
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! IGCRequestBody) return false;
return fullText.trim() == other.fullText.trim() &&
fullText == other.fullText &&
userL1 == other.userL1 &&
userL2 == other.userL2 &&
enableIT == other.enableIT &&
userId == other.userId;
}
@override
int get hashCode => Object.hash(
fullText.trim(),
userL1,
userL2,
enableIT,
enableIGC,
userId,
Object.hashAll(prevMessages),
);
}

View file

@ -0,0 +1,108 @@
import 'dart:convert';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
class IGCRequestModel {
String fullText;
String userL1;
String userL2;
bool enableIT;
bool enableIGC;
String userId;
List<PreviousMessage> prevMessages;
IGCRequestModel({
required this.fullText,
required this.userL1,
required this.userL2,
required this.enableIGC,
required this.enableIT,
required this.userId,
required this.prevMessages,
});
Map<String, dynamic> toJson() => {
ModelKey.fullText: fullText,
ModelKey.userL1: userL1,
ModelKey.userL2: userL2,
"enable_it": enableIT,
"enable_igc": enableIGC,
ModelKey.userId: userId,
ModelKey.prevMessages:
jsonEncode(prevMessages.map((x) => x.toJson()).toList()),
};
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! IGCRequestModel) return false;
return fullText.trim() == other.fullText.trim() &&
fullText == other.fullText &&
userL1 == other.userL1 &&
userL2 == other.userL2 &&
enableIT == other.enableIT &&
userId == other.userId;
}
@override
int get hashCode => Object.hash(
fullText.trim(),
userL1,
userL2,
enableIT,
enableIGC,
userId,
Object.hashAll(prevMessages),
);
}
/// Previous text/audio message sent in chat
/// Contain message content, sender, and timestamp
class PreviousMessage {
String content;
String sender;
DateTime timestamp;
PreviousMessage({
required this.content,
required this.sender,
required this.timestamp,
});
factory PreviousMessage.fromJson(Map<String, dynamic> json) =>
PreviousMessage(
content: json[ModelKey.prevContent] ?? "",
sender: json[ModelKey.prevSender] ?? "",
timestamp: json[ModelKey.prevTimestamp] == null
? DateTime.now()
: DateTime.parse(json[ModelKey.prevTimestamp]),
);
Map<String, dynamic> toJson() => {
ModelKey.prevContent: content,
ModelKey.prevSender: sender,
ModelKey.prevTimestamp: timestamp.toIso8601String(),
};
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! PreviousMessage) return false;
return content == other.content &&
sender == other.sender &&
timestamp == other.timestamp;
}
@override
int get hashCode {
return Object.hash(
content,
sender,
timestamp,
);
}
}

View file

@ -6,8 +6,8 @@ import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../common/network/requests.dart';
import '../../common/network/urls.dart';
import '../models/custom_input_translation_model.dart';
import '../models/it_response_model.dart';
import 'custom_input_request_model.dart';
import 'it_response_model.dart';
class ITRepo {
static Future<ITResponseModel> customInputTranslate(
@ -24,20 +24,4 @@ class ITRepo {
return ITResponseModel.fromJson(json);
}
// static Future<ITResponseModel> systemChoiceTranslate(
// SystemChoiceRequestModel subseqText,
// ) async {
// final Requests req = Requests(
// choreoApiKey: Environment.choreoApiKey,
// accessToken: MatrixState.pangeaController.userController.accessToken,
// );
// final Response res =
// await req.post(url: PApiUrls.subseqStep, body: subseqText.toJson());
// final decodedBody = jsonDecode(utf8.decode(res.bodyBytes).toString());
// return ITResponseModel.fromJson(decodedBody);
// }
}

View file

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
class ITResponseModel {
String fullTextTranslation;
List<Continuance> continuances;
List<Continuance>? goldContinuances;
bool isFinal;
String? translationId;
int payloadId;
ITResponseModel({
required this.fullTextTranslation,
required this.continuances,
required this.translationId,
required this.goldContinuances,
required this.isFinal,
required this.payloadId,
});
factory ITResponseModel.fromJson(Map<String, dynamic> json) {
//PTODO - is continuances a variable type? can we change that?
if (json['continuances'].runtimeType == String) {
debugPrint("continuances was string - ${json['continuances']}");
json['continuances'] = [];
json['finished'] = true;
}
final List<Continuance> interimCont = (json['continuances'] as List)
.mapIndexed((index, e) {
e["index"] = index;
return Continuance.fromJson(e);
})
.toList()
.take(ChoreoConstants.numberOfITChoices)
.toList()
.cast<Continuance>()
//can't do this on the backend because step translation can't filter them out
.where((element) => element.inDictionary)
.toList();
interimCont.shuffle();
return ITResponseModel(
fullTextTranslation: json["full_text_translation"] ?? json["translation"],
continuances: interimCont,
translationId: json['translation_id'],
payloadId: json['payload_id'] ?? 0,
isFinal: json['finished'] ?? false,
goldContinuances: json['gold_continuances'] != null
? (json['gold_continuances'] as Iterable).map((e) {
e["gold"] = true;
return Continuance.fromJson(e);
}).toList()
: null,
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['full_text_translation'] = fullTextTranslation;
data['continuances'] = continuances.map((v) => v.toJson()).toList();
if (translationId != null) {
data['translation_id'] = translationId;
}
data['payload_id'] = payloadId;
data["finished"] = isFinal;
return data;
}
}

View file

@ -1,80 +0,0 @@
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';
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;
LanguageDetectionResponse({
required this.detections,
required this.fullText,
});
factory LanguageDetectionResponse.fromJson(Map<String, dynamic> json) {
return LanguageDetectionResponse(
detections: List<LanguageDetection>.from(
(json['detections'] as Iterable).map(
(e) => LanguageDetection.fromJson(e),
),
),
fullText: json['full_text'],
);
}
Map<String, dynamic> toJson() {
return {
'detections': detections.map((e) => e.toJson()).toList(),
'full_text': fullText,
};
}
}

View file

@ -3,8 +3,6 @@ import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:http/http.dart';
import 'package:fluffychat/pangea/choreographer/enums/span_choice_type.dart';
import 'package:fluffychat/pangea/choreographer/enums/span_data_type.dart';
import 'package:fluffychat/pangea/choreographer/models/span_data.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import '../../common/constants/model_keys.dart';
@ -32,16 +30,6 @@ class SpanDataRepo {
}
}
// Future<SpanDetailsRepoReqAndRes> getMock(SpanDetailsRepoReqAndRes req) async {
// await Future.delayed(const Duration(seconds: 2));
// if (req.span.choices != null &&
// req.span.choices!.any((element) => element.selected)) {
// return req..span = mockReponseWithHintOne.span;
// } else {
// return req..span = mockReponseWithChoices.span;
// }
// }
class SpanDetailsRepoReqAndRes {
String userL1;
String userL2;
@ -113,40 +101,3 @@ class SpanDetailsRepoReqAndRes {
]);
}
}
final spanDataRepomockSpan = SpanData(
offset: 5,
length: 2,
fullText: "This be a sample text",
type: SpanDataType(typeName: SpanDataTypeEnum.correction),
choices: [SpanChoice(value: "is", type: SpanChoiceType.bestCorrection)],
message: null,
rule: null,
shortMessage: null,
);
//json mock request
final mockRequest = SpanDetailsRepoReqAndRes(
userL1: "es",
userL2: "en",
enableIGC: true,
enableIT: true,
span: spanDataRepomockSpan,
);
SpanDetailsRepoReqAndRes get mockReponseWithChoices {
final SpanDetailsRepoReqAndRes res = mockRequest;
res.span.choices = [
SpanChoice(value: "is", type: SpanChoiceType.bestCorrection),
SpanChoice(value: "are", type: SpanChoiceType.distractor),
SpanChoice(value: "was", type: SpanChoiceType.distractor),
];
return res;
}
// SpanDetailsRepoReqAndRes get mockReponseWithHintOne {
// final SpanDetailsRepoReqAndRes res = mockReponseWithChoices;
// res.span.choices![1].selected = true;
// res.span.message = "Conjugation error";
// return res;
// }

View file

@ -1,45 +0,0 @@
import '../../common/constants/model_keys.dart';
class SystemChoiceRequestModel {
String translationId;
int? nextWordIndex;
String? customInput;
String userId;
String roomId;
String targetLangCode;
String sourceLangCode;
String? classId;
SystemChoiceRequestModel({
required this.translationId,
this.nextWordIndex,
this.customInput,
required this.userId,
required this.roomId,
required this.targetLangCode,
required this.sourceLangCode,
this.classId,
});
toJson() => {
'translation_id': translationId,
'next_word_index': nextWordIndex,
'custom_input': customInput,
'user_id': userId,
'room_id': roomId,
ModelKey.tgtLang: targetLangCode,
ModelKey.srcLang: sourceLangCode,
'class_id': classId,
};
factory SystemChoiceRequestModel.fromJson(json) => SystemChoiceRequestModel(
translationId: json['translation_id'],
nextWordIndex: json['next_word_index'],
customInput: json['custom_input'],
userId: json['user_id'],
roomId: json['room_id'],
targetLangCode: json[ModelKey.tgtLang],
sourceLangCode: json[ModelKey.srcLang],
classId: json['class_id'],
);
}

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/pangea_text_controller.dart';
import 'package:fluffychat/pangea/choreographer/utils/pangea_text_controller.dart';
class InputPasteListener {
final PangeaTextController controller;

View file

@ -1,29 +0,0 @@
import 'package:diacritic/diacritic.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
String normalizeString(String input) {
try {
// Step 1: Remove diacritics (accents)
String normalized = removeDiacritics(input);
normalized = normalized.replaceAll(RegExp(r'[^\x00-\x7F]'), '');
// Step 2: Remove punctuation
normalized = normalized.replaceAll(RegExp(r'[^\w\s]'), '');
// Step 3: Convert to lowercase
normalized = normalized.toLowerCase();
// Step 4: Trim and normalize whitespace
normalized = normalized.replaceAll(RegExp(r'\s+'), ' ').trim();
return normalized.isEmpty ? input : normalized;
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {'input': input},
);
return input;
}
}

View file

@ -10,9 +10,9 @@ import 'package:fluffychat/pangea/choreographer/widgets/igc/paywall_card.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/span_card.dart';
import 'package:fluffychat/pangea/subscription/controllers/subscription_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../../common/utils/overlay.dart';
import '../../controllers/choreographer.dart';
import '../../enums/edit_type.dart';
import '../../common/utils/overlay.dart';
import '../controllers/choreographer.dart';
import '../enums/edit_type.dart';
class PangeaTextController extends TextEditingController {
Choreographer choreographer;

View file

@ -0,0 +1,31 @@
import 'package:diacritic/diacritic.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
class TextNormalizationUtil {
static String normalizeString(String input) {
try {
// Step 1: Remove diacritics (accents)
String normalized = removeDiacritics(input);
normalized = normalized.replaceAll(RegExp(r'[^\x00-\x7F]'), '');
// Step 2: Remove punctuation
normalized = normalized.replaceAll(RegExp(r'[^\w\s]'), '');
// Step 3: Convert to lowercase
normalized = normalized.toLowerCase();
// Step 4: Trim and normalize whitespace
normalized = normalized.replaceAll(RegExp(r'\s+'), ' ').trim();
return normalized.isEmpty ? input : normalized;
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {'input': input},
);
return input;
}
}
}

View file

@ -1,6 +1,3 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
@ -9,16 +6,15 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/bot/utils/bot_style.dart';
import 'package:fluffychat/pangea/choreographer/controllers/contextual_definition_controller.dart';
import 'package:fluffychat/pangea/choreographer/repo/contextual_definition_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/contextual_definition_request_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/contextual_definition_response_model.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
import 'package:fluffychat/pangea/toolbar/widgets/toolbar_content_loading_indicator.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../../learning_settings/widgets/flag.dart';
import '../../models/word_data_model.dart';
import 'card_error_widget.dart';
class WordDataCard extends StatefulWidget {
@ -80,40 +76,33 @@ class WordDataCardController extends State<WordDataCard> {
}
Future<void> getContextualDefinition() async {
ContextualDefinitionRequestModel? req;
try {
req = ContextualDefinitionRequestModel(
fullText: widget.fullText,
word: widget.word,
feedbackLang: activeL1?.langCode ?? LanguageKeys.defaultLanguage,
fullTextLang: widget.fullTextLang,
wordLang: widget.wordLang,
);
if (!mounted) return;
final ContextualDefinitionRequestModel req =
ContextualDefinitionRequestModel(
fullText: widget.fullText,
word: widget.word,
feedbackLang: activeL1?.langCode ?? LanguageKeys.defaultLanguage,
fullTextLang: widget.fullTextLang,
wordLang: widget.wordLang,
);
if (!mounted) return;
setState(() {
contextualDefinitionRes = null;
definitionError = null;
isLoadingContextualDefinition = true;
});
setState(() {
contextualDefinitionRes = null;
definitionError = null;
isLoadingContextualDefinition = true;
});
contextualDefinitionRes = await controller.definitions.get(req);
if (contextualDefinitionRes == null) {
definitionError = Exception("Error getting definition");
}
GoogleAnalytics.contextualRequest();
} catch (err, stack) {
debugger(when: kDebugMode);
ErrorHandler.logError(
e: err,
s: stack,
data: {
"request": req?.toJson(),
},
);
final resp = await ContextualDefinitionRepo.get(
MatrixState.pangeaController.userController.accessToken,
req,
);
if (resp.isError) {
definitionError = Exception("Error getting definition");
} finally {
if (mounted) setState(() => isLoadingContextualDefinition = false);
}
if (mounted) {
setState(() => isLoadingContextualDefinition = false);
}
}
@ -190,133 +179,3 @@ class WordDataCardView extends StatelessWidget {
);
}
}
class WordNetInfo extends StatelessWidget {
final WordData wordData;
final LanguageModel activeL1;
final LanguageModel activeL2;
const WordNetInfo({
super.key,
required this.wordData,
required this.activeL1,
required this.activeL2,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SensesForLanguage(
wordData: wordData,
languageType: LanguageType.target,
language: activeL2,
),
const SizedBox(height: 10),
SensesForLanguage(
wordData: wordData,
languageType: LanguageType.base,
language: activeL1,
),
],
);
}
}
enum LanguageType {
target,
base,
}
class SensesForLanguage extends StatelessWidget {
String get exampleSentence => languageType == LanguageType.target
? wordData.targetExampleSentence
: wordData.baseExampleSentence;
String get definition => languageType == LanguageType.target
? wordData.targetDefinition
: wordData.baseDefinition;
String formattedTitle(BuildContext context) {
final String word = languageType == LanguageType.target
? wordData.targetWord
: wordData.baseWord;
String? pos = wordData.formattedPartOfSpeech(languageType);
if (pos == null || pos.isEmpty) pos = L10n.of(context).unkDisplayName;
return "$word (${wordData.formattedPartOfSpeech(languageType)})";
}
const SensesForLanguage({
super.key,
required this.wordData,
required this.languageType,
required this.language,
});
final LanguageModel language;
final LanguageType languageType;
final WordData wordData;
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LanguageFlag(language: language),
const SizedBox(width: 10),
Flexible(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
formattedTitle(context),
style: BotStyle.text(context, italics: true, bold: false),
),
const SizedBox(height: 4),
if (definition.isNotEmpty)
RichText(
text: TextSpan(
style: BotStyle.text(
context,
italics: false,
bold: false,
),
children: <TextSpan>[
TextSpan(
text: "${L10n.of(context).definition}: ",
style: const TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(text: definition),
],
),
),
const SizedBox(height: 4),
if (exampleSentence.isNotEmpty)
RichText(
text: TextSpan(
style: BotStyle.text(
context,
italics: false,
bold: false,
),
children: <TextSpan>[
TextSpan(
text: "${L10n.of(context).exampleSentence}: ",
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
TextSpan(text: exampleSentence),
],
),
),
],
),
),
],
);
}
}

View file

@ -8,7 +8,8 @@ import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pangea/choreographer/controllers/it_controller.dart';
import 'package:fluffychat/pangea/choreographer/controllers/it_feedback_controller.dart';
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_request_model.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/word_data_card.dart';
import 'package:fluffychat/pangea/choreographer/widgets/it_feedback_card.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -18,7 +19,6 @@ import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart'
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../common/utils/overlay.dart';
import '../models/it_response_model.dart';
import 'choice_array.dart';
class ITBar extends StatefulWidget {
@ -80,8 +80,7 @@ class ITBarState extends State<ITBar> with SingleTickerProviderStateMixin {
!itController.isEditingSourceText &&
!itController.isTranslationDone &&
itController.currentITStep != null &&
itController.currentITStep!.continuances.isNotEmpty &&
!itController.showChoiceFeedback;
itController.currentITStep!.continuances.isNotEmpty;
}
@override
@ -225,13 +224,9 @@ class ITBarState extends State<ITBar> with SingleTickerProviderStateMixin {
child: Center(
child: itController.choreographer.errorService.isError
? ITError(controller: itController)
: itController.showChoiceFeedback
? ChoiceFeedbackText(
controller: itController,
)
: itController.isTranslationDone
? const SizedBox()
: ITChoices(controller: itController),
: itController.isTranslationDone
? const SizedBox()
: ITChoices(controller: itController),
),
),
),
@ -246,35 +241,6 @@ class ITBarState extends State<ITBar> with SingleTickerProviderStateMixin {
}
}
class ChoiceFeedbackText extends StatelessWidget {
const ChoiceFeedbackText({
super.key,
required this.controller,
});
final ITController controller;
@override
Widget build(BuildContext context) {
//reimplement if we decide we want it
return const SizedBox();
// return AnimatedTextKit(
// isRepeatingAnimation: false,
// animatedTexts: [
// ScaleAnimatedText(
// controller.latestChoiceFeedback(context),
// duration: Duration(
// milliseconds:
// (ChoreoConstants.millisecondsToDisplayFeedback / 2).round(),
// ),
// scalingFactor: 1.4,
// textStyle: BotStyle.text(context),
// ),
// ],
// );
}
}
class ITChoices extends StatelessWidget {
const ITChoices({
super.key,
@ -342,19 +308,11 @@ class ITChoices extends StatelessWidget {
room: controller.choreographer.chatController.room,
)
: ITFeedbackCard(
req: ITFeedbackRequestModel(
sourceText: sourceText!,
currentText: controller.choreographer.currentText,
chosenContinuance:
controller.currentITStep!.continuances[index].text,
bestContinuance: controller.currentITStep!.best.text,
// TODO: we want this to eventually switch between target and source lang,
// based on the learner's proficiency - maybe with the words involved in the translation
// maybe overall. For now, we'll just use the source lang.
feedbackLang: controller.choreographer.l1Lang?.langCode ??
controller.sourceLangCode,
sourceTextLang: controller.sourceLangCode,
targetLang: controller.targetLangCode,
req: FullTextTranslationRequestModel(
text: controller.currentITStep!.continuances[index].text,
tgtLang: controller.sourceLangCode,
userL1: controller.sourceLangCode,
userL2: controller.targetLangCode,
),
choiceFeedback: choiceFeedback,
),

View file

@ -7,15 +7,16 @@ import 'package:http/http.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_request_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_response_model.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import '../../../widgets/matrix.dart';
import '../../bot/utils/bot_style.dart';
import '../../common/controllers/pangea_controller.dart';
import '../controllers/it_feedback_controller.dart';
import 'igc/card_error_widget.dart';
class ITFeedbackCard extends StatefulWidget {
final ITFeedbackRequestModel req;
final FullTextTranslationRequestModel req;
final String choiceFeedback;
const ITFeedbackCard({
@ -34,7 +35,7 @@ class ITFeedbackCardController extends State<ITFeedbackCard> {
Object? error;
bool isLoadingFeedback = false;
bool isTranslating = false;
ITFeedbackResponseModel? res;
FullTextTranslationResponseModel? res;
String? translatedFeedback;
Response get noLanguages => Response("", 405);
@ -53,19 +54,10 @@ class ITFeedbackCardController extends State<ITFeedbackCard> {
});
try {
final resp = await FullTextTranslationRepo.translate(
res = await FullTextTranslationRepo.translate(
accessToken: controller.userController.accessToken,
request: FullTextTranslationRequestModel(
text: widget.req.chosenContinuance,
tgtLang: controller.languageController.userL1?.langCode ??
widget.req.sourceTextLang,
userL1: controller.languageController.userL1?.langCode ??
widget.req.sourceTextLang,
userL2: controller.languageController.userL2?.langCode ??
widget.req.targetLang,
),
request: widget.req,
);
res = ITFeedbackResponseModel(text: resp.bestTranslation);
} catch (e, s) {
error = e;
ErrorHandler.logError(
@ -112,7 +104,7 @@ class ITFeedbackCardView extends StatelessWidget {
alignment: WrapAlignment.center,
children: [
Text(
controller.widget.req.chosenContinuance,
controller.widget.req.text,
style: BotStyle.text(context),
),
const SizedBox(width: 10),
@ -121,16 +113,15 @@ class ITFeedbackCardView extends StatelessWidget {
style: BotStyle.text(context),
),
const SizedBox(width: 10),
controller.res?.text != null
controller.res?.bestTranslation != null
? Text(
controller.res!.text,
controller.res!.bestTranslation,
style: BotStyle.text(context),
)
: TextLoadingShimmer(
width: min(
140,
characterWidth *
controller.widget.req.chosenContinuance.length,
characterWidth * controller.widget.req.text.length,
),
),
],

View file

@ -1,64 +0,0 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/choreographer/widgets/choice_animation.dart';
class FillingStars extends StatefulWidget {
final int rating;
const FillingStars({
super.key,
required this.rating,
});
@override
State<FillingStars> createState() => _FillingStarsState();
}
class _FillingStarsState extends State<FillingStars> {
final List<bool> _isFilledList = List.filled(5, false);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => _animate());
}
Future<void> _animate() async {
for (int i = 0; i < widget.rating; i++) {
await Future.delayed(
const Duration(milliseconds: choiceArrayAnimationDuration), () {
if (mounted) {
setState(() => _isFilledList[i] = true);
}
});
}
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(5, (index) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: choiceArrayAnimationDuration),
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(
scale: animation,
child: child,
);
},
child: Icon(
_isFilledList[index] ? Icons.star_rounded : Icons.star_rounded,
key: ValueKey<bool>(_isFilledList[index]),
color: _isFilledList[index]
? AppConfig.gold
: Theme.of(context).cardColor.withAlpha(180),
size: 32.0,
),
);
}),
);
}
}

View file

@ -14,7 +14,6 @@ import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/bot/utils/bot_room_extension.dart';
import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart';
import 'package:fluffychat/pangea/chat_settings/utils/bot_client_extension.dart';
import 'package:fluffychat/pangea/choreographer/controllers/contextual_definition_controller.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/events/controllers/message_data_controller.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
@ -42,8 +41,6 @@ class PangeaController {
late PutAnalyticsController putAnalytics;
late MessageDataController messageData;
// TODO: make these static so we can remove from here
late ContextualDefinitionController definitions;
late SubscriptionController subscriptionController;
late TextToSpeechController textToSpeech;
late SpeechToTextController speechToText;
@ -90,7 +87,6 @@ class PangeaController {
getAnalytics = GetAnalyticsController(this);
putAnalytics = PutAnalyticsController(this);
messageData = MessageDataController(this);
definitions = ContextualDefinitionController(this);
subscriptionController = SubscriptionController(this);
textToSpeech = TextToSpeechController(this);
speechToText = SpeechToTextController(this);

View file

@ -6,6 +6,7 @@ import 'package:collection/collection.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:shimmer/shimmer.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
@ -20,7 +21,6 @@ import 'package:fluffychat/pangea/course_settings/pin_clipper.dart';
import 'package:fluffychat/pangea/course_settings/topic_participant_list.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:shimmer/shimmer.dart';
class CourseSettings extends StatelessWidget {
// final Room room;

View file

@ -6,7 +6,8 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/tokens_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_request_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_response_model.dart';
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -16,6 +17,7 @@ import 'package:fluffychat/pangea/events/models/representation_content_model.dar
import 'package:fluffychat/pangea/events/models/stt_translation_model.dart';
import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart';
import 'package:fluffychat/pangea/events/repo/token_api_models.dart';
import 'package:fluffychat/pangea/events/repo/tokens_repo.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
// TODO - make this static and take it out of the _pangeaController

View file

@ -9,14 +9,16 @@ import 'package:matrix/matrix.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:fluffychat/pangea/choreographer/models/choreo_record.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/choreographer/repo/full_text_translation_request_model.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/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/events/models/representation_content_model.dart';
import 'package:fluffychat/pangea/events/models/stt_translation_model.dart';
import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart';
import 'package:fluffychat/pangea/events/repo/language_detection_repo.dart';
import 'package:fluffychat/pangea/events/repo/language_detection_request.dart';
import 'package:fluffychat/pangea/events/repo/language_detection_response.dart';
import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart';
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';

View file

@ -13,7 +13,7 @@ import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/choreographer/event_wrappers/pangea_choreo_event.dart';
import 'package:fluffychat/pangea/choreographer/models/choreo_record.dart';
import 'package:fluffychat/pangea/choreographer/models/language_detection_model.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_repo.dart';
import 'package:fluffychat/pangea/choreographer/repo/full_text_translation_request_model.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/events/extensions/pangea_event_extension.dart';

View file

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.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/events/repo/language_detection_request.dart';
import 'package:fluffychat/pangea/events/repo/language_detection_response.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;
}
}

View file

@ -0,0 +1,19 @@
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,
};
}
}

View file

@ -0,0 +1,29 @@
import 'package:fluffychat/pangea/choreographer/models/language_detection_model.dart';
class LanguageDetectionResponse {
List<LanguageDetection> detections;
String fullText;
LanguageDetectionResponse({
required this.detections,
required this.fullText,
});
factory LanguageDetectionResponse.fromJson(Map<String, dynamic> json) {
return LanguageDetectionResponse(
detections: List<LanguageDetection>.from(
(json['detections'] as Iterable).map(
(e) => LanguageDetection.fromJson(e),
),
),
fullText: json['full_text'],
);
}
Map<String, dynamic> toJson() {
return {
'detections': detections.map((e) => e.toJson()).toList(),
'full_text': fullText,
};
}
}