Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: enable local ai and local ai chat #5755

Merged
merged 4 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion frontend/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"type": "dart",
"env": {
"RUST_LOG": "debug",
"RUST_BACKTRACE": "1"
},
// uncomment the following line to testing performance.
// "flutterMode": "profile",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
Expand All @@ -9,13 +10,12 @@ part 'chat_file_bloc.freezed.dart';
class ChatFileBloc extends Bloc<ChatFileEvent, ChatFileState> {
ChatFileBloc({
required String chatId,
dynamic message,
}) : listener = LocalLLMListener(),
super(ChatFileState.initial(message)) {
super(const ChatFileState()) {
listener.start(
stateCallback: (pluginState) {
chatStateCallback: (chatState) {
if (!isClosed) {
add(ChatFileEvent.updateLocalAIState(pluginState));
add(ChatFileEvent.updateChatState(chatState));
}
},
);
Expand All @@ -24,26 +24,30 @@ class ChatFileBloc extends Bloc<ChatFileEvent, ChatFileState> {
(event, emit) async {
await event.when(
initial: () async {
final result = await ChatEventGetPluginState().send();
final result = await ChatEventGetLocalAIChatState().send();
result.fold(
(pluginState) {
(chatState) {
if (!isClosed) {
add(ChatFileEvent.updateLocalAIState(pluginState));
add(
ChatFileEvent.updateChatState(chatState),
);
}
},
(err) {},
(err) {
Log.error(err.toString());
},
);
},
newFile: (String filePath) {
final payload = ChatFilePB(filePath: filePath, chatId: chatId);
ChatEventChatWithFile(payload).send();
},
updateLocalAIState: (PluginStatePB pluginState) {
updateChatState: (LocalAIChatPB chatState) {
// Only user enable chat with file and the plugin is already running
final supportChatWithFile = chatState.fileEnabled &&
chatState.pluginState.state == RunningStatePB.Running;
emit(
state.copyWith(
supportChatWithFile:
pluginState.state == RunningStatePB.Running,
),
state.copyWith(supportChatWithFile: supportChatWithFile),
);
},
);
Expand All @@ -64,20 +68,19 @@ class ChatFileBloc extends Bloc<ChatFileEvent, ChatFileState> {
class ChatFileEvent with _$ChatFileEvent {
const factory ChatFileEvent.initial() = Initial;
const factory ChatFileEvent.newFile(String filePath) = _NewFile;
const factory ChatFileEvent.updateLocalAIState(PluginStatePB pluginState) =
_UpdateLocalAIState;
const factory ChatFileEvent.updateChatState(LocalAIChatPB chatState) =
_UpdateChatState;
}

@freezed
class ChatFileState with _$ChatFileState {
const factory ChatFileState({
required String text,
@Default(false) bool supportChatWithFile,
}) = _ChatFileState;
}

factory ChatFileState.initial(dynamic text) {
return ChatFileState(
text: text is String ? text : "",
);
}
@freezed
class LocalAIChatFileIndicator with _$LocalAIChatFileIndicator {
const factory LocalAIChatFileIndicator.ready(bool isEnabled) = _Ready;
const factory LocalAIChatFileIndicator.loading() = _Loading;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'chat_input_bloc.freezed.dart';

class ChatInputBloc extends Bloc<ChatInputEvent, ChatInputState> {
ChatInputBloc()
: listener = LocalLLMListener(),
super(const ChatInputState(aiType: _AppFlowyAI())) {
listener.start(
stateCallback: (pluginState) {
if (!isClosed) {
add(ChatInputEvent.updateState(pluginState));
}
},
);

on<ChatInputEvent>(_handleEvent);
}

final LocalLLMListener listener;

@override
Future<void> close() async {
await listener.stop();
return super.close();
}

Future<void> _handleEvent(
ChatInputEvent event,
Emitter<ChatInputState> emit,
) async {
await event.when(
started: () async {
final result = await ChatEventGetLocalAIPluginState().send();
result.fold(
(pluginState) {
if (!isClosed) {
add(ChatInputEvent.updateState(pluginState));
}
},
(err) => Log.error(err.toString()),
);
},
updateState: (LocalAIPluginStatePB aiPluginState) {
emit(const ChatInputState(aiType: _AppFlowyAI()));
},
);
}
}

@freezed
class ChatInputEvent with _$ChatInputEvent {
const factory ChatInputEvent.started() = _Started;
const factory ChatInputEvent.updateState(LocalAIPluginStatePB aiPluginState) =
_UpdatePluginState;
}

@freezed
class ChatInputState with _$ChatInputState {
const factory ChatInputState({required AIType aiType}) = _ChatInputState;
}

@freezed
class AIType with _$AIType {
const factory AIType.appflowyAI() = _AppFlowyAI;
const factory AIType.localAI() = _LocalAI;
}
Loading
Loading