mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: show attachment on local ai (#5929)
* chore: show attachment on local ai * chore: fix compile
This commit is contained in:
parent
23997e977c
commit
f7adcae8ff
@ -16,13 +16,13 @@ part 'chat_ai_message_bloc.freezed.dart';
|
||||
class ChatAIMessageBloc extends Bloc<ChatAIMessageEvent, ChatAIMessageState> {
|
||||
ChatAIMessageBloc({
|
||||
dynamic message,
|
||||
String? metadata,
|
||||
String? refSourceJsonString,
|
||||
required this.chatId,
|
||||
required this.questionId,
|
||||
}) : super(
|
||||
ChatAIMessageState.initial(
|
||||
message,
|
||||
messageRefSourceFromString(metadata),
|
||||
messageReferenceSource(refSourceJsonString),
|
||||
),
|
||||
) {
|
||||
if (state.stream != null) {
|
||||
|
@ -374,7 +374,10 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
||||
metadata: await metadataPBFromMetadata(metadata),
|
||||
);
|
||||
|
||||
final questionStreamMessage = _createQuestionStreamMessage(questionStream);
|
||||
final questionStreamMessage = _createQuestionStreamMessage(
|
||||
questionStream,
|
||||
metadata,
|
||||
);
|
||||
add(ChatEvent.receveMessage(questionStreamMessage));
|
||||
|
||||
// Stream message to the server
|
||||
@ -432,14 +435,24 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
||||
);
|
||||
}
|
||||
|
||||
Message _createQuestionStreamMessage(QuestionStream stream) {
|
||||
Message _createQuestionStreamMessage(
|
||||
QuestionStream stream,
|
||||
Map<String, dynamic>? sentMetadata,
|
||||
) {
|
||||
questionStreamMessageId = nanoid();
|
||||
final Map<String, dynamic> metadata = {};
|
||||
|
||||
// if (sentMetadata != null) {
|
||||
// metadata[messageMetadataJsonStringKey] = sentMetadata;
|
||||
// }
|
||||
|
||||
metadata["$QuestionStream"] = stream;
|
||||
metadata["chatId"] = chatId;
|
||||
metadata[messageChatFileListKey] =
|
||||
chatFilesFromMessageMetadata(sentMetadata);
|
||||
return TextMessage(
|
||||
author: User(id: state.userProfile.id.toString()),
|
||||
metadata: {
|
||||
"$QuestionStream": stream,
|
||||
"chatId": chatId,
|
||||
},
|
||||
metadata: metadata,
|
||||
id: questionStreamMessageId,
|
||||
createdAt: DateTime.now().millisecondsSinceEpoch,
|
||||
text: '',
|
||||
@ -460,7 +473,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
||||
text: message.content,
|
||||
createdAt: message.createdAt.toInt() * 1000,
|
||||
metadata: {
|
||||
messageMetadataKey: message.metadata,
|
||||
messageRefSourceJsonStringKey: message.metadata,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -15,8 +15,14 @@ part 'chat_entity.freezed.dart';
|
||||
const sendMessageErrorKey = "sendMessageError";
|
||||
const systemUserId = "system";
|
||||
const aiResponseUserId = "0";
|
||||
const messageMetadataKey = "metadata";
|
||||
const messageQuestionIdKey = "question";
|
||||
|
||||
/// `messageRefSourceJsonStringKey` is the key used for metadata that contains the reference source of a message.
|
||||
/// Each message may include this information.
|
||||
/// - When used in a sent message, it indicates that the message includes an attachment.
|
||||
/// - When used in a received message, it indicates the AI reference sources used to answer a question.
|
||||
const messageRefSourceJsonStringKey = "ref_source_json_string";
|
||||
const messageChatFileListKey = "chat_files";
|
||||
const messageQuestionIdKey = "question_id";
|
||||
|
||||
@JsonSerializable()
|
||||
class ChatMessageRefSource {
|
||||
|
@ -32,7 +32,12 @@ List<ChatFile> chatFilesFromMetadataString(String? s) {
|
||||
|
||||
final metadataJson = jsonDecode(s);
|
||||
if (metadataJson is Map<String, dynamic>) {
|
||||
return _parseChatFile(metadataJson);
|
||||
final file = chatFileFromMap(metadataJson);
|
||||
if (file != null) {
|
||||
return [file];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} else if (metadataJson is List) {
|
||||
return metadataJson
|
||||
.map((e) => e as Map<String, dynamic>)
|
||||
@ -46,11 +51,6 @@ List<ChatFile> chatFilesFromMetadataString(String? s) {
|
||||
}
|
||||
}
|
||||
|
||||
List<ChatFile> _parseChatFile(Map<String, dynamic> map) {
|
||||
final file = chatFileFromMap(map);
|
||||
return file != null ? [file] : [];
|
||||
}
|
||||
|
||||
ChatFile? chatFileFromMap(Map<String, dynamic>? map) {
|
||||
if (map == null) return null;
|
||||
|
||||
@ -63,7 +63,7 @@ ChatFile? chatFileFromMap(Map<String, dynamic>? map) {
|
||||
return ChatFile.fromFilePath(filePath);
|
||||
}
|
||||
|
||||
List<ChatMessageRefSource> messageRefSourceFromString(String? s) {
|
||||
List<ChatMessageRefSource> messageReferenceSource(String? s) {
|
||||
if (s == null || s.isEmpty || s == "null") {
|
||||
return [];
|
||||
}
|
||||
@ -139,3 +139,18 @@ Future<List<ChatMessageMetaPB>> metadataPBFromMetadata(
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
List<ChatFile> chatFilesFromMessageMetadata(
|
||||
Map<String, dynamic>? map,
|
||||
) {
|
||||
final List<ChatFile> metadata = [];
|
||||
if (map != null) {
|
||||
for (final entry in map.entries) {
|
||||
if (entry.value is ChatFile) {
|
||||
metadata.add(entry.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class AnswerStream {
|
||||
} else if (event.startsWith("metadata:")) {
|
||||
if (_onMetadata != null) {
|
||||
final s = event.substring(9);
|
||||
_onMetadata!(messageRefSourceFromString(s));
|
||||
_onMetadata!(messageReferenceSource(s));
|
||||
}
|
||||
} else if (event == "AI_RESPONSE_LIMIT") {
|
||||
if (_onAIResponseLimit != null) {
|
||||
|
@ -11,11 +11,10 @@ class ChatUserMessageBubbleBloc
|
||||
extends Bloc<ChatUserMessageBubbleEvent, ChatUserMessageBubbleState> {
|
||||
ChatUserMessageBubbleBloc({
|
||||
required Message message,
|
||||
required String? metadata,
|
||||
}) : super(
|
||||
ChatUserMessageBubbleState.initial(
|
||||
message,
|
||||
chatFilesFromMetadataString(metadata),
|
||||
_getFiles(message.metadata),
|
||||
),
|
||||
) {
|
||||
on<ChatUserMessageBubbleEvent>(
|
||||
@ -28,6 +27,19 @@ class ChatUserMessageBubbleBloc
|
||||
}
|
||||
}
|
||||
|
||||
List<ChatFile> _getFiles(Map<String, dynamic>? metadata) {
|
||||
if (metadata == null) {
|
||||
return [];
|
||||
}
|
||||
final refSourceMetadata = metadata[messageRefSourceJsonStringKey] as String?;
|
||||
final files = metadata[messageChatFileListKey] as List<ChatFile>?;
|
||||
|
||||
if (refSourceMetadata != null) {
|
||||
return chatFilesFromMetadataString(refSourceMetadata);
|
||||
}
|
||||
return files ?? [];
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ChatUserMessageBubbleEvent with _$ChatUserMessageBubbleEvent {
|
||||
const factory ChatUserMessageBubbleEvent.initial() = Initial;
|
||||
|
@ -320,17 +320,16 @@ class _ChatContentPageState extends State<_ChatContentPage> {
|
||||
Widget _buildTextMessage(BuildContext context, TextMessage message) {
|
||||
if (message.author.id == _user.id) {
|
||||
final stream = message.metadata?["$QuestionStream"];
|
||||
final metadata = message.metadata?[messageMetadataKey] as String?;
|
||||
return ChatUserMessageWidget(
|
||||
key: ValueKey(message.id),
|
||||
user: message.author,
|
||||
message: stream is QuestionStream ? stream : message.text,
|
||||
metadata: metadata,
|
||||
);
|
||||
} else {
|
||||
final stream = message.metadata?["$AnswerStream"];
|
||||
final questionId = message.metadata?[messageQuestionIdKey];
|
||||
final metadata = message.metadata?[messageMetadataKey] as String?;
|
||||
final refSourceJsonString =
|
||||
message.metadata?[messageRefSourceJsonStringKey] as String?;
|
||||
return ChatAIMessageWidget(
|
||||
user: message.author,
|
||||
messageUserId: message.id,
|
||||
@ -338,7 +337,7 @@ class _ChatContentPageState extends State<_ChatContentPage> {
|
||||
key: ValueKey(message.id),
|
||||
questionId: questionId,
|
||||
chatId: widget.view.id,
|
||||
metadata: metadata,
|
||||
refSourceJsonString: refSourceJsonString,
|
||||
onSelectedMetadata: (ChatMessageRefSource metadata) {
|
||||
context.read<ChatSidePannelBloc>().add(
|
||||
ChatSidePannelEvent.selectedMetadata(metadata),
|
||||
|
@ -22,7 +22,7 @@ class ChatAIMessageWidget extends StatelessWidget {
|
||||
required this.message,
|
||||
required this.questionId,
|
||||
required this.chatId,
|
||||
required this.metadata,
|
||||
required this.refSourceJsonString,
|
||||
required this.onSelectedMetadata,
|
||||
});
|
||||
|
||||
@ -33,7 +33,7 @@ class ChatAIMessageWidget extends StatelessWidget {
|
||||
final dynamic message;
|
||||
final Int64? questionId;
|
||||
final String chatId;
|
||||
final String? metadata;
|
||||
final String? refSourceJsonString;
|
||||
final void Function(ChatMessageRefSource metadata) onSelectedMetadata;
|
||||
|
||||
@override
|
||||
@ -41,7 +41,7 @@ class ChatAIMessageWidget extends StatelessWidget {
|
||||
return BlocProvider(
|
||||
create: (context) => ChatAIMessageBloc(
|
||||
message: message,
|
||||
metadata: metadata,
|
||||
refSourceJsonString: refSourceJsonString,
|
||||
chatId: chatId,
|
||||
questionId: questionId,
|
||||
)..add(const ChatAIMessageEvent.initial()),
|
||||
|
@ -29,12 +29,10 @@ class ChatUserMessageBubble extends StatelessWidget {
|
||||
.read<ChatMemberBloc>()
|
||||
.add(ChatMemberEvent.getMemberInfo(message.author.id));
|
||||
}
|
||||
final metadata = message.metadata?[messageMetadataKey] as String?;
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => ChatUserMessageBubbleBloc(
|
||||
message: message,
|
||||
metadata: metadata,
|
||||
),
|
||||
child: BlocBuilder<ChatUserMessageBubbleBloc, ChatUserMessageBubbleState>(
|
||||
builder: (context, state) {
|
||||
|
@ -10,12 +10,10 @@ class ChatUserMessageWidget extends StatelessWidget {
|
||||
super.key,
|
||||
required this.user,
|
||||
required this.message,
|
||||
required this.metadata,
|
||||
});
|
||||
|
||||
final User user;
|
||||
final dynamic message;
|
||||
final String? metadata;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -63,6 +63,7 @@ impl AICloudServiceMiddleware {
|
||||
let _ = index_process_sink
|
||||
.send(StreamMessage::IndexStart.to_string())
|
||||
.await;
|
||||
|
||||
self
|
||||
.local_llm_controller
|
||||
.index_message_metadata(chat_id, metadata_list, index_process_sink)
|
||||
|
Loading…
Reference in New Issue
Block a user