update lemma meaning and phonetic transcription repos
This commit is contained in:
parent
c2defa9023
commit
84737dbca1
13 changed files with 337 additions and 88 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
|
@ -88,6 +90,10 @@ abstract class AsyncLoader<T> {
|
|||
final result = await fetch();
|
||||
if (_disposed) return;
|
||||
state.value = AsyncState.loaded(result);
|
||||
} on HttpException catch (e) {
|
||||
if (!_disposed) {
|
||||
state.value = AsyncState.error(e);
|
||||
}
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:developer';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
|
|
@ -162,7 +163,8 @@ class ConstructIdentifier {
|
|||
);
|
||||
|
||||
/// [lemmmaLang] if not set, assumed to be userL2
|
||||
Future<LemmaInfoResponse> getLemmaInfo() => LemmaInfoRepo.get(
|
||||
Future<Result<LemmaInfoResponse>> getLemmaInfo() => LemmaInfoRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
lemmaInfoRequest,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,4 +22,12 @@ class LanguageArc {
|
|||
'l2': l2.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => l1.hashCode ^ l2.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is LanguageArc && other.l1 == l1 && other.l2 == l2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,105 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
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/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class _LemmaInfoCacheItem {
|
||||
final Future<Result<LemmaInfoResponse>> resultFuture;
|
||||
final DateTime timestamp;
|
||||
|
||||
const _LemmaInfoCacheItem({
|
||||
required this.resultFuture,
|
||||
required this.timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
class LemmaInfoRepo {
|
||||
static final GetStorage _lemmaStorage = GetStorage('lemma_storage');
|
||||
// In-memory cache
|
||||
static final Map<String, _LemmaInfoCacheItem> _cache = {};
|
||||
static const Duration _cacheDuration = Duration(minutes: 10);
|
||||
|
||||
// Persistent storage
|
||||
static final GetStorage _storage = GetStorage('lemma_storage');
|
||||
|
||||
/// Public entry point
|
||||
static Future<Result<LemmaInfoResponse>> get(
|
||||
String accessToken,
|
||||
LemmaInfoRequest request,
|
||||
) {
|
||||
// 1. Try memory cache
|
||||
final cached = _getCached(request);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 2. Try disk cache
|
||||
final stored = _getStored(request);
|
||||
if (stored != null) {
|
||||
return Future.value(Result.value(stored));
|
||||
}
|
||||
|
||||
// 3. Fetch from network (safe future)
|
||||
final future = _safeFetch(accessToken, request);
|
||||
|
||||
// 4. Save to in-memory cache
|
||||
_cache[request.hashCode.toString()] = _LemmaInfoCacheItem(
|
||||
resultFuture: future,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
|
||||
// 5. Write to disk *after* the fetch finishes, without rethrowing
|
||||
writeToDisk(request, future);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
static Future<void> set(
|
||||
LemmaInfoRequest request,
|
||||
LemmaInfoResponse response,
|
||||
LemmaInfoResponse resultFuture,
|
||||
) async {
|
||||
// set expireAt if not set
|
||||
response.expireAt ??= DateTime.now().add(const Duration(days: 100));
|
||||
await _lemmaStorage.write(request.storageKey, response.toJson());
|
||||
}
|
||||
|
||||
static LemmaInfoResponse? getCached(LemmaInfoRequest request) {
|
||||
final cachedJson = _lemmaStorage.read(request.storageKey);
|
||||
|
||||
final cached =
|
||||
cachedJson == null ? null : LemmaInfoResponse.fromJson(cachedJson);
|
||||
|
||||
if (cached != null) {
|
||||
if (DateTime.now().isBefore(cached.expireAt!)) {
|
||||
return cached;
|
||||
} else {
|
||||
_lemmaStorage.remove(request.storageKey);
|
||||
}
|
||||
final key = request.hashCode.toString();
|
||||
try {
|
||||
await _storage.write(key, resultFuture.toJson());
|
||||
_cache.remove(key); // Invalidate in-memory cache
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {'lemma': request.lemma},
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get lemma info, prefering user set data over fetched data
|
||||
static Future<LemmaInfoResponse> get(LemmaInfoRequest request) async {
|
||||
final cached = getCached(request);
|
||||
if (cached != null) return cached;
|
||||
static Future<Result<LemmaInfoResponse>> _safeFetch(
|
||||
String token,
|
||||
LemmaInfoRequest request,
|
||||
) async {
|
||||
try {
|
||||
final resp = await _fetch(token, request);
|
||||
return Result.value(resp);
|
||||
} catch (e, s) {
|
||||
// Ensure error is logged and converted to a Result
|
||||
ErrorHandler.logError(e: e, s: s, data: request.toJson());
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
final Requests req = Requests(
|
||||
static Future<LemmaInfoResponse> _fetch(
|
||||
String accessToken,
|
||||
LemmaInfoRequest request,
|
||||
) async {
|
||||
final req = Requests(
|
||||
choreoApiKey: Environment.choreoApiKey,
|
||||
accessToken: MatrixState.pangeaController.userController.accessToken,
|
||||
accessToken: accessToken,
|
||||
);
|
||||
|
||||
final Response res = await req.post(
|
||||
|
|
@ -53,10 +107,59 @@ class LemmaInfoRepo {
|
|||
body: request.toJson(),
|
||||
);
|
||||
|
||||
final decodedBody = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
final response = LemmaInfoResponse.fromJson(decodedBody);
|
||||
if (res.statusCode != 200) {
|
||||
throw HttpException(
|
||||
'Failed to fetch lemma info: ${res.statusCode} ${res.reasonPhrase}',
|
||||
);
|
||||
}
|
||||
|
||||
set(request, response);
|
||||
return response;
|
||||
return LemmaInfoResponse.fromJson(
|
||||
jsonDecode(utf8.decode(res.bodyBytes)),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<Result<LemmaInfoResponse>>? _getCached(
|
||||
LemmaInfoRequest request,
|
||||
) {
|
||||
final now = DateTime.now();
|
||||
final key = request.hashCode.toString();
|
||||
|
||||
// Remove stale entries first
|
||||
_cache.removeWhere(
|
||||
(_, item) => now.difference(item.timestamp) >= _cacheDuration,
|
||||
);
|
||||
|
||||
final item = _cache[key];
|
||||
return item?.resultFuture;
|
||||
}
|
||||
|
||||
static Future<void> writeToDisk(
|
||||
LemmaInfoRequest request,
|
||||
Future<Result<LemmaInfoResponse>> resultFuture,
|
||||
) async {
|
||||
final result = await resultFuture; // SAFE: never throws
|
||||
|
||||
if (!result.isValue) return; // only cache successful responses
|
||||
await set(request, result.asValue!.value);
|
||||
}
|
||||
|
||||
static LemmaInfoResponse? _getStored(
|
||||
LemmaInfoRequest request,
|
||||
) {
|
||||
final key = request.hashCode.toString();
|
||||
try {
|
||||
final entry = _storage.read(key);
|
||||
if (entry == null) return null;
|
||||
|
||||
return LemmaInfoResponse.fromJson(entry);
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {'lemma': request.lemma},
|
||||
);
|
||||
_storage.remove(key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@ import 'package:fluffychat/pangea/events/models/content_feedback.dart';
|
|||
class LemmaInfoResponse implements JsonSerializable {
|
||||
final List<String> emoji;
|
||||
final String meaning;
|
||||
DateTime? expireAt;
|
||||
|
||||
LemmaInfoResponse({
|
||||
required this.emoji,
|
||||
required this.meaning,
|
||||
this.expireAt,
|
||||
});
|
||||
|
||||
factory LemmaInfoResponse.fromJson(Map<String, dynamic> json) {
|
||||
|
|
@ -16,9 +14,6 @@ class LemmaInfoResponse implements JsonSerializable {
|
|||
// NOTE: This is a workaround for the fact that the server sometimes sends more than 3 emojis
|
||||
emoji: (json['emoji'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
meaning: json['meaning'] as String,
|
||||
expireAt: json['expireAt'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expireAt'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -32,7 +27,6 @@ class LemmaInfoResponse implements JsonSerializable {
|
|||
return {
|
||||
'emoji': emoji,
|
||||
'meaning': meaning,
|
||||
'expireAt': expireAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,18 @@ class _LemmaMeaningLoader extends AsyncLoader<LemmaInfoResponse> {
|
|||
_LemmaMeaningLoader(this.request) : super();
|
||||
|
||||
@override
|
||||
Future<LemmaInfoResponse> fetch() => LemmaInfoRepo.get(request);
|
||||
Future<LemmaInfoResponse> fetch() async {
|
||||
final result = await LemmaInfoRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
request,
|
||||
);
|
||||
|
||||
if (result.isError) {
|
||||
throw result.asError!.error;
|
||||
}
|
||||
|
||||
return result.asValue!.value;
|
||||
}
|
||||
}
|
||||
|
||||
class LemmaMeaningBuilder extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,17 @@ class _TranscriptLoader extends AsyncLoader<String> {
|
|||
|
||||
@override
|
||||
Future<String> fetch() async {
|
||||
final resp = await PhoneticTranscriptionRepo.get(request);
|
||||
return resp.phoneticTranscriptionResult.phoneticTranscription.first
|
||||
.phoneticL1Transcription.content;
|
||||
final resp = await PhoneticTranscriptionRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
request,
|
||||
);
|
||||
|
||||
if (resp.isError) {
|
||||
throw resp.asError!.error;
|
||||
}
|
||||
|
||||
return resp.asValue!.value.phoneticTranscriptionResult.phoneticTranscription
|
||||
.first.phoneticL1Transcription.content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
|
|
@ -12,39 +11,95 @@ import 'package:fluffychat/pangea/common/network/urls.dart';
|
|||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_request.dart';
|
||||
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_response.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class _PhoneticTranscriptionCacheItem {
|
||||
final Future<Result<PhoneticTranscriptionResponse>> resultFuture;
|
||||
final DateTime timestamp;
|
||||
|
||||
const _PhoneticTranscriptionCacheItem({
|
||||
required this.resultFuture,
|
||||
required this.timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
class PhoneticTranscriptionRepo {
|
||||
// In-memory cache
|
||||
static final Map<String, _PhoneticTranscriptionCacheItem> _cache = {};
|
||||
static const Duration _cacheDuration = Duration(minutes: 10);
|
||||
|
||||
// Persistent storage
|
||||
static final GetStorage _storage =
|
||||
GetStorage('phonetic_transcription_storage');
|
||||
|
||||
static Future<Result<PhoneticTranscriptionResponse>> get(
|
||||
String accessToken,
|
||||
PhoneticTranscriptionRequest request,
|
||||
) {
|
||||
// 1. Try memory cache
|
||||
final cached = _getCached(request);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 2. Try disk cache
|
||||
final stored = _getStored(request);
|
||||
if (stored != null) {
|
||||
return Future.value(Result.value(stored));
|
||||
}
|
||||
|
||||
// 3. Fetch from network (safe future)
|
||||
final future = _safeFetch(accessToken, request);
|
||||
|
||||
// 4. Save to in-memory cache
|
||||
_cache[request.hashCode.toString()] = _PhoneticTranscriptionCacheItem(
|
||||
resultFuture: future,
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
|
||||
// 5. Write to disk *after* the fetch finishes, without rethrowing
|
||||
writeToDisk(request, future);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
static Future<void> set(
|
||||
PhoneticTranscriptionRequest request,
|
||||
PhoneticTranscriptionResponse response,
|
||||
PhoneticTranscriptionResponse resultFuture,
|
||||
) async {
|
||||
response.expireAt ??= DateTime.now().add(const Duration(days: 100));
|
||||
await _storage.write(request.storageKey, response.toJson());
|
||||
final key = request.hashCode.toString();
|
||||
try {
|
||||
await _storage.write(key, resultFuture.toJson());
|
||||
_cache.remove(key); // Invalidate in-memory cache
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {'request': request.toJson()},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Result<PhoneticTranscriptionResponse>> _safeFetch(
|
||||
String token,
|
||||
PhoneticTranscriptionRequest request,
|
||||
) async {
|
||||
try {
|
||||
final resp = await _fetch(token, request);
|
||||
return Result.value(resp);
|
||||
} catch (e, s) {
|
||||
// Ensure error is logged and converted to a Result
|
||||
ErrorHandler.logError(e: e, s: s, data: request.toJson());
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<PhoneticTranscriptionResponse> _fetch(
|
||||
String accessToken,
|
||||
PhoneticTranscriptionRequest request,
|
||||
) async {
|
||||
final cachedJson = _storage.read(request.storageKey);
|
||||
final cached = cachedJson == null
|
||||
? null
|
||||
: PhoneticTranscriptionResponse.fromJson(cachedJson);
|
||||
|
||||
if (cached != null) {
|
||||
if (DateTime.now().isBefore(cached.expireAt!)) {
|
||||
return cached;
|
||||
} else {
|
||||
_storage.remove(request.storageKey);
|
||||
}
|
||||
}
|
||||
|
||||
final Requests req = Requests(
|
||||
final req = Requests(
|
||||
choreoApiKey: Environment.choreoApiKey,
|
||||
accessToken: MatrixState.pangeaController.userController.accessToken,
|
||||
accessToken: accessToken,
|
||||
);
|
||||
|
||||
final Response res = await req.post(
|
||||
|
|
@ -52,21 +107,59 @@ class PhoneticTranscriptionRepo {
|
|||
body: request.toJson(),
|
||||
);
|
||||
|
||||
final decodedBody = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
final response = PhoneticTranscriptionResponse.fromJson(decodedBody);
|
||||
set(request, response);
|
||||
return response;
|
||||
if (res.statusCode != 200) {
|
||||
throw HttpException(
|
||||
'Failed to fetch phonetic transcription: ${res.statusCode} ${res.reasonPhrase}',
|
||||
);
|
||||
}
|
||||
|
||||
return PhoneticTranscriptionResponse.fromJson(
|
||||
jsonDecode(utf8.decode(res.bodyBytes)),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<PhoneticTranscriptionResponse> get(
|
||||
static Future<Result<PhoneticTranscriptionResponse>>? _getCached(
|
||||
PhoneticTranscriptionRequest request,
|
||||
) {
|
||||
final now = DateTime.now();
|
||||
final key = request.hashCode.toString();
|
||||
|
||||
// Remove stale entries first
|
||||
_cache.removeWhere(
|
||||
(_, item) => now.difference(item.timestamp) >= _cacheDuration,
|
||||
);
|
||||
|
||||
final item = _cache[key];
|
||||
return item?.resultFuture;
|
||||
}
|
||||
|
||||
static Future<void> writeToDisk(
|
||||
PhoneticTranscriptionRequest request,
|
||||
Future<Result<PhoneticTranscriptionResponse>> resultFuture,
|
||||
) async {
|
||||
final result = await resultFuture; // SAFE: never throws
|
||||
|
||||
if (!result.isValue) return; // only cache successful responses
|
||||
await set(request, result.asValue!.value);
|
||||
}
|
||||
|
||||
static PhoneticTranscriptionResponse? _getStored(
|
||||
PhoneticTranscriptionRequest request,
|
||||
) {
|
||||
final key = request.hashCode.toString();
|
||||
try {
|
||||
return await _fetch(request);
|
||||
} catch (e) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(e: e, data: request.toJson());
|
||||
rethrow;
|
||||
final entry = _storage.read(key);
|
||||
if (entry == null) return null;
|
||||
|
||||
return PhoneticTranscriptionResponse.fromJson(entry);
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {'request': request.toJson()},
|
||||
);
|
||||
_storage.remove(key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,4 +30,16 @@ class PhoneticTranscriptionRequest {
|
|||
}
|
||||
|
||||
String get storageKey => '${arc.l1}-${arc.l2}-${content.hashCode}';
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
content.hashCode ^ arc.hashCode ^ requiresTokenization.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PhoneticTranscriptionRequest &&
|
||||
other.content == content &&
|
||||
other.arc == arc &&
|
||||
other.requiresTokenization == requiresTokenization;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,14 +102,12 @@ class PhoneticTranscriptionResponse {
|
|||
final Map<String, dynamic>
|
||||
tokenization; // You can define a typesafe model if needed
|
||||
final PhoneticTranscription phoneticTranscriptionResult;
|
||||
DateTime? expireAt;
|
||||
|
||||
PhoneticTranscriptionResponse({
|
||||
required this.arc,
|
||||
required this.content,
|
||||
required this.tokenization,
|
||||
required this.phoneticTranscriptionResult,
|
||||
this.expireAt,
|
||||
});
|
||||
|
||||
factory PhoneticTranscriptionResponse.fromJson(Map<String, dynamic> json) {
|
||||
|
|
@ -121,9 +119,6 @@ class PhoneticTranscriptionResponse {
|
|||
phoneticTranscriptionResult: PhoneticTranscription.fromJson(
|
||||
json['phonetic_transcription_result'] as Map<String, dynamic>,
|
||||
),
|
||||
expireAt: json['expireAt'] == null
|
||||
? null
|
||||
: DateTime.parse(json['expireAt'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +128,6 @@ class PhoneticTranscriptionResponse {
|
|||
'content': content.toJson(),
|
||||
'tokenization': tokenization,
|
||||
'phonetic_transcription_result': phoneticTranscriptionResult.toJson(),
|
||||
'expireAt': expireAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:async/async.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/constructs/construct_form.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
|
|
@ -35,15 +37,20 @@ class EmojiActivityGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
final List<Future<LemmaInfoResponse>> lemmaInfoFutures = missingEmojis
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo())
|
||||
.toList();
|
||||
final List<Future<Result<LemmaInfoResponse>>> lemmaInfoFutures =
|
||||
missingEmojis
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo())
|
||||
.toList();
|
||||
|
||||
final List<LemmaInfoResponse> lemmaInfos =
|
||||
final List<Result<LemmaInfoResponse>> lemmaInfos =
|
||||
await Future.wait(lemmaInfoFutures);
|
||||
|
||||
for (int i = 0; i < missingEmojis.length; i++) {
|
||||
final e = lemmaInfos[i].emoji.firstWhere(
|
||||
if (lemmaInfos[i].isError) {
|
||||
throw lemmaInfos[i].asError!.error;
|
||||
}
|
||||
|
||||
final e = lemmaInfos[i].asValue!.value.emoji.firstWhere(
|
||||
(e) => !usedEmojis.contains(e),
|
||||
orElse: () => throw Exception(
|
||||
"Not enough unique emojis for tokens in message",
|
||||
|
|
|
|||
|
|
@ -1,26 +1,34 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/constructs/construct_form.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/message_activity_request.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/practice_match.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
|
||||
class LemmaMeaningActivityGenerator {
|
||||
static Future<MessageActivityResponse> get(
|
||||
MessageActivityRequest req,
|
||||
) async {
|
||||
final List<Future<LemmaInfoResponse>> lemmaInfoFutures = req.targetTokens
|
||||
final List<Future<Result<LemmaInfoResponse>>> lemmaInfoFutures = req
|
||||
.targetTokens
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo())
|
||||
.toList();
|
||||
|
||||
final List<LemmaInfoResponse> lemmaInfos =
|
||||
final List<Result<LemmaInfoResponse>> lemmaInfos =
|
||||
await Future.wait(lemmaInfoFutures);
|
||||
|
||||
if (lemmaInfos.any((result) => result.isError)) {
|
||||
throw lemmaInfos.firstWhere((result) => result.isError).error!;
|
||||
}
|
||||
|
||||
final Map<ConstructForm, List<String>> matchInfo = Map.fromIterables(
|
||||
req.targetTokens.map((token) => token.vocabForm),
|
||||
lemmaInfos.map((lemmaInfo) => [lemmaInfo.meaning]),
|
||||
lemmaInfos.map((lemmaInfo) => [lemmaInfo.asValue!.value.meaning]),
|
||||
);
|
||||
|
||||
return MessageActivityResponse(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
|
|
@ -69,6 +70,8 @@ class PracticeRepo {
|
|||
|
||||
_setCached(req, res);
|
||||
return Result.value(res.activity);
|
||||
} on HttpException catch (e, s) {
|
||||
return Result.error(e, s);
|
||||
} catch (e, s) {
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue