updates to cache clearing, make instance variables in request/response models final
This commit is contained in:
parent
e83f153124
commit
d9ada39c2c
15 changed files with 362 additions and 249 deletions
|
|
@ -202,8 +202,6 @@ class IgcController {
|
|||
|
||||
clear() {
|
||||
igcTextData = null;
|
||||
spanDataController.clearCache();
|
||||
spanDataController.dispose();
|
||||
MatrixState.pAnyState.closeAllOverlays(
|
||||
filter: RegExp(r'span_card_overlay_\d+'),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,17 +3,19 @@ import 'dart:developer';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/interactive_translation_repo.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.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';
|
||||
|
||||
|
|
@ -116,80 +118,73 @@ class ITController {
|
|||
// used 1) at very beginning (with custom input = null)
|
||||
// and 2) if they make direct edits to the text field
|
||||
Future<void> getTranslationData(bool useCustomInput) async {
|
||||
try {
|
||||
choreographer.startLoading();
|
||||
final String currentText = choreographer.currentText;
|
||||
|
||||
final String currentText = choreographer.currentText;
|
||||
if (sourceText == null) await _setSourceText();
|
||||
|
||||
if (sourceText == null) await _setSourceText();
|
||||
if (useCustomInput && currentITStep != null) {
|
||||
completedITSteps.add(
|
||||
ITStep(
|
||||
currentITStep!.continuances,
|
||||
customInput: currentText,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (useCustomInput && currentITStep != null) {
|
||||
completedITSteps.add(
|
||||
ITStep(
|
||||
currentITStep!.continuances,
|
||||
customInput: currentText,
|
||||
),
|
||||
);
|
||||
}
|
||||
currentITStep = null;
|
||||
|
||||
currentITStep = null;
|
||||
// During first IT step, next step will not be set
|
||||
if (nextITStep == null) {
|
||||
final res = await ITRepo.get(_request(currentText)).timeout(
|
||||
const Duration(seconds: 10),
|
||||
onTimeout: () {
|
||||
return Result.error(
|
||||
TimeoutException("ITRepo.get timed out after 10 seconds"),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// During first IT step, next step will not be set
|
||||
if (nextITStep == null) {
|
||||
final ITResponseModel res = await _customInputTranslation(currentText)
|
||||
.timeout(const Duration(seconds: 10));
|
||||
if (sourceText == null) return;
|
||||
|
||||
if (res.goldContinuances != null && res.goldContinuances!.isNotEmpty) {
|
||||
goldRouteTracker = GoldRouteTracker(
|
||||
res.goldContinuances!,
|
||||
sourceText!,
|
||||
if (res.isError) {
|
||||
if (_willOpen) {
|
||||
choreographer.errorService.setErrorAndLock(
|
||||
ChoreoError(raw: res.asError),
|
||||
);
|
||||
}
|
||||
|
||||
currentITStep = CurrentITStep(
|
||||
sourceText: sourceText!,
|
||||
currentText: currentText,
|
||||
responseModel: res,
|
||||
storedGoldContinuances: goldRouteTracker.continuances,
|
||||
);
|
||||
|
||||
_addPayloadId(res);
|
||||
} else {
|
||||
currentITStep = await nextITStep!.future;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTranslationDone) {
|
||||
nextITStep = null;
|
||||
closeIT();
|
||||
} else {
|
||||
nextITStep = Completer<CurrentITStep?>();
|
||||
final nextStep = await _getNextTranslationData();
|
||||
nextITStep?.complete(nextStep);
|
||||
if (sourceText == null) {
|
||||
return;
|
||||
}
|
||||
} catch (e, s) {
|
||||
debugger(when: kDebugMode);
|
||||
if (e is! http.Response) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {
|
||||
"currentText": choreographer.currentText,
|
||||
"sourceText": sourceText,
|
||||
"currentITStepPayloadID": currentITStep?.payloadId,
|
||||
},
|
||||
level:
|
||||
e is TimeoutException ? SentryLevel.warning : SentryLevel.error,
|
||||
|
||||
final result = res.result!;
|
||||
if (result.goldContinuances != null &&
|
||||
result.goldContinuances!.isNotEmpty) {
|
||||
goldRouteTracker = GoldRouteTracker(
|
||||
result.goldContinuances!,
|
||||
sourceText!,
|
||||
);
|
||||
}
|
||||
|
||||
if (_willOpen) {
|
||||
choreographer.errorService.setErrorAndLock(
|
||||
ChoreoError(raw: e),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
choreographer.stopLoading();
|
||||
currentITStep = CurrentITStep(
|
||||
sourceText: sourceText!,
|
||||
currentText: currentText,
|
||||
responseModel: result,
|
||||
storedGoldContinuances: goldRouteTracker.continuances,
|
||||
);
|
||||
|
||||
_addPayloadId(result);
|
||||
} else {
|
||||
currentITStep = await nextITStep!.future;
|
||||
}
|
||||
|
||||
if (isTranslationDone) {
|
||||
nextITStep = null;
|
||||
closeIT();
|
||||
} else {
|
||||
nextITStep = Completer<CurrentITStep?>();
|
||||
final nextStep = await _getNextTranslationData();
|
||||
nextITStep?.complete(nextStep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -210,42 +205,28 @@ class ITController {
|
|||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final String currentText = choreographer.currentText;
|
||||
final String nextText =
|
||||
goldRouteTracker.continuances[completedITSteps.length].text;
|
||||
final String currentText = choreographer.currentText;
|
||||
final String nextText =
|
||||
goldRouteTracker.continuances[completedITSteps.length].text;
|
||||
|
||||
final ITResponseModel res =
|
||||
await _customInputTranslation(currentText + nextText);
|
||||
if (sourceText == null) return null;
|
||||
final res = await ITRepo.get(
|
||||
_request(currentText + nextText),
|
||||
);
|
||||
|
||||
return CurrentITStep(
|
||||
sourceText: sourceText!,
|
||||
currentText: nextText,
|
||||
responseModel: res,
|
||||
storedGoldContinuances: goldRouteTracker.continuances,
|
||||
);
|
||||
} catch (e, s) {
|
||||
debugger(when: kDebugMode);
|
||||
if (e is! http.Response) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {
|
||||
"sourceText": sourceText,
|
||||
"currentITStepPayloadID": currentITStep?.payloadId,
|
||||
"continuances":
|
||||
goldRouteTracker.continuances.map((e) => e.toJson()),
|
||||
},
|
||||
);
|
||||
}
|
||||
if (sourceText == null) return null;
|
||||
if (res.isError) {
|
||||
choreographer.errorService.setErrorAndLock(
|
||||
ChoreoError(raw: e),
|
||||
ChoreoError(raw: res.asError),
|
||||
);
|
||||
} finally {
|
||||
choreographer.stopLoading();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
return CurrentITStep(
|
||||
sourceText: sourceText!,
|
||||
currentText: nextText,
|
||||
responseModel: res.result!,
|
||||
storedGoldContinuances: goldRouteTracker.continuances,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> onEditSourceTextSubmit(String newSourceText) async {
|
||||
|
|
@ -277,7 +258,6 @@ class ITController {
|
|||
ChoreoError(raw: err),
|
||||
);
|
||||
} finally {
|
||||
choreographer.stopLoading();
|
||||
choreographer.textController.setSystemText(
|
||||
"",
|
||||
EditType.other,
|
||||
|
|
@ -285,10 +265,7 @@ class ITController {
|
|||
}
|
||||
}
|
||||
|
||||
Future<ITResponseModel> _customInputTranslation(String textInput) async {
|
||||
return ITRepo.customInputTranslate(
|
||||
CustomInputRequestModel(
|
||||
//this should be set by this time
|
||||
CustomInputRequestModel _request(String textInput) => CustomInputRequestModel(
|
||||
text: sourceText!,
|
||||
customInput: textInput,
|
||||
sourceLangCode: sourceLangCode,
|
||||
|
|
@ -297,9 +274,7 @@ class ITController {
|
|||
roomId: choreographer.roomId!,
|
||||
goldTranslation: goldRouteTracker.fullTranslation,
|
||||
goldContinuances: goldRouteTracker.continuances,
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
//maybe we store IT data in the same format? make a specific kind of match?
|
||||
void selectTranslation(int chosenIndex) {
|
||||
|
|
|
|||
|
|
@ -9,35 +9,11 @@ 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/text_normalization_util.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
||||
class _SpanDetailsCacheItem {
|
||||
Future<SpanDetailsRepoReqAndRes> data;
|
||||
|
||||
_SpanDetailsCacheItem({required this.data});
|
||||
}
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
|
||||
class SpanDataController {
|
||||
late Choreographer choreographer;
|
||||
final Map<int, _SpanDetailsCacheItem> _cache = {};
|
||||
Timer? _cacheClearTimer;
|
||||
|
||||
SpanDataController(this.choreographer) {
|
||||
_initializeCacheClearing();
|
||||
}
|
||||
|
||||
void _initializeCacheClearing() {
|
||||
const duration = Duration(minutes: 2);
|
||||
_cacheClearTimer = Timer.periodic(duration, (Timer t) => clearCache());
|
||||
}
|
||||
|
||||
void clearCache() {
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_cacheClearTimer?.cancel();
|
||||
}
|
||||
SpanDataController(this.choreographer);
|
||||
|
||||
SpanData? _getSpan(int matchIndex) {
|
||||
if (choreographer.igc.igcTextData == null ||
|
||||
|
|
@ -80,41 +56,20 @@ class SpanDataController {
|
|||
}) async {
|
||||
final SpanData? span = _getSpan(matchIndex);
|
||||
if (span == null || (isNormalizationError(matchIndex) && !force)) return;
|
||||
|
||||
final req = SpanDetailsRepoReqAndRes(
|
||||
userL1: choreographer.l1LangCode!,
|
||||
userL2: choreographer.l2LangCode!,
|
||||
enableIGC: choreographer.igcEnabled,
|
||||
enableIT: choreographer.itEnabled,
|
||||
span: span,
|
||||
final response = await SpanDataRepo.get(
|
||||
choreographer.accessToken,
|
||||
request: SpanDetailsRepoReqAndRes(
|
||||
userL1: choreographer.l1LangCode!,
|
||||
userL2: choreographer.l2LangCode!,
|
||||
enableIGC: choreographer.igcEnabled,
|
||||
enableIT: choreographer.itEnabled,
|
||||
span: span,
|
||||
),
|
||||
);
|
||||
final int cacheKey = req.hashCode;
|
||||
|
||||
/// Retrieves the [SpanDetailsRepoReqAndRes] response from the cache if it exists,
|
||||
/// otherwise makes an API call to get the response and stores it in the cache.
|
||||
Future<SpanDetailsRepoReqAndRes> response;
|
||||
if (_cache.containsKey(cacheKey)) {
|
||||
response = _cache[cacheKey]!.data;
|
||||
} else {
|
||||
response = SpanDataRepo.getSpanDetails(
|
||||
choreographer.accessToken,
|
||||
request: SpanDetailsRepoReqAndRes(
|
||||
userL1: choreographer.l1LangCode!,
|
||||
userL2: choreographer.l2LangCode!,
|
||||
enableIGC: choreographer.igcEnabled,
|
||||
enableIT: choreographer.itEnabled,
|
||||
span: span,
|
||||
),
|
||||
);
|
||||
_cache[cacheKey] = _SpanDetailsCacheItem(data: response);
|
||||
}
|
||||
|
||||
try {
|
||||
if (response.result != null) {
|
||||
choreographer.igc.igcTextData!.matches[matchIndex].match =
|
||||
(await response).span;
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(e: err, s: s, data: req.toJson());
|
||||
_cache.remove(cacheKey);
|
||||
response.result!.span;
|
||||
}
|
||||
|
||||
choreographer.setState();
|
||||
|
|
|
|||
|
|
@ -165,4 +165,31 @@ class Continuance {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is Continuance &&
|
||||
runtimeType == other.runtimeType &&
|
||||
probability == other.probability &&
|
||||
level == other.level &&
|
||||
text == other.text &&
|
||||
description == other.description &&
|
||||
indexSavedByServer == other.indexSavedByServer &&
|
||||
wasClicked == other.wasClicked &&
|
||||
inDictionary == other.inDictionary &&
|
||||
hasInfo == other.hasInfo &&
|
||||
gold == other.gold;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
probability.hashCode ^
|
||||
level.hashCode ^
|
||||
text.hashCode ^
|
||||
description.hashCode ^
|
||||
indexSavedByServer.hashCode ^
|
||||
wasClicked.hashCode ^
|
||||
inDictionary.hashCode ^
|
||||
hasInfo.hashCode ^
|
||||
gold.hashCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class ContextualDefinitionRequestModel {
|
|||
final String fullTextLang;
|
||||
final String wordLang;
|
||||
|
||||
ContextualDefinitionRequestModel({
|
||||
const ContextualDefinitionRequestModel({
|
||||
required this.fullText,
|
||||
required this.word,
|
||||
required this.feedbackLang,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
class ContextualDefinitionResponseModel {
|
||||
String text;
|
||||
final String text;
|
||||
|
||||
ContextualDefinitionResponseModel({required this.text});
|
||||
const ContextualDefinitionResponseModel({required this.text});
|
||||
|
||||
factory ContextualDefinitionResponseModel.fromJson(
|
||||
Map<String, dynamic> json,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/models/it_step.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
|
||||
class CustomInputRequestModel {
|
||||
String text;
|
||||
String customInput;
|
||||
String sourceLangCode;
|
||||
String targetLangCode;
|
||||
String userId;
|
||||
String roomId;
|
||||
final String text;
|
||||
final String customInput;
|
||||
final String sourceLangCode;
|
||||
final String targetLangCode;
|
||||
final String userId;
|
||||
final String roomId;
|
||||
|
||||
String? goldTranslation;
|
||||
List<Continuance>? goldContinuances;
|
||||
final String? goldTranslation;
|
||||
final List<Continuance>? goldContinuances;
|
||||
|
||||
CustomInputRequestModel({
|
||||
const CustomInputRequestModel({
|
||||
required this.text,
|
||||
required this.customInput,
|
||||
required this.sourceLangCode,
|
||||
|
|
@ -38,7 +40,7 @@ class CustomInputRequestModel {
|
|||
: null,
|
||||
);
|
||||
|
||||
toJson() => {
|
||||
Map<String, dynamic> toJson() => {
|
||||
'text': text,
|
||||
'custom_input': customInput,
|
||||
ModelKey.srcLang: sourceLangCode,
|
||||
|
|
@ -50,4 +52,30 @@ class CustomInputRequestModel {
|
|||
? List.from(goldContinuances!.map((e) => e.toJson()))
|
||||
: null,
|
||||
};
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is CustomInputRequestModel &&
|
||||
other.text == text &&
|
||||
other.customInput == customInput &&
|
||||
other.sourceLangCode == sourceLangCode &&
|
||||
other.targetLangCode == targetLangCode &&
|
||||
other.userId == userId &&
|
||||
other.roomId == roomId &&
|
||||
other.goldTranslation == goldTranslation &&
|
||||
listEquals(other.goldContinuances, goldContinuances);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
text.hashCode ^
|
||||
customInput.hashCode ^
|
||||
sourceLangCode.hashCode ^
|
||||
targetLangCode.hashCode ^
|
||||
userId.hashCode ^
|
||||
roomId.hashCode ^
|
||||
goldTranslation.hashCode ^
|
||||
Object.hashAll(goldContinuances ?? []);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class _TranslateCacheItem {
|
|||
final Future<FullTextTranslationResponseModel> response;
|
||||
final DateTime timestamp;
|
||||
|
||||
_TranslateCacheItem({
|
||||
const _TranslateCacheItem({
|
||||
required this.response,
|
||||
required this.timestamp,
|
||||
});
|
||||
|
|
@ -87,17 +87,14 @@ class FullTextTranslationRepo {
|
|||
static Future<FullTextTranslationResponseModel>? _getCached(
|
||||
FullTextTranslationRequestModel request,
|
||||
) {
|
||||
final cached = _cache[request.hashCode.toString()];
|
||||
if (cached == null) {
|
||||
return null;
|
||||
final cacheKeys = [..._cache.keys];
|
||||
for (final key in cacheKeys) {
|
||||
if (DateTime.now().difference(_cache[key]!.timestamp) >= _cacheDuration) {
|
||||
_cache.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (DateTime.now().difference(cached.timestamp) < _cacheDuration) {
|
||||
return cached.response;
|
||||
}
|
||||
|
||||
_cache.remove(request.hashCode.toString());
|
||||
return null;
|
||||
return _cache[request.hashCode.toString()]?.response;
|
||||
}
|
||||
|
||||
static void _setCached(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
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;
|
||||
final String text;
|
||||
final String? srcLang;
|
||||
final String tgtLang;
|
||||
final String userL1;
|
||||
final String userL2;
|
||||
final bool? deepL;
|
||||
final int? offset;
|
||||
final int? length;
|
||||
|
||||
FullTextTranslationRequestModel({
|
||||
const FullTextTranslationRequestModel({
|
||||
required this.text,
|
||||
this.srcLang,
|
||||
required this.tgtLang,
|
||||
|
|
@ -21,8 +21,6 @@ class FullTextTranslationRequestModel {
|
|||
this.length,
|
||||
});
|
||||
|
||||
//PTODO throw error for null
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"text": text,
|
||||
ModelKey.srcLang: srcLang,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
|
||||
class FullTextTranslationResponseModel {
|
||||
List<String> translations;
|
||||
final List<String> translations;
|
||||
final String source;
|
||||
final String? deepL;
|
||||
|
||||
/// detected source
|
||||
/// PTODO -
|
||||
String source;
|
||||
String? deepL;
|
||||
|
||||
FullTextTranslationResponseModel({
|
||||
const FullTextTranslationResponseModel({
|
||||
required this.translations,
|
||||
required this.source,
|
||||
required this.deepL,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class _IgcCacheItem {
|
|||
final Future<IGCTextData> data;
|
||||
final DateTime timestamp;
|
||||
|
||||
_IgcCacheItem({
|
||||
const _IgcCacheItem({
|
||||
required this.data,
|
||||
required this.timestamp,
|
||||
});
|
||||
|
|
@ -115,17 +115,16 @@ class IgcRepo {
|
|||
static Future<IGCTextData>? _getCached(
|
||||
IGCRequestModel request,
|
||||
) {
|
||||
final cached = _igcCache[request.hashCode.toString()];
|
||||
if (cached == null) {
|
||||
return null;
|
||||
final cacheKeys = [..._igcCache.keys];
|
||||
for (final key in cacheKeys) {
|
||||
if (_igcCache[key]!
|
||||
.timestamp
|
||||
.isBefore(DateTime.now().subtract(_cacheDuration))) {
|
||||
_igcCache.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (DateTime.now().difference(cached.timestamp) < _cacheDuration) {
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
_igcCache.remove(request.hashCode.toString());
|
||||
return null;
|
||||
return _igcCache[request.hashCode.toString()]?.data;
|
||||
}
|
||||
|
||||
static void _setCached(
|
||||
|
|
@ -149,22 +148,19 @@ class IgcRepo {
|
|||
static PangeaMatch? _getCachedIgnoredSpan(
|
||||
PangeaMatch match,
|
||||
) {
|
||||
final cacheKeys = [..._ignoredMatchCache.keys];
|
||||
for (final key in cacheKeys) {
|
||||
final entry = _ignoredMatchCache[key]!;
|
||||
if (DateTime.now().difference(entry.timestamp) >= _cacheDuration) {
|
||||
_ignoredMatchCache.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
final cacheEntry = _IgnoredMatchCacheItem(
|
||||
match: match,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
|
||||
final cached = _ignoredMatchCache[cacheEntry.hashCode.toString()];
|
||||
if (cached == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (DateTime.now().difference(cached.timestamp) < _cacheDuration) {
|
||||
return cached.match;
|
||||
}
|
||||
|
||||
_ignoredMatchCache.remove(cacheEntry.hashCode.toString());
|
||||
return null;
|
||||
return _ignoredMatchCache[cacheEntry.hashCode.toString()]?.match;
|
||||
}
|
||||
|
||||
static void _setCachedIgnoredSpan(
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@ 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;
|
||||
final String fullText;
|
||||
final String userL1;
|
||||
final String userL2;
|
||||
final bool enableIT;
|
||||
final bool enableIGC;
|
||||
final String userId;
|
||||
final List<PreviousMessage> prevMessages;
|
||||
|
||||
IGCRequestModel({
|
||||
const IGCRequestModel({
|
||||
required this.fullText,
|
||||
required this.userL1,
|
||||
required this.userL2,
|
||||
|
|
@ -54,18 +54,17 @@ class IGCRequestModel {
|
|||
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;
|
||||
final String content;
|
||||
final String sender;
|
||||
final DateTime timestamp;
|
||||
|
||||
PreviousMessage({
|
||||
const PreviousMessage({
|
||||
required this.content,
|
||||
required this.sender,
|
||||
required this.timestamp,
|
||||
|
|
|
|||
|
|
@ -1,27 +1,98 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../../common/network/requests.dart';
|
||||
import '../../common/network/urls.dart';
|
||||
import 'custom_input_request_model.dart';
|
||||
import 'it_response_model.dart';
|
||||
|
||||
class _ITCacheItem {
|
||||
final Future<ITResponseModel> response;
|
||||
final DateTime timestamp;
|
||||
|
||||
const _ITCacheItem({
|
||||
required this.response,
|
||||
required this.timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
class ITRepo {
|
||||
static Future<ITResponseModel> customInputTranslate(
|
||||
CustomInputRequestModel initalText,
|
||||
static final Map<String, _ITCacheItem> _cache = {};
|
||||
static const Duration _cacheDuration = Duration(minutes: 10);
|
||||
|
||||
static Future<Result<ITResponseModel>> get(
|
||||
CustomInputRequestModel request,
|
||||
) {
|
||||
final cached = _getCached(request);
|
||||
if (cached != null) {
|
||||
return _getResult(request, cached);
|
||||
}
|
||||
|
||||
final future = _fetch(request);
|
||||
_setCached(request, future);
|
||||
return _getResult(request, future);
|
||||
}
|
||||
|
||||
static Future<ITResponseModel> _fetch(
|
||||
CustomInputRequestModel request,
|
||||
) async {
|
||||
final Requests req = Requests(
|
||||
choreoApiKey: Environment.choreoApiKey,
|
||||
accessToken: MatrixState.pangeaController.userController.accessToken,
|
||||
);
|
||||
final Response res =
|
||||
await req.post(url: PApiUrls.firstStep, body: initalText.toJson());
|
||||
await req.post(url: PApiUrls.firstStep, body: request.toJson());
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw Exception('Failed to load interactive translation');
|
||||
}
|
||||
|
||||
final json = jsonDecode(utf8.decode(res.bodyBytes).toString());
|
||||
|
||||
return ITResponseModel.fromJson(json);
|
||||
}
|
||||
|
||||
static Future<Result<ITResponseModel>> _getResult(
|
||||
CustomInputRequestModel request,
|
||||
Future<ITResponseModel> 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<ITResponseModel>? _getCached(
|
||||
CustomInputRequestModel request,
|
||||
) {
|
||||
final cacheKeys = [..._cache.keys];
|
||||
for (final key in cacheKeys) {
|
||||
if (DateTime.now().difference(_cache[key]!.timestamp) >= _cacheDuration) {
|
||||
_cache.remove(key);
|
||||
}
|
||||
}
|
||||
return _cache[request.hashCode.toString()]?.response;
|
||||
}
|
||||
|
||||
static void _setCached(
|
||||
CustomInputRequestModel request,
|
||||
Future<ITResponseModel> response,
|
||||
) {
|
||||
_cache[request.hashCode.toString()] = _ITCacheItem(
|
||||
response: response,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ 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;
|
||||
final String fullTextTranslation;
|
||||
final List<Continuance> continuances;
|
||||
final List<Continuance>? goldContinuances;
|
||||
final bool isFinal;
|
||||
final String? translationId;
|
||||
final int payloadId;
|
||||
|
||||
ITResponseModel({
|
||||
const ITResponseModel({
|
||||
required this.fullTextTranslation,
|
||||
required this.continuances,
|
||||
required this.translationId,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,48 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/models/span_data.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/network/requests.dart';
|
||||
import '../../common/network/urls.dart';
|
||||
|
||||
class _SpanDetailsCacheItem {
|
||||
final Future<SpanDetailsRepoReqAndRes> data;
|
||||
final DateTime timestamp;
|
||||
|
||||
const _SpanDetailsCacheItem({
|
||||
required this.data,
|
||||
required this.timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
class SpanDataRepo {
|
||||
static Future<SpanDetailsRepoReqAndRes> getSpanDetails(
|
||||
static final Map<String, _SpanDetailsCacheItem> _cache = {};
|
||||
static const Duration _cacheDuration = Duration(minutes: 10);
|
||||
|
||||
static Future<Result<SpanDetailsRepoReqAndRes>> get(
|
||||
String? accessToken, {
|
||||
required SpanDetailsRepoReqAndRes request,
|
||||
}) async {
|
||||
final cached = _getCached(request);
|
||||
if (cached != null) {
|
||||
return _getResult(request, cached);
|
||||
}
|
||||
|
||||
final future = _fetch(
|
||||
accessToken,
|
||||
request: request,
|
||||
);
|
||||
_setCached(request, future);
|
||||
return _getResult(request, future);
|
||||
}
|
||||
|
||||
static Future<SpanDetailsRepoReqAndRes> _fetch(
|
||||
String? accessToken, {
|
||||
required SpanDetailsRepoReqAndRes request,
|
||||
}) async {
|
||||
|
|
@ -28,6 +60,46 @@ class SpanDataRepo {
|
|||
|
||||
return SpanDetailsRepoReqAndRes.fromJson(json);
|
||||
}
|
||||
|
||||
static Future<Result<SpanDetailsRepoReqAndRes>> _getResult(
|
||||
SpanDetailsRepoReqAndRes request,
|
||||
Future<SpanDetailsRepoReqAndRes> 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<SpanDetailsRepoReqAndRes>? _getCached(
|
||||
SpanDetailsRepoReqAndRes request,
|
||||
) {
|
||||
final cacheKeys = [..._cache.keys];
|
||||
for (final key in cacheKeys) {
|
||||
if (DateTime.now().difference(_cache[key]!.timestamp) >= _cacheDuration) {
|
||||
_cache.remove(key);
|
||||
}
|
||||
}
|
||||
return _cache[request.hashCode.toString()]?.data;
|
||||
}
|
||||
|
||||
static void _setCached(
|
||||
SpanDetailsRepoReqAndRes request,
|
||||
Future<SpanDetailsRepoReqAndRes> response,
|
||||
) {
|
||||
_cache[request.hashCode.toString()] = _SpanDetailsCacheItem(
|
||||
data: response,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SpanDetailsRepoReqAndRes {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue