mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-29 00:30:35 +00:00
chore: show not ready state when using ai writer with local ai
This commit is contained in:
parent
3c74208ab9
commit
f76ce2be14
@ -28,6 +28,7 @@ abstract class AIRepository {
|
|||||||
required Future<void> Function(String text) processAssistMessage,
|
required Future<void> Function(String text) processAssistMessage,
|
||||||
required Future<void> Function() onEnd,
|
required Future<void> Function() onEnd,
|
||||||
required void Function(AIError error) onError,
|
required void Function(AIError error) onError,
|
||||||
|
required void Function() onLocalAIInitializing,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,12 +46,14 @@ class AppFlowyAIService implements AIRepository {
|
|||||||
required Future<void> Function(String text) processAssistMessage,
|
required Future<void> Function(String text) processAssistMessage,
|
||||||
required Future<void> Function() onEnd,
|
required Future<void> Function() onEnd,
|
||||||
required void Function(AIError error) onError,
|
required void Function(AIError error) onError,
|
||||||
|
required void Function() onLocalAIInitializing,
|
||||||
}) async {
|
}) async {
|
||||||
final stream = AppFlowyCompletionStream(
|
final stream = AppFlowyCompletionStream(
|
||||||
onStart: onStart,
|
onStart: onStart,
|
||||||
processMessage: processMessage,
|
processMessage: processMessage,
|
||||||
processAssistMessage: processAssistMessage,
|
processAssistMessage: processAssistMessage,
|
||||||
processError: onError,
|
processError: onError,
|
||||||
|
onLocalAIInitializing: onLocalAIInitializing,
|
||||||
onEnd: onEnd,
|
onEnd: onEnd,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -85,6 +88,7 @@ abstract class CompletionStream {
|
|||||||
required this.processMessage,
|
required this.processMessage,
|
||||||
required this.processAssistMessage,
|
required this.processAssistMessage,
|
||||||
required this.processError,
|
required this.processError,
|
||||||
|
required this.onLocalAIInitializing,
|
||||||
required this.onEnd,
|
required this.onEnd,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -92,6 +96,7 @@ abstract class CompletionStream {
|
|||||||
final Future<void> Function(String text) processMessage;
|
final Future<void> Function(String text) processMessage;
|
||||||
final Future<void> Function(String text) processAssistMessage;
|
final Future<void> Function(String text) processAssistMessage;
|
||||||
final void Function(AIError error) processError;
|
final void Function(AIError error) processError;
|
||||||
|
final void Function() onLocalAIInitializing;
|
||||||
final Future<void> Function() onEnd;
|
final Future<void> Function() onEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +107,7 @@ class AppFlowyCompletionStream extends CompletionStream {
|
|||||||
required super.processAssistMessage,
|
required super.processAssistMessage,
|
||||||
required super.processError,
|
required super.processError,
|
||||||
required super.onEnd,
|
required super.onEnd,
|
||||||
|
required super.onLocalAIInitializing,
|
||||||
}) {
|
}) {
|
||||||
_startListening();
|
_startListening();
|
||||||
}
|
}
|
||||||
@ -159,6 +165,10 @@ class AppFlowyCompletionStream extends CompletionStream {
|
|||||||
await onEnd();
|
await onEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.startsWith("LOCAL_AI_NOT_READY:")) {
|
||||||
|
onLocalAIInitializing();
|
||||||
|
}
|
||||||
|
|
||||||
if (event.startsWith("error:")) {
|
if (event.startsWith("error:")) {
|
||||||
processError(
|
processError(
|
||||||
AIError(message: event.substring(6), code: AIErrorCode.other),
|
AIError(message: event.substring(6), code: AIErrorCode.other),
|
||||||
|
|||||||
@ -568,6 +568,24 @@ class MainContentArea extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (state is LocalAIRunningAiWriterState) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const HSpace(8.0),
|
||||||
|
Opacity(
|
||||||
|
opacity: 0.5,
|
||||||
|
child: FlowyText(
|
||||||
|
LocaleKeys.settings_aiPage_keys_localAIInitializing.tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(8.0),
|
||||||
|
const CircularProgressIndicator.adaptive(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -390,6 +390,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
|||||||
AiWriterRecord.ai(content: _textRobot.markdownText),
|
AiWriterRecord.ai(content: _textRobot.markdownText),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onLocalAIInitializing: () {
|
||||||
|
emit(LocalAIRunningAiWriterState(command));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
@ -481,6 +484,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
|||||||
AiWriterRecord.ai(content: _textRobot.markdownText),
|
AiWriterRecord.ai(content: _textRobot.markdownText),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onLocalAIInitializing: () {
|
||||||
|
emit(LocalAIRunningAiWriterState(command));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
emit(
|
emit(
|
||||||
@ -569,6 +575,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
|||||||
AiWriterRecord.ai(content: _textRobot.markdownText),
|
AiWriterRecord.ai(content: _textRobot.markdownText),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onLocalAIInitializing: () {
|
||||||
|
emit(LocalAIRunningAiWriterState(command));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
emit(
|
emit(
|
||||||
@ -639,6 +648,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
|||||||
}
|
}
|
||||||
emit(ErrorAiWriterState(command, error: error));
|
emit(ErrorAiWriterState(command, error: error));
|
||||||
},
|
},
|
||||||
|
onLocalAIInitializing: () {
|
||||||
|
emit(LocalAIRunningAiWriterState(command));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
emit(
|
emit(
|
||||||
@ -714,3 +726,11 @@ class DocumentContentEmptyAiWriterState extends AiWriterState
|
|||||||
|
|
||||||
final void Function() onConfirm;
|
final void Function() onConfirm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LocalAIRunningAiWriterState extends AiWriterState
|
||||||
|
with RegisteredAiWriter {
|
||||||
|
const LocalAIRunningAiWriterState(this.command);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final AiWriterCommand command;
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ class _MockAIRepository extends Mock implements AppFlowyAIService {
|
|||||||
required Future<void> Function(String text) processAssistMessage,
|
required Future<void> Function(String text) processAssistMessage,
|
||||||
required Future<void> Function() onEnd,
|
required Future<void> Function() onEnd,
|
||||||
required void Function(AIError error) onError,
|
required void Function(AIError error) onError,
|
||||||
|
required void Function() onLocalAIInitializing,
|
||||||
}) async {
|
}) async {
|
||||||
final stream = _MockCompletionStream();
|
final stream = _MockCompletionStream();
|
||||||
unawaited(
|
unawaited(
|
||||||
@ -62,6 +63,7 @@ class _MockAIRepositoryLess extends Mock implements AppFlowyAIService {
|
|||||||
required Future<void> Function(String text) processAssistMessage,
|
required Future<void> Function(String text) processAssistMessage,
|
||||||
required Future<void> Function() onEnd,
|
required Future<void> Function() onEnd,
|
||||||
required void Function(AIError error) onError,
|
required void Function(AIError error) onError,
|
||||||
|
required void Function() onLocalAIInitializing,
|
||||||
}) async {
|
}) async {
|
||||||
final stream = _MockCompletionStream();
|
final stream = _MockCompletionStream();
|
||||||
unawaited(
|
unawaited(
|
||||||
@ -90,6 +92,7 @@ class _MockAIRepositoryMore extends Mock implements AppFlowyAIService {
|
|||||||
required Future<void> Function(String text) processAssistMessage,
|
required Future<void> Function(String text) processAssistMessage,
|
||||||
required Future<void> Function() onEnd,
|
required Future<void> Function() onEnd,
|
||||||
required void Function(AIError error) onError,
|
required void Function(AIError error) onError,
|
||||||
|
required void Function() onLocalAIInitializing,
|
||||||
}) async {
|
}) async {
|
||||||
final stream = _MockCompletionStream();
|
final stream = _MockCompletionStream();
|
||||||
unawaited(
|
unawaited(
|
||||||
@ -120,6 +123,7 @@ class _MockErrorRepository extends Mock implements AppFlowyAIService {
|
|||||||
required Future<void> Function(String text) processAssistMessage,
|
required Future<void> Function(String text) processAssistMessage,
|
||||||
required Future<void> Function() onEnd,
|
required Future<void> Function() onEnd,
|
||||||
required void Function(AIError error) onError,
|
required void Function(AIError error) onError,
|
||||||
|
required void Function() onLocalAIInitializing,
|
||||||
}) async {
|
}) async {
|
||||||
final stream = _MockCompletionStream();
|
final stream = _MockCompletionStream();
|
||||||
unawaited(
|
unawaited(
|
||||||
|
|||||||
@ -858,7 +858,8 @@
|
|||||||
"localAILoading": "Local AI Chat Model is loading...",
|
"localAILoading": "Local AI Chat Model is loading...",
|
||||||
"localAIStopped": "Local AI stopped",
|
"localAIStopped": "Local AI stopped",
|
||||||
"localAIRunning": "Local AI is running",
|
"localAIRunning": "Local AI is running",
|
||||||
"localAIInitializing": "Local AI is loading and may take a few minutes, depending on your device",
|
"localAIInitializing": "Local AI is loading and may take a few seconds, depending on your device",
|
||||||
|
"localAINotReadyRetryLater": "Local AI is initializing, please retry later",
|
||||||
"localAINotReadyTextFieldPrompt": "You can not edit while Local AI is loading",
|
"localAINotReadyTextFieldPrompt": "You can not edit while Local AI is loading",
|
||||||
"failToLoadLocalAI": "Failed to start local AI",
|
"failToLoadLocalAI": "Failed to start local AI",
|
||||||
"restartLocalAI": "Restart Local AI",
|
"restartLocalAI": "Restart Local AI",
|
||||||
|
|||||||
@ -12,6 +12,7 @@ use flowy_error::{FlowyError, FlowyResult};
|
|||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use lib_infra::isolate_stream::IsolateSink;
|
use lib_infra::isolate_stream::IsolateSink;
|
||||||
|
|
||||||
|
use crate::stream_message::StreamMessage;
|
||||||
use crate::util::ai_available_models_key;
|
use crate::util::ai_available_models_key;
|
||||||
use flowy_sqlite::kv::KVStorePreferences;
|
use flowy_sqlite::kv::KVStorePreferences;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
@ -188,12 +189,18 @@ impl CompletionTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_error(sink: &mut IsolateSink, error: FlowyError) {
|
async fn handle_error(sink: &mut IsolateSink, err: FlowyError) {
|
||||||
if error.is_ai_response_limit_exceeded() {
|
if err.is_ai_response_limit_exceeded() {
|
||||||
let _ = sink.send("AI_RESPONSE_LIMIT".to_string()).await;
|
let _ = sink.send("AI_RESPONSE_LIMIT".to_string()).await;
|
||||||
} else if error.is_ai_image_response_limit_exceeded() {
|
} else if err.is_ai_image_response_limit_exceeded() {
|
||||||
let _ = sink.send("AI_IMAGE_RESPONSE_LIMIT".to_string()).await;
|
let _ = sink.send("AI_IMAGE_RESPONSE_LIMIT".to_string()).await;
|
||||||
|
} else if err.is_ai_max_required() {
|
||||||
|
let _ = sink.send(format!("AI_MAX_REQUIRED:{}", err.msg)).await;
|
||||||
|
} else if err.is_local_ai_not_ready() {
|
||||||
|
let _ = sink.send(format!("LOCAL_AI_NOT_READY:{}", err.msg)).await;
|
||||||
} else {
|
} else {
|
||||||
let _ = sink.send(format!("error:{}", error)).await;
|
let _ = sink
|
||||||
|
.send(StreamMessage::OnError(err.msg.clone()).to_string())
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user