Skip to content

Commit 1d4aaa1

Browse files
committed
fix: compile
1 parent 9755135 commit 1d4aaa1

File tree

20 files changed

+190
-243
lines changed

20 files changed

+190
-243
lines changed

frontend/appflowy_flutter/lib/ai/service/ai_entities.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ class AIStreamEventPrefix {
1515
static const start = 'start:';
1616
static const finish = 'finish:';
1717
static const comment = 'comment:';
18-
static const aiResponseLimit = 'AI_RESPONSE_LIMIT';
19-
static const aiImageResponseLimit = 'AI_IMAGE_RESPONSE_LIMIT';
20-
static const aiMaxRequired = 'AI_MAX_REQUIRED:';
21-
static const localAINotReady = 'LOCAL_AI_NOT_READY';
22-
static const localAIDisabled = 'LOCAL_AI_DISABLED';
23-
static const aiQuestionData = 'ai_question:';
18+
static const aiResponseLimit = 'ai_response_limit:';
19+
static const aiImageResponseLimit = 'ai_image_response_limit:';
20+
static const aiMaxRequired = 'ai_max_required:';
21+
static const localAINotReady = 'local_ai_not_ready:';
22+
static const localAIDisabled = 'local_ai_disabled:';
23+
static const aiFollowUp = 'ai_follow_up:';
2424
}
2525

2626
enum AiType {

frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_ai_message_bloc.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ class ChatAIMessageBloc extends Bloc<ChatAIMessageEvent, ChatAIMessageState> {
118118
);
119119
});
120120

121-
on<_OnAIQuestionData>((event, emit) {
121+
on<_OnAIFollowUp>((event, emit) {
122122
emit(
123123
state.copyWith(
124-
messageState: MessageState.onAIQuestion(event.questionData),
124+
messageState: MessageState.aiFollowUp(event.followUpData),
125125
),
126126
);
127127
});
@@ -145,8 +145,8 @@ class ChatAIMessageBloc extends Bloc<ChatAIMessageEvent, ChatAIMessageState> {
145145
},
146146
onLocalAIInitializing: () =>
147147
_safeAdd(const ChatAIMessageEvent.onLocalAIInitializing()),
148-
onAIQuestionData: (data) {
149-
_safeAdd(ChatAIMessageEvent.onAIQuestionData(data));
148+
onAIFollowUp: (data) {
149+
_safeAdd(ChatAIMessageEvent.onAIFollowUp(data));
150150
},
151151
);
152152
}
@@ -185,9 +185,9 @@ class ChatAIMessageEvent with _$ChatAIMessageEvent {
185185
const factory ChatAIMessageEvent.receiveMetadata(
186186
MetadataCollection metadata,
187187
) = _ReceiveMetadata;
188-
const factory ChatAIMessageEvent.onAIQuestionData(
189-
AIQuestionData questionData,
190-
) = _OnAIQuestionData;
188+
const factory ChatAIMessageEvent.onAIFollowUp(
189+
AIFollowUpData followUpData,
190+
) = _OnAIFollowUp;
191191
}
192192

193193
@freezed
@@ -223,6 +223,6 @@ class MessageState with _$MessageState {
223223
const factory MessageState.onInitializingLocalAI() = _LocalAIInitializing;
224224
const factory MessageState.ready() = _Ready;
225225
const factory MessageState.loading() = _Loading;
226-
const factory MessageState.onAIQuestion(AIQuestionData questionData) =
227-
_OnAIQuestion;
226+
const factory MessageState.aiFollowUp(AIFollowUpData followUpData) =
227+
_AIFollowUp;
228228
}

frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
276276
deleteMessage: (mesesage) async {
277277
await chatController.remove(mesesage);
278278
},
279+
onAIFollowUp: (followUpData) {
280+
shouldFetchRelatedQuestions =
281+
followUpData.shouldGenerateRelatedQuestion;
282+
},
279283
);
280284
},
281285
);
@@ -349,22 +353,22 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
349353
);
350354

351355
isFetchingRelatedQuestions = true;
352-
// await AIEventGetRelatedQuestion(payload).send().fold(
353-
// (list) {
354-
// // while fetching related questions, the user might enter a new
355-
// // question or regenerate a previous response. In such cases, don't
356-
// // display the relatedQuestions
357-
// if (!isClosed && isFetchingRelatedQuestions) {
358-
// add(
359-
// ChatEvent.didReceiveRelatedQuestions(
360-
// list.items.map((e) => e.content).toList(),
361-
// ),
362-
// );
363-
// isFetchingRelatedQuestions = false;
364-
// }
365-
// },
366-
// (err) => Log.error("Failed to get related questions: $err"),
367-
// );
356+
await AIEventGetRelatedQuestion(payload).send().fold(
357+
(list) {
358+
// while fetching related questions, the user might enter a new
359+
// question or regenerate a previous response. In such cases, don't
360+
// display the relatedQuestions
361+
if (!isClosed && isFetchingRelatedQuestions) {
362+
add(
363+
ChatEvent.didReceiveRelatedQuestions(
364+
list.items.map((e) => e.content).toList(),
365+
),
366+
);
367+
isFetchingRelatedQuestions = false;
368+
}
369+
},
370+
(err) => Log.error("Failed to get related questions: $err"),
371+
);
368372
},
369373
);
370374
}
@@ -672,6 +676,9 @@ class ChatEvent with _$ChatEvent {
672676
) = _DidReceiveRelatedQueston;
673677

674678
const factory ChatEvent.deleteMessage(Message message) = _DeleteMessage;
679+
680+
const factory ChatEvent.onAIFollowUp(AIFollowUpData followUpData) =
681+
_OnAIFollowUp;
675682
}
676683

677684
@freezed

frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_message_stream.dart

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'dart:isolate';
55

66
import 'package:appflowy/ai/service/ai_entities.dart';
77
import 'package:appflowy/plugins/ai_chat/application/chat_message_service.dart';
8+
import 'package:appflowy_backend/log.dart';
89
import 'package:json_annotation/json_annotation.dart';
910

1011
part 'chat_message_stream.g.dart';
@@ -41,7 +42,7 @@ class AnswerStream {
4142
void Function()? _onAIImageResponseLimit;
4243
void Function(String message)? _onAIMaxRequired;
4344
void Function(MetadataCollection metadata)? _onMetadata;
44-
void Function(AIQuestionData)? _onAIQuestionData;
45+
void Function(AIFollowUpData)? _onAIFollowUp;
4546
// Caches for events that occur before listen() is called.
4647
final List<String> _pendingAIMaxRequiredEvents = [];
4748
bool _pendingLocalAINotReady = false;
@@ -92,9 +93,15 @@ class AnswerStream {
9293
} else {
9394
_pendingLocalAINotReady = true;
9495
}
95-
} else if (event.startsWith(AIStreamEventPrefix.aiQuestionData)) {
96-
final s = event.substring(AIStreamEventPrefix.aiQuestionData.length);
97-
_onAIQuestionData?.call(AIQuestionData.fromJson(jsonDecode(s)));
96+
} else if (event.startsWith(AIStreamEventPrefix.aiFollowUp)) {
97+
final s = event.substring(AIStreamEventPrefix.aiFollowUp.length);
98+
try {
99+
final dynamic jsonData = jsonDecode(s);
100+
final data = AIFollowUpData.fromJson(jsonData);
101+
_onAIFollowUp?.call(data);
102+
} catch (e) {
103+
Log.error('Error deserializing AIFollowUp data: $e\nRaw JSON: $s');
104+
}
98105
}
99106
}
100107

@@ -121,7 +128,7 @@ class AnswerStream {
121128
void Function(String message)? onAIMaxRequired,
122129
void Function(MetadataCollection metadata)? onMetadata,
123130
void Function()? onLocalAIInitializing,
124-
void Function(AIQuestionData)? onAIQuestionData,
131+
void Function(AIFollowUpData)? onAIFollowUp,
125132
}) {
126133
_onData = onData;
127134
_onStart = onStart;
@@ -132,7 +139,7 @@ class AnswerStream {
132139
_onAIMaxRequired = onAIMaxRequired;
133140
_onMetadata = onMetadata;
134141
_onLocalAIInitializing = onLocalAIInitializing;
135-
_onAIQuestionData = onAIQuestionData;
142+
_onAIFollowUp = onAIFollowUp;
136143
// Flush pending AI_MAX_REQUIRED events.
137144
if (_onAIMaxRequired != null && _pendingAIMaxRequiredEvents.isNotEmpty) {
138145
for (final msg in _pendingAIMaxRequiredEvents) {
@@ -250,30 +257,16 @@ class QuestionStream {
250257
}
251258

252259
@JsonSerializable()
253-
class AIQuestionData {
254-
AIQuestionData({
255-
required this.data,
256-
required this.content,
260+
class AIFollowUpData {
261+
AIFollowUpData({
262+
required this.shouldGenerateRelatedQuestion,
257263
});
258264

259-
factory AIQuestionData.fromJson(Map<String, dynamic> json) =>
260-
_$AIQuestionDataFromJson(json);
261-
final AIQuestionDataMetadata data;
262-
final String content;
263-
264-
Map<String, dynamic> toJson() => _$AIQuestionDataToJson(this);
265-
}
266-
267-
@JsonSerializable()
268-
class AIQuestionDataMetadata {
269-
factory AIQuestionDataMetadata.fromJson(Map<String, dynamic> json) =>
270-
_$AIQuestionDataMetadataFromJson(json);
265+
factory AIFollowUpData.fromJson(Map<String, dynamic> json) =>
266+
_$AIFollowUpDataFromJson(json);
271267

272-
AIQuestionDataMetadata({
273-
this.suggestedQuestions,
274-
});
275-
@JsonKey(name: 'SuggestedQuestion')
276-
final List<String>? suggestedQuestions;
268+
@JsonKey(name: 'should_generate_related_question')
269+
final bool shouldGenerateRelatedQuestion;
277270

278-
Map<String, dynamic> toJson() => _$AIQuestionDataMetadataToJson(this);
271+
Map<String, dynamic> toJson() => _$AIFollowUpDataToJson(this);
279272
}

frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/ai_text_message.dart

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'package:appflowy/plugins/ai_chat/application/chat_ai_message_bloc.dart';
44
import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
55
import 'package:appflowy/plugins/ai_chat/application/chat_entity.dart';
66
import 'package:appflowy/plugins/ai_chat/application/chat_message_stream.dart';
7-
import 'package:appflowy_backend/log.dart';
87
import 'package:appflowy_backend/protobuf/flowy-ai/protobuf.dart';
98
import 'package:easy_localization/easy_localization.dart';
109
import 'package:fixnum/fixnum.dart';
@@ -75,12 +74,7 @@ class ChatAIMessageWidget extends StatelessWidget {
7574
child: BlocConsumer<ChatAIMessageBloc, ChatAIMessageState>(
7675
listenWhen: (previous, current) =>
7776
previous.messageState != current.messageState,
78-
listener: (context, state) {
79-
if (state.stream?.error?.isEmpty != false) {
80-
return;
81-
}
82-
context.read<ChatBloc>().add(ChatEvent.deleteMessage(message));
83-
},
77+
listener: (context, state) => _handleMessageState(state, context),
8478
builder: (context, blocState) {
8579
final loadingText = blocState.progress?.step ??
8680
LocaleKeys.chat_generatingResponse.tr();
@@ -150,18 +144,33 @@ class ChatAIMessageWidget extends StatelessWidget {
150144
LocaleKeys.settings_aiPage_keys_localAIInitializing.tr(),
151145
);
152146
},
153-
onAIQuestion: (questionData) {
154-
return AIQuestionDataWidget(
155-
message: message,
156-
questionData: questionData,
157-
);
147+
aiFollowUp: (followUpData) {
148+
return const SizedBox.shrink();
158149
},
159150
),
160151
);
161152
},
162153
),
163154
);
164155
}
156+
157+
void _handleMessageState(ChatAIMessageState state, BuildContext context) {
158+
if (state.stream?.error?.isEmpty != false) {
159+
state.messageState.maybeMap(
160+
aiFollowUp: (messageState) {
161+
context
162+
.read<ChatBloc>()
163+
.add(ChatEvent.onAIFollowUp(messageState.followUpData));
164+
},
165+
orElse: () {
166+
// do nothing
167+
},
168+
);
169+
170+
return;
171+
}
172+
context.read<ChatBloc>().add(ChatEvent.deleteMessage(message));
173+
}
165174
}
166175

167176
class _LoadingMessage extends StatelessWidget {
@@ -256,58 +265,3 @@ class _NonEmptyMessage extends StatelessWidget {
256265
);
257266
}
258267
}
259-
260-
class AIQuestionDataWidget extends StatelessWidget {
261-
const AIQuestionDataWidget({
262-
super.key,
263-
required this.message,
264-
required this.questionData,
265-
});
266-
267-
final AIQuestionData questionData;
268-
final Message message;
269-
270-
@override
271-
Widget build(BuildContext context) {
272-
return ChatAIMessageBubble(
273-
message: message,
274-
showActions: false,
275-
child: Column(
276-
crossAxisAlignment: CrossAxisAlignment.start,
277-
children: [
278-
AIMarkdownText(
279-
markdown: questionData.content,
280-
),
281-
const VSpace(8.0),
282-
...questionData.data.suggestedQuestions?.map(
283-
(question) => _AIQuestionDataItem(question: question),
284-
) ??
285-
[],
286-
],
287-
),
288-
);
289-
}
290-
}
291-
292-
class _AIQuestionDataItem extends StatelessWidget {
293-
const _AIQuestionDataItem({
294-
required this.question,
295-
});
296-
297-
final String question;
298-
299-
@override
300-
Widget build(BuildContext context) {
301-
return SizedBox(
302-
height: 32,
303-
child: FlowyButton(
304-
text: FlowyText(question),
305-
onTap: () {
306-
context.read<ChatBloc>().add(
307-
ChatEvent.sendMessage(message: question),
308-
);
309-
},
310-
),
311-
);
312-
}
313-
}

0 commit comments

Comments
 (0)