mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-14 02:20:12 +01:00
Fix PFPs
TODO: Fix default user profile image Add User and Assistant workspace response
This commit is contained in:
parent
956eeccfce
commit
9bf6b974a0
@ -11,7 +11,6 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@metamask/jazzicon": "^2.0.0",
|
|
||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
"@microsoft/fetch-event-source": "^2.0.1",
|
||||||
"@phosphor-icons/react": "^2.0.13",
|
"@phosphor-icons/react": "^2.0.13",
|
||||||
"@tremor/react": "^3.15.1",
|
"@tremor/react": "^3.15.1",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Jazzicon from "../UserIcon";
|
import UserIcon from "../UserIcon";
|
||||||
import { userFromStorage } from "@/utils/request";
|
import { userFromStorage } from "@/utils/request";
|
||||||
import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants";
|
import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants";
|
||||||
|
|
||||||
@ -11,8 +11,7 @@ export default function ChatBubble({ message, type, popMsg }) {
|
|||||||
<div className={`flex justify-center items-end w-full ${backgroundColor}`}>
|
<div className={`flex justify-center items-end w-full ${backgroundColor}`}>
|
||||||
<div className={`py-8 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}>
|
<div className={`py-8 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<UserIcon
|
||||||
size={36}
|
|
||||||
user={{ uid: isUser ? userFromStorage()?.username : "system" }}
|
user={{ uid: isUser ? userFromStorage()?.username : "system" }}
|
||||||
role={type}
|
role={type}
|
||||||
/>
|
/>
|
||||||
|
@ -13,7 +13,7 @@ import { isMobile } from "react-device-detect";
|
|||||||
import { SidebarMobileHeader } from "../Sidebar";
|
import { SidebarMobileHeader } from "../Sidebar";
|
||||||
import ChatBubble from "../ChatBubble";
|
import ChatBubble from "../ChatBubble";
|
||||||
import System from "@/models/system";
|
import System from "@/models/system";
|
||||||
import Jazzicon from "../UserIcon";
|
import UserIcon from "../UserIcon";
|
||||||
import { userFromStorage } from "@/utils/request";
|
import { userFromStorage } from "@/utils/request";
|
||||||
import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants";
|
import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants";
|
||||||
import useUser from "@/hooks/useUser";
|
import useUser from "@/hooks/useUser";
|
||||||
@ -46,7 +46,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`pt-10 pb-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`pt-10 pb-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: "system" }} role={"assistant"} />
|
<UserIcon user={{ uid: "system" }} role={"assistant"} />
|
||||||
|
|
||||||
<span
|
<span
|
||||||
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
||||||
@ -70,7 +70,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`pb-4 pt-2 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`pb-4 pt-2 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: "system" }} role={"assistant"} />
|
<UserIcon user={{ uid: "system" }} role={"assistant"} />
|
||||||
|
|
||||||
<span
|
<span
|
||||||
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
||||||
@ -93,7 +93,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`pt-2 pb-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`pt-2 pb-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: "system" }} role={"assistant"} />
|
<UserIcon user={{ uid: "system" }} role={"assistant"} />
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
||||||
@ -127,8 +127,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<UserIcon
|
||||||
size={36}
|
|
||||||
user={{ uid: userFromStorage()?.username }}
|
user={{ uid: userFromStorage()?.username }}
|
||||||
role={"user"}
|
role={"user"}
|
||||||
/>
|
/>
|
||||||
@ -151,7 +150,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: "system" }} role={"assistant"} />
|
<UserIcon user={{ uid: "system" }} role={"assistant"} />
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
||||||
@ -188,8 +187,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<UserIcon
|
||||||
size={36}
|
|
||||||
user={{ uid: userFromStorage()?.username }}
|
user={{ uid: userFromStorage()?.username }}
|
||||||
role={"user"}
|
role={"user"}
|
||||||
/>
|
/>
|
||||||
@ -213,7 +211,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: "system" }} role={"assistant"} />
|
<UserIcon user={{ uid: "system" }} role={"assistant"} />
|
||||||
|
|
||||||
<span
|
<span
|
||||||
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
||||||
@ -251,8 +249,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<UserIcon
|
||||||
size={36}
|
|
||||||
user={{ uid: userFromStorage()?.username }}
|
user={{ uid: userFromStorage()?.username }}
|
||||||
role={"user"}
|
role={"user"}
|
||||||
/>
|
/>
|
||||||
@ -275,7 +272,7 @@ export default function DefaultChatContainer() {
|
|||||||
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: "system" }} role={"assistant"} />
|
<UserIcon user={{ uid: "system" }} role={"assistant"} />
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
|
||||||
|
@ -1,35 +1,44 @@
|
|||||||
import React, { useRef, useEffect } from "react";
|
import React from "react";
|
||||||
import JAZZ from "@metamask/jazzicon";
|
|
||||||
import usePfp from "../../hooks/usePfp";
|
import usePfp from "../../hooks/usePfp";
|
||||||
|
import WorkspaceDefault from "./workspace.png";
|
||||||
|
|
||||||
export default function Jazzicon({ size = 10, user, role }) {
|
export default function UserIcon({ user, role }) {
|
||||||
const { pfp } = usePfp();
|
const { pfp } = usePfp();
|
||||||
const divRef = useRef(null);
|
|
||||||
const seed = user?.uid
|
|
||||||
? toPseudoRandomInteger(user.uid)
|
|
||||||
: Math.floor(100000 + Math.random() * 900000);
|
|
||||||
|
|
||||||
useEffect(() => {
|
if (role === "user") {
|
||||||
if (!divRef.current || (role === "user" && pfp)) return;
|
if (!pfp) {
|
||||||
|
return (
|
||||||
const result = JAZZ(size, seed);
|
<div className="relative w-[36px] h-[36px] rounded-full flex-shrink-0 overflow-hidden">
|
||||||
divRef.current.appendChild(result);
|
<div className="absolute top-0 left-0 w-full h-full object-cover rounded-full flex items-center justify-center bg-[#2DF4D0] text-black text-lg font-semibold">
|
||||||
}, [pfp, role, seed, size]);
|
<p className="p-0 !m-0">{user?.username?.slice(0, 2) || "U"}</p>
|
||||||
|
</div>
|
||||||
return (
|
</div>
|
||||||
<div className="relative w-[35px] h-[35px] rounded-full flex-shrink-0 overflow-hidden">
|
);
|
||||||
<div ref={divRef} />
|
}
|
||||||
{role === "user" && pfp && (
|
return (
|
||||||
|
<div className="relative w-[36px] h-[36px] rounded-full flex-shrink-0 overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={pfp}
|
src={pfp}
|
||||||
|
width={36}
|
||||||
|
height={36}
|
||||||
alt="User profile picture"
|
alt="User profile picture"
|
||||||
className="absolute top-0 left-0 w-full h-full object-cover rounded-full bg-white"
|
className={`absolute top-0 left-0 w-full h-full object-cover rounded-full ${
|
||||||
|
!!pfp ? "" : "border border-white/40"
|
||||||
|
}`}
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-[36px] h-[36px] rounded-full flex-shrink-0 overflow-hidden">
|
||||||
|
<img
|
||||||
|
src={pfp ?? WorkspaceDefault}
|
||||||
|
alt="User profile picture"
|
||||||
|
className={`absolute top-0 left-0 w-full h-full object-cover rounded-full ${
|
||||||
|
!!pfp ? "" : "border border-white/40"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toPseudoRandomInteger(uidString = "") {
|
|
||||||
return uidString.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
||||||
}
|
|
||||||
|
BIN
frontend/src/components/UserIcon/workspace.png
Normal file
BIN
frontend/src/components/UserIcon/workspace.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
@ -29,24 +29,28 @@ export function useEditMessage({ chatId, role }) {
|
|||||||
return { isEditing, setIsEditing };
|
return { isEditing, setIsEditing };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EditMessageAction({ chatId = null, role }) {
|
export function EditMessageAction({ chatId = null, role, isEditing }) {
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
|
||||||
function handleEditClick() {
|
function handleEditClick() {
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
new CustomEvent(EDIT_EVENT, { detail: { chatId, role } })
|
new CustomEvent(EDIT_EVENT, { detail: { chatId, role } })
|
||||||
);
|
);
|
||||||
setIsEditing(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chatId || isEditing) return null;
|
if (!chatId || isEditing) return null;
|
||||||
return (
|
return (
|
||||||
<div className="mt-3 relative">
|
<div
|
||||||
|
className={`mt-3 relative ${
|
||||||
|
role === "user" && !isEditing ? "opacity-0" : ""
|
||||||
|
} group-hover:opacity-100 transition-all duration-300`}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
onClick={handleEditClick}
|
onClick={handleEditClick}
|
||||||
data-tooltip-id="edit-input-text"
|
data-tooltip-id="edit-input-text"
|
||||||
data-tooltip-content="Edit"
|
data-tooltip-content={`Edit ${
|
||||||
|
role === "user" ? "Prompt" : "Response"
|
||||||
|
} `}
|
||||||
className="border-none text-zinc-300"
|
className="border-none text-zinc-300"
|
||||||
aria-label="Edit"
|
aria-label={`Edit ${role === "user" ? "Prompt" : "Response"}`}
|
||||||
>
|
>
|
||||||
<Pencil size={18} className="mb-1" />
|
<Pencil size={18} className="mb-1" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
ThumbsUp,
|
ThumbsUp,
|
||||||
ThumbsDown,
|
ThumbsDown,
|
||||||
ArrowsClockwise,
|
ArrowsClockwise,
|
||||||
|
Copy,
|
||||||
} from "@phosphor-icons/react";
|
} from "@phosphor-icons/react";
|
||||||
import { Tooltip } from "react-tooltip";
|
import { Tooltip } from "react-tooltip";
|
||||||
import Workspace from "@/models/workspace";
|
import Workspace from "@/models/workspace";
|
||||||
@ -19,6 +20,7 @@ const Actions = ({
|
|||||||
slug,
|
slug,
|
||||||
isLastMessage,
|
isLastMessage,
|
||||||
regenerateMessage,
|
regenerateMessage,
|
||||||
|
isEditing,
|
||||||
role,
|
role,
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore);
|
const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore);
|
||||||
@ -33,15 +35,15 @@ const Actions = ({
|
|||||||
<div className="flex w-full justify-between items-center">
|
<div className="flex w-full justify-between items-center">
|
||||||
<div className="flex justify-start items-center gap-x-4">
|
<div className="flex justify-start items-center gap-x-4">
|
||||||
<CopyMessage message={message} />
|
<CopyMessage message={message} />
|
||||||
<EditMessageAction chatId={chatId} role={role} />
|
<EditMessageAction chatId={chatId} role={role} isEditing={isEditing} />
|
||||||
{isLastMessage && (
|
{isLastMessage && !isEditing && (
|
||||||
<RegenerateMessage
|
<RegenerateMessage
|
||||||
regenerateMessage={regenerateMessage}
|
regenerateMessage={regenerateMessage}
|
||||||
slug={slug}
|
slug={slug}
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{chatId && role !== "user" && (
|
{chatId && role !== "user" && !isEditing && (
|
||||||
<>
|
<>
|
||||||
<FeedbackButton
|
<FeedbackButton
|
||||||
isSelected={selectedFeedback === true}
|
isSelected={selectedFeedback === true}
|
||||||
@ -113,7 +115,7 @@ function CopyMessage({ message }) {
|
|||||||
{copied ? (
|
{copied ? (
|
||||||
<Check size={18} className="mb-1" />
|
<Check size={18} className="mb-1" />
|
||||||
) : (
|
) : (
|
||||||
<ClipboardText size={18} className="mb-1" />
|
<Copy size={18} className="mb-1" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useState, useRef, useEffect } from "react";
|
import React, { memo } from "react";
|
||||||
import { Warning } from "@phosphor-icons/react";
|
import { Warning } from "@phosphor-icons/react";
|
||||||
import Jazzicon from "../../../../UserIcon";
|
import UserIcon from "../../../../UserIcon";
|
||||||
import Actions from "./Actions";
|
import Actions from "./Actions";
|
||||||
import renderMarkdown from "@/utils/chat/markdown";
|
import renderMarkdown from "@/utils/chat/markdown";
|
||||||
import { userFromStorage } from "@/utils/request";
|
import { userFromStorage } from "@/utils/request";
|
||||||
@ -60,7 +60,7 @@ const HistoricalMessage = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={uuid}
|
key={uuid}
|
||||||
className={`flex justify-center items-end w-full ${
|
className={`flex justify-center items-end w-full group ${
|
||||||
role === "user" ? USER_BACKGROUND_COLOR : AI_BACKGROUND_COLOR
|
role === "user" ? USER_BACKGROUND_COLOR : AI_BACKGROUND_COLOR
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@ -93,6 +93,7 @@ const HistoricalMessage = ({
|
|||||||
slug={workspace?.slug}
|
slug={workspace?.slug}
|
||||||
isLastMessage={isLastMessage}
|
isLastMessage={isLastMessage}
|
||||||
regenerateMessage={regenerateMessage}
|
regenerateMessage={regenerateMessage}
|
||||||
|
isEditing={isEditing}
|
||||||
role={role}
|
role={role}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -116,8 +117,7 @@ function ProfileImage({ role, workspace }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Jazzicon
|
<UserIcon
|
||||||
size={36}
|
|
||||||
user={{
|
user={{
|
||||||
uid: role === "user" ? userFromStorage()?.username : workspace.slug,
|
uid: role === "user" ? userFromStorage()?.username : workspace.slug,
|
||||||
}}
|
}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import { Warning } from "@phosphor-icons/react";
|
import { Warning } from "@phosphor-icons/react";
|
||||||
import Jazzicon from "../../../../UserIcon";
|
import UserIcon from "../../../../UserIcon";
|
||||||
import renderMarkdown from "@/utils/chat/markdown";
|
import renderMarkdown from "@/utils/chat/markdown";
|
||||||
import Citations from "../Citation";
|
import Citations from "../Citation";
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ export function WorkspaceProfileImage({ workspace }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Jazzicon size={36} user={{ uid: workspace.slug }} role="assistant" />;
|
return <UserIcon user={{ uid: workspace.slug }} role="assistant" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default memo(PromptReply);
|
export default memo(PromptReply);
|
||||||
|
@ -8,14 +8,17 @@ import debounce from "lodash.debounce";
|
|||||||
import useUser from "@/hooks/useUser";
|
import useUser from "@/hooks/useUser";
|
||||||
import Chartable from "./Chartable";
|
import Chartable from "./Chartable";
|
||||||
import Workspace from "@/models/workspace";
|
import Workspace from "@/models/workspace";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
export default function ChatHistory({
|
export default function ChatHistory({
|
||||||
history = [],
|
history = [],
|
||||||
workspace,
|
workspace,
|
||||||
sendCommand,
|
sendCommand,
|
||||||
|
updateHistory,
|
||||||
regenerateAssistantMessage,
|
regenerateAssistantMessage,
|
||||||
}) {
|
}) {
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
const { threadSlug = null } = useParams();
|
||||||
const { showing, showModal, hideModal } = useManageWorkspaceModal();
|
const { showing, showModal, hideModal } = useManageWorkspaceModal();
|
||||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||||
const chatHistoryRef = useRef(null);
|
const chatHistoryRef = useRef(null);
|
||||||
@ -89,8 +92,6 @@ export default function ChatHistory({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Be able to edit both user and system response message.
|
// TODO: Be able to edit both user and system response message.
|
||||||
// TODO: Pencil does not appear under user message while chatting because it
|
|
||||||
// does not know its own chatId since not response is present.
|
|
||||||
const saveEditedMessage = async ({ editedMessage, chatId, role }) => {
|
const saveEditedMessage = async ({ editedMessage, chatId, role }) => {
|
||||||
if (!editedMessage) return; // Don't save empty edits.
|
if (!editedMessage) return; // Don't save empty edits.
|
||||||
|
|
||||||
@ -107,13 +108,27 @@ export default function ChatHistory({
|
|||||||
// update last message in history to edited message
|
// update last message in history to edited message
|
||||||
updatedHistory[updatedHistory.length - 1].content = editedMessage;
|
updatedHistory[updatedHistory.length - 1].content = editedMessage;
|
||||||
// remove all edited messages after the edited message in backend
|
// remove all edited messages after the edited message in backend
|
||||||
await Workspace.deleteEditedChats(workspace.slug, chatId);
|
await Workspace.deleteEditedChats(workspace.slug, threadSlug, chatId);
|
||||||
sendCommand(editedMessage, true, updatedHistory);
|
sendCommand(editedMessage, true, updatedHistory);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If role is an assistant we simply want to update the comment and save on the backend as an edit.
|
// If role is an assistant we simply want to update the comment and save on the backend as an edit.
|
||||||
if (role === "assistant") {
|
if (role === "assistant") {
|
||||||
|
const updatedHistory = [...history];
|
||||||
|
const targetIdx = history.findIndex(
|
||||||
|
(msg) => msg.chatId === chatId && msg.role === role
|
||||||
|
);
|
||||||
|
if (targetIdx < 0) return;
|
||||||
|
updatedHistory[targetIdx].content = editedMessage;
|
||||||
|
updateHistory(updatedHistory);
|
||||||
|
await Workspace.updateChatResponse(
|
||||||
|
workspace.slug,
|
||||||
|
threadSlug,
|
||||||
|
chatId,
|
||||||
|
editedMessage
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,6 +240,7 @@ export default function ChatContainer({ workspace, knownHistory = [] }) {
|
|||||||
history={chatHistory}
|
history={chatHistory}
|
||||||
workspace={workspace}
|
workspace={workspace}
|
||||||
sendCommand={sendCommand}
|
sendCommand={sendCommand}
|
||||||
|
updateHistory={setChatHistory}
|
||||||
regenerateAssistantMessage={regenerateAssistantMessage}
|
regenerateAssistantMessage={regenerateAssistantMessage}
|
||||||
/>
|
/>
|
||||||
<PromptInput
|
<PromptInput
|
||||||
|
@ -23,7 +23,6 @@ export default function WorkspaceChat({ loading, workspace }) {
|
|||||||
? await Workspace.threads.chatHistory(workspace.slug, threadSlug)
|
? await Workspace.threads.chatHistory(workspace.slug, threadSlug)
|
||||||
: await Workspace.chatHistory(workspace.slug);
|
: await Workspace.chatHistory(workspace.slug);
|
||||||
|
|
||||||
console.log("CHAT HISTORY", chatHistory);
|
|
||||||
setHistory(chatHistory);
|
setHistory(chatHistory);
|
||||||
setLoadingHistory(false);
|
setLoadingHistory(false);
|
||||||
}
|
}
|
||||||
|
@ -90,22 +90,25 @@ const Workspace = {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
deleteEditedChats: async function (slug = "", threadSlug = "", startingId) {
|
||||||
//TODO, This can also delete chats in different. Needs thread scoping.
|
if (!!threadSlug)
|
||||||
deleteEditedChats: async function (slug = "", startingId) {
|
return this.threads._deleteEditedChats(slug, threadSlug, startingId);
|
||||||
return await fetch(`${API_BASE}/workspace/${slug}/delete-edited-chats`, {
|
return this._deleteEditedChats(slug, startingId);
|
||||||
method: "DELETE",
|
},
|
||||||
headers: baseHeaders(),
|
updateChatResponse: async function (
|
||||||
body: JSON.stringify({ startingId }),
|
slug = "",
|
||||||
})
|
threadSlug = "",
|
||||||
.then((res) => {
|
chatId,
|
||||||
if (res.ok) return true;
|
newText
|
||||||
throw new Error("Failed to delete chats.");
|
) {
|
||||||
})
|
if (!!threadSlug)
|
||||||
.catch((e) => {
|
return this.threads._updateChatResponse(
|
||||||
console.log(e);
|
slug,
|
||||||
return false;
|
threadSlug,
|
||||||
});
|
chatId,
|
||||||
|
newText
|
||||||
|
);
|
||||||
|
return this._updateChatResponse(slug, chatId, newText);
|
||||||
},
|
},
|
||||||
streamChat: async function ({ slug }, message, handleChat) {
|
streamChat: async function ({ slug }, message, handleChat) {
|
||||||
const ctrl = new AbortController();
|
const ctrl = new AbortController();
|
||||||
@ -304,8 +307,6 @@ const Workspace = {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
threads: WorkspaceThread,
|
|
||||||
|
|
||||||
uploadPfp: async function (formData, slug) {
|
uploadPfp: async function (formData, slug) {
|
||||||
return await fetch(`${API_BASE}/workspace/${slug}/upload-pfp`, {
|
return await fetch(`${API_BASE}/workspace/${slug}/upload-pfp`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@ -353,6 +354,37 @@ const Workspace = {
|
|||||||
return { success: false, error: e.message };
|
return { success: false, error: e.message };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
_updateChatResponse: async function (slug = "", chatId, newText) {
|
||||||
|
return await fetch(`${API_BASE}/workspace/${slug}/update-chat`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
body: JSON.stringify({ chatId, newText }),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok) return true;
|
||||||
|
throw new Error("Failed to update chat.");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_deleteEditedChats: async function (slug = "", startingId) {
|
||||||
|
return await fetch(`${API_BASE}/workspace/${slug}/delete-edited-chats`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
body: JSON.stringify({ startingId }),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok) return true;
|
||||||
|
throw new Error("Failed to delete chats.");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
threads: WorkspaceThread,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Workspace;
|
export default Workspace;
|
||||||
|
@ -163,6 +163,51 @@ const WorkspaceThread = {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
_deleteEditedChats: async function (
|
||||||
|
workspaceSlug = "",
|
||||||
|
threadSlug = "",
|
||||||
|
startingId
|
||||||
|
) {
|
||||||
|
return await fetch(
|
||||||
|
`${API_BASE}/workspace/${workspaceSlug}/thread/${threadSlug}/delete-edited-chats`,
|
||||||
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
body: JSON.stringify({ startingId }),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok) return true;
|
||||||
|
throw new Error("Failed to delete chats.");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_updateChatResponse: async function (
|
||||||
|
workspaceSlug = "",
|
||||||
|
threadSlug = "",
|
||||||
|
chatId,
|
||||||
|
newText
|
||||||
|
) {
|
||||||
|
return await fetch(
|
||||||
|
`${API_BASE}/workspace/${workspaceSlug}/thread/${threadSlug}/update-chat`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
body: JSON.stringify({ chatId, newText }),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok) return true;
|
||||||
|
throw new Error("Failed to update chat.");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WorkspaceThread;
|
export default WorkspaceThread;
|
||||||
|
@ -487,14 +487,6 @@
|
|||||||
"@jridgewell/resolve-uri" "^3.1.0"
|
"@jridgewell/resolve-uri" "^3.1.0"
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||||
|
|
||||||
"@metamask/jazzicon@^2.0.0":
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@metamask/jazzicon/-/jazzicon-2.0.0.tgz#5615528e91c0fc5c9d79202d1f0954a7922525a0"
|
|
||||||
integrity sha512-7M+WSZWKcQAo0LEhErKf1z+D3YX0tEDAcGvcKbDyvDg34uvgeKR00mFNIYwAhdAS9t8YXxhxZgsrRBBg6X8UQg==
|
|
||||||
dependencies:
|
|
||||||
color "^0.11.3"
|
|
||||||
mersenne-twister "^1.1.0"
|
|
||||||
|
|
||||||
"@microsoft/fetch-event-source@^2.0.1":
|
"@microsoft/fetch-event-source@^2.0.1":
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
|
resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
|
||||||
@ -1025,11 +1017,6 @@ cliui@^8.0.1:
|
|||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
wrap-ansi "^7.0.0"
|
wrap-ansi "^7.0.0"
|
||||||
|
|
||||||
clone@^1.0.2:
|
|
||||||
version "1.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
|
||||||
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
|
|
||||||
|
|
||||||
clsx@^1.1.1:
|
clsx@^1.1.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||||
@ -1040,7 +1027,7 @@ clsx@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb"
|
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb"
|
||||||
integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==
|
integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==
|
||||||
|
|
||||||
color-convert@^1.3.0, color-convert@^1.9.0:
|
color-convert@^1.9.0:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||||
@ -1059,27 +1046,11 @@ color-name@1.1.3:
|
|||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||||
|
|
||||||
color-name@^1.0.0, color-name@~1.1.4:
|
color-name@~1.1.4:
|
||||||
version "1.1.4"
|
version "1.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
color-string@^0.3.0:
|
|
||||||
version "0.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
|
|
||||||
integrity sha512-sz29j1bmSDfoAxKIEU6zwoIZXN6BrFbAMIhfYCNyiZXBDuU/aiHlN84lp/xDzL2ubyFhLDobHIlU1X70XRrMDA==
|
|
||||||
dependencies:
|
|
||||||
color-name "^1.0.0"
|
|
||||||
|
|
||||||
color@^0.11.3:
|
|
||||||
version "0.11.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
|
|
||||||
integrity sha512-Ajpjd8asqZ6EdxQeqGzU5WBhhTfJ/0cA4Wlbre7e5vXfmDSmda7Ov6jeKoru+b0vHcb1CqvuroTHp5zIWzhVMA==
|
|
||||||
dependencies:
|
|
||||||
clone "^1.0.2"
|
|
||||||
color-convert "^1.3.0"
|
|
||||||
color-string "^0.3.0"
|
|
||||||
|
|
||||||
commander@^4.0.0:
|
commander@^4.0.0:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
||||||
@ -2401,11 +2372,6 @@ merge2@^1.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
|
||||||
mersenne-twister@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"
|
|
||||||
integrity sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==
|
|
||||||
|
|
||||||
micromatch@^4.0.4, micromatch@^4.0.5:
|
micromatch@^4.0.4, micromatch@^4.0.5:
|
||||||
version "4.0.5"
|
version "4.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
const { multiUserMode, userFromSession, reqBody } = require("../utils/http");
|
const {
|
||||||
|
multiUserMode,
|
||||||
|
userFromSession,
|
||||||
|
reqBody,
|
||||||
|
safeJsonParse,
|
||||||
|
} = require("../utils/http");
|
||||||
const { validatedRequest } = require("../utils/middleware/validatedRequest");
|
const { validatedRequest } = require("../utils/middleware/validatedRequest");
|
||||||
const { Telemetry } = require("../models/telemetry");
|
const { Telemetry } = require("../models/telemetry");
|
||||||
const {
|
const {
|
||||||
@ -168,6 +173,77 @@ function workspaceThreadEndpoints(app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.delete(
|
||||||
|
"/workspace/:slug/thread/:threadSlug/delete-edited-chats",
|
||||||
|
[
|
||||||
|
validatedRequest,
|
||||||
|
flexUserRoleValid([ROLES.all]),
|
||||||
|
validWorkspaceAndThreadSlug,
|
||||||
|
],
|
||||||
|
async (request, response) => {
|
||||||
|
try {
|
||||||
|
const { startingId } = reqBody(request);
|
||||||
|
const user = await userFromSession(request, response);
|
||||||
|
const workspace = response.locals.workspace;
|
||||||
|
const thread = response.locals.thread;
|
||||||
|
|
||||||
|
await WorkspaceChats.delete({
|
||||||
|
workspaceId: Number(workspace.id),
|
||||||
|
thread_id: Number(thread.id),
|
||||||
|
user_id: user?.id,
|
||||||
|
id: { gte: Number(startingId) },
|
||||||
|
});
|
||||||
|
|
||||||
|
response.sendStatus(200).end();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message, e);
|
||||||
|
response.sendStatus(500).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
"/workspace/:slug/thread/:threadSlug/update-chat",
|
||||||
|
[
|
||||||
|
validatedRequest,
|
||||||
|
flexUserRoleValid([ROLES.all]),
|
||||||
|
validWorkspaceAndThreadSlug,
|
||||||
|
],
|
||||||
|
async (request, response) => {
|
||||||
|
try {
|
||||||
|
const { chatId, newText = null } = reqBody(request);
|
||||||
|
if (!newText || !String(newText).trim())
|
||||||
|
throw new Error("Cannot save empty response");
|
||||||
|
|
||||||
|
const user = await userFromSession(request, response);
|
||||||
|
const workspace = response.locals.workspace;
|
||||||
|
const thread = response.locals.thread;
|
||||||
|
const existingChat = await WorkspaceChats.get({
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
thread_id: thread.id,
|
||||||
|
user_id: user?.id,
|
||||||
|
id: Number(chatId),
|
||||||
|
});
|
||||||
|
if (!existingChat) throw new Error("Invalid chat.");
|
||||||
|
|
||||||
|
const chatResponse = safeJsonParse(existingChat.response, null);
|
||||||
|
if (!chatResponse) throw new Error("Failed to parse chat response");
|
||||||
|
|
||||||
|
await WorkspaceChats._update(existingChat.id, {
|
||||||
|
response: JSON.stringify({
|
||||||
|
...chatResponse,
|
||||||
|
text: String(newText),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
response.sendStatus(200).end();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message, e);
|
||||||
|
response.sendStatus(500).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { workspaceThreadEndpoints };
|
module.exports = { workspaceThreadEndpoints };
|
||||||
|
@ -377,14 +377,9 @@ function workspaceEndpoints(app) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("in here");
|
|
||||||
|
|
||||||
const history = multiUserMode(response)
|
const history = multiUserMode(response)
|
||||||
? await WorkspaceChats.forWorkspaceByUser(workspace.id, user.id)
|
? await WorkspaceChats.forWorkspaceByUser(workspace.id, user.id)
|
||||||
: await WorkspaceChats.forWorkspace(workspace.id);
|
: await WorkspaceChats.forWorkspace(workspace.id);
|
||||||
|
|
||||||
console.log(history);
|
|
||||||
|
|
||||||
response.status(200).json({ history: convertToChatHistory(history) });
|
response.status(200).json({ history: convertToChatHistory(history) });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e.message, e);
|
console.log(e.message, e);
|
||||||
@ -430,15 +425,13 @@ function workspaceEndpoints(app) {
|
|||||||
async (request, response) => {
|
async (request, response) => {
|
||||||
try {
|
try {
|
||||||
const { startingId } = reqBody(request);
|
const { startingId } = reqBody(request);
|
||||||
|
const user = await userFromSession(request, response);
|
||||||
const workspace = response.locals.workspace;
|
const workspace = response.locals.workspace;
|
||||||
|
|
||||||
if (!workspace) {
|
|
||||||
response.sendStatus(400).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await WorkspaceChats.delete({
|
await WorkspaceChats.delete({
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
|
thread_id: null,
|
||||||
|
user_id: user?.id,
|
||||||
id: { gte: Number(startingId) },
|
id: { gte: Number(startingId) },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -450,6 +443,43 @@ function workspaceEndpoints(app) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
"/workspace/:slug/update-chat",
|
||||||
|
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
|
||||||
|
async (request, response) => {
|
||||||
|
try {
|
||||||
|
const { chatId, newText = null } = reqBody(request);
|
||||||
|
if (!newText || !String(newText).trim())
|
||||||
|
throw new Error("Cannot save empty response");
|
||||||
|
|
||||||
|
const user = await userFromSession(request, response);
|
||||||
|
const workspace = response.locals.workspace;
|
||||||
|
const existingChat = await WorkspaceChats.get({
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
thread_id: null,
|
||||||
|
user_id: user?.id,
|
||||||
|
id: Number(chatId),
|
||||||
|
});
|
||||||
|
if (!existingChat) throw new Error("Invalid chat.");
|
||||||
|
|
||||||
|
const chatResponse = safeJsonParse(existingChat.response, null);
|
||||||
|
if (!chatResponse) throw new Error("Failed to parse chat response");
|
||||||
|
|
||||||
|
await WorkspaceChats._update(existingChat.id, {
|
||||||
|
response: JSON.stringify({
|
||||||
|
...chatResponse,
|
||||||
|
text: String(newText),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
response.sendStatus(200).end();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message, e);
|
||||||
|
response.sendStatus(500).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
app.post(
|
app.post(
|
||||||
"/workspace/:slug/chat-feedback/:chatId",
|
"/workspace/:slug/chat-feedback/:chatId",
|
||||||
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
|
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
|
||||||
|
@ -220,6 +220,24 @@ const WorkspaceChats = {
|
|||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Explicit update of settings + key validations.
|
||||||
|
// Only use this method when directly setting a key value
|
||||||
|
// that takes no user input for the keys being modified.
|
||||||
|
_update: async function (id = null, data = {}) {
|
||||||
|
if (!id) throw new Error("No workspace chat id provided for update");
|
||||||
|
|
||||||
|
try {
|
||||||
|
await prisma.workspace_chats.update({
|
||||||
|
where: { id },
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { WorkspaceChats };
|
module.exports = { WorkspaceChats };
|
||||||
|
@ -168,8 +168,6 @@ function convertToChatHistory(history = []) {
|
|||||||
const formattedHistory = [];
|
const formattedHistory = [];
|
||||||
history.forEach((history) => {
|
history.forEach((history) => {
|
||||||
const { prompt, response, createdAt, feedbackScore = null, id } = history;
|
const { prompt, response, createdAt, feedbackScore = null, id } = history;
|
||||||
|
|
||||||
console.log("HISTORY", history);
|
|
||||||
const data = JSON.parse(response);
|
const data = JSON.parse(response);
|
||||||
formattedHistory.push([
|
formattedHistory.push([
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user