Skip to content

Commit 1ba83bb

Browse files
authored
Merge pull request #5 from RonasIT/PRD-2076-continue-response
PRD-2076: Continue response functionality
2 parents e007748 + 6712983 commit 1ba83bb

9 files changed

Lines changed: 71 additions & 5 deletions

File tree

i18n/mobile/chat/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@
120120
},
121121
"AI_MESSAGE_ACTIONS": {
122122
"TEXT_EDIT": "Edit",
123-
"TEXT_COPY": "Copy"
123+
"TEXT_COPY": "Copy",
124+
"TEXT_CONTINUE_RESPONSE": "Continue response"
124125
},
125126
"EDIT_MESSAGE_INPUT": {
126127
"TEXT_EDIT_MESSAGE": "Edit message",

libs/mobile/chat/features/ai-message-actions/src/lib/component.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ import { ToastService } from '@open-webui-react-native/shared/utils/toast-servic
1212
interface AiMessageActionsProps {
1313
message: Message;
1414
onEditPress: (messageId: string, content: string) => void;
15+
onContinueResponsePress: (messageId: string, content: string) => void;
16+
isLast: boolean;
1517
}
1618

1719
//TODO Extend with more actions - https://www.figma.com/design/YPCZjyVlD86psDwUxvMVBc/OpenWebUI-Redesign-React-Native?node-id=27540-25291&t=kg2yUIDp3UQDStLf-0
1820
export function AiMessageActions({
1921
message,
2022
onEditPress,
23+
onContinueResponsePress,
24+
isLast,
2125
children,
2226
}: PropsWithChildren<AiMessageActionsProps>): ReactElement {
2327
const translate = useTranslation('CHAT.AI_MESSAGE_ACTIONS');
@@ -35,6 +39,11 @@ export function AiMessageActions({
3539
actionsSheetRef.current?.dismiss();
3640
};
3741

42+
const handleContinueResponsePress = (): void => {
43+
onContinueResponsePress(message.id, message.content);
44+
actionsSheetRef.current?.dismiss();
45+
};
46+
3847
const actions: Array<ActionSheetItemProps> = compact([
3948
isFeatureEnabled(FeatureID.AI_EDIT_MESSAGE) && {
4049
title: translate('TEXT_EDIT'),
@@ -46,6 +55,11 @@ export function AiMessageActions({
4655
iconName: 'copy',
4756
onPress: copyToClipboard,
4857
},
58+
isLast && {
59+
title: translate('TEXT_CONTINUE_RESPONSE'),
60+
iconName: 'play',
61+
onPress: handleContinueResponsePress,
62+
},
4963
]);
5064

5165
return (

libs/mobile/chat/features/chat/src/lib/components/messages-list/component.tsx

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
import { FlashList } from '@shopify/flash-list';
2+
import { useLocalSearchParams } from 'expo-router';
23
import { delay } from 'lodash-es';
34
import { ReactElement, useCallback, useRef, useState } from 'react';
45
import { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
56
import { useSharedValue, withTiming } from 'react-native-reanimated';
67
import { AiMessageActions } from '@open-webui-react-native/mobile/chat/features/ai-message-actions';
78
import { useManageMessageSiblings } from '@open-webui-react-native/mobile/chat/features/use-manage-messages-siblings';
89
import { UserMessageActions } from '@open-webui-react-native/mobile/chat/features/user-message-actions';
10+
import { useSetSelectedModel } from '@open-webui-react-native/mobile/shared/features/use-set-selected-model';
911
import { View, AppFlashList } from '@open-webui-react-native/mobile/shared/ui/ui-kit';
10-
import { History as ChatHistory, Message } from '@open-webui-react-native/shared/data-access/api';
12+
import { ChatScreenParams } from '@open-webui-react-native/mobile/shared/utils/navigation';
13+
import {
14+
chatApi,
15+
History as ChatHistory,
16+
Message,
17+
prepareCompleteChatPayload,
18+
} from '@open-webui-react-native/shared/data-access/api';
1119
import { Role } from '@open-webui-react-native/shared/data-access/common';
20+
import { socketService } from '@open-webui-react-native/shared/data-access/websocket';
1221
import { ChatAiMessage } from '../ai-message';
1322
import { ChatBottomButton } from '../chat-bottom-button';
1423
import { ChatUserMessage } from '../user-message';
@@ -18,9 +27,9 @@ interface ChatMessagesListProps {
1827
isMessagesListLoaded: boolean;
1928
onLayout: () => void;
2029
isInputFocusing: boolean;
30+
onEditPress: (messageId: string, content: string) => void;
2131
history?: ChatHistory;
2232
messages?: Array<Message>;
23-
onEditPress: (messageId: string, content: string) => void;
2433
editingMessageId?: string;
2534
}
2635

@@ -42,6 +51,9 @@ export default function ChatMessagesList({
4251
const [autoscrollToBottomThreshold, setAutoscrollToBottomThreshold] = useState<number | undefined>(1);
4352

4453
const { showPreviousSibling, showNextSibling, getSiblingsInfo } = useManageMessageSiblings(chatId, history);
54+
const { mutate: completeChat } = chatApi.useCompleteChat();
55+
const { id }: ChatScreenParams = useLocalSearchParams();
56+
const { modelId } = useSetSelectedModel(id);
4557

4658
const handleContentSizeChange = (): void => {
4759
//NOTE: Needs to wait until the initial scroll to the bottom or content generation finished and not show the ChatBottomButton before
@@ -116,13 +128,32 @@ export default function ChatMessagesList({
116128
}, 1000);
117129
};
118130

131+
const handleContinueResponsePress = (messageId: string): void => {
132+
if (!modelId) return;
133+
134+
const completePayload = prepareCompleteChatPayload({
135+
chatId,
136+
messages,
137+
messageId: messageId,
138+
sessionId: socketService.socketSessionId,
139+
model: modelId,
140+
});
141+
completeChat(completePayload);
142+
};
143+
119144
const renderItem = useCallback(
120145
({ item, index }: { item: Message; index: number }) => {
121146
const message = history?.messages[item.id];
122147
if (!message) return null;
123148

149+
const isLast = item.id === history?.lastAssistantMessage?.id;
150+
124151
return item.role === Role.ASSISTANT ? (
125-
<AiMessageActions message={message} onEditPress={onEditPress}>
152+
<AiMessageActions
153+
message={message}
154+
onEditPress={onEditPress}
155+
onContinueResponsePress={handleContinueResponsePress}
156+
isLast={isLast}>
126157
<ChatAiMessage
127158
message={message}
128159
onEditPress={() => handleEditPress(index, message.id, message.content)}
@@ -144,7 +175,7 @@ export default function ChatMessagesList({
144175
</UserMessageActions>
145176
);
146177
},
147-
[history, onEditPress, editingMessageId, showPreviousSibling, showNextSibling, getSiblingsInfo],
178+
[history, onEditPress, editingMessageId, showPreviousSibling, showNextSibling, getSiblingsInfo, modelId],
148179
);
149180

150181
return (

libs/mobile/shared/ui/ui-kit/src/assets/icons/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import microphone from './microphone.svg';
3636
import moreDots from './more-dots.svg';
3737
import noWifi from './no-wifi.svg';
3838
import pin from './pin.svg';
39+
import play from './play.svg';
3940
import plusInCircle from './plus-in-circle.svg';
4041
import plus from './plus.svg';
4142
import search from './search.svg';
@@ -96,4 +97,5 @@ export const Icons = {
9697
strokeLeft,
9798
tick,
9899
stop,
100+
play,
99101
};
Lines changed: 3 additions & 0 deletions
Loading

libs/shared/data-access/api/src/lib/chats/models/history.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,14 @@ export class History {
1313
constructor(history: Partial<History> = {}) {
1414
Object.assign(this, history);
1515
}
16+
17+
public get lastAssistantMessage(): Message | undefined {
18+
if (!this.messages) return undefined;
19+
20+
const assistantMessages = Object.values(this.messages).filter((m) => m.role === 'assistant');
21+
22+
if (assistantMessages.length === 0) return undefined;
23+
24+
return assistantMessages.sort((a, b) => b.timestamp - a.timestamp)[0];
25+
}
1626
}

libs/shared/data-access/api/src/lib/chats/utils/patch-chat-message-with-completion.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export function patchChatMessagesWithCompletion(
4141
? {
4242
...history,
4343
messages: updatedHistoryMessages,
44+
lastAssistantMessage: history?.lastAssistantMessage ?? updatedLastMessage,
4445
}
4546
: history;
4647

libs/shared/data-access/api/src/lib/chats/utils/patch-completed-message.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export function patchCompletedMessage(oldData: ChatResponse | undefined): ChatRe
3636
? {
3737
...history,
3838
messages: updatedHistoryMessages,
39+
lastAssistantMessage: history?.lastAssistantMessage ?? updatedLastMessage,
3940
}
4041
: history;
4142

libs/shared/data-access/api/src/lib/chats/utils/prepare-update-message-in-chat-payload.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ export function prepareUpdateMessageInChatPayload(
1717
msg.id === messageId ? { ...messagesMap[messageId] } : msg,
1818
);
1919

20+
const lastAssistantMessage = oldData.chat.history.lastAssistantMessage;
21+
2022
const newChatData: ChatResponse = {
2123
...oldData,
2224
chat: {
2325
...oldData.chat,
2426
history: {
2527
...oldData.chat.history,
2628
messages: messagesMap,
29+
lastAssistantMessage,
2730
},
2831
messages: messagesArray,
2932
},

0 commit comments

Comments
 (0)