Skip to content

Commit b87a6ad

Browse files
committed
fix thumbs feedback
1 parent 4c4093c commit b87a6ad

File tree

2 files changed

+62
-52
lines changed

2 files changed

+62
-52
lines changed

src/components/Bot.tsx

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ export type MessageResponseVersion = {
129129
artifacts?: Partial<FileUpload>[];
130130
thinking?: string;
131131
thinkingDuration?: number;
132-
isThinking?: boolean;
133132
rating?: FeedbackRatingType;
134133
dateTime?: string;
135134
};
@@ -516,7 +515,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
516515
const [isMessageStopping, setIsMessageStopping] = createSignal(false);
517516
const [starterPrompts, setStarterPrompts] = createSignal<string[]>([], { equals: false });
518517
const [chatFeedbackStatus, setChatFeedbackStatus] = createSignal<boolean>(false);
519-
const [chatFeedbackRegenerateResponseStatus, setChatFeedbackRegenerateResponseStatus] = createSignal<boolean>(false);
518+
const [messageRatings, setMessageRatings] = createSignal<Record<string, FeedbackRatingType>>({});
520519
const [fullFileUpload, setFullFileUpload] = createSignal<boolean>(false);
521520
const [uploadsConfig, setUploadsConfig] = createSignal<UploadsConfig>();
522521
const [leadsConfig, setLeadsConfig] = createSignal<LeadsConfig>();
@@ -915,21 +914,10 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
915914
artifacts: message.artifacts,
916915
thinking: message.thinking,
917916
thinkingDuration: message.thinkingDuration,
918-
isThinking: message.isThinking,
919917
rating: message.rating,
920918
dateTime: message.dateTime,
921919
});
922920

923-
const parseConfigBoolean = (value: unknown, defaultValue: boolean) => {
924-
if (typeof value === 'boolean') return value;
925-
if (typeof value === 'string') {
926-
const normalized = value.trim().toLowerCase();
927-
if (normalized === 'true') return true;
928-
if (normalized === 'false') return false;
929-
}
930-
return defaultValue;
931-
};
932-
933921
const getLastApiMessageIndex = () => {
934922
const currentMessages = messages();
935923
for (let i = currentMessages.length - 1; i >= 0; i--) {
@@ -939,30 +927,44 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
939927
};
940928

941929
const canRegenerateResponse = (messageIndex: number) => {
942-
if (!chatFeedbackStatus() || !chatFeedbackRegenerateResponseStatus() || loading()) return false;
930+
if (!chatFeedbackStatus() || loading()) return false;
943931
if (messageIndex !== getLastApiMessageIndex()) return false;
944932
const previousMessage = messages()[messageIndex - 1];
945933
if (!previousMessage || previousMessage.type !== 'userMessage') return false;
946934
if (previousMessage.fileUploads?.length) return false;
947935
return true;
948936
};
949937

938+
const handleRatingUpdate = (messageId: string, rating: FeedbackRatingType) => {
939+
setMessageRatings((prev) => ({ ...prev, [messageId]: rating }));
940+
};
941+
950942
const handleRegenerateResponse = async (messageIndex: number) => {
951943
if (loading()) return;
952944
if (previews().length) return;
953945
if (startInputType() === 'formInput') return;
954946

955947
const currentMessages = messages();
956948
const targetMessage = currentMessages[messageIndex];
957-
if (!targetMessage || targetMessage.type !== 'apiMessage') return;
958-
959949
const previousMessage = currentMessages[messageIndex - 1];
960-
if (!previousMessage || previousMessage.type !== 'userMessage' || previousMessage.fileUploads?.length) return;
961950

962-
const existingResponseVersions =
963-
targetMessage.responseVersions && targetMessage.responseVersions.length > 0
964-
? [...targetMessage.responseVersions]
965-
: [createResponseVersion(targetMessage)];
951+
const ratings = messageRatings();
952+
const withRating = (v: MessageResponseVersion): MessageResponseVersion =>
953+
v.messageId && ratings[v.messageId] ? { ...v, rating: ratings[v.messageId] } : v;
954+
955+
const existingResponseVersions = (() => {
956+
if (targetMessage.responseVersions && targetMessage.responseVersions.length > 0) {
957+
const versions = [...targetMessage.responseVersions].map(withRating);
958+
// The latest slot may have message:'' if it was loaded from localStorage before
959+
// the end-event persist ran. Overwrite it with the actual content on the top-level message.
960+
const last = versions.length - 1;
961+
if (!versions[last].message) {
962+
versions[last] = withRating(createResponseVersion(targetMessage));
963+
}
964+
return versions;
965+
}
966+
return [withRating(createResponseVersion(targetMessage))];
967+
})();
966968

967969
setFollowUpPrompts([]);
968970
const updatedMessages = currentMessages.slice(0, messageIndex);
@@ -1118,6 +1120,17 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
11181120
break;
11191121
case 'end':
11201122
finalizeThinking();
1123+
if (options?.responseVersions && options.responseVersions.length > 0) {
1124+
setMessages((prevMessages) => {
1125+
const lastMsg = prevMessages[prevMessages.length - 1];
1126+
if (lastMsg.type === 'userMessage' || !lastMsg.responseVersions?.length) return prevMessages;
1127+
const versions = [...lastMsg.responseVersions];
1128+
versions[versions.length - 1] = createResponseVersion(lastMsg);
1129+
const updatedMessages = [...prevMessages.slice(0, -1), { ...lastMsg, responseVersions: versions }];
1130+
addChatMessage(updatedMessages);
1131+
return updatedMessages;
1132+
});
1133+
}
11211134
setLocalStorageChatflow(chatflowid, chatId);
11221135
closeResponse();
11231136
break;
@@ -2743,6 +2756,7 @@ export const Bot = (botProps: BotProps & { class?: string }) => {
27432756
chatFeedbackStatus={chatFeedbackStatus()}
27442757
onRegenerateResponse={() => handleRegenerateResponse(index())}
27452758
showRegenerateResponseButton={canRegenerateResponse(index())}
2759+
onRatingUpdate={handleRatingUpdate}
27462760
fontSize={props.fontSize}
27472761
isLoading={loading() && index() === messages().length - 1}
27482762
showAgentMessages={props.showAgentMessages}

src/components/bubbles/BotBubble.tsx

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createEffect, createMemo, Show, createSignal, onMount, For } from 'solid-js';
1+
import { createEffect, createMemo, Show, createSignal, onMount, For, untrack } from 'solid-js';
22
import { Avatar } from '../avatars/Avatar';
33
import { Marked } from '@ts-stack/markdown';
44
import DOMPurify from 'dompurify';
@@ -38,6 +38,7 @@ type Props = {
3838
handleSourceDocumentsClick: (src: any) => void;
3939
onRegenerateResponse?: () => void;
4040
showRegenerateResponseButton?: boolean;
41+
onRatingUpdate?: (messageId: string, rating: FeedbackRatingType) => void;
4142
// TTS props
4243
isTTSEnabled?: boolean;
4344
isTTSLoading?: Record<string, boolean>;
@@ -58,12 +59,9 @@ export const BotBubble = (props: Props) => {
5859

5960
Marked.setOptions({ isNoP: true, sanitize: props.renderHTML !== undefined ? !props.renderHTML : true });
6061

61-
const [rating, setRating] = createSignal('');
6262
const [feedbackId, setFeedbackId] = createSignal('');
6363
const [showFeedbackContentDialog, setShowFeedbackContentModal] = createSignal(false);
6464
const [copiedMessage, setCopiedMessage] = createSignal(false);
65-
const [thumbsUpColor, setThumbsUpColor] = createSignal(props.feedbackColor ?? defaultFeedbackColor); // default color
66-
const [thumbsDownColor, setThumbsDownColor] = createSignal(props.feedbackColor ?? defaultFeedbackColor); // default color
6765
const [responseVersionIndex, setResponseVersionIndex] = createSignal(0);
6866
const [ratingByMessageId, setRatingByMessageId] = createSignal<Record<string, FeedbackRatingType>>({});
6967

@@ -77,7 +75,6 @@ export const BotBubble = (props: Props) => {
7775

7876
const totalResponseVersions = createMemo(() => responseVersions().length);
7977
const hasMultipleResponseVersions = createMemo(() => totalResponseVersions() > 1);
80-
console.log('hasMultipleResponseVersions', hasMultipleResponseVersions());
8178

8279
const activeMessage = createMemo(() => {
8380
const versions = responseVersions();
@@ -98,6 +95,9 @@ export const BotBubble = (props: Props) => {
9895
return active.rating ?? '';
9996
};
10097

98+
const thumbsUpColor = () => currentRating() === 'THUMBS_UP' ? '#006400' : (props.feedbackColor ?? defaultFeedbackColor);
99+
const thumbsDownColor = () => currentRating() === 'THUMBS_DOWN' ? '#8B0000' : (props.feedbackColor ?? defaultFeedbackColor);
100+
101101
const setBotMessageRef = (el: HTMLSpanElement) => {
102102
if (el) {
103103
setBotMessageElement(el);
@@ -115,6 +115,18 @@ export const BotBubble = (props: Props) => {
115115
setResponseVersionIndex(safeIndex);
116116
});
117117

118+
createEffect(() => {
119+
responseVersionIndex(); // subscribe to version switches
120+
untrack(() => {
121+
responseVersions().forEach((version) => {
122+
const id = version.id || version.messageId;
123+
if (id && (props.isTTSPlaying?.[id] || props.isTTSLoading?.[id])) {
124+
props.handleTTSStop?.(id);
125+
}
126+
});
127+
});
128+
});
129+
118130
createEffect(() => {
119131
const el = botMessageElement();
120132
const messageData = activeMessage();
@@ -146,18 +158,6 @@ export const BotBubble = (props: Props) => {
146158
link.target = '_blank';
147159
});
148160

149-
const activeRating = currentRating();
150-
setRating(activeRating);
151-
if (activeRating === 'THUMBS_UP') {
152-
setThumbsUpColor('#006400');
153-
setThumbsDownColor(props.feedbackColor ?? defaultFeedbackColor);
154-
} else if (activeRating === 'THUMBS_DOWN') {
155-
setThumbsDownColor('#8B0000');
156-
setThumbsUpColor(props.feedbackColor ?? defaultFeedbackColor);
157-
} else {
158-
setThumbsUpColor(props.feedbackColor ?? defaultFeedbackColor);
159-
setThumbsDownColor(props.feedbackColor ?? defaultFeedbackColor);
160-
}
161161
const fileAnnotations = messageData.fileAnnotations ?? props.fileAnnotations;
162162
if (fileAnnotations && fileAnnotations.length) {
163163
for (const annotations of fileAnnotations) {
@@ -267,7 +267,7 @@ export const BotBubble = (props: Props) => {
267267
};
268268

269269
const onThumbsUpClick = async () => {
270-
if (rating() === '') {
270+
if (currentRating() === '') {
271271
const activeMessageId = activeMessage().messageId;
272272
if (!activeMessageId) return;
273273
const body = {
@@ -288,19 +288,17 @@ export const BotBubble = (props: Props) => {
288288
const data = result.data as any;
289289
let id = '';
290290
if (data && data.id) id = data.id;
291-
setRating('THUMBS_UP');
292291
setRatingByMessageId((prev) => ({ ...prev, [activeMessageId]: 'THUMBS_UP' }));
292+
props.onRatingUpdate?.(activeMessageId, 'THUMBS_UP');
293293
setFeedbackId(id);
294294
setShowFeedbackContentModal(true);
295-
// update the thumbs up color state
296-
setThumbsUpColor('#006400');
297295
saveToLocalStorage('THUMBS_UP');
298296
}
299297
}
300298
};
301299

302300
const onThumbsDownClick = async () => {
303-
if (rating() === '') {
301+
if (currentRating() === '') {
304302
const activeMessageId = activeMessage().messageId;
305303
if (!activeMessageId) return;
306304
const body = {
@@ -321,12 +319,10 @@ export const BotBubble = (props: Props) => {
321319
const data = result.data as any;
322320
let id = '';
323321
if (data && data.id) id = data.id;
324-
setRating('THUMBS_DOWN');
325322
setRatingByMessageId((prev) => ({ ...prev, [activeMessageId]: 'THUMBS_DOWN' }));
323+
props.onRatingUpdate?.(activeMessageId, 'THUMBS_DOWN');
326324
setFeedbackId(id);
327325
setShowFeedbackContentModal(true);
328-
// update the thumbs down color state
329-
setThumbsDownColor('#8B0000');
330326
saveToLocalStorage('THUMBS_DOWN');
331327
}
332328
}
@@ -544,7 +540,7 @@ export const BotBubble = (props: Props) => {
544540
<ThinkingCard
545541
thinking={activeMessage().thinking}
546542
thinkingDuration={activeMessage().thinkingDuration}
547-
isThinking={activeMessage().isThinking}
543+
isThinking={props.message.isThinking}
548544
backgroundColor={props.backgroundColor ?? defaultBackgroundColor}
549545
textColor={props.textColor ?? defaultTextColor}
550546
/>
@@ -696,14 +692,14 @@ export const BotBubble = (props: Props) => {
696692
Copied!
697693
</div>
698694
</Show>
699-
{rating() === '' || rating() === 'THUMBS_UP' ? (
700-
<ThumbsUpButton feedbackColor={thumbsUpColor()} isDisabled={rating() === 'THUMBS_UP'} rating={rating()} onClick={onThumbsUpClick} />
695+
{currentRating() === '' || currentRating() === 'THUMBS_UP' ? (
696+
<ThumbsUpButton feedbackColor={thumbsUpColor()} isDisabled={currentRating() === 'THUMBS_UP'} rating={currentRating()} onClick={onThumbsUpClick} />
701697
) : null}
702-
{rating() === '' || rating() === 'THUMBS_DOWN' ? (
698+
{currentRating() === '' || currentRating() === 'THUMBS_DOWN' ? (
703699
<ThumbsDownButton
704700
feedbackColor={thumbsDownColor()}
705-
isDisabled={rating() === 'THUMBS_DOWN'}
706-
rating={rating()}
701+
isDisabled={currentRating() === 'THUMBS_DOWN'}
702+
rating={currentRating()}
707703
onClick={onThumbsDownClick}
708704
/>
709705
) : null}

0 commit comments

Comments
 (0)