Skip to content

Commit 65a42a2

Browse files
authored
[AAQ-577] Playground feedback (#285)
* initial attempt at feedback buttons * use alt buttons * thinner margine above buttons * save wip code * fix feedback buttons * remove finally * remove unused import
1 parent c58cbde commit 65a42a2

File tree

4 files changed

+170
-11
lines changed

4 files changed

+170
-11
lines changed

admin_app/src/app/integrations/components/ChatManagerCard.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const ChatManagerCard: React.FC<ChatManagerCardInfo> = ({ logo_src, name }) => (
1212
justifyContent: "center",
1313
alignItems: "center",
1414
display: "flex",
15+
cursor: "pointer",
1516
}}
1617
>
1718
<CardContent

admin_app/src/app/playground/components/PlaygroundComponents.tsx

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,15 @@ import PersonIcon from "@mui/icons-material/Person";
2424
import SendIcon from "@mui/icons-material/Send";
2525
import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";
2626
import TextField from "@mui/material/TextField";
27+
import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt";
28+
import ThumbUpOffAltIcon from "@mui/icons-material/ThumbUpOffAlt";
29+
import ThumbDownAltIcon from "@mui/icons-material/ThumbDownAlt";
30+
import ThumbDownOffAltIcon from "@mui/icons-material/ThumbDownOffAlt";
2731

2832
type QueryType = "embeddings-search" | "llm-response" | "urgency-detection";
2933

34+
type FeedbackSentimentType = "positive" | "negative";
35+
3036
interface ResponseSummary {
3137
index: string;
3238
title: string;
@@ -227,8 +233,19 @@ const MessageSkeleton = () => {
227233
);
228234
};
229235

230-
const MessageBox = (message: Message) => {
236+
const MessageBox = ({
237+
message,
238+
onFeedbackSend,
239+
}: {
240+
message: Message;
241+
onFeedbackSend: (
242+
message: ResponseMessage,
243+
feedbackSentiment: FeedbackSentimentType,
244+
) => void;
245+
}) => {
231246
const [open, setOpen] = useState(false);
247+
const [thumbsUp, setThumbsUp] = useState(false);
248+
const [thumbsDown, setThumbsDown] = useState(false);
232249

233250
const renderResults = (content: ResponseSummary[]) => {
234251
return content.map((c: ResponseSummary) => (
@@ -240,6 +257,38 @@ const MessageBox = (message: Message) => {
240257
</Box>
241258
));
242259
};
260+
const handlePositiveFeedback = (
261+
event: React.MouseEvent<HTMLButtonElement>,
262+
) => {
263+
if (thumbsUp) {
264+
console.log("Already sent positive feedback");
265+
} else {
266+
setThumbsUp(true);
267+
return onFeedbackSend(
268+
message as ResponseMessage,
269+
"positive" as FeedbackSentimentType,
270+
);
271+
}
272+
};
273+
const handleNegativeFeedback = (
274+
event: React.MouseEvent<HTMLButtonElement>,
275+
) => {
276+
if (thumbsDown) {
277+
console.log("Already sent negative feedback");
278+
} else {
279+
setThumbsDown(true);
280+
return onFeedbackSend(
281+
message as ResponseMessage,
282+
"negative" as FeedbackSentimentType,
283+
);
284+
}
285+
};
286+
const feedbackButtonStyle = {
287+
background: "none",
288+
border: "none",
289+
cursor: "pointer",
290+
};
291+
243292
const toggleJsonModal = () => setOpen(!open);
244293
const modalStyle = {
245294
position: "absolute",
@@ -255,6 +304,7 @@ const MessageBox = (message: Message) => {
255304
overflow: "scroll",
256305
borderRadius: "10px",
257306
};
307+
258308
return (
259309
<Box
260310
sx={{
@@ -310,16 +360,51 @@ const MessageBox = (message: Message) => {
310360
? message.content
311361
: renderResults(message.content)}
312362
</Typography>
313-
{message.hasOwnProperty("json") && (
314-
<Link
315-
onClick={toggleJsonModal}
316-
variant="caption"
317-
align="right"
318-
underline="hover"
319-
sx={{ cursor: "pointer" }}
363+
{message.type == "response" && (
364+
<Box
365+
style={{
366+
marginTop: "5px",
367+
display: "flex",
368+
justifyContent: "flex-end",
369+
alignItems: "center",
370+
}}
320371
>
321-
{"<json>"}
322-
</Link>
372+
{message.json.hasOwnProperty("feedback_secret_key") && (
373+
<Box sx={{ marginRight: "8px" }}>
374+
<IconButton
375+
aria-label="thumbs up"
376+
onClick={handlePositiveFeedback}
377+
style={feedbackButtonStyle}
378+
>
379+
{thumbsUp ? (
380+
<ThumbUpAltIcon fontSize="small" />
381+
) : (
382+
<ThumbUpOffAltIcon fontSize="small" />
383+
)}
384+
</IconButton>
385+
<IconButton
386+
aria-label="thumbs down"
387+
onClick={handleNegativeFeedback}
388+
style={feedbackButtonStyle}
389+
>
390+
{thumbsDown ? (
391+
<ThumbDownAltIcon fontSize="small" />
392+
) : (
393+
<ThumbDownOffAltIcon fontSize="small" />
394+
)}
395+
</IconButton>
396+
</Box>
397+
)}
398+
<Link
399+
onClick={toggleJsonModal}
400+
variant="caption"
401+
align="right"
402+
underline="hover"
403+
sx={{ cursor: "pointer" }}
404+
>
405+
{"<json>"}
406+
</Link>
407+
</Box>
323408
)}
324409
</Box>
325410

@@ -393,6 +478,7 @@ export { ErrorSnackBar, MessageBox, MessageSkeleton, PersistentSearchBar };
393478
export type {
394479
Message,
395480
QueryType,
481+
FeedbackSentimentType,
396482
ResponseMessage,
397483
ResponseSummary,
398484
UserMessage,

admin_app/src/app/playground/page.tsx

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
MessageSkeleton,
1313
PersistentSearchBar,
1414
QueryType,
15+
FeedbackSentimentType,
1516
ResponseSummary,
1617
UserMessage,
18+
ResponseMessage,
1719
} from "./components/PlaygroundComponents";
1820
import { Box } from "@mui/material";
1921
import { useAuth } from "@/utils/auth";
@@ -202,6 +204,42 @@ const Page = () => {
202204
}
203205
}
204206
};
207+
208+
const sendResponseFeedback = (
209+
message: ResponseMessage,
210+
feedback_sentiment: FeedbackSentimentType,
211+
) => {
212+
if (token) {
213+
// Assuming message.json is a JSON string. Parse it if necessary.
214+
const jsonResponse =
215+
typeof message.json === "string"
216+
? JSON.parse(message.json)
217+
: message.json;
218+
219+
const queryID = jsonResponse.query_id;
220+
const feedbackSecretKey = jsonResponse.feedback_secret_key;
221+
222+
apiCalls
223+
.postResponseFeedback(
224+
queryID,
225+
feedback_sentiment,
226+
feedbackSecretKey,
227+
token,
228+
)
229+
.then((response) => {
230+
if (response.status === 200) {
231+
console.log("Feedback sent successfully");
232+
} else {
233+
console.error(response);
234+
}
235+
})
236+
.catch((error: Error) => {
237+
setError("Failed to send response feedback.");
238+
console.error(error);
239+
});
240+
}
241+
};
242+
205243
const handleErrorClose = (
206244
event?: React.SyntheticEvent | Event,
207245
reason?: string,
@@ -211,6 +249,7 @@ const Page = () => {
211249
}
212250
setError(null);
213251
};
252+
214253
return (
215254
<>
216255
<Global
@@ -237,7 +276,11 @@ const Page = () => {
237276
}}
238277
>
239278
{messages.map((message, index) => (
240-
<MessageBox key={index} {...message} />
279+
<MessageBox
280+
key={index}
281+
message={message}
282+
onFeedbackSend={sendResponseFeedback}
283+
/>
241284
))}
242285
{loading && <MessageSkeleton />}
243286
<div ref={bottomRef} />

admin_app/src/utils/api.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,34 @@ const getLLMResponse = async (search: string, token: string) => {
314314
});
315315
};
316316

317+
const postResponseFeedback = async (
318+
query_id: number,
319+
feedback_sentiment: string,
320+
feedback_secret_key: string,
321+
token: string,
322+
) => {
323+
const feedbackUrl = `${NEXT_PUBLIC_BACKEND_URL}/response-feedback`;
324+
return fetch(feedbackUrl, {
325+
method: "POST",
326+
headers: {
327+
"Content-Type": "application/json",
328+
Authorization: `Bearer ${token}`,
329+
},
330+
body: JSON.stringify({
331+
query_id: query_id,
332+
feedback_sentiment: feedback_sentiment,
333+
feedback_secret_key: feedback_secret_key,
334+
}),
335+
}).then((response) => {
336+
if (response.ok) {
337+
let resp = response.json();
338+
return resp;
339+
} else {
340+
throw new Error("Error sending response feedback");
341+
}
342+
});
343+
};
344+
317345
const getQuestionStats = async (token: string) => {
318346
return fetch(`${NEXT_PUBLIC_BACKEND_URL}/dashboard/question_stats`, {
319347
method: "GET",
@@ -428,6 +456,7 @@ export const apiCalls = {
428456
getGoogleLoginToken,
429457
getEmbeddingsSearch,
430458
getLLMResponse,
459+
postResponseFeedback,
431460
getQuestionStats,
432461
getUrgencyDetection,
433462
createTag,

0 commit comments

Comments
 (0)