mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-11 01:10:11 +01:00
[FEAT] Implement regenerate response button (#1341)
* implement regenerate response button * wip on rerenders * remove function that was duplicate * update delete-chats function --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
2345424b03
commit
734c5a9e96
@ -5,11 +5,19 @@ import {
|
||||
ClipboardText,
|
||||
ThumbsUp,
|
||||
ThumbsDown,
|
||||
ArrowsClockwise,
|
||||
} from "@phosphor-icons/react";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import Workspace from "@/models/workspace";
|
||||
|
||||
const Actions = ({ message, feedbackScore, chatId, slug }) => {
|
||||
const Actions = ({
|
||||
message,
|
||||
feedbackScore,
|
||||
chatId,
|
||||
slug,
|
||||
isLastMessage,
|
||||
regenerateMessage,
|
||||
}) => {
|
||||
const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore);
|
||||
|
||||
const handleFeedback = async (newFeedback) => {
|
||||
@ -22,6 +30,14 @@ const Actions = ({ message, feedbackScore, chatId, slug }) => {
|
||||
return (
|
||||
<div className="flex justify-start items-center gap-x-4">
|
||||
<CopyMessage message={message} />
|
||||
{isLastMessage &&
|
||||
!message?.includes("Workspace chat memory was reset!") && (
|
||||
<RegenerateMessage
|
||||
regenerateMessage={regenerateMessage}
|
||||
slug={slug}
|
||||
chatId={chatId}
|
||||
/>
|
||||
)}
|
||||
{chatId && (
|
||||
<>
|
||||
<FeedbackButton
|
||||
@ -106,4 +122,26 @@ function CopyMessage({ message }) {
|
||||
);
|
||||
}
|
||||
|
||||
function RegenerateMessage({ regenerateMessage, chatId }) {
|
||||
return (
|
||||
<div className="mt-3 relative">
|
||||
<button
|
||||
onClick={() => regenerateMessage(chatId)}
|
||||
data-tooltip-id="regenerate-assistant-text"
|
||||
data-tooltip-content="Regenerate response"
|
||||
className="border-none text-zinc-300"
|
||||
aria-label="Regenerate"
|
||||
>
|
||||
<ArrowsClockwise size={18} className="mb-1" weight="fill" />
|
||||
</button>
|
||||
<Tooltip
|
||||
id="regenerate-assistant-text"
|
||||
place="bottom"
|
||||
delayShow={300}
|
||||
className="tooltip !text-xs"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Actions);
|
||||
|
@ -19,6 +19,8 @@ const HistoricalMessage = ({
|
||||
error = false,
|
||||
feedbackScore = null,
|
||||
chatId = null,
|
||||
isLastMessage = false,
|
||||
regenerateMessage,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
@ -59,6 +61,8 @@ const HistoricalMessage = ({
|
||||
feedbackScore={feedbackScore}
|
||||
chatId={chatId}
|
||||
slug={workspace?.slug}
|
||||
isLastMessage={isLastMessage}
|
||||
regenerateMessage={regenerateMessage}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -8,7 +8,12 @@ import debounce from "lodash.debounce";
|
||||
import useUser from "@/hooks/useUser";
|
||||
import Chartable from "./Chartable";
|
||||
|
||||
export default function ChatHistory({ history = [], workspace, sendCommand }) {
|
||||
export default function ChatHistory({
|
||||
history = [],
|
||||
workspace,
|
||||
sendCommand,
|
||||
regenerateAssistantMessage,
|
||||
}) {
|
||||
const { user } = useUser();
|
||||
const { showing, showModal, hideModal } = useManageWorkspaceModal();
|
||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||
@ -165,6 +170,8 @@ export default function ChatHistory({ history = [], workspace, sendCommand }) {
|
||||
feedbackScore={props.feedbackScore}
|
||||
chatId={props.chatId}
|
||||
error={props.error}
|
||||
regenerateMessage={regenerateAssistantMessage}
|
||||
isLastMessage={isLastBotReply}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -26,7 +26,7 @@ export default function ChatContainer({ workspace, knownHistory = [] }) {
|
||||
setMessage(event.target.value);
|
||||
};
|
||||
|
||||
// Emit an update to the sate of the prompt input without directly
|
||||
// Emit an update to the state of the prompt input without directly
|
||||
// passing a prop in so that it does not re-render constantly.
|
||||
function setMessageEmit(messageContent = "") {
|
||||
setMessage(messageContent);
|
||||
@ -56,24 +56,47 @@ export default function ChatContainer({ workspace, knownHistory = [] }) {
|
||||
setLoadingResponse(true);
|
||||
};
|
||||
|
||||
const sendCommand = async (command, submit = false) => {
|
||||
const regenerateAssistantMessage = (chatId) => {
|
||||
const updatedHistory = chatHistory.slice(0, -1);
|
||||
const lastUserMessage = updatedHistory.slice(-1)[0];
|
||||
Workspace.deleteChats(workspace.slug, [chatId])
|
||||
.then(() => sendCommand(lastUserMessage.content, true, updatedHistory))
|
||||
.catch((e) => console.error(e));
|
||||
};
|
||||
|
||||
const sendCommand = async (command, submit = false, history = []) => {
|
||||
if (!command || command === "") return false;
|
||||
if (!submit) {
|
||||
setMessageEmit(command);
|
||||
return;
|
||||
}
|
||||
|
||||
const prevChatHistory = [
|
||||
...chatHistory,
|
||||
{ content: command, role: "user" },
|
||||
{
|
||||
content: "",
|
||||
role: "assistant",
|
||||
pending: true,
|
||||
userMessage: command,
|
||||
animate: true,
|
||||
},
|
||||
];
|
||||
let prevChatHistory;
|
||||
if (history.length > 0) {
|
||||
// use pre-determined history chain.
|
||||
prevChatHistory = [
|
||||
...history,
|
||||
{
|
||||
content: "",
|
||||
role: "assistant",
|
||||
pending: true,
|
||||
userMessage: command,
|
||||
animate: true,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
prevChatHistory = [
|
||||
...chatHistory,
|
||||
{ content: command, role: "user" },
|
||||
{
|
||||
content: "",
|
||||
role: "assistant",
|
||||
pending: true,
|
||||
userMessage: command,
|
||||
animate: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
setChatHistory(prevChatHistory);
|
||||
setMessageEmit("");
|
||||
@ -217,6 +240,7 @@ export default function ChatContainer({ workspace, knownHistory = [] }) {
|
||||
history={chatHistory}
|
||||
workspace={workspace}
|
||||
sendCommand={sendCommand}
|
||||
regenerateAssistantMessage={regenerateAssistantMessage}
|
||||
/>
|
||||
<PromptInput
|
||||
submit={handleSubmit}
|
||||
|
@ -74,6 +74,22 @@ const Workspace = {
|
||||
.catch(() => false);
|
||||
return result;
|
||||
},
|
||||
|
||||
deleteChats: async function (slug = "", chatIds = []) {
|
||||
return await fetch(`${API_BASE}/workspace/${slug}/delete-chats`, {
|
||||
method: "DELETE",
|
||||
headers: baseHeaders(),
|
||||
body: JSON.stringify({ chatIds }),
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.ok) return true;
|
||||
throw new Error("Failed to delete chats.");
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
streamChat: async function ({ slug }, message, handleChat) {
|
||||
const ctrl = new AbortController();
|
||||
|
||||
|
@ -372,6 +372,37 @@ function workspaceEndpoints(app) {
|
||||
}
|
||||
);
|
||||
|
||||
app.delete(
|
||||
"/workspace/:slug/delete-chats",
|
||||
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
|
||||
async (request, response) => {
|
||||
try {
|
||||
const { chatIds = [] } = reqBody(request);
|
||||
const user = await userFromSession(request, response);
|
||||
const workspace = response.locals.workspace;
|
||||
|
||||
if (!workspace || !Array.isArray(chatIds)) {
|
||||
response.sendStatus(400).end();
|
||||
return;
|
||||
}
|
||||
|
||||
// This works for both workspace and threads.
|
||||
// we simplify this by just looking at workspace<>user overlap
|
||||
// since they are all on the same table.
|
||||
await WorkspaceChats.delete({
|
||||
id: { in: chatIds.map((id) => Number(id)) },
|
||||
user_id: user?.id ?? null,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
response.sendStatus(200).end();
|
||||
} catch (e) {
|
||||
console.log(e.message, e);
|
||||
response.sendStatus(500).end();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
app.post(
|
||||
"/workspace/:slug/chat-feedback/:chatId",
|
||||
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
|
||||
|
Loading…
Reference in New Issue
Block a user