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> {
|
class ChatAIMessageBloc extends Bloc<ChatAIMessageEvent, ChatAIMessageState> {
|
||||||
ChatAIMessageBloc({
|
ChatAIMessageBloc({
|
||||||
dynamic message,
|
dynamic message,
|
||||||
String? metadata,
|
String? refSourceJsonString,
|
||||||
required this.chatId,
|
required this.chatId,
|
||||||
required this.questionId,
|
required this.questionId,
|
||||||
}) : super(
|
}) : super(
|
||||||
ChatAIMessageState.initial(
|
ChatAIMessageState.initial(
|
||||||
message,
|
message,
|
||||||
messageRefSourceFromString(metadata),
|
messageReferenceSource(refSourceJsonString),
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
if (state.stream != null) {
|
if (state.stream != null) {
|
||||||
|
@ -374,7 +374,10 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
|||||||
metadata: await metadataPBFromMetadata(metadata),
|
metadata: await metadataPBFromMetadata(metadata),
|
||||||
);
|
);
|
||||||
|
|
||||||
final questionStreamMessage = _createQuestionStreamMessage(questionStream);
|
final questionStreamMessage = _createQuestionStreamMessage(
|
||||||
|
questionStream,
|
||||||
|
metadata,
|
||||||
|
);
|
||||||
add(ChatEvent.receveMessage(questionStreamMessage));
|
add(ChatEvent.receveMessage(questionStreamMessage));
|
||||||
|
|
||||||
// Stream message to the server
|
// 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();
|
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(
|
return TextMessage(
|
||||||
author: User(id: state.userProfile.id.toString()),
|
author: User(id: state.userProfile.id.toString()),
|
||||||
metadata: {
|
metadata: metadata,
|
||||||
"$QuestionStream": stream,
|
|
||||||
"chatId": chatId,
|
|
||||||
},
|
|
||||||
id: questionStreamMessageId,
|
id: questionStreamMessageId,
|
||||||
createdAt: DateTime.now().millisecondsSinceEpoch,
|
createdAt: DateTime.now().millisecondsSinceEpoch,
|
||||||
text: '',
|
text: '',
|
||||||
@ -460,7 +473,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
|||||||
text: message.content,
|
text: message.content,
|
||||||
createdAt: message.createdAt.toInt() * 1000,
|
createdAt: message.createdAt.toInt() * 1000,
|
||||||
metadata: {
|
metadata: {
|
||||||
messageMetadataKey: message.metadata,
|
messageRefSourceJsonStringKey: message.metadata,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,14 @@ part 'chat_entity.freezed.dart';
|
|||||||
const sendMessageErrorKey = "sendMessageError";
|
const sendMessageErrorKey = "sendMessageError";
|
||||||
const systemUserId = "system";
|
const systemUserId = "system";
|
||||||
const aiResponseUserId = "0";
|
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()
|
@JsonSerializable()
|
||||||
class ChatMessageRefSource {
|
class ChatMessageRefSource {
|
||||||
|
@ -32,7 +32,12 @@ List<ChatFile> chatFilesFromMetadataString(String? s) {
|
|||||||
|
|
||||||
final metadataJson = jsonDecode(s);
|
final metadataJson = jsonDecode(s);
|
||||||
if (metadataJson is Map<String, dynamic>) {
|
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) {
|
} else if (metadataJson is List) {
|
||||||
return metadataJson
|
return metadataJson
|
||||||
.map((e) => e as Map<String, dynamic>)
|
.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) {
|
ChatFile? chatFileFromMap(Map<String, dynamic>? map) {
|
||||||
if (map == null) return null;
|
if (map == null) return null;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ ChatFile? chatFileFromMap(Map<String, dynamic>? map) {
|
|||||||
return ChatFile.fromFilePath(filePath);
|
return ChatFile.fromFilePath(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ChatMessageRefSource> messageRefSourceFromString(String? s) {
|
List<ChatMessageRefSource> messageReferenceSource(String? s) {
|
||||||
if (s == null || s.isEmpty || s == "null") {
|
if (s == null || s.isEmpty || s == "null") {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -139,3 +139,18 @@ Future<List<ChatMessageMetaPB>> metadataPBFromMetadata(
|
|||||||
|
|
||||||
return metadata;
|
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:")) {
|
} else if (event.startsWith("metadata:")) {
|
||||||
if (_onMetadata != null) {
|
if (_onMetadata != null) {
|
||||||
final s = event.substring(9);
|
final s = event.substring(9);
|
||||||
_onMetadata!(messageRefSourceFromString(s));
|
_onMetadata!(messageReferenceSource(s));
|
||||||
}
|
}
|
||||||
} else if (event == "AI_RESPONSE_LIMIT") {
|
} else if (event == "AI_RESPONSE_LIMIT") {
|
||||||
if (_onAIResponseLimit != null) {
|
if (_onAIResponseLimit != null) {
|
||||||
|
@ -11,11 +11,10 @@ class ChatUserMessageBubbleBloc
|
|||||||
extends Bloc<ChatUserMessageBubbleEvent, ChatUserMessageBubbleState> {
|
extends Bloc<ChatUserMessageBubbleEvent, ChatUserMessageBubbleState> {
|
||||||
ChatUserMessageBubbleBloc({
|
ChatUserMessageBubbleBloc({
|
||||||
required Message message,
|
required Message message,
|
||||||
required String? metadata,
|
|
||||||
}) : super(
|
}) : super(
|
||||||
ChatUserMessageBubbleState.initial(
|
ChatUserMessageBubbleState.initial(
|
||||||
message,
|
message,
|
||||||
chatFilesFromMetadataString(metadata),
|
_getFiles(message.metadata),
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
on<ChatUserMessageBubbleEvent>(
|
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
|
@freezed
|
||||||
class ChatUserMessageBubbleEvent with _$ChatUserMessageBubbleEvent {
|
class ChatUserMessageBubbleEvent with _$ChatUserMessageBubbleEvent {
|
||||||
const factory ChatUserMessageBubbleEvent.initial() = Initial;
|
const factory ChatUserMessageBubbleEvent.initial() = Initial;
|
||||||
|
@ -320,17 +320,16 @@ class _ChatContentPageState extends State<_ChatContentPage> {
|
|||||||
Widget _buildTextMessage(BuildContext context, TextMessage message) {
|
Widget _buildTextMessage(BuildContext context, TextMessage message) {
|
||||||
if (message.author.id == _user.id) {
|
if (message.author.id == _user.id) {
|
||||||
final stream = message.metadata?["$QuestionStream"];
|
final stream = message.metadata?["$QuestionStream"];
|
||||||
final metadata = message.metadata?[messageMetadataKey] as String?;
|
|
||||||
return ChatUserMessageWidget(
|
return ChatUserMessageWidget(
|
||||||
key: ValueKey(message.id),
|
key: ValueKey(message.id),
|
||||||
user: message.author,
|
user: message.author,
|
||||||
message: stream is QuestionStream ? stream : message.text,
|
message: stream is QuestionStream ? stream : message.text,
|
||||||
metadata: metadata,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final stream = message.metadata?["$AnswerStream"];
|
final stream = message.metadata?["$AnswerStream"];
|
||||||
final questionId = message.metadata?[messageQuestionIdKey];
|
final questionId = message.metadata?[messageQuestionIdKey];
|
||||||
final metadata = message.metadata?[messageMetadataKey] as String?;
|
final refSourceJsonString =
|
||||||
|
message.metadata?[messageRefSourceJsonStringKey] as String?;
|
||||||
return ChatAIMessageWidget(
|
return ChatAIMessageWidget(
|
||||||
user: message.author,
|
user: message.author,
|
||||||
messageUserId: message.id,
|
messageUserId: message.id,
|
||||||
@ -338,7 +337,7 @@ class _ChatContentPageState extends State<_ChatContentPage> {
|
|||||||
key: ValueKey(message.id),
|
key: ValueKey(message.id),
|
||||||
questionId: questionId,
|
questionId: questionId,
|
||||||
chatId: widget.view.id,
|
chatId: widget.view.id,
|
||||||
metadata: metadata,
|
refSourceJsonString: refSourceJsonString,
|
||||||
onSelectedMetadata: (ChatMessageRefSource metadata) {
|
onSelectedMetadata: (ChatMessageRefSource metadata) {
|
||||||
context.read<ChatSidePannelBloc>().add(
|
context.read<ChatSidePannelBloc>().add(
|
||||||
ChatSidePannelEvent.selectedMetadata(metadata),
|
ChatSidePannelEvent.selectedMetadata(metadata),
|
||||||
|
@ -22,7 +22,7 @@ class ChatAIMessageWidget extends StatelessWidget {
|
|||||||
required this.message,
|
required this.message,
|
||||||
required this.questionId,
|
required this.questionId,
|
||||||
required this.chatId,
|
required this.chatId,
|
||||||
required this.metadata,
|
required this.refSourceJsonString,
|
||||||
required this.onSelectedMetadata,
|
required this.onSelectedMetadata,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class ChatAIMessageWidget extends StatelessWidget {
|
|||||||
final dynamic message;
|
final dynamic message;
|
||||||
final Int64? questionId;
|
final Int64? questionId;
|
||||||
final String chatId;
|
final String chatId;
|
||||||
final String? metadata;
|
final String? refSourceJsonString;
|
||||||
final void Function(ChatMessageRefSource metadata) onSelectedMetadata;
|
final void Function(ChatMessageRefSource metadata) onSelectedMetadata;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -41,7 +41,7 @@ class ChatAIMessageWidget extends StatelessWidget {
|
|||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => ChatAIMessageBloc(
|
create: (context) => ChatAIMessageBloc(
|
||||||
message: message,
|
message: message,
|
||||||
metadata: metadata,
|
refSourceJsonString: refSourceJsonString,
|
||||||
chatId: chatId,
|
chatId: chatId,
|
||||||
questionId: questionId,
|
questionId: questionId,
|
||||||
)..add(const ChatAIMessageEvent.initial()),
|
)..add(const ChatAIMessageEvent.initial()),
|
||||||
|
@ -29,12 +29,10 @@ class ChatUserMessageBubble extends StatelessWidget {
|
|||||||
.read<ChatMemberBloc>()
|
.read<ChatMemberBloc>()
|
||||||
.add(ChatMemberEvent.getMemberInfo(message.author.id));
|
.add(ChatMemberEvent.getMemberInfo(message.author.id));
|
||||||
}
|
}
|
||||||
final metadata = message.metadata?[messageMetadataKey] as String?;
|
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => ChatUserMessageBubbleBloc(
|
create: (context) => ChatUserMessageBubbleBloc(
|
||||||
message: message,
|
message: message,
|
||||||
metadata: metadata,
|
|
||||||
),
|
),
|
||||||
child: BlocBuilder<ChatUserMessageBubbleBloc, ChatUserMessageBubbleState>(
|
child: BlocBuilder<ChatUserMessageBubbleBloc, ChatUserMessageBubbleState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -10,12 +10,10 @@ class ChatUserMessageWidget extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.user,
|
required this.user,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.metadata,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final User user;
|
final User user;
|
||||||
final dynamic message;
|
final dynamic message;
|
||||||
final String? metadata;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -63,6 +63,7 @@ impl AICloudServiceMiddleware {
|
|||||||
let _ = index_process_sink
|
let _ = index_process_sink
|
||||||
.send(StreamMessage::IndexStart.to_string())
|
.send(StreamMessage::IndexStart.to_string())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
self
|
self
|
||||||
.local_llm_controller
|
.local_llm_controller
|
||||||
.index_message_metadata(chat_id, metadata_list, index_process_sink)
|
.index_message_metadata(chat_id, metadata_list, index_process_sink)
|
||||||
|
Loading…
Reference in New Issue
Block a user