Fetch prompts from scribePromptUrl

First, we try to fetch prompts from scribePromptUrl. At fallback, we
use local prompts.
This commit is contained in:
Théo Poizat
2026-02-19 15:08:57 +01:00
committed by Dat H. Pham
parent a98368e6a6
commit b84b2ce703
5 changed files with 114 additions and 4 deletions
@@ -84,16 +84,19 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_sort_o
import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/app_grid_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/app_grid_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/linagora_ecosystem_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/search_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/search_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/app_grid_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/app_grid_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/linagora_ecosystem_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/search_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/search_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/spam_report_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/spam_report_repository.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_app_dashboard_configuration_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_app_dashboard_configuration_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_app_grid_linagra_ecosystem_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_app_grid_linagra_ecosystem_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_composer_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_scribe_prompt_url_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_mailbox_cached_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_mailbox_cached_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_report_state_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spam_report_state_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_stored_email_sort_order_interactor.dart';
@@ -381,6 +384,7 @@ class MailboxDashBoardBindings extends BaseBindings {
Get.lazyPut(() => EmptySpamFolderInteractor(Get.find<ThreadRepository>())); Get.lazyPut(() => EmptySpamFolderInteractor(Get.find<ThreadRepository>()));
Get.lazyPut(() => GetAppDashboardConfigurationInteractor(Get.find<AppGridRepository>())); Get.lazyPut(() => GetAppDashboardConfigurationInteractor(Get.find<AppGridRepository>()));
Get.lazyPut(() => GetAppGridLinagraEcosystemInteractor(Get.find<AppGridRepository>())); Get.lazyPut(() => GetAppGridLinagraEcosystemInteractor(Get.find<AppGridRepository>()));
Get.lazyPut(() => GetScribePromptUrlInteractor(Get.find<LinagoraEcosystemRepository>()));
Get.lazyPut(() => GetEmailByIdInteractor( Get.lazyPut(() => GetEmailByIdInteractor(
Get.find<ThreadRepository>(), Get.find<ThreadRepository>(),
Get.find<EmailRepository>())); Get.find<EmailRepository>()));
@@ -443,6 +447,7 @@ class MailboxDashBoardBindings extends BaseBindings {
Get.lazyPut<ServerSettingsRepository>(() => Get.find<ServerSettingsRepositoryImpl>()); Get.lazyPut<ServerSettingsRepository>(() => Get.find<ServerSettingsRepositoryImpl>());
Get.lazyPut<IdentityCreatorRepository>(() => Get.find<IdentityCreatorRepositoryImpl>()); Get.lazyPut<IdentityCreatorRepository>(() => Get.find<IdentityCreatorRepositoryImpl>());
Get.lazyPut<AppGridRepository>(() => Get.find<AppGridRepositoryImpl>()); Get.lazyPut<AppGridRepository>(() => Get.find<AppGridRepositoryImpl>());
Get.lazyPut<LinagoraEcosystemRepository>(() => Get.find<LinagoraEcosystemRepositoryImpl>());
} }
@override @override
@@ -495,5 +500,6 @@ class MailboxDashBoardBindings extends BaseBindings {
DataSourceType.network: Get.find<AppGridDatasource>(), DataSourceType.network: Get.find<AppGridDatasource>(),
DataSourceType.local: Get.find<LocalAppGridDatasourceImpl>() DataSourceType.local: Get.find<LocalAppGridDatasourceImpl>()
},)); },));
Get.lazyPut(() => LinagoraEcosystemRepositoryImpl(Get.find<LinagoraEcosystemApi>()));
} }
} }
@@ -106,6 +106,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_action
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/exceptions/spam_report_exception.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_composer_cache_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_scribe_prompt_url_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_stored_email_sort_order_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_stored_email_sort_order_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_text_formatting_menu_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_text_formatting_menu_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart';
@@ -124,6 +125,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_ai_needs_action_setting_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_ai_needs_action_setting_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_cached_ai_scribe_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_cached_ai_scribe_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_scribe_prompt_url_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/cleanup_recent_search_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/cleanup_recent_search_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/delete_emails_in_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/delete_emails_in_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_action_type_for_email_selection.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_action_type_for_email_selection.dart';
@@ -542,6 +544,8 @@ class MailboxDashBoardController extends ReloadableController
updateTextFormattingMenuState(success.isDisplayed); updateTextFormattingMenuState(success.isDisplayed);
} else if (success is GetAIScribeConfigSuccess) { } else if (success is GetAIScribeConfigSuccess) {
handleLoadAIScribeConfigSuccess(success.aiScribeConfig); handleLoadAIScribeConfigSuccess(success.aiScribeConfig);
} else if (success is GetScribePromptUrlSuccess) {
handleGetScribePromptUrlSuccess(success);
} else { } else {
super.handleSuccessViewState(success); super.handleSuccessViewState(success);
} }
@@ -592,6 +596,8 @@ class MailboxDashBoardController extends ReloadableController
updateTextFormattingMenuState(false); updateTextFormattingMenuState(false);
} else if (failure is GetAIScribeConfigFailure) { } else if (failure is GetAIScribeConfigFailure) {
handleLoadAIScribeConfigFailure(); handleLoadAIScribeConfigFailure();
} else if (failure is GetScribePromptUrlFailure) {
handleGetScribePromptUrlFailure(failure);
} else { } else {
super.handleFailureViewState(failure); super.handleFailureViewState(failure);
} }
@@ -922,6 +928,8 @@ class MailboxDashBoardController extends ReloadableController
} else { } else {
injectWebSocket(session: session, accountId: currentAccountId); injectWebSocket(session: session, accountId: currentAccountId);
} }
loadScribePromptUrl();
} }
void _handleMailtoURL(MailtoArguments arguments) { void _handleMailtoURL(MailtoArguments arguments) {
@@ -0,0 +1,32 @@
import 'package:core/utils/app_logger.dart';
import 'package:scribe/scribe/ai/domain/service/prompt_service.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_scribe_prompt_url_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_scribe_prompt_url_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension SetupScribePromptUrlExtension on MailboxDashBoardController {
void loadScribePromptUrl() {
final interactor = getBinding<GetScribePromptUrlInteractor>();
if (interactor != null) {
final baseUrl = dynamicUrlInterceptors.jmapUrl;
if (baseUrl != null && baseUrl.isNotEmpty) {
consumeState(interactor.execute(baseUrl));
} else {
logError('SetupScribePromptUrlExtension::loadScribePromptUrl: jmapUrl is null or empty');
}
} else {
logError('SetupScribePromptUrlExtension::loadScribePromptUrl: GetScribePromptUrlInteractor not found');
}
}
void handleGetScribePromptUrlSuccess(GetScribePromptUrlSuccess success) {
PromptService().setPromptUrl(success.promptUrl);
}
void handleGetScribePromptUrlFailure(GetScribePromptUrlFailure failure) {
logError('SetupScribePromptUrlExtension::handleGetScribePromptUrlFailure: GetScribePromptUrl failed - ${failure.exception}');
PromptService().setPromptUrl(null);
}
}
+1
View File
@@ -4,6 +4,7 @@ export 'scribe/ai/data/datasource/ai_datasource.dart';
export 'scribe/ai/data/repository/ai_repository_impl.dart'; export 'scribe/ai/data/repository/ai_repository_impl.dart';
export 'scribe/ai/domain/model/ai_response.dart'; export 'scribe/ai/domain/model/ai_response.dart';
export 'scribe/ai/domain/repository/ai_scribe_repository.dart'; export 'scribe/ai/domain/repository/ai_scribe_repository.dart';
export 'scribe/ai/domain/service/prompt_service.dart';
export 'scribe/ai/domain/state/generate_ai_text_state.dart'; export 'scribe/ai/domain/state/generate_ai_text_state.dart';
export 'scribe/ai/domain/usecases/generate_ai_text_interactor.dart'; export 'scribe/ai/domain/usecases/generate_ai_text_interactor.dart';
export 'scribe/ai/localizations/scribe_localizations.dart'; export 'scribe/ai/localizations/scribe_localizations.dart';
@@ -1,22 +1,85 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle; import 'package:core/data/network/dio_client.dart';
import 'package:core/utils/app_logger.dart';
import 'package:dio/dio.dart';
import 'package:scribe/scribe/ai/data/model/ai_message.dart'; import 'package:scribe/scribe/ai/data/model/ai_message.dart';
import 'package:scribe/scribe/ai/domain/model/prompt_data.dart'; import 'package:scribe/scribe/ai/domain/model/prompt_data.dart';
import 'package:flutter/services.dart' show rootBundle;
class PromptService { class PromptService {
static final PromptService _instance = PromptService._internal(); static PromptService? _instance;
final DioClient _dioClient;
factory PromptService() => _instance; factory PromptService({DioClient? dioClient}) {
_instance ??= PromptService._internal(dioClient: dioClient);
return _instance!;
}
PromptService._internal(); PromptService._internal({DioClient? dioClient})
: _dioClient = dioClient ?? DioClient(Dio(BaseOptions(
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
)));
PromptData? _promptData; PromptData? _promptData;
String? _promptUrl;
void setPromptUrl(String? url) {
_promptUrl = url;
}
String? get promptUrl => _promptUrl;
Future<PromptData> loadPrompts() async { Future<PromptData> loadPrompts() async {
// App in memory cache
if (_promptData != null) { if (_promptData != null) {
return _promptData!; return _promptData!;
} }
// First try: remote prompts
if (_promptUrl != null) {
try {
_promptData = await _fetchPromptsFromUrl(_promptUrl!);
return _promptData!;
} catch (e) {
log('PromptService::loadPrompts: failed to fetch from remote URL: $e');
}
}
// Fallback: local prompts
return _loadPromptsFromAssets();
}
Future<PromptData> _fetchPromptsFromUrl(String url) async {
log('PromptService::_fetchPromptsFromUrl: Fetching from $url');
try {
final response = await _dioClient.get(url);
if (response.statusCode == 200) {
final jsonData = response.data;
Map<String, dynamic> promptsMap;
if (jsonData is String) {
promptsMap = jsonDecode(jsonData) as Map<String, dynamic>;
} else if (jsonData is Map<String, dynamic>) {
promptsMap = jsonData;
} else {
throw Exception('Failed to fetch prompts: invalid response format');
}
log('PromptService::_fetchPromptsFromUrl: Successfully fetched prompts');
return PromptData.fromJson(promptsMap);
} else {
throw Exception('Failed to fetch prompts: unexpected status code ${response.statusCode}');
}
} catch (e) {
log('PromptService::_fetchPromptsFromUrl: Exception: $e');
rethrow;
}
}
Future<PromptData> _loadPromptsFromAssets() async {
try { try {
final jsonString = await rootBundle.loadString('packages/scribe/assets/prompts.json'); final jsonString = await rootBundle.loadString('packages/scribe/assets/prompts.json');
final jsonData = jsonDecode(jsonString) as Map<String, dynamic>; final jsonData = jsonDecode(jsonString) as Map<String, dynamic>;