Add ability to delete messages from the web app

This commit is contained in:
Debanjum 2024-10-30 04:24:22 -07:00
parent ba15686682
commit ca5a6831b6
4 changed files with 76 additions and 3 deletions

View file

@ -278,6 +278,16 @@ export default function ChatHistory(props: ChatHistoryProps) {
return data.agent?.persona; return data.agent?.persona;
} }
const handleDeleteMessage = (turnId?: string) => {
setData((prevData) => {
if (!prevData || !turnId) return prevData;
return {
...prevData,
chat: prevData.chat.filter((msg) => msg.turnId !== turnId),
};
});
};
if (!props.conversationId && !props.publicConversationSlug) { if (!props.conversationId && !props.publicConversationSlug) {
return null; return null;
} }
@ -312,6 +322,8 @@ export default function ChatHistory(props: ChatHistoryProps) {
customClassName="fullHistory" customClassName="fullHistory"
borderLeftColor={`${data?.agent?.color}-500`} borderLeftColor={`${data?.agent?.color}-500`}
isLastMessage={index === data.chat.length - 1} isLastMessage={index === data.chat.length - 1}
onDeleteMessage={handleDeleteMessage}
conversationId={props.conversationId}
/> />
{chatMessage.trainOfThought && chatMessage.by === "khoj" && ( {chatMessage.trainOfThought && chatMessage.by === "khoj" && (
<TrainOfThoughtComponent <TrainOfThoughtComponent
@ -342,9 +354,14 @@ export default function ChatHistory(props: ChatHistoryProps) {
by: "you", by: "you",
automationId: "", automationId: "",
images: message.images, images: message.images,
conversationId: props.conversationId,
turnId: message.turnId,
onDeleteMessage: handleDeleteMessage,
}} }}
customClassName="fullHistory" customClassName="fullHistory"
borderLeftColor={`${data?.agent?.color}-500`} borderLeftColor={`${data?.agent?.color}-500`}
onDeleteMessage={handleDeleteMessage}
conversationId={props.conversationId}
/> />
{message.trainOfThought && ( {message.trainOfThought && (
<TrainOfThoughtComponent <TrainOfThoughtComponent
@ -373,7 +390,12 @@ export default function ChatHistory(props: ChatHistoryProps) {
"memory-type": "", "memory-type": "",
"inferred-queries": message.inferredQueries || [], "inferred-queries": message.inferredQueries || [],
}, },
conversationId: props.conversationId,
turnId: message.turnId,
onDeleteMessage: handleDeleteMessage,
}} }}
conversationId={props.conversationId}
onDeleteMessage={handleDeleteMessage}
customClassName="fullHistory" customClassName="fullHistory"
borderLeftColor={`${data?.agent?.color}-500`} borderLeftColor={`${data?.agent?.color}-500`}
isLastMessage={true} isLastMessage={true}
@ -393,7 +415,11 @@ export default function ChatHistory(props: ChatHistoryProps) {
created: new Date().getTime().toString(), created: new Date().getTime().toString(),
by: "you", by: "you",
automationId: "", automationId: "",
conversationId: props.conversationId,
onDeleteMessage: handleDeleteMessage,
}} }}
conversationId={props.conversationId}
onDeleteMessage={handleDeleteMessage}
customClassName="fullHistory" customClassName="fullHistory"
borderLeftColor={`${data?.agent?.color}-500`} borderLeftColor={`${data?.agent?.color}-500`}
isLastMessage={true} isLastMessage={true}

View file

@ -29,6 +29,7 @@ import {
Check, Check,
Code, Code,
Shapes, Shapes,
Trash,
} from "@phosphor-icons/react"; } from "@phosphor-icons/react";
import DOMPurify from "dompurify"; import DOMPurify from "dompurify";
@ -146,6 +147,9 @@ export interface SingleChatMessage {
intent?: Intent; intent?: Intent;
agent?: AgentData; agent?: AgentData;
images?: string[]; images?: string[];
conversationId: string;
turnId?: string;
onDeleteMessage: (turnId: string) => void;
} }
export interface StreamMessage { export interface StreamMessage {
@ -161,6 +165,7 @@ export interface StreamMessage {
images?: string[]; images?: string[];
intentType?: string; intentType?: string;
inferredQueries?: string[]; inferredQueries?: string[];
turnId?: string;
} }
export interface ChatHistoryData { export interface ChatHistoryData {
@ -242,6 +247,8 @@ interface ChatMessageProps {
borderLeftColor?: string; borderLeftColor?: string;
isLastMessage?: boolean; isLastMessage?: boolean;
agent?: AgentData; agent?: AgentData;
onDeleteMessage: (turnId?: string) => void;
conversationId: string;
} }
interface TrainOfThoughtProps { interface TrainOfThoughtProps {
@ -654,6 +661,26 @@ const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>((props, ref) =>
}); });
} }
const deleteMessage = async (message: SingleChatMessage) => {
const response = await fetch("/api/chat/conversation/message", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
conversation_id: props.conversationId,
turn_id: message.turnId,
}),
});
if (response.ok) {
// Update the UI after successful deletion
props.onDeleteMessage(message.turnId);
} else {
console.error("Failed to delete message");
}
};
const allReferences = constructAllReferences( const allReferences = constructAllReferences(
props.chatMessage.context, props.chatMessage.context,
props.chatMessage.onlineContext, props.chatMessage.onlineContext,
@ -737,6 +764,16 @@ const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>((props, ref) =>
/> />
)} )}
</button> </button>
<button
title="Delete"
className={`${styles.deleteButton}`}
onClick={() => deleteMessage(props.chatMessage)}
>
<Trash
alt="Delete Message"
className="hsl(var(--muted-foreground)) hover:text-red-500"
/>
</button>
{props.chatMessage.by === "khoj" && {props.chatMessage.by === "khoj" &&
(props.chatMessage.intent ? ( (props.chatMessage.intent ? (
<FeedbackButtons <FeedbackButtons

View file

@ -195,8 +195,13 @@ function ReferenceVerification(props: ReferenceVerificationProps) {
created: new Date().toISOString(), created: new Date().toISOString(),
onlineContext: {}, onlineContext: {},
codeContext: {}, codeContext: {},
conversationId: props.conversationId,
turnId: "",
onDeleteMessage: (turnId?: string) => {},
}} }}
isMobileWidth={isMobileWidth} isMobileWidth={isMobileWidth}
onDeleteMessage={(turnId?: string) => {}}
conversationId={props.conversationId}
/> />
</div> </div>
); );
@ -626,7 +631,12 @@ export default function FactChecker() {
created: new Date().toISOString(), created: new Date().toISOString(),
onlineContext: {}, onlineContext: {},
codeContext: {}, codeContext: {},
conversationId: conversationID,
turnId: "",
onDeleteMessage: (turnId?: string) => {},
}} }}
conversationId={conversationID}
onDeleteMessage={(turnId?: string) => {}}
isMobileWidth={isMobileWidth} isMobileWidth={isMobileWidth}
/> />
</div> </div>

View file

@ -1351,11 +1351,11 @@ class ConversationAdapters:
@staticmethod @staticmethod
def delete_message_by_turn_id(user: KhojUser, conversation_id: str, turn_id: str): def delete_message_by_turn_id(user: KhojUser, conversation_id: str, turn_id: str):
conversation = ConversationAdapters.get_conversation_by_user(user, conversation_id=conversation_id) conversation = ConversationAdapters.get_conversation_by_user(user, conversation_id=conversation_id)
if not conversation: if not conversation or not conversation.conversation_log or not conversation.conversation_log.get("chat"):
return False return False
conversation_log = conversation.conversation_log conversation_log = conversation.conversation_log
updated_log = [msg for msg in conversation_log if msg.get("turnId") != turn_id] updated_log = [msg for msg in conversation_log["chat"] if msg.get("turnId") != turn_id]
conversation.conversation_log = updated_log conversation.conversation_log["chat"] = updated_log
conversation.save() conversation.save()
return True return True