Skip to content

Commit a4d9e6f

Browse files
committed
feat: add plain regenerate response action
add a regenerate control to feedback actions andrerun the latest prompt without duplicating the user message - coupled with chatflow config
1 parent 029ad04 commit a4d9e6f

File tree

10 files changed

+68
-13
lines changed

10 files changed

+68
-13
lines changed

dist/components/Bot.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/components/bubbles/BotBubble.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type Props = {
2121
renderHTML?: boolean;
2222
handleActionClick: (elem: any, action: IAction | undefined | null) => void;
2323
handleSourceDocumentsClick: (src: any) => void;
24+
onRegenerateResponse?: () => void;
2425
isTTSEnabled?: boolean;
2526
isTTSLoading?: Record<string, boolean>;
2627
isTTSPlaying?: Record<string, boolean>;

dist/components/bubbles/BotBubble.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/components/buttons/FeedbackButtons.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ type RatingButtonProps = {
99
export declare const CopyToClipboardButton: (props: RatingButtonProps) => JSX.Element;
1010
export declare const ThumbsUpButton: (props: RatingButtonProps) => JSX.Element;
1111
export declare const ThumbsDownButton: (props: RatingButtonProps) => JSX.Element;
12+
export declare const RegenerateResponseButton: (props: RatingButtonProps) => JSX.Element;
1213
export {};
1314
//# sourceMappingURL=FeedbackButtons.d.ts.map

dist/components/buttons/FeedbackButtons.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/web.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/web.umd.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Bot.tsx

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,29 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
865865
handleSubmit(prompt);
866866
};
867867

868+
const handleRegenerateResponse = async (messageIndex: number) => {
869+
if (loading()) return;
870+
871+
const currentMessages = messages();
872+
const targetMessage = currentMessages[messageIndex];
873+
if (!targetMessage || targetMessage.type !== 'apiMessage') return;
874+
const lastApiMessageIndex = currentMessages.map((message) => message.type).lastIndexOf('apiMessage');
875+
// Regenerate should only replace the latest assistant response (including starter prompt responses).
876+
if (messageIndex !== lastApiMessageIndex) return;
877+
878+
const previousMessage = currentMessages[messageIndex - 1];
879+
if (!previousMessage || previousMessage.type !== 'userMessage' || previousMessage.fileUploads?.length) return;
880+
881+
setFollowUpPrompts([]);
882+
setMessages((prevMessages) => {
883+
const updatedMessages = prevMessages.slice(0, messageIndex);
884+
addChatMessage(updatedMessages);
885+
return updatedMessages;
886+
});
887+
888+
await handleSubmit(previousMessage.message, undefined, undefined, { skipAddUserMessage: true });
889+
};
890+
868891
const updateMetadata = (data: any, input: string) => {
869892
if (data.chatId) {
870893
setChatId(data.chatId);
@@ -1141,7 +1164,12 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
11411164
};
11421165

11431166
// Handle form submission
1144-
const handleSubmit = async (value: string | object, action?: IAction | undefined | null, humanInput?: any) => {
1167+
const handleSubmit = async (
1168+
value: string | object,
1169+
action?: IAction | undefined | null,
1170+
humanInput?: any,
1171+
options?: { skipAddUserMessage?: boolean },
1172+
) => {
11451173
if (typeof value === 'string' && value.trim() === '') {
11461174
const containsFile = previews().filter((item) => !item.mime.startsWith('image') && item.type !== 'audio').length > 0;
11471175
if (!previews().length || (previews().length && containsFile)) {
@@ -1178,11 +1206,13 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
11781206

11791207
clearPreviews();
11801208

1181-
setMessages((prevMessages) => {
1182-
const messages: MessageType[] = [...prevMessages, { message: value as string, type: 'userMessage', fileUploads: uploads }];
1183-
addChatMessage(messages);
1184-
return messages;
1185-
});
1209+
if (!options?.skipAddUserMessage) {
1210+
setMessages((prevMessages) => {
1211+
const messages: MessageType[] = [...prevMessages, { message: value as string, type: 'userMessage', fileUploads: uploads }];
1212+
addChatMessage(messages);
1213+
return messages;
1214+
});
1215+
}
11861216

11871217
const body: IncomingInput = {
11881218
question: value,
@@ -2581,6 +2611,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
25812611
showAvatar={props.botMessage?.showAvatar}
25822612
avatarSrc={props.botMessage?.avatarSrc}
25832613
chatFeedbackStatus={chatFeedbackStatus()}
2614+
onRegenerateResponse={() => handleRegenerateResponse(index())}
25842615
fontSize={props.fontSize}
25852616
isLoading={loading() && index() === messages().length - 1}
25862617
showAgentMessages={props.showAgentMessages}

src/components/bubbles/BotBubble.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Marked } from '@ts-stack/markdown';
44
import DOMPurify from 'dompurify';
55
import { FeedbackRatingType, sendFeedbackQuery, sendFileDownloadQuery, updateFeedbackQuery } from '@/queries/sendMessageQuery';
66
import { FileUpload, IAction, MessageType } from '../Bot';
7-
import { CopyToClipboardButton, ThumbsDownButton, ThumbsUpButton } from '../buttons/FeedbackButtons';
7+
import { CopyToClipboardButton, RegenerateResponseButton, ThumbsDownButton, ThumbsUpButton } from '../buttons/FeedbackButtons';
88
import { TTSButton } from '../buttons/TTSButton';
99
import FeedbackContentDialog from '../FeedbackContentDialog';
1010
import { AgentReasoningBubble } from './AgentReasoningBubble';
@@ -35,6 +35,7 @@ type Props = {
3535
renderHTML?: boolean;
3636
handleActionClick: (elem: any, action: IAction | undefined | null) => void;
3737
handleSourceDocumentsClick: (src: any) => void;
38+
onRegenerateResponse?: () => void;
3839
// TTS props
3940
isTTSEnabled?: boolean;
4041
isTTSLoading?: Record<string, boolean>;
@@ -577,6 +578,7 @@ export const BotBubble = (props: Props) => {
577578
</Show>
578579
{props.chatFeedbackStatus && props.message.messageId && (
579580
<>
581+
<RegenerateResponseButton feedbackColor={props.feedbackColor} onClick={() => props.onRegenerateResponse?.()} />
580582
<CopyToClipboardButton feedbackColor={props.feedbackColor} onClick={() => copyMessageToClipboard()} />
581583
<Show when={copiedMessage()}>
582584
<div class="copied-message" style={{ color: props.feedbackColor ?? defaultFeedbackColor }}>

src/components/buttons/FeedbackButtons.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { JSX, Show } from 'solid-js';
22
import { Spinner } from './SendButton';
3-
import { ClipboardIcon, ThumbsDownIcon, ThumbsUpIcon } from '../icons';
3+
import { ClipboardIcon, DeleteIcon as RefreshIcon, ThumbsDownIcon, ThumbsUpIcon } from '../icons';
44

55
type RatingButtonProps = {
66
feedbackColor?: string;
@@ -70,3 +70,23 @@ export const ThumbsDownButton = (props: RatingButtonProps) => {
7070
</button>
7171
);
7272
};
73+
74+
export const RegenerateResponseButton = (props: RatingButtonProps) => {
75+
return (
76+
<button
77+
type="button"
78+
disabled={props.isDisabled || props.isLoading}
79+
{...props}
80+
class={
81+
'w-4 h-4 p-0 justify-center font-semibold text-white focus:outline-none inline-flex items-center disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100 transition-all filter hover:brightness-90 active:brightness-75 chatbot-button ' +
82+
props.class
83+
}
84+
style={{ background: 'transparent', border: 'none' }}
85+
title="Regenerate response"
86+
>
87+
<Show when={!props.isLoading} fallback={<Spinner class="text-white" />}>
88+
<RefreshIcon color={props.feedbackColor ?? defaultFeedbackColor} class={'send-icon flex ' + (props.disableIcon ? 'hidden' : '')} />
89+
</Show>
90+
</button>
91+
);
92+
};

0 commit comments

Comments
 (0)