From f3e917e1b4a038f61363f2667f609b76cad584f2 Mon Sep 17 00:00:00 2001 From: shatfield4 Date: Fri, 9 Feb 2024 16:52:26 -0800 Subject: [PATCH 1/7] WIP RLHF works on historical messages --- .../ChatContainer/ChatHistory/index.jsx | 2 + .../HistoricalMessage/Actions/index.jsx | 95 ++++++++++++++++--- .../ChatHistory/HistoricalMessage/index.jsx | 17 +++- .../ChatContainer/ChatHistory/index.jsx | 2 + frontend/src/models/workspace.js | 10 ++ server/endpoints/workspaces.js | 20 ++++ server/models/workspaceChats.js | 17 ++++ .../20240210004405_init/migration.sql | 2 + server/prisma/schema.prisma | 1 + server/utils/chats/index.js | 4 +- 10 files changed, 156 insertions(+), 14 deletions(-) create mode 100644 server/prisma/migrations/20240210004405_init/migration.sql diff --git a/embed/src/components/ChatWindow/ChatContainer/ChatHistory/index.jsx b/embed/src/components/ChatWindow/ChatContainer/ChatHistory/index.jsx index 6a5e7eb67de..786d630a572 100644 --- a/embed/src/components/ChatWindow/ChatContainer/ChatHistory/index.jsx +++ b/embed/src/components/ChatWindow/ChatContainer/ChatHistory/index.jsx @@ -89,6 +89,8 @@ export default function ChatHistory({ settings = {}, history = [] }) { message={props.content} role={props.role} sources={props.sources} + chatId={props.chatId} + feedbackScore={props.feedbackScore} error={props.error} /> ); diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx index 12fa7dc7393..4a1c5600be7 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx @@ -1,27 +1,100 @@ +import React, { memo, useState, useEffect } from "react"; import useCopyText from "@/hooks/useCopyText"; -import { Check, ClipboardText } from "@phosphor-icons/react"; -import { memo } from "react"; +import { + Check, + ClipboardText, + ThumbsUp, + ThumbsDown, +} from "@phosphor-icons/react"; import { Tooltip } from "react-tooltip"; +import Workspace from "@/models/workspace"; + +const Actions = ({ message, feedbackScore, chatId }) => { + const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore); + const updateFeedback = async (newFeedback) => { + if (selectedFeedback === newFeedback) { + newFeedback = 0; + } + await Workspace.updateChatFeedback(chatId, newFeedback); + setSelectedFeedback(newFeedback); + }; -const Actions = ({ message }) => { return (
+ 0} + handleFeedback={() => updateFeedback(1)} + /> + updateFeedback(-1)} + /> - {/* Other actions to go here later. */}
); }; +function ThumbUp({ isSelected, handleFeedback }) { + return ( +
+ + +
+ ); +} + +function ThumbDown({ isSelected, handleFeedback }) { + return ( +
+ + +
+ ); +} + function CopyMessage({ message }) { const { copied, copyText } = useCopyText(); + return ( <>
+
- ); } diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx index ba3b687b0e4..92d624da4bf 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx @@ -12,7 +12,16 @@ import createDOMPurify from "dompurify"; const DOMPurify = createDOMPurify(window); const HistoricalMessage = forwardRef( ( - { uuid = v4(), message, role, workspace, sources = [], error = false }, + { + uuid = v4(), + message, + role, + workspace, + sources = [], + error = false, + feedbackScore, + chatId, + }, ref ) => { return ( @@ -60,7 +69,11 @@ const HistoricalMessage = forwardRef( {role === "assistant" && !error && (
- +
)} {role === "assistant" && } diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx index 74c159f4ac5..c9b6f783fc9 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx @@ -117,6 +117,8 @@ export default function ChatHistory({ history = [], workspace, sendCommand }) { role={props.role} workspace={workspace} sources={props.sources} + feedbackScore={props.feedbackScore} + chatId={props.chatId} error={props.error} /> ); diff --git a/frontend/src/models/workspace.js b/frontend/src/models/workspace.js index 0adcf3fa0f7..a17837ee828 100644 --- a/frontend/src/models/workspace.js +++ b/frontend/src/models/workspace.js @@ -60,6 +60,16 @@ const Workspace = { .catch(() => []); return history; }, + updateChatFeedback: async function (chatId, feedback) { + const result = await fetch(`${API_BASE}/workspace/chat-feedback`, { + method: "POST", + headers: baseHeaders(), + body: JSON.stringify({ chatId, feedback }), + }) + .then((res) => res.ok) + .catch(() => false); + return result; + }, streamChat: async function ({ slug }, message, mode = "query", handleChat) { const ctrl = new AbortController(); await fetchEventSource(`${API_BASE}/workspace/${slug}/stream-chat`, { diff --git a/server/endpoints/workspaces.js b/server/endpoints/workspaces.js index 574180627b9..5c710a60796 100644 --- a/server/endpoints/workspaces.js +++ b/server/endpoints/workspaces.js @@ -321,6 +321,26 @@ function workspaceEndpoints(app) { } ); + app.post( + "/workspace/chat-feedback", + [validatedRequest], + async (request, response) => { + try { + const { chatId, feedback } = reqBody(request); + const result = await WorkspaceChats.updateFeedbackScore( + Number(chatId), + Number(feedback) + ); + response.status(200).json({ success: result }); + } catch (error) { + console.error("Error updating chat feedback:", error); + response + .status(500) + .json({ success: false, message: "Internal server error" }); + } + } + ); + app.get( "/workspace/:slug/suggested-messages", [validatedRequest, flexUserRoleValid([ROLES.all])], diff --git a/server/models/workspaceChats.js b/server/models/workspaceChats.js index 4fae46b9f98..b56f445b02a 100644 --- a/server/models/workspaceChats.js +++ b/server/models/workspaceChats.js @@ -203,6 +203,23 @@ const WorkspaceChats = { return []; } }, + + updateFeedbackScore: async function (chatId = null, feedbackScore = null) { + if (!chatId) return; + try { + await prisma.workspace_chats.update({ + where: { + id: chatId, + }, + data: { + feedbackScore, + }, + }); + return; + } catch (error) { + console.error(error.message); + } + }, }; module.exports = { WorkspaceChats }; diff --git a/server/prisma/migrations/20240210004405_init/migration.sql b/server/prisma/migrations/20240210004405_init/migration.sql new file mode 100644 index 00000000000..0b337e2c21c --- /dev/null +++ b/server/prisma/migrations/20240210004405_init/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "workspace_chats" ADD COLUMN "feedbackScore" INTEGER; diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index c52e1a4b534..ae127f18208 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -142,6 +142,7 @@ model workspace_chats { thread_id Int? // No relation to prevent whole table migration createdAt DateTime @default(now()) lastUpdatedAt DateTime @default(now()) + feedbackScore Int? users users? @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: Cascade) } diff --git a/server/utils/chats/index.js b/server/utils/chats/index.js index 8ec7d90061d..20ab4e7407c 100644 --- a/server/utils/chats/index.js +++ b/server/utils/chats/index.js @@ -7,7 +7,7 @@ const { getVectorDbClass, getLLMProvider } = require("../helpers"); function convertToChatHistory(history = []) { const formattedHistory = []; history.forEach((history) => { - const { prompt, response, createdAt } = history; + const { prompt, response, createdAt, feedbackScore, id } = history; const data = JSON.parse(response); formattedHistory.push([ { @@ -19,6 +19,8 @@ function convertToChatHistory(history = []) { role: "assistant", content: data.text, sources: data.sources || [], + feedbackScore, + chatId: id, sentAt: moment(createdAt).unix(), }, ]); From b61b338cd8570151678ffcd5bf91ef9222e3e228 Mon Sep 17 00:00:00 2001 From: shatfield4 Date: Fri, 9 Feb 2024 17:57:52 -0800 Subject: [PATCH 2/7] refactor Actions component --- .../HistoricalMessage/Actions/index.jsx | 51 +++++++------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx index 4a1c5600be7..729a4e27876 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx @@ -21,61 +21,48 @@ const Actions = ({ message, feedbackScore, chatId }) => { return (
- 0} handleFeedback={() => updateFeedback(1)} + tooltipId="thumbs-up" + tooltipContent="Thumbs up" + IconComponent={ThumbsUp} /> - updateFeedback(-1)} + tooltipId="thumbs-down" + tooltipContent="Thumbs down" + IconComponent={ThumbsDown} />
); }; -function ThumbUp({ isSelected, handleFeedback }) { +function FeedbackButton({ + isSelected, + handleFeedback, + tooltipId, + tooltipContent, + IconComponent, +}) { return (
-
- ); -} - -function ThumbDown({ isSelected, handleFeedback }) { - return ( -
- - Date: Mon, 12 Feb 2024 18:12:04 -0800 Subject: [PATCH 3/7] completed RLHF up and down votes for chats --- .../HistoricalMessage/Actions/index.jsx | 46 ++++++++++--------- .../ChatHistory/HistoricalMessage/index.jsx | 1 + frontend/src/models/workspace.js | 15 +++--- frontend/src/utils/chat/index.js | 28 ++++++++++- server/endpoints/workspaces.js | 24 ++++++++-- server/models/workspaceChats.js | 5 +- .../20240210004405_init/migration.sql | 2 +- server/prisma/schema.prisma | 2 +- server/utils/chats/index.js | 7 +-- server/utils/chats/stream.js | 20 +++++++- 10 files changed, 107 insertions(+), 43 deletions(-) diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx index 729a4e27876..ef6ffe593a2 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx @@ -9,33 +9,37 @@ import { import { Tooltip } from "react-tooltip"; import Workspace from "@/models/workspace"; -const Actions = ({ message, feedbackScore, chatId }) => { +const Actions = ({ message, feedbackScore, chatId, slug }) => { const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore); - const updateFeedback = async (newFeedback) => { - if (selectedFeedback === newFeedback) { - newFeedback = 0; - } - await Workspace.updateChatFeedback(chatId, newFeedback); - setSelectedFeedback(newFeedback); + + const handleFeedback = async (newFeedback) => { + const updatedFeedback = + selectedFeedback === newFeedback ? null : newFeedback; + await Workspace.updateChatFeedback(chatId, slug, updatedFeedback); + setSelectedFeedback(updatedFeedback); }; return (
- 0} - handleFeedback={() => updateFeedback(1)} - tooltipId="thumbs-up" - tooltipContent="Thumbs up" - IconComponent={ThumbsUp} - /> - updateFeedback(-1)} - tooltipId="thumbs-down" - tooltipContent="Thumbs down" - IconComponent={ThumbsDown} - /> + {chatId && ( + <> + handleFeedback(true)} + tooltipId="thumbs-up" + tooltipContent="Good response" + IconComponent={ThumbsUp} + /> + handleFeedback(false)} + tooltipId="thumbs-down" + tooltipContent="Bad response" + IconComponent={ThumbsDown} + /> + + )}
); }; diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx index 92d624da4bf..c40a3a1aa4e 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx @@ -73,6 +73,7 @@ const HistoricalMessage = forwardRef( message={DOMPurify.sanitize(message)} feedbackScore={feedbackScore} chatId={chatId} + slug={workspace?.slug} />
)} diff --git a/frontend/src/models/workspace.js b/frontend/src/models/workspace.js index a17837ee828..3b31646dfdc 100644 --- a/frontend/src/models/workspace.js +++ b/frontend/src/models/workspace.js @@ -60,12 +60,15 @@ const Workspace = { .catch(() => []); return history; }, - updateChatFeedback: async function (chatId, feedback) { - const result = await fetch(`${API_BASE}/workspace/chat-feedback`, { - method: "POST", - headers: baseHeaders(), - body: JSON.stringify({ chatId, feedback }), - }) + updateChatFeedback: async function (chatId, slug, feedback) { + const result = await fetch( + `${API_BASE}/workspace/${slug}/chat-feedback/${chatId}`, + { + method: "POST", + headers: baseHeaders(), + body: JSON.stringify({ feedback }), + } + ) .then((res) => res.ok) .catch(() => false); return result; diff --git a/frontend/src/utils/chat/index.js b/frontend/src/utils/chat/index.js index f2587484368..e74fe2f6cba 100644 --- a/frontend/src/utils/chat/index.js +++ b/frontend/src/utils/chat/index.js @@ -6,7 +6,15 @@ export default function handleChat( remHistory, _chatHistory ) { - const { uuid, textResponse, type, sources = [], error, close } = chatResult; + const { + uuid, + textResponse, + type, + sources = [], + error, + close, + chatId, + } = chatResult; if (type === "abort") { setLoadingResponse(false); @@ -46,6 +54,7 @@ export default function handleChat( error, animate: !close, pending: false, + chatId, }, ]); _chatHistory.push({ @@ -57,6 +66,7 @@ export default function handleChat( error, animate: !close, pending: false, + chatId, }); } else if (type === "textResponseChunk") { const chatIdx = _chatHistory.findIndex((chat) => chat.uuid === uuid); @@ -70,6 +80,7 @@ export default function handleChat( closed: close, animate: !close, pending: false, + chatId, }; _chatHistory[chatIdx] = updatedHistory; } else { @@ -82,9 +93,24 @@ export default function handleChat( closed: close, animate: !close, pending: false, + chatId, }); } setChatHistory([..._chatHistory]); + } else if (type === "finalizeResponseStream") { + const chatIdx = _chatHistory.findIndex((chat) => chat.uuid === uuid); + if (chatIdx !== -1) { + const existingHistory = { ..._chatHistory[chatIdx] }; + const updatedHistory = { + ...existingHistory, + closed: close, + animate: !close, + pending: false, + chatId, + }; + _chatHistory[chatIdx] = updatedHistory; + } + setChatHistory([..._chatHistory]); } } diff --git a/server/endpoints/workspaces.js b/server/endpoints/workspaces.js index 5c710a60796..3e3e3559b69 100644 --- a/server/endpoints/workspaces.js +++ b/server/endpoints/workspaces.js @@ -21,6 +21,7 @@ const { EventLogs } = require("../models/eventLogs"); const { WorkspaceSuggestedMessages, } = require("../models/workspacesSuggestedMessages"); +const { validWorkspaceSlug } = require("../utils/middleware/validWorkspace"); const { handleUploads } = setupMulter(); function workspaceEndpoints(app) { @@ -322,14 +323,27 @@ function workspaceEndpoints(app) { ); app.post( - "/workspace/chat-feedback", - [validatedRequest], + "/workspace/:slug/chat-feedback/:chatId", + [validatedRequest, validWorkspaceSlug], async (request, response) => { try { - const { chatId, feedback } = reqBody(request); + const { chatId } = request.params; + const { feedback } = reqBody(request); + const existingChat = await WorkspaceChats.get({ + id: Number(chatId), + workspaceId: response.locals.workspace.id, + }); + + if (!existingChat) { + response + .status(404) + .json({ success: false, message: "Chat not found" }); + return; + } + const result = await WorkspaceChats.updateFeedbackScore( - Number(chatId), - Number(feedback) + chatId, + feedback ); response.status(200).json({ success: result }); } catch (error) { diff --git a/server/models/workspaceChats.js b/server/models/workspaceChats.js index b56f445b02a..f7271c06506 100644 --- a/server/models/workspaceChats.js +++ b/server/models/workspaceChats.js @@ -203,16 +203,15 @@ const WorkspaceChats = { return []; } }, - updateFeedbackScore: async function (chatId = null, feedbackScore = null) { if (!chatId) return; try { await prisma.workspace_chats.update({ where: { - id: chatId, + id: Number(chatId), }, data: { - feedbackScore, + feedbackScore: feedbackScore, }, }); return; diff --git a/server/prisma/migrations/20240210004405_init/migration.sql b/server/prisma/migrations/20240210004405_init/migration.sql index 0b337e2c21c..3d824ab0573 100644 --- a/server/prisma/migrations/20240210004405_init/migration.sql +++ b/server/prisma/migrations/20240210004405_init/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "workspace_chats" ADD COLUMN "feedbackScore" INTEGER; +ALTER TABLE "workspace_chats" ADD COLUMN "feedbackScore" BOOLEAN; diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index ae127f18208..55b469cfc1b 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -142,7 +142,7 @@ model workspace_chats { thread_id Int? // No relation to prevent whole table migration createdAt DateTime @default(now()) lastUpdatedAt DateTime @default(now()) - feedbackScore Int? + feedbackScore Boolean? users users? @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: Cascade) } diff --git a/server/utils/chats/index.js b/server/utils/chats/index.js index 20ab4e7407c..15d5a81d8d8 100644 --- a/server/utils/chats/index.js +++ b/server/utils/chats/index.js @@ -187,8 +187,7 @@ async function chatWithWorkspace( error: "No text completion could be completed with this input.", }; } - - await WorkspaceChats.new({ + const { chat } = await WorkspaceChats.new({ workspaceId: workspace.id, prompt: message, response: { text: textResponse, sources, type: chatMode }, @@ -199,6 +198,7 @@ async function chatWithWorkspace( type: "textResponse", close: true, textResponse, + chatId: chat.id, sources, error, }; @@ -273,7 +273,7 @@ async function emptyEmbeddingChat({ workspace, rawHistory ); - await WorkspaceChats.new({ + const { chat } = await WorkspaceChats.new({ workspaceId: workspace.id, prompt: message, response: { text: textResponse, sources: [], type: "chat" }, @@ -285,6 +285,7 @@ async function emptyEmbeddingChat({ sources: [], close: true, error: null, + chatId: chat.id, textResponse, }; } diff --git a/server/utils/chats/stream.js b/server/utils/chats/stream.js index 11190d63dca..dbb01783032 100644 --- a/server/utils/chats/stream.js +++ b/server/utils/chats/stream.js @@ -177,13 +177,20 @@ async function streamChatWithWorkspace( }); } - await WorkspaceChats.new({ + const { chat } = await WorkspaceChats.new({ workspaceId: workspace.id, prompt: message, response: { text: completeText, sources, type: chatMode }, user, threadId: thread?.id, }); + writeResponseChunk(response, { + uuid, + type: "finalizeResponseStream", + close: true, + error: false, + chatId: chat.id, + }); return; } @@ -235,13 +242,22 @@ async function streamEmptyEmbeddingChat({ }); } - await WorkspaceChats.new({ + const { chat } = await WorkspaceChats.new({ workspaceId: workspace.id, prompt: message, response: { text: completeText, sources: [], type: "chat" }, user, threadId: thread?.id, }); + + writeResponseChunk(response, { + uuid, + type: "finalizeResponseStream", + close: true, + error: false, + chatId: chat.id, + }); + return; } From b128ebb65a94275c1be613d950397b36694bdeca Mon Sep 17 00:00:00 2001 From: shatfield4 Date: Mon, 12 Feb 2024 18:16:51 -0800 Subject: [PATCH 4/7] add defaults for HistoricalMessage params --- .../ChatContainer/ChatHistory/HistoricalMessage/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx index c40a3a1aa4e..aa62e2edc78 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx @@ -19,8 +19,8 @@ const HistoricalMessage = forwardRef( workspace, sources = [], error = false, - feedbackScore, - chatId, + feedbackScore = null, + chatId = null, }, ref ) => { From fd869041d7c57c6b19880e7e5f1b46469bcfbf81 Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Tue, 13 Feb 2024 10:58:47 -0800 Subject: [PATCH 5/7] refactor RLHF implmenation remove forwardRef on history items to prevent rerenders --- .../HistoricalMessage/Actions/index.jsx | 5 +- .../ChatHistory/HistoricalMessage/index.jsx | 126 ++++++++---------- .../ChatHistory/PromptReply/index.jsx | 111 ++++++++------- .../ChatContainer/ChatHistory/index.jsx | 4 - frontend/src/utils/chat/index.js | 9 +- server/endpoints/workspaces.js | 12 +- server/models/workspaceChats.js | 3 +- server/utils/chats/index.js | 8 +- server/utils/chats/stream.js | 6 +- 9 files changed, 132 insertions(+), 152 deletions(-) diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx index ef6ffe593a2..7976baf2856 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx @@ -1,4 +1,4 @@ -import React, { memo, useState, useEffect } from "react"; +import React, { memo, useState } from "react"; import useCopyText from "@/hooks/useCopyText"; import { Check, @@ -27,13 +27,14 @@ const Actions = ({ message, feedbackScore, chatId, slug }) => { handleFeedback(true)} - tooltipId="thumbs-up" + tooltipId={`${chatId}-thumbs-up`} tooltipContent="Good response" IconComponent={ThumbsUp} /> handleFeedback(false)} + tooltipId={`${chatId}-thumbs-down`} tooltipId="thumbs-down" tooltipContent="Bad response" IconComponent={ThumbsDown} diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx index aa62e2edc78..f4c5c86a712 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx @@ -1,4 +1,4 @@ -import React, { memo, forwardRef } from "react"; +import React, { memo } from "react"; import { Warning } from "@phosphor-icons/react"; import Jazzicon from "../../../../UserIcon"; import Actions from "./Actions"; @@ -10,78 +10,70 @@ import { v4 } from "uuid"; import createDOMPurify from "dompurify"; const DOMPurify = createDOMPurify(window); -const HistoricalMessage = forwardRef( - ( - { - uuid = v4(), - message, - role, - workspace, - sources = [], - error = false, - feedbackScore = null, - chatId = null, - }, - ref - ) => { - return ( +const HistoricalMessage = ({ + uuid = v4(), + message, + role, + workspace, + sources = [], + error = false, + feedbackScore = null, + chatId = null, +}) => { + return ( +
-
-
- +
+ - {error ? ( -
- - Could not - respond to message. - -

- {error} -

-
- ) : ( - - )} -
- {role === "assistant" && !error && ( -
-
- + {error ? ( +
+ + Could not + respond to message. + +

+ {error} +

+ ) : ( + )} - {role === "assistant" && }
+ {role === "assistant" && !error && ( +
+
+ +
+ )} + {role === "assistant" && }
- ); - } -); +
+ ); +}; export default memo(HistoricalMessage); diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/PromptReply/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/PromptReply/index.jsx index a219f1202c0..f7777841179 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/PromptReply/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/PromptReply/index.jsx @@ -1,67 +1,44 @@ -import { forwardRef, memo } from "react"; +import { memo } from "react"; import { Warning } from "@phosphor-icons/react"; import Jazzicon from "../../../../UserIcon"; import renderMarkdown from "@/utils/chat/markdown"; import Citations from "../Citation"; -const PromptReply = forwardRef( - ( - { uuid, reply, pending, error, workspace, sources = [], closed = true }, - ref - ) => { - const assistantBackgroundColor = "bg-historical-msg-system"; +const PromptReply = ({ + uuid, + reply, + pending, + error, + workspace, + sources = [], + closed = true, +}) => { + const assistantBackgroundColor = "bg-historical-msg-system"; - if (!reply && sources.length === 0 && !pending && !error) return null; + if (!reply && sources.length === 0 && !pending && !error) return null; - if (pending) { - return ( -
-
-
- -
-
-
-
- ); - } - - if (error) { - return ( -
-
-
- - - Could not - respond to message. - Reason: {error || "unknown"} - -
+ if (pending) { + return ( +
+
+
+ +
- ); - } +
+ ); + } + if (error) { return (
@@ -72,15 +49,35 @@ const PromptReply = forwardRef( role="assistant" /> + className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`} + > + Could not + respond to message. + Reason: {error || "unknown"} +
-
); } -); + + return ( +
+
+
+ + +
+ +
+
+ ); +}; export default memo(PromptReply); diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx index c9b6f783fc9..5be8afc1324 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx @@ -7,7 +7,6 @@ import { ArrowDown } from "@phosphor-icons/react"; import debounce from "lodash.debounce"; export default function ChatHistory({ history = [], workspace, sendCommand }) { - const replyRef = useRef(null); const { showing, showModal, hideModal } = useManageWorkspaceModal(); const [isAtBottom, setIsAtBottom] = useState(true); const chatHistoryRef = useRef(null); @@ -89,7 +88,6 @@ export default function ChatHistory({ history = [], workspace, sendCommand }) { ref={chatHistoryRef} > {history.map((props, index) => { - const isLastMessage = index === history.length - 1; const isLastBotReply = index === history.length - 1 && props.role === "assistant"; @@ -97,7 +95,6 @@ export default function ChatHistory({ history = [], workspace, sendCommand }) { return ( { try { const { chatId } = request.params; - const { feedback } = reqBody(request); + const { feedback = null } = reqBody(request); const existingChat = await WorkspaceChats.get({ id: Number(chatId), workspaceId: response.locals.workspace.id, }); if (!existingChat) { - response - .status(404) - .json({ success: false, message: "Chat not found" }); + response.status(404).end(); return; } @@ -348,9 +346,7 @@ function workspaceEndpoints(app) { response.status(200).json({ success: result }); } catch (error) { console.error("Error updating chat feedback:", error); - response - .status(500) - .json({ success: false, message: "Internal server error" }); + response.status(500).end(); } } ); diff --git a/server/models/workspaceChats.js b/server/models/workspaceChats.js index f7271c06506..c81992caadb 100644 --- a/server/models/workspaceChats.js +++ b/server/models/workspaceChats.js @@ -211,7 +211,8 @@ const WorkspaceChats = { id: Number(chatId), }, data: { - feedbackScore: feedbackScore, + feedbackScore: + feedbackScore === null ? null : Number(feedbackScore) === 1, }, }); return; diff --git a/server/utils/chats/index.js b/server/utils/chats/index.js index 15d5a81d8d8..d25d2a93bf7 100644 --- a/server/utils/chats/index.js +++ b/server/utils/chats/index.js @@ -7,7 +7,7 @@ const { getVectorDbClass, getLLMProvider } = require("../helpers"); function convertToChatHistory(history = []) { const formattedHistory = []; history.forEach((history) => { - const { prompt, response, createdAt, feedbackScore, id } = history; + const { prompt, response, createdAt, feedbackScore = null, id } = history; const data = JSON.parse(response); formattedHistory.push([ { @@ -19,9 +19,9 @@ function convertToChatHistory(history = []) { role: "assistant", content: data.text, sources: data.sources || [], - feedbackScore, chatId: id, sentAt: moment(createdAt).unix(), + feedbackScore, }, ]); }); @@ -197,10 +197,10 @@ async function chatWithWorkspace( id: uuid, type: "textResponse", close: true, - textResponse, + error: null, chatId: chat.id, + textResponse, sources, - error, }; } diff --git a/server/utils/chats/stream.js b/server/utils/chats/stream.js index dbb01783032..0fe5a7eaf2d 100644 --- a/server/utils/chats/stream.js +++ b/server/utils/chats/stream.js @@ -181,9 +181,10 @@ async function streamChatWithWorkspace( workspaceId: workspace.id, prompt: message, response: { text: completeText, sources, type: chatMode }, - user, threadId: thread?.id, + user, }); + writeResponseChunk(response, { uuid, type: "finalizeResponseStream", @@ -246,8 +247,8 @@ async function streamEmptyEmbeddingChat({ workspaceId: workspace.id, prompt: message, response: { text: completeText, sources: [], type: "chat" }, - user, threadId: thread?.id, + user, }); writeResponseChunk(response, { @@ -257,7 +258,6 @@ async function streamEmptyEmbeddingChat({ error: false, chatId: chat.id, }); - return; } From 1de3c5d4384dc00620d14d1a33f543baba0be018 Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Tue, 13 Feb 2024 11:28:22 -0800 Subject: [PATCH 6/7] remove dup id --- .../ChatHistory/HistoricalMessage/Actions/index.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx index 7976baf2856..b68bc92b024 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx @@ -35,7 +35,6 @@ const Actions = ({ message, feedbackScore, chatId, slug }) => { isSelected={selectedFeedback === false} handleFeedback={() => handleFeedback(false)} tooltipId={`${chatId}-thumbs-down`} - tooltipId="thumbs-down" tooltipContent="Bad response" IconComponent={ThumbsDown} /> From 8ccc982d35da1a9608fdd848fdf8c17e4864d669 Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Tue, 13 Feb 2024 11:32:37 -0800 Subject: [PATCH 7/7] Add rating to CSV output --- server/utils/helpers/chat/convertTo.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server/utils/helpers/chat/convertTo.js b/server/utils/helpers/chat/convertTo.js index 5bd5b37eb20..2109ecbea9a 100644 --- a/server/utils/helpers/chat/convertTo.js +++ b/server/utils/helpers/chat/convertTo.js @@ -6,7 +6,7 @@ const { WorkspaceChats } = require("../../../models/workspaceChats"); // Todo: add RLHF feedbackScore field support async function convertToCSV(preparedData) { - const rows = ["id,username,workspace,prompt,response,sent_at"]; + const rows = ["id,username,workspace,prompt,response,sent_at,rating"]; for (const item of preparedData) { const record = [ item.id, @@ -15,6 +15,7 @@ async function convertToCSV(preparedData) { escapeCsv(item.prompt), escapeCsv(item.response), item.sent_at, + item.feedback, ].join(","); rows.push(record); } @@ -53,6 +54,12 @@ async function prepareWorkspaceChatsForExport(format = "jsonl") { prompt: chat.prompt, response: responseJson.text, sent_at: chat.createdAt, + feedback: + chat.feedbackScore === null + ? "--" + : chat.feedbackScore + ? "GOOD" + : "BAD", }; });