Skip to content

Commit 86d9551

Browse files
committed
feat(ai-scribe): Improve data & domain layer for ai scribe
1 parent f994698 commit 86d9551

File tree

17 files changed

+94
-119
lines changed

17 files changed

+94
-119
lines changed

core/lib/data/network/dio_client.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,12 @@ class DioClient {
4040
CancelToken? cancelToken,
4141
ProgressCallback? onSendProgress,
4242
ProgressCallback? onReceiveProgress,
43+
bool useJMAPHeader = true,
4344
}) async {
44-
final newOptions = options?.appendHeaders({HttpHeaders.acceptHeader : jmapHeader})
45-
?? Options(headers: {HttpHeaders.acceptHeader : jmapHeader}) ;
45+
Map<String, dynamic> defaultHeaders =
46+
useJMAPHeader ? {HttpHeaders.acceptHeader: jmapHeader} : {};
47+
final newOptions = options?.appendHeaders(defaultHeaders) ??
48+
Options(headers: defaultHeaders);
4649

4750
return await _dio.post(path,
4851
data: data,
Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
1+
import 'package:core/utils/app_logger.dart';
2+
import 'package:core/utils/platform_info.dart';
13
import 'package:jmap_dart_client/jmap/account_id.dart';
24
import 'package:jmap_dart_client/jmap/core/session/session.dart';
5+
import 'package:scribe/scribe.dart';
6+
import 'package:scribe/scribe/ai/presentation/bindings/ai_scribe_bindings.dart';
37
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
48

59
mixin AiScribeMixin {
6-
bool isAICapabilitySupported({Session? session, AccountId? accountId}) {
10+
AICapability? getAICapability({Session? session, AccountId? accountId}) {
11+
if (PlatformInfo.isMobile) return null;
12+
713
if (accountId == null || session == null) {
8-
return false;
14+
return null;
15+
}
16+
17+
return session.getAICapability(accountId);
18+
}
19+
20+
void injectAIScribeBindings(Session? session, AccountId? accountId) {
21+
try {
22+
final aiCapability = getAICapability(
23+
session: session,
24+
accountId: accountId,
25+
);
26+
final scribeEndpoint = aiCapability?.scribeEndpoint;
27+
28+
if (scribeEndpoint == null || scribeEndpoint.isEmpty) return;
29+
30+
AIScribeBindings(scribeEndpoint).dependencies();
31+
} catch (e) {
32+
logError('AiScribeMixin::injectAIScribeBindings(): $e');
933
}
10-
final aiCapability = session.getAICapability(accountId);
11-
return aiCapability != null;
1234
}
1335
}

lib/features/composer/presentation/composer_controller.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,6 @@ class ComposerController extends BaseController
263263

264264
TransformHtmlEmailContentInteractor get transformHtmlEmailContentInteractor => _transformHtmlEmailContentInteractor;
265265

266-
GenerateAITextInteractor get generateAITextInteractor => Get.find<GenerateAITextInteractor>();
267-
268266
String get ownEmailAddress =>
269267
mailboxDashBoardController.ownEmailAddress.value;
270268

lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import 'package:tmail_ui_user/features/composer/presentation/mixin/text_selectio
1010

1111
extension HandleAiScribeInComposerExtension on ComposerController {
1212
bool get isAIScribeAvailable {
13-
return isAICapabilitySupported(
13+
final aiCapability = getAICapability(
1414
session: mailboxDashBoardController.sessionCurrent,
1515
accountId: mailboxDashBoardController.accountId.value,
1616
);
17+
return aiCapability?.isScribeEndpointAvailable == true;
1718
}
1819

1920
Future<String> _getTextOnlyContentInEditor() async {

lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import 'package:receive_sharing_intent/receive_sharing_intent.dart';
3131
import 'package:rxdart/transformers.dart';
3232
import 'package:server_settings/server_settings/tmail_server_settings_extension.dart';
3333
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
34+
import 'package:tmail_ui_user/features/base/mixin/ai_scribe_mixin.dart';
3435
import 'package:tmail_ui_user/features/base/mixin/contact_support_mixin.dart';
3536
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart';
3637
import 'package:tmail_ui_user/features/base/mixin/own_email_address_mixin.dart';
@@ -78,15 +79,8 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen
7879
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
7980
import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_arguments.dart';
8081
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
81-
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
8282
import 'package:tmail_ui_user/features/home/domain/state/auto_sign_in_via_deep_link_state.dart';
8383
import 'package:tmail_ui_user/features/home/domain/usecases/store_session_interactor.dart';
84-
import 'package:scribe/scribe/ai/data/datasource/ai_datasource.dart';
85-
import 'package:scribe/scribe/ai/data/datasource_impl/ai_datasource_impl.dart';
86-
import 'package:scribe/scribe/ai/data/repository/ai_repository_impl.dart';
87-
import 'package:scribe/scribe/ai/domain/repository/ai_scribe_repository.dart';
88-
import 'package:scribe/scribe/ai/domain/usecases/generate_ai_text_interactor.dart';
89-
import 'package:scribe/scribe/ai/presentation/bindings/ai_scribe_bindings.dart';
9084
import 'package:tmail_ui_user/features/identity_creator/domain/state/get_identity_cache_on_web_state.dart';
9185
import 'package:tmail_ui_user/features/identity_creator/domain/usecase/get_identity_cache_on_web_interactor.dart';
9286
import 'package:tmail_ui_user/features/login/domain/exceptions/logout_exception.dart';
@@ -223,7 +217,8 @@ import 'package:uuid/uuid.dart';
223217
class MailboxDashBoardController extends ReloadableController
224218
with ContactSupportMixin,
225219
OwnEmailAddressMixin,
226-
SaaSPremiumMixin {
220+
SaaSPremiumMixin,
221+
AiScribeMixin {
227222

228223
final RemoveEmailDraftsInteractor _removeEmailDraftsInteractor = Get.find<RemoveEmailDraftsInteractor>();
229224
final EmailReceiveManager _emailReceiveManager = Get.find<EmailReceiveManager>();
@@ -825,41 +820,6 @@ class MailboxDashBoardController extends ReloadableController
825820
}
826821
}
827822

828-
void injectAIScribeBindings(Session? session, AccountId? accountId) {
829-
try {
830-
if (!PlatformInfo.isWeb) return;
831-
832-
if (session == null || accountId == null) return;
833-
834-
final aiCapability = session.getAICapability(accountId);
835-
final scribeEndpoint = aiCapability?.scribeEndpoint;
836-
837-
if (scribeEndpoint == null || scribeEndpoint.isEmpty) return;
838-
839-
// Delete existing AI bindings if they exist
840-
if (Get.isRegistered<AIDataSourceImpl>()) {
841-
Get.delete<AIDataSourceImpl>(force: true);
842-
}
843-
if (Get.isRegistered<AIDataSource>()) {
844-
Get.delete<AIDataSource>(force: true);
845-
}
846-
if (Get.isRegistered<AIScribeRepositoryImpl>()) {
847-
Get.delete<AIScribeRepositoryImpl>(force: true);
848-
}
849-
if (Get.isRegistered<AIScribeRepository>()) {
850-
Get.delete<AIScribeRepository>(force: true);
851-
}
852-
if (Get.isRegistered<GenerateAITextInteractor>()) {
853-
Get.delete<GenerateAITextInteractor>(force: true);
854-
}
855-
856-
// Reinitialize with the correct endpoint
857-
AIScribeBindings(scribeEndpoint: scribeEndpoint).dependencies();
858-
} catch (e) {
859-
logError('MailboxDashBoardController::injectAIScribeBindings(): $e');
860-
}
861-
}
862-
863823
@override
864824
Future<void> injectFCMBindings(Session? session, AccountId? accountId) async {
865825
try {

lib/features/manage_account/presentation/manage_account_dashboard_controller.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:model/model.dart';
1414
import 'package:rule_filter/rule_filter/capability_rule_filter.dart';
1515
import 'package:server_settings/server_settings/capability_server_settings.dart';
1616
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
17+
import 'package:tmail_ui_user/features/base/mixin/ai_scribe_mixin.dart';
1718
import 'package:tmail_ui_user/features/base/mixin/own_email_address_mixin.dart';
1819
import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart';
1920
import 'package:tmail_ui_user/features/base/widget/dialog_picker/color_dialog_picker.dart';
@@ -55,7 +56,7 @@ import 'package:tmail_ui_user/main/routes/route_utils.dart';
5556
import 'package:tmail_ui_user/main/utils/app_config.dart';
5657

5758
class ManageAccountDashBoardController extends ReloadableController
58-
with OwnEmailAddressMixin {
59+
with OwnEmailAddressMixin, AiScribeMixin {
5960

6061
GetAllVacationInteractor? _getAllVacationInteractor;
6162
UpdateVacationInteractor? _updateVacationInteractor;
@@ -152,6 +153,7 @@ class ManageAccountDashBoardController extends ReloadableController
152153
_setUpMinInputLengthAutocomplete();
153154
_bindingInteractorForMenuItemView(sessionCurrent, accountId.value);
154155
_getVacationResponse();
156+
injectAIScribeBindings(sessionCurrent, accountId.value);
155157
paywallController = PaywallController(
156158
ownEmailAddress: ownEmailAddress.value,
157159
);

lib/main/bindings/main_bindings.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'package:core/utils/platform_info.dart';
22
import 'package:get/get.dart';
3-
import 'package:scribe/scribe/ai/presentation/bindings/ai_scribe_bindings.dart';
43
import 'package:tmail_ui_user/main/bindings/core/core_bindings.dart';
54
import 'package:tmail_ui_user/main/bindings/credential/credential_bindings.dart';
65
import 'package:tmail_ui_user/main/bindings/deep_link/deep_link_bindings.dart';
@@ -22,7 +21,6 @@ class MainBindings extends Bindings {
2221
CredentialBindings().dependencies();
2322
SessionBindings().dependencies();
2423
NetWorkConnectionBindings().dependencies();
25-
AIScribeBindings().dependencies();
2624
if (PlatformInfo.isMobile) {
2725
DeepLinkBindings().dependencies();
2826
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:scribe/scribe/ai/domain/model/ai_response.dart';
22

33
abstract class AIDataSource {
4-
Future<AIResponse> request(String prompt);
4+
Future<AIResponse> generateMessage(String prompt);
55
}

scribe/lib/scribe/ai/data/datasource_impl/ai_datasource_impl.dart

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,17 @@
11
import 'package:dio/dio.dart';
22
import 'package:scribe/scribe/ai/data/datasource/ai_datasource.dart';
3-
import 'package:scribe/scribe/ai/data/model/ai_message.dart';
4-
import 'package:scribe/scribe/ai/data/model/ai_api_request.dart';
53
import 'package:scribe/scribe/ai/data/network/ai_api.dart';
64
import 'package:scribe/scribe/ai/domain/model/ai_response.dart';
75

86
class AIDataSourceImpl implements AIDataSource {
97
final AIApi _aiApi;
108

11-
AIDataSourceImpl({
12-
required Dio dio,
13-
String? endpoint,
14-
}) : _aiApi = AIApi(
15-
dio: dio,
16-
endpoint: endpoint,
17-
);
9+
AIDataSourceImpl(this._aiApi);
1810

1911
@override
20-
Future<AIResponse> request(String prompt) async {
12+
Future<AIResponse> generateMessage(String prompt) async {
2113
try {
22-
final aiRequest = AIAPIRequest(
23-
messages: [
24-
AIMessage(
25-
role: 'user',
26-
content: prompt,
27-
),
28-
],
29-
);
30-
31-
final apiResponse = await _aiApi.chatCompletion(aiRequest);
14+
final apiResponse = await _aiApi.generateMessage(prompt);
3215
return AIResponse(result: apiResponse.content);
3316
} on DioError catch (e) {
3417
throw Exception('Failed to generate AI text: ${e.message}');

scribe/lib/scribe/ai/data/model/ai_message.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ class AIMessage {
1212
required this.content,
1313
});
1414

15-
factory AIMessage.fromJson(Map<String, dynamic> json) => _$AIMessageFromJson(json);
15+
factory AIMessage.fromJson(Map<String, dynamic> json) =>
16+
_$AIMessageFromJson(json);
1617

1718
Map<String, dynamic> toJson() => _$AIMessageToJson(this);
19+
20+
factory AIMessage.ofUser(String content) => AIMessage(
21+
role: 'user',
22+
content: content,
23+
);
1824
}

0 commit comments

Comments
 (0)