feat: suppport translate and summary using local ai (#5858)

* chore: fix ui

* chore: fix ui

* chore: rename

* chore: rename

* chore: rename

* chore: refactor database ai interface

* chore: support local ai for database

* chore: clippy
This commit is contained in:
Nathan.fooo 2024-08-01 23:13:35 +08:00 committed by GitHub
parent b9fd3701cd
commit 73421e0d58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
81 changed files with 671 additions and 582 deletions

View File

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -74,7 +74,7 @@ class ChatAIMessageBloc extends Bloc<ChatAIMessageEvent, ChatAIMessageState> {
chatId: chatId,
messageId: questionId,
);
ChatEventGetAnswerForQuestion(payload).send().then((result) {
AIEventGetAnswerForQuestion(payload).send().then((result) {
if (!isClosed) {
result.fold(
(answer) {

View File

@ -5,7 +5,7 @@ import 'dart:isolate';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/code.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
@ -70,7 +70,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
chatId: state.view.id,
limit: Int64(10),
);
ChatEventLoadNextMessage(payload).send().then(
AIEventLoadNextMessage(payload).send().then(
(result) {
result.fold((list) {
if (!isClosed) {
@ -202,7 +202,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
}
final payload = StopStreamPB(chatId: chatId);
await ChatEventStopStream(payload).send();
await AIEventStopStream(payload).send();
final allMessages = _perminentMessages();
if (state.streamingStatus != const LoadingState.finish()) {
// If the streaming is not started, remove the message from the list
@ -273,7 +273,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
messageId: state.lastSentMessage!.messageId,
);
// When user message was sent to the server, we start gettting related question
ChatEventGetRelatedQuestion(payload).send().then((result) {
AIEventGetRelatedQuestion(payload).send().then((result) {
if (!isClosed) {
result.fold(
(list) {
@ -322,7 +322,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
limit: Int64(10),
beforeMessageId: beforeMessageId,
);
ChatEventLoadPrevMessage(payload).send();
AIEventLoadPrevMessage(payload).send();
}
Future<void> _startStreamingMessage(
@ -344,7 +344,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
);
// Stream message to the server
final result = await ChatEventStreamMessage(payload).send();
final result = await AIEventStreamMessage(payload).send();
result.fold(
(ChatMessagePB question) {
if (!isClosed) {

View File

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:appflowy/workspace/application/settings/ai/local_llm_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -31,7 +31,7 @@ class ChatFileBloc extends Bloc<ChatFileEvent, ChatFileState> {
(event, emit) async {
await event.when(
initial: () async {
final result = await ChatEventGetLocalAIChatState().send();
final result = await AIEventGetLocalAIChatState().send();
result.fold(
(chatState) {
if (!isClosed) {
@ -53,7 +53,7 @@ class ChatFileBloc extends Bloc<ChatFileEvent, ChatFileState> {
);
final payload = ChatFilePB(filePath: filePath, chatId: chatId);
unawaited(
ChatEventChatWithFile(payload).send().then((result) {
AIEventChatWithFile(payload).send().then((result) {
if (!isClosed) {
result.fold((_) {
add(

View File

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:appflowy/workspace/application/settings/ai/local_llm_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'chat_input_bloc.freezed.dart';
@ -37,7 +37,7 @@ class ChatInputBloc extends Bloc<ChatInputEvent, ChatInputState> {
) async {
await event.when(
started: () async {
final result = await ChatEventGetLocalAIPluginState().send();
final result = await AIEventGetLocalAIPluginState().send();
result.fold(
(pluginState) {
if (!isClosed) {

View File

@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:typed_data';
import 'package:appflowy/core/notification/notification_helper.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/protobuf.dart';
import 'package:appflowy_backend/rust_stream.dart';

View File

@ -1,6 +1,6 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';

View File

@ -1,6 +1,6 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/error.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/text_completion.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
abstract class AIRepository {

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/ai_client.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pbenum.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:http/http.dart' as http;

View File

@ -7,7 +7,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/wid
import 'package:appflowy/user/application/ai_service.dart';
import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';

View File

@ -8,7 +8,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/ser
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/text_completion.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/smart_edit_action.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:fixnum/fixnum.dart' as fixnum;
@ -59,7 +59,7 @@ class AppFlowyAIService implements AIRepository {
);
// ignore: unawaited_futures
ChatEventCompleteText(payload).send();
AIEventCompleteText(payload).send();
return stream;
}
}

View File

@ -5,7 +5,7 @@ import 'dart:isolate';
import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:fixnum/fixnum.dart';
@ -47,7 +47,7 @@ class DownloadModelBloc extends Bloc<DownloadModelEvent, DownloadModelState> {
final payload =
DownloadLLMPB(progressStream: Int64(downloadStream.nativePort));
final result = await ChatEventDownloadLLMResource(payload).send();
final result = await AIEventDownloadLLMResource(payload).send();
result.fold((_) {
emit(
state.copyWith(

View File

@ -18,7 +18,7 @@ class DownloadOfflineAIBloc
) async {
await event.when(
started: () async {
final result = await ChatEventGetOfflineAIAppLink().send();
final result = await AIEventGetOfflineAIAppLink().send();
await result.fold(
(app) async {
await launchUrl(Uri.parse(app.link));

View File

@ -1,7 +1,7 @@
import 'dart:async';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:bloc/bloc.dart';
@ -19,7 +19,7 @@ class LocalAIToggleBloc extends Bloc<LocalAIToggleEvent, LocalAIToggleState> {
) async {
await event.when(
started: () async {
final result = await ChatEventGetLocalAIState().send();
final result = await AIEventGetLocalAIState().send();
_handleResult(emit, result);
},
toggle: () async {
@ -29,7 +29,7 @@ class LocalAIToggleBloc extends Bloc<LocalAIToggleEvent, LocalAIToggleState> {
),
);
unawaited(
ChatEventToggleLocalAI().send().then(
AIEventToggleLocalAI().send().then(
(result) {
if (!isClosed) {
add(LocalAIToggleEvent.handleResult(result));

View File

@ -4,7 +4,7 @@ import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
import 'package:appflowy/workspace/application/settings/ai/local_llm_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:bloc/bloc.dart';
@ -60,7 +60,7 @@ class LocalAIChatSettingBloc
);
},
selectLLMConfig: (LLMModelPB llmModel) async {
final result = await ChatEventUpdateLocalLLM(llmModel).send();
final result = await AIEventUpdateLocalLLM(llmModel).send();
result.fold(
(llmResource) {
// If all resources are downloaded, show reload plugin
@ -144,7 +144,7 @@ class LocalAIChatSettingBloc
);
},
cancelDownload: () async {
final _ = await ChatEventCancelDownloadLLMResource().send();
final _ = await AIEventCancelDownloadLLMResource().send();
_fetchCurremtLLMState();
},
finishDownload: () async {
@ -156,7 +156,7 @@ class LocalAIChatSettingBloc
},
updatePluginState: (LocalAIPluginStatePB pluginState) {
if (pluginState.offlineAiReady) {
ChatEventRefreshLocalAIModelInfo().send().then((result) {
AIEventRefreshLocalAIModelInfo().send().then((result) {
if (!isClosed) {
add(LocalAIChatSettingEvent.didLoadModelInfo(result));
}
@ -188,7 +188,7 @@ class LocalAIChatSettingBloc
}
void _fetchCurremtLLMState() async {
final result = await ChatEventGetLocalLLMState().send();
final result = await AIEventGetLocalLLMState().send();
result.fold(
(llmResource) {
if (!isClosed) {
@ -203,13 +203,13 @@ class LocalAIChatSettingBloc
/// Handles the event to fetch local AI settings when the application starts.
Future<void> _handleStarted() async {
final result = await ChatEventGetLocalAIPluginState().send();
final result = await AIEventGetLocalAIPluginState().send();
result.fold(
(pluginState) async {
if (!isClosed) {
add(LocalAIChatSettingEvent.updatePluginState(pluginState));
if (pluginState.offlineAiReady) {
final result = await ChatEventRefreshLocalAIModelInfo().send();
final result = await AIEventRefreshLocalAIModelInfo().send();
if (!isClosed) {
add(LocalAIChatSettingEvent.didLoadModelInfo(result));
}

View File

@ -1,7 +1,7 @@
import 'dart:async';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:bloc/bloc.dart';
@ -20,7 +20,7 @@ class LocalAIChatToggleBloc
) async {
await event.when(
started: () async {
final result = await ChatEventGetLocalAIChatState().send();
final result = await AIEventGetLocalAIChatState().send();
_handleResult(emit, result);
},
toggle: () async {
@ -30,7 +30,7 @@ class LocalAIChatToggleBloc
),
);
unawaited(
ChatEventToggleLocalAIChat().send().then(
AIEventToggleLocalAIChat().send().then(
(result) {
if (!isClosed) {
add(LocalAIChatToggleEvent.handleResult(result));

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:typed_data';
import 'package:appflowy/plugins/ai_chat/application/chat_notification.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';

View File

@ -4,7 +4,7 @@ import 'package:appflowy/core/helpers/url_launcher.dart';
import 'package:appflowy/workspace/application/settings/ai/local_llm_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:url_launcher/url_launcher.dart' show launchUrl;
@ -43,7 +43,7 @@ class PluginStateBloc extends Bloc<PluginStateEvent, PluginStateState> {
) async {
await event.when(
started: () async {
final result = await ChatEventGetLocalAIPluginState().send();
final result = await AIEventGetLocalAIPluginState().send();
result.fold(
(pluginState) {
if (!isClosed) {
@ -85,10 +85,10 @@ class PluginStateBloc extends Bloc<PluginStateEvent, PluginStateState> {
emit(
const PluginStateState(action: PluginStateAction.loadingPlugin()),
);
unawaited(ChatEventRestartLocalAIChat().send());
unawaited(AIEventRestartLocalAIChat().send());
},
openModelDirectory: () async {
final result = await ChatEventGetModelStorageDirectory().send();
final result = await AIEventGetModelStorageDirectory().send();
result.fold(
(data) {
afLaunchUrl(Uri.file(data.filePath));
@ -97,7 +97,7 @@ class PluginStateBloc extends Bloc<PluginStateEvent, PluginStateState> {
);
},
downloadOfflineAIApp: () async {
final result = await ChatEventGetOfflineAIAppLink().send();
final result = await AIEventGetOfflineAIAppLink().send();
await result.fold(
(app) async {
await launchUrl(Uri.parse(app.link));

View File

@ -1,6 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/ai/download_model_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';

View File

@ -1,7 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/ai/local_ai_chat_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';

View File

@ -7,7 +7,7 @@ import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/i
import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/plugin_state.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:expandable/expandable.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';

View File

@ -106,19 +106,28 @@ class _LocalAIReadyToUse extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const HSpace(8),
const FlowySvg(
FlowySvgs.download_success_s,
color: Color(0xFF2E7D32),
Flexible(
child: Row(
children: [
const HSpace(8),
const FlowySvg(
FlowySvgs.download_success_s,
color: Color(0xFF2E7D32),
),
const HSpace(6),
Flexible(
child: FlowyText(
LocaleKeys.settings_aiPage_keys_localAILoaded.tr(),
fontSize: 11,
color: const Color(0xFF1E4620),
maxLines: 3,
),
),
],
),
),
const HSpace(6),
FlowyText(
LocaleKeys.settings_aiPage_keys_localAILoaded.tr(),
fontSize: 11,
color: const Color(0xFF1E4620),
),
const Spacer(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6),
child: FlowyButton(

View File

@ -16,7 +16,7 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-search/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-chat/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:ffi/ffi.dart';
import 'package:isolates/isolates.dart';
@ -37,7 +37,7 @@ part 'dart_event/flowy-document/dart_event.dart';
part 'dart_event/flowy-config/dart_event.dart';
part 'dart_event/flowy-date/dart_event.dart';
part 'dart_event/flowy-search/dart_event.dart';
part 'dart_event/flowy-chat/dart_event.dart';
part 'dart_event/flowy-ai/dart_event.dart';
enum FFIException {
RequestIsEmpty,

View File

@ -172,7 +172,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bincode",
@ -192,7 +192,7 @@ dependencies = [
[[package]]
name = "appflowy-ai-client"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bytes",
@ -206,7 +206,7 @@ dependencies = [
[[package]]
name = "appflowy-local-ai"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec#8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=7dd879a6b9b3246e5cd06f1647e620553db9b960#7dd879a6b9b3246e5cd06f1647e620553db9b960"
dependencies = [
"anyhow",
"appflowy-plugin",
@ -225,7 +225,7 @@ dependencies = [
[[package]]
name = "appflowy-plugin"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec#8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=7dd879a6b9b3246e5cd06f1647e620553db9b960#7dd879a6b9b3246e5cd06f1647e620553db9b960"
dependencies = [
"anyhow",
"cfg-if",
@ -248,7 +248,7 @@ version = "0.0.0"
dependencies = [
"bytes",
"dotenv",
"flowy-chat",
"flowy-ai",
"flowy-config",
"flowy-core",
"flowy-date",
@ -825,7 +825,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.2.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"again",
"anyhow",
@ -875,7 +875,7 @@ dependencies = [
[[package]]
name = "client-api-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"collab-entity",
"collab-rt-entity",
@ -887,7 +887,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"futures-channel",
"futures-util",
@ -1131,7 +1131,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bincode",
@ -1156,7 +1156,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"async-trait",
@ -1531,7 +1531,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",
@ -1950,16 +1950,7 @@ dependencies = [
]
[[package]]
name = "flowy-ast"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "flowy-chat"
name = "flowy-ai"
version = "0.1.0"
dependencies = [
"allo-isolate",
@ -1969,7 +1960,7 @@ dependencies = [
"base64 0.21.5",
"bytes",
"dashmap",
"flowy-chat-pub",
"flowy-ai-pub",
"flowy-codegen",
"flowy-derive",
"flowy-error",
@ -2000,7 +1991,7 @@ dependencies = [
]
[[package]]
name = "flowy-chat-pub"
name = "flowy-ai-pub"
version = "0.1.0"
dependencies = [
"bytes",
@ -2010,6 +2001,15 @@ dependencies = [
"lib-infra",
]
[[package]]
name = "flowy-ast"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "flowy-codegen"
version = "0.1.0"
@ -2061,8 +2061,8 @@ dependencies = [
"collab-integrate",
"collab-plugins",
"diesel",
"flowy-chat",
"flowy-chat-pub",
"flowy-ai",
"flowy-ai-pub",
"flowy-config",
"flowy-database-pub",
"flowy-database2",
@ -2407,7 +2407,7 @@ dependencies = [
"collab-entity",
"collab-folder",
"collab-plugins",
"flowy-chat-pub",
"flowy-ai-pub",
"flowy-database-pub",
"flowy-document-pub",
"flowy-encrypt",
@ -3047,7 +3047,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"futures-util",
@ -3064,7 +3064,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",
@ -3496,7 +3496,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bytes",
@ -6094,7 +6094,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",

View File

@ -53,7 +53,7 @@ collab-user = { version = "0.2" }
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "0062c950677f7f633f5b7edabc827a35d3bc92c3" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f61e6d03469aac73b9ad88e37ac6898a691289d" }
[dependencies]
serde_json.workspace = true
@ -76,7 +76,7 @@ flowy-core = { path = "../../rust-lib/flowy-core", features = [
flowy-user = { path = "../../rust-lib/flowy-user", features = ["tauri_ts"] }
flowy-config = { path = "../../rust-lib/flowy-config", features = ["tauri_ts"] }
flowy-date = { path = "../../rust-lib/flowy-date", features = ["tauri_ts"] }
flowy-chat = { path = "../../rust-lib/flowy-chat", features = ["tauri_ts"] }
flowy-ai = { path = "../../rust-lib/flowy-ai", features = ["tauri_ts"] }
flowy-error = { path = "../../rust-lib/flowy-error", features = [
"impl_from_sqlite",
"impl_from_dispatch_error",
@ -128,5 +128,5 @@ collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-
# To update the commit ID, run:
# scripts/tool/update_local_ai_rev.sh new_rev_id
# ⚠️⚠️⚠️️
appflowy-local-ai = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec" }
appflowy-plugin = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec" }
appflowy-local-ai = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "7dd879a6b9b3246e5cd06f1647e620553db9b960" }
appflowy-plugin = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "7dd879a6b9b3246e5cd06f1647e620553db9b960" }

View File

@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bincode",
@ -183,7 +183,7 @@ dependencies = [
[[package]]
name = "appflowy-ai-client"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bytes",
@ -197,7 +197,7 @@ dependencies = [
[[package]]
name = "appflowy-local-ai"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec#8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=7dd879a6b9b3246e5cd06f1647e620553db9b960#7dd879a6b9b3246e5cd06f1647e620553db9b960"
dependencies = [
"anyhow",
"appflowy-plugin",
@ -216,7 +216,7 @@ dependencies = [
[[package]]
name = "appflowy-plugin"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec#8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=7dd879a6b9b3246e5cd06f1647e620553db9b960#7dd879a6b9b3246e5cd06f1647e620553db9b960"
dependencies = [
"anyhow",
"cfg-if",
@ -239,7 +239,7 @@ version = "0.0.0"
dependencies = [
"bytes",
"dotenv",
"flowy-chat",
"flowy-ai",
"flowy-config",
"flowy-core",
"flowy-date",
@ -799,7 +799,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.2.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"again",
"anyhow",
@ -849,7 +849,7 @@ dependencies = [
[[package]]
name = "client-api-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"collab-entity",
"collab-rt-entity",
@ -861,7 +861,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"futures-channel",
"futures-util",
@ -1114,7 +1114,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bincode",
@ -1139,7 +1139,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"async-trait",
@ -1521,7 +1521,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",
@ -1980,16 +1980,7 @@ dependencies = [
]
[[package]]
name = "flowy-ast"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "flowy-chat"
name = "flowy-ai"
version = "0.1.0"
dependencies = [
"allo-isolate",
@ -1999,7 +1990,7 @@ dependencies = [
"base64 0.21.7",
"bytes",
"dashmap",
"flowy-chat-pub",
"flowy-ai-pub",
"flowy-codegen",
"flowy-derive",
"flowy-error",
@ -2030,7 +2021,7 @@ dependencies = [
]
[[package]]
name = "flowy-chat-pub"
name = "flowy-ai-pub"
version = "0.1.0"
dependencies = [
"bytes",
@ -2040,6 +2031,15 @@ dependencies = [
"lib-infra",
]
[[package]]
name = "flowy-ast"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "flowy-codegen"
version = "0.1.0"
@ -2091,8 +2091,8 @@ dependencies = [
"collab-integrate",
"collab-plugins",
"diesel",
"flowy-chat",
"flowy-chat-pub",
"flowy-ai",
"flowy-ai-pub",
"flowy-config",
"flowy-database-pub",
"flowy-database2",
@ -2437,7 +2437,7 @@ dependencies = [
"collab-entity",
"collab-folder",
"collab-plugins",
"flowy-chat-pub",
"flowy-ai-pub",
"flowy-database-pub",
"flowy-document-pub",
"flowy-encrypt",
@ -3114,7 +3114,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"futures-util",
@ -3131,7 +3131,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",
@ -3568,7 +3568,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bytes",
@ -6158,7 +6158,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",

View File

@ -52,7 +52,7 @@ collab-user = { version = "0.2" }
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "0062c950677f7f633f5b7edabc827a35d3bc92c3" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f61e6d03469aac73b9ad88e37ac6898a691289d" }
[dependencies]
serde_json.workspace = true
@ -89,7 +89,7 @@ flowy-document = { path = "../../rust-lib/flowy-document", features = [
flowy-notification = { path = "../../rust-lib/flowy-notification", features = [
"tauri_ts",
] }
flowy-chat = { path = "../../rust-lib/flowy-chat", features = [
flowy-ai = { path = "../../rust-lib/flowy-ai", features = [
"tauri_ts",
] }
@ -128,6 +128,6 @@ collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-
# To update the commit ID, run:
# scripts/tool/update_local_ai_rev.sh new_rev_id
# ⚠️⚠️⚠️️
appflowy-local-ai = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec" }
appflowy-plugin = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec" }
appflowy-local-ai = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "7dd879a6b9b3246e5cd06f1647e620553db9b960" }
appflowy-plugin = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "7dd879a6b9b3246e5cd06f1647e620553db9b960" }

View File

@ -657,7 +657,7 @@
"downloadLLMPrompt": "Download {}",
"downloadAppFlowyOfflineAI": "Downloading AI offline package will enable AI to run on your device. Do you want to continue?",
"downloadLLMPromptDetail": "Downloading {} local model will take up to {} of storage. Do you want to continue?",
"downloadAIModelButton": "Download AI model",
"downloadAIModelButton": "Download",
"downloadingModel": "Downloading",
"localAILoaded": "Local AI Model successfully added and ready to use",
"localAIStart": "Local AI Chat is starting...",

View File

@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bincode",
@ -183,7 +183,7 @@ dependencies = [
[[package]]
name = "appflowy-ai-client"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bytes",
@ -197,7 +197,7 @@ dependencies = [
[[package]]
name = "appflowy-local-ai"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec#8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=7dd879a6b9b3246e5cd06f1647e620553db9b960#7dd879a6b9b3246e5cd06f1647e620553db9b960"
dependencies = [
"anyhow",
"appflowy-plugin",
@ -216,7 +216,7 @@ dependencies = [
[[package]]
name = "appflowy-plugin"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec#8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-LocalAI?rev=7dd879a6b9b3246e5cd06f1647e620553db9b960#7dd879a6b9b3246e5cd06f1647e620553db9b960"
dependencies = [
"anyhow",
"cfg-if",
@ -717,7 +717,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.2.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"again",
"anyhow",
@ -767,7 +767,7 @@ dependencies = [
[[package]]
name = "client-api-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"collab-entity",
"collab-rt-entity",
@ -779,7 +779,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"futures-channel",
"futures-util",
@ -992,7 +992,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bincode",
@ -1017,7 +1017,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"async-trait",
@ -1255,7 +1255,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -1355,7 +1355,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",
@ -1624,8 +1624,8 @@ dependencies = [
"collab-folder",
"collab-plugins",
"dotenv",
"flowy-chat",
"flowy-chat-pub",
"flowy-ai",
"flowy-ai-pub",
"flowy-core",
"flowy-database-pub",
"flowy-database2",
@ -1773,16 +1773,7 @@ dependencies = [
]
[[package]]
name = "flowy-ast"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "flowy-chat"
name = "flowy-ai"
version = "0.1.0"
dependencies = [
"allo-isolate",
@ -1793,7 +1784,7 @@ dependencies = [
"bytes",
"dashmap",
"dotenv",
"flowy-chat-pub",
"flowy-ai-pub",
"flowy-codegen",
"flowy-derive",
"flowy-error",
@ -1826,7 +1817,7 @@ dependencies = [
]
[[package]]
name = "flowy-chat-pub"
name = "flowy-ai-pub"
version = "0.1.0"
dependencies = [
"bytes",
@ -1836,6 +1827,15 @@ dependencies = [
"lib-infra",
]
[[package]]
name = "flowy-ast"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "flowy-codegen"
version = "0.1.0"
@ -1879,6 +1879,7 @@ name = "flowy-core"
version = "0.1.0"
dependencies = [
"anyhow",
"appflowy-local-ai",
"base64 0.21.5",
"bytes",
"client-api",
@ -1888,8 +1889,8 @@ dependencies = [
"collab-plugins",
"console-subscriber",
"diesel",
"flowy-chat",
"flowy-chat-pub",
"flowy-ai",
"flowy-ai-pub",
"flowy-config",
"flowy-database-pub",
"flowy-database2",
@ -2240,7 +2241,7 @@ dependencies = [
"collab-folder",
"collab-plugins",
"dotenv",
"flowy-chat-pub",
"flowy-ai-pub",
"flowy-database-pub",
"flowy-document-pub",
"flowy-encrypt",
@ -2726,7 +2727,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"futures-util",
@ -2743,7 +2744,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",
@ -3108,7 +3109,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"bytes",
@ -4064,7 +4065,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_macros 0.8.0",
"phf_macros",
"phf_shared 0.8.0",
"proc-macro-hack",
]
@ -4084,7 +4085,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2",
]
@ -4152,19 +4152,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.47",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@ -5317,7 +5304,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=0062c950677f7f633f5b7edabc827a35d3bc92c3#0062c950677f7f633f5b7edabc827a35d3bc92c3"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=8f61e6d03469aac73b9ad88e37ac6898a691289d#8f61e6d03469aac73b9ad88e37ac6898a691289d"
dependencies = [
"anyhow",
"app-error",

View File

@ -29,8 +29,8 @@ members = [
"build-tool/flowy-codegen",
"build-tool/flowy-derive",
"flowy-search-pub",
"flowy-chat",
"flowy-chat-pub",
"flowy-ai",
"flowy-ai-pub",
"flowy-storage-pub",
]
resolver = "2"
@ -65,8 +65,8 @@ flowy-search = { workspace = true, path = "flowy-search" }
flowy-search-pub = { workspace = true, path = "flowy-search-pub" }
collab-integrate = { workspace = true, path = "collab-integrate" }
flowy-date = { workspace = true, path = "flowy-date" }
flowy-chat = { workspace = true, path = "flowy-chat" }
flowy-chat-pub = { workspace = true, path = "flowy-chat-pub" }
flowy-ai = { workspace = true, path = "flowy-ai" }
flowy-ai-pub = { workspace = true, path = "flowy-ai-pub" }
anyhow = "1.0"
tracing = "0.1.40"
bytes = "1.5.0"
@ -99,8 +99,8 @@ zip = "2.1.3"
# Run the script.add_workspace_members:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "0062c950677f7f633f5b7edabc827a35d3bc92c3" }
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "0062c950677f7f633f5b7edabc827a35d3bc92c3" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f61e6d03469aac73b9ad88e37ac6898a691289d" }
client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "8f61e6d03469aac73b9ad88e37ac6898a691289d" }
[profile.dev]
opt-level = 0
@ -147,5 +147,5 @@ collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-
# To update the commit ID, run:
# scripts/tool/update_local_ai_rev.sh new_rev_id
# ⚠️⚠️⚠️️
appflowy-local-ai = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec" }
appflowy-plugin = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "8ef7d3e4c38fbf92ff9b3630fe79017e95a496ec" }
appflowy-local-ai = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "7dd879a6b9b3246e5cd06f1647e620553db9b960" }
appflowy-plugin = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-LocalAI", rev = "7dd879a6b9b3246e5cd06f1647e620553db9b960" }

View File

@ -16,7 +16,7 @@ flowy-database-pub = { workspace = true }
flowy-document = { path = "../flowy-document" }
flowy-document-pub = { workspace = true }
flowy-encrypt = { workspace = true }
flowy-chat = { workspace = true }
flowy-ai = { workspace = true }
lib-dispatch = { workspace = true }
lib-infra = { workspace = true }
flowy-server = { path = "../flowy-server" }
@ -58,7 +58,7 @@ chrono = "0.4.31"
zip.workspace = true
walkdir = "2.5.0"
futures = "0.3.30"
flowy-chat-pub = { workspace = true }
flowy-ai-pub = { workspace = true }
[features]
default = ["supabase_cloud_test"]

View File

@ -1,10 +1,10 @@
use crate::event_builder::EventBuilder;
use crate::EventIntegrationTest;
use flowy_chat::entities::{
use flowy_ai::entities::{
ChatMessageListPB, ChatMessageTypePB, CompleteTextPB, CompleteTextTaskPB, CompletionTypePB,
LoadNextChatMessagePB, LoadPrevChatMessagePB, SendChatPayloadPB,
};
use flowy_chat::event_map::ChatEvent;
use flowy_ai::event_map::AIEvent;
use flowy_folder::entities::{CreateViewPayloadPB, ViewLayoutPB, ViewPB};
use flowy_folder::event_map::FolderEvent;
@ -45,7 +45,7 @@ impl EventIntegrationTest {
};
EventBuilder::new(self.clone())
.event(ChatEvent::StreamMessage)
.event(AIEvent::StreamMessage)
.payload(payload)
.async_send()
.await;
@ -63,7 +63,7 @@ impl EventIntegrationTest {
before_message_id,
};
EventBuilder::new(self.clone())
.event(ChatEvent::LoadPrevMessage)
.event(AIEvent::LoadPrevMessage)
.payload(payload)
.async_send()
.await
@ -82,7 +82,7 @@ impl EventIntegrationTest {
after_message_id,
};
EventBuilder::new(self.clone())
.event(ChatEvent::LoadNextMessage)
.event(AIEvent::LoadNextMessage)
.payload(payload)
.async_send()
.await
@ -100,7 +100,7 @@ impl EventIntegrationTest {
stream_port: 0,
};
EventBuilder::new(self.clone())
.event(ChatEvent::CompleteText)
.event(AIEvent::CompleteText)
.payload(payload)
.async_send()
.await

View File

@ -1,6 +1,6 @@
use event_integration_test::user_event::user_localhost_af_cloud;
use event_integration_test::EventIntegrationTest;
use flowy_chat::entities::CompletionTypePB;
use flowy_ai::entities::CompletionTypePB;
use std::time::Duration;

View File

@ -1,10 +1,10 @@
use crate::util::receive_with_timeout;
use event_integration_test::user_event::user_localhost_af_cloud;
use event_integration_test::EventIntegrationTest;
use flowy_chat::entities::ChatMessageListPB;
use flowy_chat::notification::ChatNotification;
use flowy_ai::entities::ChatMessageListPB;
use flowy_ai::notification::ChatNotification;
use flowy_chat_pub::cloud::ChatMessageType;
use flowy_ai_pub::cloud::ChatMessageType;
use std::time::Duration;

View File

@ -1,5 +1,5 @@
[package]
name = "flowy-chat-pub"
name = "flowy-ai-pub"
version = "0.1.0"
edition = "2021"

View File

@ -1,5 +1,5 @@
[package]
name = "flowy-chat"
name = "flowy-ai"
version = "0.1.0"
edition = "2021"
@ -21,7 +21,7 @@ protobuf.workspace = true
bytes.workspace = true
validator = { workspace = true, features = ["derive"] }
lib-infra = { workspace = true, features = ["isolate_flutter"] }
flowy-chat-pub.workspace = true
flowy-ai-pub.workspace = true
dashmap = "5.5"
flowy-sqlite = { workspace = true }
tokio.workspace = true

View File

@ -1,12 +1,12 @@
use crate::chat::Chat;
use crate::entities::{ChatMessageListPB, ChatMessagePB, RepeatedRelatedQuestionPB};
use crate::local_ai::local_llm_chat::LocalAIController;
use crate::middleware::chat_service_mw::CloudServiceMiddleware;
use crate::middleware::chat_service_mw::AICloudServiceMiddleware;
use crate::persistence::{insert_chat, ChatTable};
use appflowy_plugin::manager::PluginManager;
use dashmap::DashMap;
use flowy_chat_pub::cloud::{ChatCloudService, ChatMessageType};
use flowy_ai_pub::cloud::{ChatCloudService, ChatMessageType};
use flowy_error::{FlowyError, FlowyResult};
use flowy_sqlite::kv::KVStorePreferences;
use flowy_sqlite::DBConnection;
@ -16,7 +16,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use tracing::{info, trace};
pub trait ChatUserService: Send + Sync + 'static {
pub trait AIUserService: Send + Sync + 'static {
fn user_id(&self) -> Result<i64, FlowyError>;
fn device_id(&self) -> Result<String, FlowyError>;
fn workspace_id(&self) -> Result<String, FlowyError>;
@ -24,32 +24,32 @@ pub trait ChatUserService: Send + Sync + 'static {
fn data_root_dir(&self) -> Result<PathBuf, FlowyError>;
}
pub struct ChatManager {
pub cloud_service_wm: Arc<CloudServiceMiddleware>,
pub user_service: Arc<dyn ChatUserService>,
pub struct AIManager {
pub cloud_service_wm: Arc<AICloudServiceMiddleware>,
pub user_service: Arc<dyn AIUserService>,
chats: Arc<DashMap<String, Arc<Chat>>>,
pub local_ai_controller: Arc<LocalAIController>,
}
impl ChatManager {
impl AIManager {
pub fn new(
cloud_service: Arc<dyn ChatCloudService>,
user_service: impl ChatUserService,
chat_cloud_service: Arc<dyn ChatCloudService>,
user_service: impl AIUserService,
store_preferences: Arc<KVStorePreferences>,
) -> ChatManager {
) -> AIManager {
let user_service = Arc::new(user_service);
let plugin_manager = Arc::new(PluginManager::new());
let local_ai_controller = Arc::new(LocalAIController::new(
plugin_manager.clone(),
store_preferences.clone(),
user_service.clone(),
cloud_service.clone(),
chat_cloud_service.clone(),
));
// setup local chat service
let cloud_service_wm = Arc::new(CloudServiceMiddleware::new(
let cloud_service_wm = Arc::new(AICloudServiceMiddleware::new(
user_service.clone(),
cloud_service,
chat_cloud_service,
local_ai_controller.clone(),
));

View File

@ -1,12 +1,12 @@
use crate::chat_manager::ChatUserService;
use crate::ai_manager::AIUserService;
use crate::entities::{
ChatMessageErrorPB, ChatMessageListPB, ChatMessagePB, RepeatedRelatedQuestionPB,
};
use crate::middleware::chat_service_mw::CloudServiceMiddleware;
use crate::middleware::chat_service_mw::AICloudServiceMiddleware;
use crate::notification::{make_notification, ChatNotification};
use crate::persistence::{insert_chat_messages, select_chat_messages, ChatMessageTable};
use allo_isolate::Isolate;
use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, ChatMessageType, MessageCursor};
use flowy_ai_pub::cloud::{ChatCloudService, ChatMessage, ChatMessageType, MessageCursor};
use flowy_error::{FlowyError, FlowyResult};
use flowy_sqlite::DBConnection;
use futures::{SinkExt, StreamExt};
@ -26,8 +26,8 @@ enum PrevMessageState {
pub struct Chat {
chat_id: String,
uid: i64,
user_service: Arc<dyn ChatUserService>,
chat_service: Arc<CloudServiceMiddleware>,
user_service: Arc<dyn AIUserService>,
chat_service: Arc<AICloudServiceMiddleware>,
prev_message_state: Arc<RwLock<PrevMessageState>>,
latest_message_id: Arc<AtomicI64>,
stop_stream: Arc<AtomicBool>,
@ -38,8 +38,8 @@ impl Chat {
pub fn new(
uid: i64,
chat_id: String,
user_service: Arc<dyn ChatUserService>,
chat_service: Arc<CloudServiceMiddleware>,
user_service: Arc<dyn AIUserService>,
chat_service: Arc<AICloudServiceMiddleware>,
) -> Chat {
Chat {
uid,
@ -189,7 +189,7 @@ impl Chat {
fn save_answer(
uid: i64,
chat_id: &str,
user_service: &Arc<dyn ChatUserService>,
user_service: &Arc<dyn AIUserService>,
answer: ChatMessage,
) -> Result<(), FlowyError> {
save_chat_message(

View File

@ -1,9 +1,9 @@
use crate::chat_manager::ChatUserService;
use crate::ai_manager::AIUserService;
use crate::entities::{CompleteTextPB, CompleteTextTaskPB, CompletionTypePB};
use allo_isolate::Isolate;
use dashmap::DashMap;
use flowy_chat_pub::cloud::{ChatCloudService, CompletionType};
use flowy_ai_pub::cloud::{ChatCloudService, CompletionType};
use flowy_error::{FlowyError, FlowyResult};
use futures::{SinkExt, StreamExt};
@ -12,16 +12,16 @@ use lib_infra::isolate_stream::IsolateSink;
use std::sync::{Arc, Weak};
use tokio::select;
pub struct AITools {
pub struct AICompletion {
tasks: Arc<DashMap<String, tokio::sync::mpsc::Sender<()>>>,
cloud_service: Weak<dyn ChatCloudService>,
user_service: Weak<dyn ChatUserService>,
user_service: Weak<dyn AIUserService>,
}
impl AITools {
impl AICompletion {
pub fn new(
cloud_service: Weak<dyn ChatCloudService>,
user_service: Weak<dyn ChatUserService>,
user_service: Weak<dyn AIUserService>,
) -> Self {
Self {
tasks: Arc::new(DashMap::new()),
@ -40,7 +40,7 @@ impl AITools {
.ok_or_else(FlowyError::internal)?
.workspace_id()?;
let (tx, rx) = tokio::sync::mpsc::channel(1);
let task = ToolTask::new(workspace_id, complete, self.cloud_service.clone(), rx);
let task = CompletionTask::new(workspace_id, complete, self.cloud_service.clone(), rx);
let task_id = task.task_id.clone();
self.tasks.insert(task_id.clone(), tx);
@ -55,7 +55,7 @@ impl AITools {
}
}
pub struct ToolTask {
pub struct CompletionTask {
workspace_id: String,
task_id: String,
stop_rx: tokio::sync::mpsc::Receiver<()>,
@ -63,7 +63,7 @@ pub struct ToolTask {
cloud_service: Weak<dyn ChatCloudService>,
}
impl ToolTask {
impl CompletionTask {
pub fn new(
workspace_id: String,
context: CompleteTextPB,

View File

@ -2,7 +2,7 @@ use crate::local_ai::local_llm_chat::LLMModelInfo;
use appflowy_plugin::core::plugin::RunningState;
use crate::local_ai::local_llm_resource::PendingResource;
use flowy_chat_pub::cloud::{
use flowy_ai_pub::cloud::{
ChatMessage, LLMModel, RelatedQuestion, RepeatedChatMessage, RepeatedRelatedQuestion,
};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};

View File

@ -1,4 +1,4 @@
use flowy_chat_pub::cloud::ChatMessageType;
use flowy_ai_pub::cloud::ChatMessageType;
use std::path::PathBuf;
@ -7,30 +7,28 @@ use std::sync::{Arc, Weak};
use tokio::sync::oneshot;
use validator::Validate;
use crate::chat_manager::ChatManager;
use crate::ai_manager::AIManager;
use crate::completion::AICompletion;
use crate::entities::*;
use crate::local_ai::local_llm_chat::LLMModelInfo;
use crate::notification::{make_notification, ChatNotification, APPFLOWY_AI_NOTIFICATION_KEY};
use crate::tools::AITools;
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
use lib_infra::isolate_stream::IsolateSink;
fn upgrade_chat_manager(
chat_manager: AFPluginState<Weak<ChatManager>>,
) -> FlowyResult<Arc<ChatManager>> {
let chat_manager = chat_manager
fn upgrade_ai_manager(ai_manager: AFPluginState<Weak<AIManager>>) -> FlowyResult<Arc<AIManager>> {
let ai_manager = ai_manager
.upgrade()
.ok_or(FlowyError::internal().with_context("The chat manager is already dropped"))?;
Ok(chat_manager)
Ok(ai_manager)
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn stream_chat_message_handler(
data: AFPluginData<StreamChatPayloadPB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<ChatMessagePB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let data = data.into_inner();
data.validate()?;
@ -39,7 +37,7 @@ pub(crate) async fn stream_chat_message_handler(
ChatMessageTypePB::User => ChatMessageType::User,
};
let question = chat_manager
let question = ai_manager
.stream_chat_message(
&data.chat_id,
&data.message,
@ -53,13 +51,13 @@ pub(crate) async fn stream_chat_message_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn load_prev_message_handler(
data: AFPluginData<LoadPrevChatMessagePB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<ChatMessageListPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let data = data.into_inner();
data.validate()?;
let messages = chat_manager
let messages = ai_manager
.load_prev_chat_messages(&data.chat_id, data.limit, data.before_message_id)
.await?;
data_result_ok(messages)
@ -68,13 +66,13 @@ pub(crate) async fn load_prev_message_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn load_next_message_handler(
data: AFPluginData<LoadNextChatMessagePB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<ChatMessageListPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let data = data.into_inner();
data.validate()?;
let messages = chat_manager
let messages = ai_manager
.load_latest_chat_messages(&data.chat_id, data.limit, data.after_message_id)
.await?;
data_result_ok(messages)
@ -83,13 +81,13 @@ pub(crate) async fn load_next_message_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_related_question_handler(
data: AFPluginData<ChatMessageIdPB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<RepeatedRelatedQuestionPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let data = data.into_inner();
let (tx, rx) = tokio::sync::oneshot::channel();
tokio::spawn(async move {
let messages = chat_manager
let messages = ai_manager
.get_related_questions(&data.chat_id, data.message_id)
.await?;
let _ = tx.send(messages);
@ -102,13 +100,13 @@ pub(crate) async fn get_related_question_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_answer_handler(
data: AFPluginData<ChatMessageIdPB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<ChatMessagePB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let data = data.into_inner();
let (tx, rx) = tokio::sync::oneshot::channel();
tokio::spawn(async move {
let message = chat_manager
let message = ai_manager
.generate_answer(&data.chat_id, data.message_id)
.await?;
let _ = tx.send(message);
@ -121,26 +119,26 @@ pub(crate) async fn get_answer_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn stop_stream_handler(
data: AFPluginData<StopStreamPB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> Result<(), FlowyError> {
let data = data.into_inner();
data.validate()?;
let chat_manager = upgrade_chat_manager(chat_manager)?;
chat_manager.stop_stream(&data.chat_id).await?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
ai_manager.stop_stream(&data.chat_id).await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn refresh_local_ai_info_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LLMModelInfoPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let (tx, rx) = oneshot::channel::<Result<LLMModelInfo, FlowyError>>();
tokio::spawn(async move {
let model_info = chat_manager.local_ai_controller.refresh().await;
let model_info = ai_manager.local_ai_controller.refresh().await;
if model_info.is_err() {
if let Some(llm_model) = chat_manager.local_ai_controller.get_current_model() {
if let Some(llm_model) = ai_manager.local_ai_controller.get_current_model() {
let model_info = LLMModelInfo {
selected_model: llm_model.clone(),
models: vec![llm_model],
@ -160,11 +158,11 @@ pub(crate) async fn refresh_local_ai_info_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn update_local_llm_model_handler(
data: AFPluginData<LLMModelPB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalModelResourcePB, FlowyError> {
let data = data.into_inner();
let chat_manager = upgrade_chat_manager(chat_manager)?;
let state = chat_manager
let ai_manager = upgrade_ai_manager(ai_manager)?;
let state = ai_manager
.local_ai_controller
.select_local_llm(data.llm_id)
.await?;
@ -173,19 +171,16 @@ pub(crate) async fn update_local_llm_model_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_local_llm_state_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalModelResourcePB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let state = chat_manager
.local_ai_controller
.get_local_llm_state()
.await?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let state = ai_manager.local_ai_controller.get_local_llm_state().await?;
data_result_ok(state)
}
pub(crate) async fn start_complete_text_handler(
data: AFPluginData<CompleteTextPB>,
tools: AFPluginState<Arc<AITools>>,
tools: AFPluginState<Arc<AICompletion>>,
) -> DataResult<CompleteTextTaskPB, FlowyError> {
let task = tools.create_complete_task(data.into_inner()).await?;
data_result_ok(task)
@ -194,7 +189,7 @@ pub(crate) async fn start_complete_text_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn stop_complete_text_handler(
data: AFPluginData<CompleteTextTaskPB>,
tools: AFPluginState<Arc<AITools>>,
tools: AFPluginState<Arc<AICompletion>>,
) -> Result<(), FlowyError> {
let data = data.into_inner();
tools.cancel_complete_task(&data.task_id).await;
@ -204,7 +199,7 @@ pub(crate) async fn stop_complete_text_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn chat_file_handler(
data: AFPluginData<ChatFilePB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> Result<(), FlowyError> {
let data = data.try_into_inner()?;
let file_path = PathBuf::from(&data.file_path);
@ -229,10 +224,8 @@ pub(crate) async fn chat_file_handler(
let (tx, rx) = oneshot::channel::<Result<(), FlowyError>>();
tokio::spawn(async move {
let chat_manager = upgrade_chat_manager(chat_manager)?;
chat_manager
.chat_with_file(&data.chat_id, file_path)
.await?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
ai_manager.chat_with_file(&data.chat_id, file_path).await?;
let _ = tx.send(Ok(()));
Ok::<_, FlowyError>(())
});
@ -243,12 +236,12 @@ pub(crate) async fn chat_file_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn download_llm_resource_handler(
data: AFPluginData<DownloadLLMPB>,
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<DownloadTaskPB, FlowyError> {
let data = data.into_inner();
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let text_sink = IsolateSink::new(Isolate::new(data.progress_stream));
let task_id = chat_manager
let task_id = ai_manager
.local_ai_controller
.start_downloading(text_sink)
.await?;
@ -257,32 +250,32 @@ pub(crate) async fn download_llm_resource_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn cancel_download_llm_resource_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> Result<(), FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
chat_manager.local_ai_controller.cancel_download()?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
ai_manager.local_ai_controller.cancel_download()?;
Ok(())
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_plugin_state_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalAIPluginStatePB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let state = chat_manager.local_ai_controller.get_chat_plugin_state();
let ai_manager = upgrade_ai_manager(ai_manager)?;
let state = ai_manager.local_ai_controller.get_chat_plugin_state();
data_result_ok(state)
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn toggle_local_ai_chat_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalAIChatPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let enabled = chat_manager
let ai_manager = upgrade_ai_manager(ai_manager)?;
let enabled = ai_manager
.local_ai_controller
.toggle_local_ai_chat()
.await?;
let file_enabled = chat_manager.local_ai_controller.is_rag_enabled();
let plugin_state = chat_manager.local_ai_controller.get_chat_plugin_state();
let file_enabled = ai_manager.local_ai_controller.is_rag_enabled();
let plugin_state = ai_manager.local_ai_controller.get_chat_plugin_state();
let pb = LocalAIChatPB {
enabled,
file_enabled,
@ -299,15 +292,15 @@ pub(crate) async fn toggle_local_ai_chat_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn toggle_local_ai_chat_file_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalAIChatPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let enabled = chat_manager.local_ai_controller.is_chat_enabled();
let file_enabled = chat_manager
let ai_manager = upgrade_ai_manager(ai_manager)?;
let enabled = ai_manager.local_ai_controller.is_chat_enabled();
let file_enabled = ai_manager
.local_ai_controller
.toggle_local_ai_chat_rag()
.await?;
let plugin_state = chat_manager.local_ai_controller.get_chat_plugin_state();
let plugin_state = ai_manager.local_ai_controller.get_chat_plugin_state();
let pb = LocalAIChatPB {
enabled,
file_enabled,
@ -325,12 +318,12 @@ pub(crate) async fn toggle_local_ai_chat_file_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_local_ai_chat_state_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalAIChatPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let enabled = chat_manager.local_ai_controller.is_chat_enabled();
let file_enabled = chat_manager.local_ai_controller.is_rag_enabled();
let plugin_state = chat_manager.local_ai_controller.get_chat_plugin_state();
let ai_manager = upgrade_ai_manager(ai_manager)?;
let enabled = ai_manager.local_ai_controller.is_chat_enabled();
let file_enabled = ai_manager.local_ai_controller.is_rag_enabled();
let plugin_state = ai_manager.local_ai_controller.get_chat_plugin_state();
data_result_ok(LocalAIChatPB {
enabled,
file_enabled,
@ -339,37 +332,37 @@ pub(crate) async fn get_local_ai_chat_state_handler(
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn restart_local_ai_chat_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> Result<(), FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
chat_manager.local_ai_controller.restart_chat_plugin();
let ai_manager = upgrade_ai_manager(ai_manager)?;
ai_manager.local_ai_controller.restart_chat_plugin();
Ok(())
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn toggle_local_ai_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalAIPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let enabled = chat_manager.local_ai_controller.toggle_local_ai().await?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let enabled = ai_manager.local_ai_controller.toggle_local_ai().await?;
data_result_ok(LocalAIPB { enabled })
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_local_ai_state_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalAIPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let enabled = chat_manager.local_ai_controller.is_enabled();
let ai_manager = upgrade_ai_manager(ai_manager)?;
let enabled = ai_manager.local_ai_controller.is_enabled();
data_result_ok(LocalAIPB { enabled })
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_model_storage_directory_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<LocalModelStoragePB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let file_path = chat_manager
let ai_manager = upgrade_ai_manager(ai_manager)?;
let file_path = ai_manager
.local_ai_controller
.get_model_storage_directory()?;
data_result_ok(LocalModelStoragePB { file_path })
@ -377,12 +370,12 @@ pub(crate) async fn get_model_storage_directory_handler(
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_offline_app_handler(
chat_manager: AFPluginState<Weak<ChatManager>>,
ai_manager: AFPluginState<Weak<AIManager>>,
) -> DataResult<OfflineAIPB, FlowyError> {
let chat_manager = upgrade_chat_manager(chat_manager)?;
let ai_manager = upgrade_ai_manager(ai_manager)?;
let (tx, rx) = oneshot::channel::<Result<String, FlowyError>>();
tokio::spawn(async move {
let link = chat_manager
let link = ai_manager
.local_ai_controller
.get_offline_ai_app_download_link()
.await?;

View File

@ -2,67 +2,64 @@ use std::sync::{Arc, Weak};
use strum_macros::Display;
use crate::tools::AITools;
use crate::completion::AICompletion;
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
use lib_dispatch::prelude::*;
use crate::chat_manager::ChatManager;
use crate::ai_manager::AIManager;
use crate::event_handler::*;
pub fn init(chat_manager: Weak<ChatManager>) -> AFPlugin {
let user_service = Arc::downgrade(&chat_manager.upgrade().unwrap().user_service);
let cloud_service = Arc::downgrade(&chat_manager.upgrade().unwrap().cloud_service_wm);
let ai_tools = Arc::new(AITools::new(cloud_service, user_service));
pub fn init(ai_manager: Weak<AIManager>) -> AFPlugin {
let user_service = Arc::downgrade(&ai_manager.upgrade().unwrap().user_service);
let cloud_service = Arc::downgrade(&ai_manager.upgrade().unwrap().cloud_service_wm);
let ai_tools = Arc::new(AICompletion::new(cloud_service, user_service));
AFPlugin::new()
.name("Flowy-Chat")
.state(chat_manager)
.name("flowy-ai")
.state(ai_manager)
.state(ai_tools)
.event(ChatEvent::StreamMessage, stream_chat_message_handler)
.event(ChatEvent::LoadPrevMessage, load_prev_message_handler)
.event(ChatEvent::LoadNextMessage, load_next_message_handler)
.event(ChatEvent::GetRelatedQuestion, get_related_question_handler)
.event(ChatEvent::GetAnswerForQuestion, get_answer_handler)
.event(ChatEvent::StopStream, stop_stream_handler)
.event(AIEvent::StreamMessage, stream_chat_message_handler)
.event(AIEvent::LoadPrevMessage, load_prev_message_handler)
.event(AIEvent::LoadNextMessage, load_next_message_handler)
.event(AIEvent::GetRelatedQuestion, get_related_question_handler)
.event(AIEvent::GetAnswerForQuestion, get_answer_handler)
.event(AIEvent::StopStream, stop_stream_handler)
.event(
ChatEvent::RefreshLocalAIModelInfo,
AIEvent::RefreshLocalAIModelInfo,
refresh_local_ai_info_handler,
)
.event(ChatEvent::UpdateLocalLLM, update_local_llm_model_handler)
.event(ChatEvent::GetLocalLLMState, get_local_llm_state_handler)
.event(ChatEvent::CompleteText, start_complete_text_handler)
.event(ChatEvent::StopCompleteText, stop_complete_text_handler)
.event(ChatEvent::ChatWithFile, chat_file_handler)
.event(AIEvent::UpdateLocalLLM, update_local_llm_model_handler)
.event(AIEvent::GetLocalLLMState, get_local_llm_state_handler)
.event(AIEvent::CompleteText, start_complete_text_handler)
.event(AIEvent::StopCompleteText, stop_complete_text_handler)
.event(AIEvent::ChatWithFile, chat_file_handler)
.event(AIEvent::DownloadLLMResource, download_llm_resource_handler)
.event(
ChatEvent::DownloadLLMResource,
download_llm_resource_handler,
)
.event(
ChatEvent::CancelDownloadLLMResource,
AIEvent::CancelDownloadLLMResource,
cancel_download_llm_resource_handler,
)
.event(ChatEvent::GetLocalAIPluginState, get_plugin_state_handler)
.event(ChatEvent::ToggleLocalAIChat, toggle_local_ai_chat_handler)
.event(AIEvent::GetLocalAIPluginState, get_plugin_state_handler)
.event(AIEvent::ToggleLocalAIChat, toggle_local_ai_chat_handler)
.event(
ChatEvent::GetLocalAIChatState,
AIEvent::GetLocalAIChatState,
get_local_ai_chat_state_handler,
)
.event(ChatEvent::RestartLocalAIChat, restart_local_ai_chat_handler)
.event(ChatEvent::ToggleLocalAI, toggle_local_ai_handler)
.event(ChatEvent::GetLocalAIState, get_local_ai_state_handler)
.event(AIEvent::RestartLocalAIChat, restart_local_ai_chat_handler)
.event(AIEvent::ToggleLocalAI, toggle_local_ai_handler)
.event(AIEvent::GetLocalAIState, get_local_ai_state_handler)
.event(
ChatEvent::ToggleChatWithFile,
AIEvent::ToggleChatWithFile,
toggle_local_ai_chat_file_handler,
)
.event(
ChatEvent::GetModelStorageDirectory,
AIEvent::GetModelStorageDirectory,
get_model_storage_directory_handler,
)
.event(ChatEvent::GetOfflineAIAppLink, get_offline_app_handler)
.event(AIEvent::GetOfflineAIAppLink, get_offline_app_handler)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
#[event_err = "FlowyError"]
pub enum ChatEvent {
pub enum AIEvent {
/// Create a new workspace
#[event(input = "LoadPrevChatMessagePB", output = "ChatMessageListPB")]
LoadPrevMessage = 0,

View File

@ -1,12 +1,12 @@
mod event_handler;
pub mod event_map;
pub mod ai_manager;
mod chat;
pub mod chat_manager;
mod completion;
pub mod entities;
mod local_ai;
mod middleware;
pub mod notification;
mod persistence;
mod protobuf;
mod tools;

View File

@ -1,12 +1,12 @@
use crate::chat_manager::ChatUserService;
use crate::ai_manager::AIUserService;
use crate::entities::{LocalAIPluginStatePB, LocalModelResourcePB, RunningStatePB};
use crate::local_ai::local_llm_resource::{LLMResourceController, LLMResourceService};
use crate::local_ai::local_llm_resource::{LLMResourceService, LocalAIResourceController};
use crate::notification::{make_notification, ChatNotification, APPFLOWY_AI_NOTIFICATION_KEY};
use anyhow::Error;
use appflowy_local_ai::chat_plugin::{AIPluginConfig, LocalChatLLMChat};
use appflowy_local_ai::chat_plugin::{AIPluginConfig, AppFlowyLocalAI};
use appflowy_plugin::manager::PluginManager;
use appflowy_plugin::util::is_apple_silicon;
use flowy_chat_pub::cloud::{AppFlowyOfflineAI, ChatCloudService, LLMModel, LocalAIConfig};
use flowy_ai_pub::cloud::{AppFlowyOfflineAI, ChatCloudService, LLMModel, LocalAIConfig};
use flowy_error::{FlowyError, FlowyResult};
use flowy_sqlite::kv::KVStorePreferences;
use futures::Sink;
@ -18,7 +18,7 @@ use std::ops::Deref;
use std::sync::Arc;
use tokio::select;
use tokio_stream::StreamExt;
use tracing::{debug, error, info, instrument, trace};
use tracing::{debug, error, info, instrument};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LLMSetting {
@ -37,17 +37,17 @@ const APPFLOWY_LOCAL_AI_CHAT_RAG_ENABLED: &str = "appflowy_local_ai_chat_rag_ena
const LOCAL_AI_SETTING_KEY: &str = "appflowy_local_ai_setting:v0";
pub struct LocalAIController {
llm_chat: Arc<LocalChatLLMChat>,
llm_res: Arc<LLMResourceController>,
local_ai: Arc<AppFlowyLocalAI>,
local_ai_resource: Arc<LocalAIResourceController>,
current_chat_id: Mutex<Option<String>>,
store_preferences: Arc<KVStorePreferences>,
}
impl Deref for LocalAIController {
type Target = Arc<LocalChatLLMChat>;
type Target = Arc<AppFlowyLocalAI>;
fn deref(&self) -> &Self::Target {
&self.llm_chat
&self.local_ai
}
}
@ -55,10 +55,10 @@ impl LocalAIController {
pub fn new(
plugin_manager: Arc<PluginManager>,
store_preferences: Arc<KVStorePreferences>,
user_service: Arc<dyn ChatUserService>,
user_service: Arc<dyn AIUserService>,
cloud_service: Arc<dyn ChatCloudService>,
) -> Self {
let llm_chat = Arc::new(LocalChatLLMChat::new(plugin_manager));
let local_ai = Arc::new(AppFlowyLocalAI::new(plugin_manager));
let res_impl = LLMResourceServiceImpl {
user_service: user_service.clone(),
cloud_service,
@ -66,10 +66,10 @@ impl LocalAIController {
};
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
let llm_res = Arc::new(LLMResourceController::new(user_service, res_impl, tx));
let llm_res = Arc::new(LocalAIResourceController::new(user_service, res_impl, tx));
let current_chat_id = Mutex::new(None);
let mut running_state_rx = llm_chat.subscribe_running_state();
let mut running_state_rx = local_ai.subscribe_running_state();
let cloned_llm_res = llm_res.clone();
tokio::spawn(async move {
while let Some(state) = running_state_rx.next().await {
@ -89,16 +89,16 @@ impl LocalAIController {
});
let this = Self {
llm_chat,
llm_res,
local_ai,
local_ai_resource: llm_res,
current_chat_id,
store_preferences,
};
let rag_enabled = this.is_rag_enabled();
let cloned_llm_chat = this.llm_chat.clone();
let cloned_llm_res = this.llm_res.clone();
let mut offline_ai_watch = this.llm_res.subscribe_offline_app_state();
let cloned_llm_chat = this.local_ai.clone();
let cloned_llm_res = this.local_ai_resource.clone();
let mut offline_ai_watch = this.local_ai_resource.subscribe_offline_app_state();
tokio::spawn(async move {
let init_fn = || {
if let Ok(chat_config) = cloned_llm_res.get_chat_config(rag_enabled) {
@ -122,9 +122,11 @@ impl LocalAIController {
});
if this.can_init_plugin() {
let result = this.llm_res.get_chat_config(this.is_rag_enabled());
let result = this
.local_ai_resource
.get_chat_config(this.is_rag_enabled());
if let Ok(chat_config) = result {
if let Err(err) = initialize_ai_plugin(&this.llm_chat, chat_config, None) {
if let Err(err) = initialize_ai_plugin(&this.local_ai, chat_config, None) {
error!("[AI Plugin] failed to setup plugin: {:?}", err);
}
}
@ -133,17 +135,17 @@ impl LocalAIController {
this
}
pub async fn refresh(&self) -> FlowyResult<LLMModelInfo> {
self.llm_res.refresh_llm_resource().await
self.local_ai_resource.refresh_llm_resource().await
}
/// Returns true if the local AI is enabled and ready to use.
pub fn can_init_plugin(&self) -> bool {
self.is_enabled() && self.llm_res.is_resource_ready()
self.is_enabled() && self.local_ai_resource.is_resource_ready()
}
/// Indicate whether the local AI plugin is running.
pub fn is_running(&self) -> bool {
self.llm_chat.get_plugin_running_state().is_ready()
self.local_ai.get_plugin_running_state().is_ready()
}
/// Indicate whether the local AI is enabled.
@ -184,7 +186,7 @@ impl LocalAIController {
*self.current_chat_id.lock() = Some(chat_id.to_string());
let chat_id = chat_id.to_string();
let weak_ctrl = Arc::downgrade(&self.llm_chat);
let weak_ctrl = Arc::downgrade(&self.local_ai);
tokio::spawn(async move {
if let Some(ctrl) = weak_ctrl.upgrade() {
if let Err(err) = ctrl.create_chat(&chat_id).await {
@ -195,7 +197,7 @@ impl LocalAIController {
}
pub fn close_chat(&self, chat_id: &str) {
let weak_ctrl = Arc::downgrade(&self.llm_chat);
let weak_ctrl = Arc::downgrade(&self.local_ai);
let chat_id = chat_id.to_string();
tokio::spawn(async move {
if let Some(ctrl) = weak_ctrl.upgrade() {
@ -211,11 +213,19 @@ impl LocalAIController {
return Err(FlowyError::local_ai_unavailable());
}
let state = self.llm_res.use_local_llm(llm_id)?;
if let Some(model) = self.local_ai_resource.get_selected_model() {
if model.llm_id == llm_id {
return self.local_ai_resource.get_local_llm_state();
}
}
let state = self.local_ai_resource.use_local_llm(llm_id)?;
// Re-initialize the plugin if the setting is updated and ready to use
if self.llm_res.is_resource_ready() {
let chat_config = self.llm_res.get_chat_config(self.is_rag_enabled())?;
if let Err(err) = initialize_ai_plugin(&self.llm_chat, chat_config, None) {
if self.local_ai_resource.is_resource_ready() {
let chat_config = self
.local_ai_resource
.get_chat_config(self.is_rag_enabled())?;
if let Err(err) = initialize_ai_plugin(&self.local_ai, chat_config, None) {
error!("failed to setup plugin: {:?}", err);
}
}
@ -223,29 +233,32 @@ impl LocalAIController {
}
pub async fn get_local_llm_state(&self) -> FlowyResult<LocalModelResourcePB> {
self.llm_res.get_local_llm_state()
self.local_ai_resource.get_local_llm_state()
}
pub fn get_current_model(&self) -> Option<LLMModel> {
self.llm_res.get_selected_model()
self.local_ai_resource.get_selected_model()
}
pub async fn start_downloading<T>(&self, progress_sink: T) -> FlowyResult<String>
where
T: Sink<String, Error = anyhow::Error> + Unpin + Sync + Send + 'static,
{
let task_id = self.llm_res.start_downloading(progress_sink).await?;
let task_id = self
.local_ai_resource
.start_downloading(progress_sink)
.await?;
Ok(task_id)
}
pub fn cancel_download(&self) -> FlowyResult<()> {
self.llm_res.cancel_download()?;
self.local_ai_resource.cancel_download()?;
Ok(())
}
pub fn get_chat_plugin_state(&self) -> LocalAIPluginStatePB {
let offline_ai_ready = self.llm_res.is_offline_app_ready();
let state = self.llm_chat.get_plugin_running_state();
let offline_ai_ready = self.local_ai_resource.is_offline_app_ready();
let state = self.local_ai.get_plugin_running_state();
LocalAIPluginStatePB {
state: RunningStatePB::from(state),
offline_ai_ready,
@ -254,8 +267,8 @@ impl LocalAIController {
pub fn restart_chat_plugin(&self) {
let rag_enabled = self.is_rag_enabled();
if let Ok(chat_config) = self.llm_res.get_chat_config(rag_enabled) {
if let Err(err) = initialize_ai_plugin(&self.llm_chat, chat_config, None) {
if let Ok(chat_config) = self.local_ai_resource.get_chat_config(rag_enabled) {
if let Err(err) = initialize_ai_plugin(&self.local_ai, chat_config, None) {
error!("[AI Plugin] failed to setup plugin: {:?}", err);
}
}
@ -263,13 +276,16 @@ impl LocalAIController {
pub fn get_model_storage_directory(&self) -> FlowyResult<String> {
self
.llm_res
.local_ai_resource
.user_model_folder()
.map(|path| path.to_string_lossy().to_string())
}
pub async fn get_offline_ai_app_download_link(&self) -> FlowyResult<String> {
self.llm_res.get_offline_ai_app_download_link().await
self
.local_ai_resource
.get_offline_ai_app_download_link()
.await
}
pub async fn toggle_local_ai(&self) -> FlowyResult<bool> {
@ -322,12 +338,14 @@ impl LocalAIController {
info!("[AI Plugin] enable chat plugin: {}", enabled);
if enabled {
let (tx, rx) = tokio::sync::oneshot::channel();
let chat_config = self.llm_res.get_chat_config(self.is_rag_enabled())?;
if let Err(err) = initialize_ai_plugin(&self.llm_chat, chat_config, Some(tx)) {
let chat_config = self
.local_ai_resource
.get_chat_config(self.is_rag_enabled())?;
if let Err(err) = initialize_ai_plugin(&self.local_ai, chat_config, Some(tx)) {
error!("[AI Plugin] failed to initialize local ai: {:?}", err);
}
let _ = rx.await;
} else if let Err(err) = self.llm_chat.destroy_chat_plugin().await {
} else if let Err(err) = self.local_ai.destroy_chat_plugin().await {
error!("[AI Plugin] failed to destroy plugin: {:?}", err);
}
Ok(())
@ -336,14 +354,14 @@ impl LocalAIController {
#[instrument(level = "debug", skip_all, err)]
fn initialize_ai_plugin(
llm_chat: &Arc<LocalChatLLMChat>,
llm_chat: &Arc<AppFlowyLocalAI>,
mut chat_config: AIPluginConfig,
ret: Option<tokio::sync::oneshot::Sender<()>>,
) -> FlowyResult<()> {
let llm_chat = llm_chat.clone();
tokio::spawn(async move {
trace!("[AI Plugin] config: {:?}", chat_config);
info!("[AI Plugin] config: {:?}", chat_config);
if is_apple_silicon().await.unwrap_or(false) {
chat_config = chat_config.with_device("gpu");
}
@ -360,7 +378,7 @@ fn initialize_ai_plugin(
}
pub struct LLMResourceServiceImpl {
user_service: Arc<dyn ChatUserService>,
user_service: Arc<dyn AIUserService>,
cloud_service: Arc<dyn ChatCloudService>,
store_preferences: Arc<KVStorePreferences>,
}

View File

@ -1,10 +1,10 @@
use crate::chat_manager::ChatUserService;
use crate::ai_manager::AIUserService;
use crate::entities::{LocalModelResourcePB, PendingResourcePB, PendingResourceTypePB};
use crate::local_ai::local_llm_chat::{LLMModelInfo, LLMSetting};
use crate::local_ai::model_request::download_model;
use appflowy_local_ai::chat_plugin::AIPluginConfig;
use flowy_chat_pub::cloud::{LLMModel, LocalAIConfig, ModelInfo};
use flowy_ai_pub::cloud::{LLMModel, LocalAIConfig, ModelInfo};
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use futures::Sink;
use futures_util::SinkExt;
@ -61,8 +61,8 @@ impl DownloadTask {
}
}
pub struct LLMResourceController {
user_service: Arc<dyn ChatUserService>,
pub struct LocalAIResourceController {
user_service: Arc<dyn AIUserService>,
resource_service: Arc<dyn LLMResourceService>,
llm_setting: RwLock<Option<LLMSetting>>,
// The ai_config will be set when user try to get latest local ai config from server
@ -75,9 +75,9 @@ pub struct LLMResourceController {
offline_app_state_sender: tokio::sync::broadcast::Sender<WatchDiskEvent>,
}
impl LLMResourceController {
impl LocalAIResourceController {
pub fn new(
user_service: Arc<dyn ChatUserService>,
user_service: Arc<dyn AIUserService>,
resource_service: impl LLMResourceService,
resource_notify: tokio::sync::mpsc::Sender<()>,
) -> Self {
@ -171,7 +171,7 @@ impl LLMResourceController {
#[instrument(level = "info", skip_all, err)]
pub fn use_local_llm(&self, llm_id: i64) -> FlowyResult<LocalModelResourcePB> {
let (package, llm_config) = self
let (app, llm_model) = self
.ai_config
.read()
.as_ref()
@ -186,8 +186,8 @@ impl LLMResourceController {
.ok_or_else(|| FlowyError::local_ai().with_context("No local ai config found"))?;
let llm_setting = LLMSetting {
app: package,
llm_model: llm_config.clone(),
app,
llm_model: llm_model.clone(),
};
trace!("[LLM Resource] Selected AI setting: {:?}", llm_setting);

View File

@ -1,11 +1,11 @@
use crate::chat_manager::ChatUserService;
use crate::ai_manager::AIUserService;
use crate::entities::{ChatStatePB, ModelTypePB};
use crate::local_ai::local_llm_chat::LocalAIController;
use crate::notification::{make_notification, ChatNotification, APPFLOWY_AI_NOTIFICATION_KEY};
use crate::persistence::select_single_message;
use appflowy_plugin::error::PluginError;
use flowy_chat_pub::cloud::{
use flowy_ai_pub::cloud::{
ChatCloudService, ChatMessage, ChatMessageType, CompletionType, LocalAIConfig, MessageCursor,
RelatedQuestion, RepeatedChatMessage, RepeatedRelatedQuestion, StreamAnswer, StreamComplete,
};
@ -17,15 +17,15 @@ use lib_infra::future::FutureResult;
use std::path::PathBuf;
use std::sync::Arc;
pub struct CloudServiceMiddleware {
pub struct AICloudServiceMiddleware {
cloud_service: Arc<dyn ChatCloudService>,
user_service: Arc<dyn ChatUserService>,
user_service: Arc<dyn AIUserService>,
local_llm_controller: Arc<LocalAIController>,
}
impl CloudServiceMiddleware {
impl AICloudServiceMiddleware {
pub fn new(
user_service: Arc<dyn ChatUserService>,
user_service: Arc<dyn AIUserService>,
cloud_service: Arc<dyn ChatCloudService>,
local_llm_controller: Arc<LocalAIController>,
) -> Self {
@ -67,7 +67,7 @@ impl CloudServiceMiddleware {
}
#[async_trait]
impl ChatCloudService for CloudServiceMiddleware {
impl ChatCloudService for AICloudServiceMiddleware {
fn create_chat(
&self,
uid: &i64,

View File

@ -33,8 +33,10 @@ uuid.workspace = true
flowy-storage = { workspace = true }
flowy-storage-pub = { workspace = true }
client-api.workspace = true
flowy-chat = { workspace = true }
flowy-chat-pub = { workspace = true }
flowy-ai = { workspace = true }
flowy-ai-pub = { workspace = true }
appflowy-local-ai = { version = "0.1.0" }
tracing.workspace = true
futures-core = { version = "0.3", default-features = false }
@ -65,7 +67,7 @@ dart = [
"flowy-search/dart",
"flowy-folder/dart",
"flowy-database2/dart",
"flowy-chat/dart",
"flowy-ai/dart",
"flowy-storage/dart",
]
ts = [
@ -74,7 +76,7 @@ ts = [
"flowy-search/tauri_ts",
"flowy-database2/ts",
"flowy-config/tauri_ts",
"flowy-chat/tauri_ts",
"flowy-ai/tauri_ts",
"flowy-storage/tauri_ts",
]
openssl_vendored = ["flowy-sqlite/openssl_vendored"]

View File

@ -1,5 +1,5 @@
use flowy_chat::chat_manager::{ChatManager, ChatUserService};
use flowy_chat_pub::cloud::ChatCloudService;
use flowy_ai::ai_manager::{AIManager, AIUserService};
use flowy_ai_pub::cloud::ChatCloudService;
use flowy_error::FlowyError;
use flowy_sqlite::kv::KVStorePreferences;
use flowy_sqlite::DBConnection;
@ -14,9 +14,9 @@ impl ChatDepsResolver {
authenticate_user: Weak<AuthenticateUser>,
cloud_service: Arc<dyn ChatCloudService>,
store_preferences: Arc<KVStorePreferences>,
) -> Arc<ChatManager> {
) -> Arc<AIManager> {
let user_service = ChatUserServiceImpl(authenticate_user);
Arc::new(ChatManager::new(
Arc::new(AIManager::new(
cloud_service,
user_service,
store_preferences,
@ -35,7 +35,7 @@ impl ChatUserServiceImpl {
}
}
impl ChatUserService for ChatUserServiceImpl {
impl AIUserService for ChatUserServiceImpl {
fn user_id(&self) -> Result<i64, FlowyError> {
self.upgrade_user()?.user_id()
}

View File

@ -1,12 +1,19 @@
use appflowy_local_ai::ai_ops::{LocalAITranslateItem, LocalAITranslateRowData};
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
use collab_integrate::CollabKVDB;
use flowy_ai::ai_manager::AIManager;
use flowy_database2::{DatabaseManager, DatabaseUser};
use flowy_database_pub::cloud::DatabaseCloudService;
use flowy_database_pub::cloud::{
DatabaseAIService, DatabaseCloudService, SummaryRowContent, TranslateRowContent,
TranslateRowResponse,
};
use flowy_error::FlowyError;
use flowy_user::services::authenticate_user::AuthenticateUser;
use lib_infra::async_trait::async_trait;
use lib_infra::priority_task::TaskDispatcher;
use std::sync::{Arc, Weak};
use tokio::sync::RwLock;
pub struct DatabaseDepsResolver();
impl DatabaseDepsResolver {
@ -15,6 +22,8 @@ impl DatabaseDepsResolver {
task_scheduler: Arc<RwLock<TaskDispatcher>>,
collab_builder: Arc<AppFlowyCollabBuilder>,
cloud_service: Arc<dyn DatabaseCloudService>,
ai_service: Arc<dyn DatabaseAIService>,
ai_manager: Arc<AIManager>,
) -> Arc<DatabaseManager> {
let user = Arc::new(DatabaseUserImpl(authenticate_user));
Arc::new(DatabaseManager::new(
@ -22,10 +31,76 @@ impl DatabaseDepsResolver {
task_scheduler,
collab_builder,
cloud_service,
Arc::new(DatabaseAIServiceMiddleware {
ai_manager,
ai_service,
}),
))
}
}
struct DatabaseAIServiceMiddleware {
ai_manager: Arc<AIManager>,
ai_service: Arc<dyn DatabaseAIService>,
}
#[async_trait]
impl DatabaseAIService for DatabaseAIServiceMiddleware {
async fn summary_database_row(
&self,
workspace_id: &str,
object_id: &str,
summary_row: SummaryRowContent,
) -> Result<String, FlowyError> {
if self.ai_manager.local_ai_controller.is_running() {
self
.ai_manager
.local_ai_controller
.summary_database_row(summary_row)
.await
.map_err(|err| FlowyError::local_ai().with_context(err))
} else {
self
.ai_service
.summary_database_row(workspace_id, object_id, summary_row)
.await
}
}
async fn translate_database_row(
&self,
workspace_id: &str,
translate_row: TranslateRowContent,
language: &str,
) -> Result<TranslateRowResponse, FlowyError> {
if self.ai_manager.local_ai_controller.is_running() {
let data = LocalAITranslateRowData {
cells: translate_row
.into_iter()
.map(|row| LocalAITranslateItem {
title: row.title,
content: row.content,
})
.collect(),
language: language.to_string(),
include_header: false,
};
let resp = self
.ai_manager
.local_ai_controller
.translate_database_row(data)
.await
.map_err(|err| FlowyError::local_ai().with_context(err))?;
Ok(TranslateRowResponse { items: resp.items })
} else {
self
.ai_service
.translate_database_row(workspace_id, translate_row, language)
.await
}
}
}
struct DatabaseUserImpl(Weak<AuthenticateUser>);
impl DatabaseUserImpl {
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {

View File

@ -3,7 +3,7 @@ use bytes::Bytes;
use collab_entity::{CollabType, EncodedCollab};
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
use collab_integrate::CollabKVDB;
use flowy_chat::chat_manager::ChatManager;
use flowy_ai::ai_manager::AIManager;
use flowy_database2::entities::DatabaseLayoutPB;
use flowy_database2::services::share::csv::CSVFormat;
use flowy_database2::template::{make_default_board, make_default_calendar, make_default_grid};
@ -68,7 +68,7 @@ impl FolderDepsResolver {
pub fn folder_operation_handlers(
document_manager: Arc<DocumentManager>,
database_manager: Arc<DatabaseManager>,
chat_manager: Arc<ChatManager>,
chat_manager: Arc<AIManager>,
) -> FolderOperationHandlers {
let mut map: HashMap<ViewLayout, Arc<dyn FolderOperationHandler + Send + Sync>> = HashMap::new();
@ -598,7 +598,7 @@ impl CreateDatabaseExtParams {
}
}
struct ChatFolderOperation(Arc<ChatManager>);
struct ChatFolderOperation(Arc<AIManager>);
impl FolderOperationHandler for ChatFolderOperation {
fn open_view(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let manager = self.0.clone();

View File

@ -18,13 +18,13 @@ use tracing::{debug, info};
use collab_integrate::collab_builder::{
CollabCloudPluginProvider, CollabPluginProviderContext, CollabPluginProviderType,
};
use flowy_chat_pub::cloud::{
use flowy_ai_pub::cloud::{
ChatCloudService, ChatMessage, LocalAIConfig, MessageCursor, RepeatedChatMessage, StreamAnswer,
StreamComplete,
};
use flowy_database_pub::cloud::{
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
TranslateRowContent, TranslateRowResponse,
CollabDocStateByOid, DatabaseAIService, DatabaseCloudService, DatabaseSnapshot,
SummaryRowContent, TranslateRowContent, TranslateRowResponse,
};
use flowy_document::deps::DocumentData;
use flowy_document_pub::cloud::{DocumentCloudService, DocumentSnapshot};
@ -364,6 +364,7 @@ impl FolderCloudService for ServerProvider {
}
}
#[async_trait]
impl DatabaseCloudService for ServerProvider {
fn get_database_object_doc_state(
&self,
@ -412,39 +413,36 @@ impl DatabaseCloudService for ServerProvider {
.await
})
}
}
fn summary_database_row(
#[async_trait]
impl DatabaseAIService for ServerProvider {
async fn summary_database_row(
&self,
workspace_id: &str,
object_id: &str,
summary_row: SummaryRowContent,
) -> FutureResult<String, FlowyError> {
let workspace_id = workspace_id.to_string();
let server = self.get_server();
let object_id = object_id.to_string();
FutureResult::new(async move {
server?
.database_service()
.summary_database_row(&workspace_id, &object_id, summary_row)
.await
})
) -> Result<String, FlowyError> {
self
.get_server()?
.database_ai_service()
.ok_or_else(FlowyError::not_support)?
.summary_database_row(workspace_id, object_id, summary_row)
.await
}
fn translate_database_row(
async fn translate_database_row(
&self,
workspace_id: &str,
translate_row: TranslateRowContent,
language: &str,
) -> FutureResult<TranslateRowResponse, FlowyError> {
let workspace_id = workspace_id.to_string();
let server = self.get_server();
let language = language.to_string();
FutureResult::new(async move {
server?
.database_service()
.translate_database_row(&workspace_id, translate_row, &language)
.await
})
) -> Result<TranslateRowResponse, FlowyError> {
self
.get_server()?
.database_ai_service()
.ok_or_else(FlowyError::not_support)?
.translate_database_row(workspace_id, translate_row, language)
.await
}
}

View File

@ -6,7 +6,7 @@ use tracing::{event, trace};
use collab_entity::CollabType;
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
use flowy_chat::chat_manager::ChatManager;
use flowy_ai::ai_manager::AIManager;
use flowy_database2::DatabaseManager;
use flowy_document::manager::DocumentManager;
use flowy_error::{FlowyError, FlowyResult};
@ -26,7 +26,7 @@ pub(crate) struct UserStatusCallbackImpl {
pub(crate) document_manager: Arc<DocumentManager>,
pub(crate) server_provider: Arc<ServerProvider>,
pub(crate) storage_manager: Arc<StorageManager>,
pub(crate) chat_manager: Arc<ChatManager>,
pub(crate) ai_manager: Arc<AIManager>,
}
impl UserStatusCallback for UserStatusCallbackImpl {
@ -235,7 +235,7 @@ impl UserStatusCallback for UserStatusCallbackImpl {
}
if local_ai_enabled {
self.chat_manager.local_ai_purchased();
self.ai_manager.local_ai_purchased();
}
}

View File

@ -9,7 +9,7 @@ use tokio::sync::RwLock;
use tracing::{debug, error, event, info, instrument};
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabPluginProviderType};
use flowy_chat::chat_manager::ChatManager;
use flowy_ai::ai_manager::AIManager;
use flowy_database2::DatabaseManager;
use flowy_document::manager::DocumentManager;
use flowy_error::{FlowyError, FlowyResult};
@ -59,7 +59,7 @@ pub struct AppFlowyCore {
pub task_dispatcher: Arc<RwLock<TaskDispatcher>>,
pub store_preference: Arc<KVStorePreferences>,
pub search_manager: Arc<SearchManager>,
pub chat_manager: Arc<ChatManager>,
pub ai_manager: Arc<AIManager>,
pub storage_manager: Arc<StorageManager>,
}
@ -143,7 +143,7 @@ impl AppFlowyCore {
document_manager,
collab_builder,
search_manager,
chat_manager,
ai_manager,
storage_manager,
) = async {
let storage_manager = FileStorageResolver::resolve(
@ -161,11 +161,19 @@ impl AppFlowyCore {
collab_builder
.set_snapshot_persistence(Arc::new(SnapshotDBImpl(Arc::downgrade(&authenticate_user))));
let ai_manager = ChatDepsResolver::resolve(
Arc::downgrade(&authenticate_user),
server_provider.clone(),
store_preference.clone(),
);
let database_manager = DatabaseDepsResolver::resolve(
Arc::downgrade(&authenticate_user),
task_dispatcher.clone(),
collab_builder.clone(),
server_provider.clone(),
server_provider.clone(),
ai_manager.clone(),
)
.await;
@ -177,12 +185,6 @@ impl AppFlowyCore {
Arc::downgrade(&storage_manager.storage_service),
);
let chat_manager = ChatDepsResolver::resolve(
Arc::downgrade(&authenticate_user),
server_provider.clone(),
store_preference.clone(),
);
let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Some(Arc::downgrade(
&authenticate_user,
))));
@ -190,7 +192,7 @@ impl AppFlowyCore {
let folder_operation_handlers = folder_operation_handlers(
document_manager.clone(),
database_manager.clone(),
chat_manager.clone(),
ai_manager.clone(),
);
let folder_manager = FolderDepsResolver::resolve(
@ -228,7 +230,7 @@ impl AppFlowyCore {
document_manager,
collab_builder,
search_manager,
chat_manager,
ai_manager,
storage_manager,
)
}
@ -241,7 +243,7 @@ impl AppFlowyCore {
document_manager: document_manager.clone(),
server_provider: server_provider.clone(),
storage_manager: storage_manager.clone(),
chat_manager: chat_manager.clone(),
ai_manager: ai_manager.clone(),
};
let collab_interact_impl = CollabInteractImpl {
@ -266,7 +268,7 @@ impl AppFlowyCore {
Arc::downgrade(&user_manager),
Arc::downgrade(&document_manager),
Arc::downgrade(&search_manager),
Arc::downgrade(&chat_manager),
Arc::downgrade(&ai_manager),
),
));
@ -281,7 +283,7 @@ impl AppFlowyCore {
task_dispatcher,
store_preference,
search_manager,
chat_manager,
ai_manager,
storage_manager,
}
}

View File

@ -1,4 +1,4 @@
use flowy_chat::chat_manager::ChatManager;
use flowy_ai::ai_manager::AIManager;
use std::sync::Weak;
use flowy_database2::DatabaseManager;
@ -14,7 +14,7 @@ pub fn make_plugins(
user_session: Weak<UserManager>,
document_manager2: Weak<DocumentManager2>,
search_manager: Weak<SearchManager>,
chat_manager: Weak<ChatManager>,
ai_manager: Weak<AIManager>,
) -> Vec<AFPlugin> {
let store_preferences = user_session
.upgrade()
@ -27,7 +27,7 @@ pub fn make_plugins(
let config_plugin = flowy_config::event_map::init(store_preferences);
let date_plugin = flowy_date::event_map::init();
let search_plugin = flowy_search::event_map::init(search_manager);
let chat_plugin = flowy_chat::event_map::init(chat_manager);
let ai_plugin = flowy_ai::event_map::init(ai_manager);
vec![
user_plugin,
folder_plugin,
@ -36,6 +36,6 @@ pub fn make_plugins(
config_plugin,
date_plugin,
search_plugin,
chat_plugin,
ai_plugin,
]
}

View File

@ -3,18 +3,43 @@ pub use client_api::entity::ai_dto::{TranslateItem, TranslateRowResponse};
use collab::core::collab::DataSource;
use collab_entity::CollabType;
use flowy_error::FlowyError;
use lib_infra::async_trait::async_trait;
use lib_infra::future::FutureResult;
use std::collections::HashMap;
pub type CollabDocStateByOid = HashMap<String, DataSource>;
pub type SummaryRowContent = HashMap<String, String>;
pub type TranslateRowContent = Vec<TranslateItem>;
#[async_trait]
pub trait DatabaseAIService: Send + Sync {
async fn summary_database_row(
&self,
_workspace_id: &str,
_object_id: &str,
_summary_row: SummaryRowContent,
) -> Result<String, FlowyError> {
Ok("".to_string())
}
async fn translate_database_row(
&self,
_workspace_id: &str,
_translate_row: TranslateRowContent,
_language: &str,
) -> Result<TranslateRowResponse, FlowyError> {
Ok(TranslateRowResponse::default())
}
}
/// A trait for database cloud service.
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
/// [flowy-server] crate for more information.
///
/// returns the doc state of the object with the given object_id.
/// None if the object is not found.
///
#[async_trait]
pub trait DatabaseCloudService: Send + Sync {
fn get_database_object_doc_state(
&self,
@ -35,20 +60,6 @@ pub trait DatabaseCloudService: Send + Sync {
object_id: &str,
limit: usize,
) -> FutureResult<Vec<DatabaseSnapshot>, Error>;
fn summary_database_row(
&self,
workspace_id: &str,
object_id: &str,
summary_row: SummaryRowContent,
) -> FutureResult<String, FlowyError>;
fn translate_database_row(
&self,
workspace_id: &str,
translate_row: TranslateRowContent,
language: &str,
) -> FutureResult<TranslateRowResponse, FlowyError>;
}
pub struct DatabaseSnapshot {

View File

@ -1099,9 +1099,15 @@ pub(crate) async fn summarize_row_handler(
let manager = upgrade_manager(manager)?;
let data = data.into_inner();
let row_id = RowId::from(data.row_id);
manager
.summarize_row(data.view_id, row_id, data.field_id)
.await?;
let (tx, rx) = oneshot::channel();
af_spawn(async move {
let result = manager
.summarize_row(data.view_id, row_id, data.field_id)
.await;
let _ = tx.send(result);
});
rx.await??;
Ok(())
}
@ -1112,8 +1118,14 @@ pub(crate) async fn translate_row_handler(
let manager = upgrade_manager(manager)?;
let data = data.try_into_inner()?;
let row_id = RowId::from(data.row_id);
manager
.translate_row(data.view_id, row_id, data.field_id)
.await?;
let (tx, rx) = oneshot::channel();
af_spawn(async move {
let result = manager
.translate_row(data.view_id, row_id, data.field_id)
.await;
let _ = tx.send(result);
});
rx.await??;
Ok(())
}

View File

@ -18,7 +18,7 @@ use tracing::{event, instrument, trace};
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig};
use collab_integrate::{CollabKVAction, CollabKVDB, CollabPersistenceConfig};
use flowy_database_pub::cloud::{
DatabaseCloudService, SummaryRowContent, TranslateItem, TranslateRowContent,
DatabaseAIService, DatabaseCloudService, SummaryRowContent, TranslateItem, TranslateRowContent,
};
use flowy_error::{internal_error, FlowyError, FlowyResult};
use lib_infra::box_any::BoxAny;
@ -47,6 +47,7 @@ pub struct DatabaseManager {
editors: Mutex<HashMap<String, Arc<DatabaseEditor>>>,
collab_builder: Arc<AppFlowyCollabBuilder>,
cloud_service: Arc<dyn DatabaseCloudService>,
ai_service: Arc<dyn DatabaseAIService>,
}
impl DatabaseManager {
@ -55,6 +56,7 @@ impl DatabaseManager {
task_scheduler: Arc<RwLock<TaskDispatcher>>,
collab_builder: Arc<AppFlowyCollabBuilder>,
cloud_service: Arc<dyn DatabaseCloudService>,
ai_service: Arc<dyn DatabaseAIService>,
) -> Self {
Self {
user: database_user,
@ -63,6 +65,7 @@ impl DatabaseManager {
editors: Default::default(),
collab_builder,
cloud_service,
ai_service,
}
}
@ -479,7 +482,7 @@ impl DatabaseManager {
summary_row_content
);
let response = self
.cloud_service
.ai_service
.summary_database_row(&self.user.workspace_id()?, &row_id, summary_row_content)
.await?;
trace!("[AI]:summarize row response: {}", response);
@ -540,7 +543,7 @@ impl DatabaseManager {
translate_row_content
);
let response = self
.cloud_service
.ai_service
.translate_database_row(&self.user.workspace_id()?, translate_row_content, &language)
.await?;

View File

@ -43,7 +43,7 @@ flowy-search-pub = { workspace = true }
flowy-encrypt = { workspace = true }
flowy-storage = { workspace = true }
flowy-storage-pub = { workspace = true }
flowy-chat-pub = { workspace = true }
flowy-ai-pub = { workspace = true }
mime_guess = "2.0"
url = "2.4"
tokio-util = "0.7"

View File

@ -4,7 +4,7 @@ use client_api::entity::{
CreateAnswerMessageParams, CreateChatMessageParams, CreateChatParams, MessageCursor,
RepeatedChatMessage,
};
use flowy_chat_pub::cloud::{
use flowy_ai_pub::cloud::{
ChatCloudService, ChatMessage, ChatMessageType, LocalAIConfig, StreamAnswer, StreamComplete,
};
use flowy_error::FlowyError;

View File

@ -13,10 +13,11 @@ use std::sync::Arc;
use tracing::{error, instrument};
use flowy_database_pub::cloud::{
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
TranslateRowContent, TranslateRowResponse,
CollabDocStateByOid, DatabaseAIService, DatabaseCloudService, DatabaseSnapshot,
SummaryRowContent, TranslateRowContent, TranslateRowResponse,
};
use flowy_error::FlowyError;
use lib_infra::async_trait::async_trait;
use lib_infra::future::FutureResult;
use crate::af_cloud::define::ServerUser;
@ -28,6 +29,7 @@ pub(crate) struct AFCloudDatabaseCloudServiceImpl<T> {
pub user: Arc<dyn ServerUser>,
}
#[async_trait]
impl<T> DatabaseCloudService for AFCloudDatabaseCloudServiceImpl<T>
where
T: AFServer,
@ -121,48 +123,48 @@ where
) -> FutureResult<Vec<DatabaseSnapshot>, Error> {
FutureResult::new(async move { Ok(vec![]) })
}
}
fn summary_database_row(
#[async_trait]
impl<T> DatabaseAIService for AFCloudDatabaseCloudServiceImpl<T>
where
T: AFServer,
{
async fn summary_database_row(
&self,
workspace_id: &str,
_object_id: &str,
summary_row: SummaryRowContent,
) -> FutureResult<String, FlowyError> {
let workspace_id = workspace_id.to_string();
) -> Result<String, FlowyError> {
let try_get_client = self.inner.try_get_client();
FutureResult::new(async move {
let map: Map<String, Value> = summary_row
.into_iter()
.map(|(key, value)| (key, Value::String(value)))
.collect();
let params = SummarizeRowParams {
workspace_id,
data: SummarizeRowData::Content(map),
};
let data = try_get_client?.summarize_row(params).await?;
Ok(data.text)
})
let map: Map<String, Value> = summary_row
.into_iter()
.map(|(key, value)| (key, Value::String(value)))
.collect();
let params = SummarizeRowParams {
workspace_id: workspace_id.to_string(),
data: SummarizeRowData::Content(map),
};
let data = try_get_client?.summarize_row(params).await?;
Ok(data.text)
}
fn translate_database_row(
async fn translate_database_row(
&self,
workspace_id: &str,
translate_row: TranslateRowContent,
language: &str,
) -> FutureResult<TranslateRowResponse, FlowyError> {
let language = language.to_string();
) -> Result<TranslateRowResponse, FlowyError> {
let workspace_id = workspace_id.to_string();
let try_get_client = self.inner.try_get_client();
FutureResult::new(async move {
let data = TranslateRowData {
cells: translate_row,
language,
include_header: false,
};
let data = TranslateRowData {
cells: translate_row,
language: language.to_string(),
include_header: false,
};
let params = TranslateRowParams { workspace_id, data };
let data = try_get_client?.translate_row(params).await?;
Ok(data)
})
let params = TranslateRowParams { workspace_id, data };
let data = try_get_client?.translate_row(params).await?;
Ok(data)
}
}

View File

@ -14,8 +14,8 @@ use client_api::ws::{
};
use client_api::{Client, ClientConfiguration};
use flowy_chat_pub::cloud::ChatCloudService;
use flowy_database_pub::cloud::DatabaseCloudService;
use flowy_ai_pub::cloud::ChatCloudService;
use flowy_database_pub::cloud::{DatabaseAIService, DatabaseCloudService};
use flowy_document_pub::cloud::DocumentCloudService;
use flowy_error::{ErrorCode, FlowyError};
use flowy_folder_pub::cloud::FolderCloudService;
@ -216,6 +216,16 @@ impl AppFlowyServer for AppFlowyCloudServer {
})
}
fn database_ai_service(&self) -> Option<Arc<dyn DatabaseAIService>> {
let server = AFServerImpl {
client: self.get_client(),
};
Some(Arc::new(AFCloudDatabaseCloudServiceImpl {
inner: server,
user: self.user.clone(),
}))
}
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
let server = AFServerImpl {
client: self.get_client(),

View File

@ -1,6 +1,6 @@
use client_api::entity::ai_dto::{CompletionType, LocalAIConfig, RepeatedRelatedQuestion};
use client_api::entity::{ChatMessageType, MessageCursor, RepeatedChatMessage};
use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, StreamAnswer, StreamComplete};
use flowy_ai_pub::cloud::{ChatCloudService, ChatMessage, StreamAnswer, StreamComplete};
use flowy_error::FlowyError;
use lib_infra::async_trait::async_trait;
use lib_infra::future::FutureResult;

View File

@ -4,15 +4,14 @@ use collab_entity::define::{DATABASE, DATABASE_ROW_DATA, WORKSPACE_DATABASES};
use collab_entity::CollabType;
use yrs::MapPrelim;
use flowy_database_pub::cloud::{
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
TranslateRowContent, TranslateRowResponse,
};
use flowy_error::FlowyError;
use flowy_database_pub::cloud::{CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot};
use lib_infra::async_trait::async_trait;
use lib_infra::future::FutureResult;
pub(crate) struct LocalServerDatabaseCloudServiceImpl();
#[async_trait]
impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
fn get_database_object_doc_state(
&self,
@ -77,24 +76,4 @@ impl DatabaseCloudService for LocalServerDatabaseCloudServiceImpl {
) -> FutureResult<Vec<DatabaseSnapshot>, Error> {
FutureResult::new(async move { Ok(vec![]) })
}
fn summary_database_row(
&self,
_workspace_id: &str,
_object_id: &str,
_summary_row: SummaryRowContent,
) -> FutureResult<String, FlowyError> {
// TODO(lucas): local ai
FutureResult::new(async move { Ok("".to_string()) })
}
fn translate_database_row(
&self,
_workspace_id: &str,
_translate_row: TranslateRowContent,
_language: &str,
) -> FutureResult<TranslateRowResponse, FlowyError> {
// TODO(lucas): local ai
FutureResult::new(async move { Ok(TranslateRowResponse::default()) })
}
}

View File

@ -4,7 +4,7 @@ use std::sync::Arc;
use parking_lot::RwLock;
use tokio::sync::mpsc;
use flowy_database_pub::cloud::DatabaseCloudService;
use flowy_database_pub::cloud::{DatabaseAIService, DatabaseCloudService};
use flowy_document_pub::cloud::DocumentCloudService;
use flowy_error::FlowyError;
use flowy_folder_pub::cloud::FolderCloudService;
@ -75,4 +75,8 @@ impl AppFlowyServer for LocalServer {
fn search_service(&self) -> Option<Arc<dyn SearchCloudService>> {
None
}
fn database_ai_service(&self) -> Option<Arc<dyn DatabaseAIService>> {
None
}
}

View File

@ -6,14 +6,14 @@ use std::sync::Arc;
use anyhow::Error;
use client_api::collab_sync::ServerCollabMessage;
use flowy_chat_pub::cloud::ChatCloudService;
use flowy_ai_pub::cloud::ChatCloudService;
use parking_lot::RwLock;
use tokio_stream::wrappers::WatchStream;
#[cfg(feature = "enable_supabase")]
use {collab_entity::CollabObject, collab_plugins::cloud_storage::RemoteCollabStorage};
use crate::default_impl::DefaultChatCloudServiceImpl;
use flowy_database_pub::cloud::DatabaseCloudService;
use flowy_database_pub::cloud::{DatabaseAIService, DatabaseCloudService};
use flowy_document_pub::cloud::DocumentCloudService;
use flowy_folder_pub::cloud::FolderCloudService;
use flowy_storage_pub::cloud::StorageCloudService;
@ -93,6 +93,8 @@ pub trait AppFlowyServer: Send + Sync + 'static {
/// An `Arc` wrapping the `DatabaseCloudService` interface.
fn database_service(&self) -> Arc<dyn DatabaseCloudService>;
fn database_ai_service(&self) -> Option<Arc<dyn DatabaseAIService>>;
/// Facilitates cloud-based document management. This service offers operations for updating documents,
/// fetching snapshots, and accessing primary document data in an asynchronous manner.
///

View File

@ -2,12 +2,10 @@ use anyhow::Error;
use collab_entity::CollabType;
use tokio::sync::oneshot::channel;
use flowy_database_pub::cloud::{
CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent,
TranslateRowContent, TranslateRowResponse,
};
use flowy_error::FlowyError;
use flowy_database_pub::cloud::{CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot};
use lib_dispatch::prelude::af_spawn;
use lib_infra::async_trait::async_trait;
use lib_infra::future::FutureResult;
use crate::supabase::api::request::{
@ -25,6 +23,7 @@ impl<T> SupabaseDatabaseServiceImpl<T> {
}
}
#[async_trait]
impl<T> DatabaseCloudService for SupabaseDatabaseServiceImpl<T>
where
T: SupabaseServerService,
@ -98,22 +97,4 @@ where
Ok(snapshots)
})
}
fn summary_database_row(
&self,
_workspace_id: &str,
_object_id: &str,
_summary_row: SummaryRowContent,
) -> FutureResult<String, FlowyError> {
FutureResult::new(async move { Ok("".to_string()) })
}
fn translate_database_row(
&self,
_workspace_id: &str,
_translate_row: TranslateRowContent,
_language: &str,
) -> FutureResult<TranslateRowResponse, FlowyError> {
FutureResult::new(async move { Ok(TranslateRowResponse::default()) })
}
}

View File

@ -6,7 +6,7 @@ use collab_entity::CollabObject;
use collab_plugins::cloud_storage::{RemoteCollabStorage, RemoteUpdateSender};
use parking_lot::RwLock;
use flowy_database_pub::cloud::DatabaseCloudService;
use flowy_database_pub::cloud::{DatabaseAIService, DatabaseCloudService};
use flowy_document_pub::cloud::DocumentCloudService;
use flowy_folder_pub::cloud::FolderCloudService;
use flowy_server_pub::supabase_config::SupabaseConfiguration;
@ -144,6 +144,10 @@ impl AppFlowyServer for SupabaseServer {
)))
}
fn database_ai_service(&self) -> Option<Arc<dyn DatabaseAIService>> {
None
}
fn document_service(&self) -> Arc<dyn DocumentCloudService> {
Arc::new(SupabaseDocumentServiceImpl::new(SupabaseServerServiceImpl(
self.restful_postgres.clone(),