Skip to content

Commit

Permalink
feat: replay img chat
Browse files Browse the repository at this point in the history
  • Loading branch information
lollipopkit committed Jun 7, 2024
1 parent 1daecf1 commit 91ba519
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 89 deletions.
1 change: 1 addition & 0 deletions lib/core/util/chat_title.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ GPTBOX>>>''';
if (title.endsWith('》')) title = title.substring(0, title.length - 1);

title = title.replaceAll(_punctionsRm, '');
title = title.replaceAll('\n', ' ');

if (title.length > _maxLen) {
title = title.substring(0, _maxLen);
Expand Down
2 changes: 1 addition & 1 deletion lib/data/store/setting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class SettingStore extends PersistentStore {
/// Calcualte tokens length
// late final calcTokenLen = property('calcTokenLen', true);

late final replay = property('replay', false);
late final replay = property('replay', true);

late final countly = property('countly', true);

Expand Down
10 changes: 5 additions & 5 deletions lib/view/page/home/bottom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ class _HomeBottom extends StatelessWidget {
listenable: _chatType,
builder: (_, __) {
return switch (_chatType.value) {
ChatType.text || ChatType.img => Badge(
isLabelVisible: _filePicked.value != null,
child: IconButton(
onPressed: () => _onTapImgPick(context),
icon: const Icon(Icons.image, size: 19),
ChatType.text || ChatType.img => IconButton(
onPressed: () => _onTapImgPick(context),
icon: Badge(
isLabelVisible: _filePicked.value != null,
child: const Icon(Icons.image, size: 19),
),
),
// ChatType.audio => const IconButton(
Expand Down
5 changes: 0 additions & 5 deletions lib/view/page/home/chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,6 @@ class _ChatPageState extends State<_ChatPage>
ListenableBuilder(
listenable: _sendBtnRN,
builder: (_, __) {
/// TODO: Can't replay image message.
final isImgChat =
chatItem.content.any((e) => e.type == ChatContentType.image) ||
_chatType.value != ChatType.text;
if (isImgChat) return UIs.placeholder;
final isWorking = _chatStreamSubs.containsKey(_curChatId);
if (isWorking) return UIs.placeholder;
return buildCircleBtn(
Expand Down
89 changes: 12 additions & 77 deletions lib/view/page/home/req.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// OpenAI chat request related funcs
part of 'home.dart';

bool _checkSettingsValid(BuildContext context) {
bool _validChatCfg(BuildContext context) {
final config = OpenAICfg.current;
final urlEmpty = config.url == 'https://api.openai.com' || config.url.isEmpty;
if (urlEmpty && config.key.isEmpty) {
Expand All @@ -15,7 +15,7 @@ bool _checkSettingsValid(BuildContext context) {

/// Auto select model and send the request
void _onCreateRequest(BuildContext context, String chatId) async {
if (!_checkSettingsValid(context)) return;
if (!_validChatCfg(context)) return;

final chatType = _chatType.value;
final notSupport = switch (chatType) {
Expand Down Expand Up @@ -441,7 +441,7 @@ void _onReplay({
required String chatId,
required ChatHistoryItem item,
}) async {
if (!_checkSettingsValid(context)) return;
if (!_validChatCfg(context)) return;

// If is receiving the reply, ignore this action
if (_chatStreamSubs.containsKey(chatId)) {
Expand Down Expand Up @@ -473,82 +473,17 @@ void _onReplay({
chatHistory.items.removeAt(itemIdx + 1);
}

final config = OpenAICfg.current;
final questionContent = switch ((
config.prompt,
config.historyLen,
chatHistory.items.length,
)) {
('', _, _) => item.toMarkdown,
chatHistory.items.removeAt(itemIdx);

/// If prompt is not empty and historyCount == null || 0,
/// append it to the input
(final prompt, 0, _) => '$prompt\n${item.toMarkdown}',
final text =
item.content.firstWhereOrNull((e) => e.type == ChatContentType.text)?.raw;
if (text != null) _inputCtrl.text = text;
final img = item.content
.firstWhereOrNull((e) => e.type == ChatContentType.image)
?.raw;
if (img != null) _filePicked.value = XFile(img);

/// If this the first msg, append it to the input
(final prompt, _, 1) => '$prompt\n${item.toMarkdown}',
_ => item.content.first.raw,
};
final question = ChatHistoryItem.single(
raw: questionContent,
role: ChatRole.user,
);

final historyCarried = chatHistory.items.reversed
.take(config.historyLen)
.map(
(e) => e.toOpenAI,
)
.toList();

final chatStream = OpenAI.instance.chat.createStream(
model: config.model,
messages: [...historyCarried.reversed, question.toOpenAI],
);
final assistReply = ChatHistoryItem.single(role: ChatRole.assist);
chatHistory.items.insert(itemIdx + 1, assistReply);
_chatRN.build();
try {
final sub = chatStream.listen(
(event) {
final delta = event.choices.first.delta.content?.first?.text;
if (delta == null) return;
assistReply.content.first.raw += delta;
_chatItemRNMap[assistReply.id]?.build();

_autoScroll(chatId);
},
onError: (e, trace) {
Loggers.app.warning('Listen chat stream: $e');
_onStopStreamSub(chatId);

final msg = 'Error: $e\nTrace:\n$trace';
chatHistory.items.add(ChatHistoryItem.single(
raw: msg,
role: ChatRole.system,
));
_chatRN.build();
_storeChat(chatId);
_sendBtnRN.build();
},
onDone: () {
_onStopStreamSub(chatId);
_storeChat(chatId);
_sendBtnRN.build();
_appbarTitleRN.build();
SyncService.sync();
},
);
_chatStreamSubs[chatId] = sub;
_sendBtnRN.build();
} catch (e) {
_onStopStreamSub(chatId);
final msg = 'Chat stream: $e';
Loggers.app.warning(msg);
context.showSnackBar(msg);
assistReply.content.first.raw += '\n$msg';
_sendBtnRN.build();
}
_onCreateRequest(context, chatId);
}

void _onErr(Object e, StackTrace s, String chatId, String action) {
Expand Down
2 changes: 1 addition & 1 deletion lib/view/page/setting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildReplay() {
return ListTile(
leading: const Icon(Icons.replay),
title: Text('${l10n.replay} (experimental)'),
title: Text(l10n.replay),
trailing: StoreSwitch(prop: _store.replay),
);
}
Expand Down

0 comments on commit 91ba519

Please sign in to comment.