From a03d8b2ba9fdfaac4a4f08a18e5534e69cf437f0 Mon Sep 17 00:00:00 2001 From: Mckay Wrigley Date: Sat, 25 Mar 2023 05:49:41 -0600 Subject: [PATCH] edit message --- components/Chat/Chat.tsx | 11 +++- components/Chat/ChatInput.tsx | 6 +- components/Chat/ChatMessage.tsx | 103 ++++++++++++++++++++++++++++++-- pages/index.tsx | 39 ++++++++++++ 4 files changed, 149 insertions(+), 10 deletions(-) diff --git a/components/Chat/Chat.tsx b/components/Chat/Chat.tsx index 9bb6c7e..3da9b02 100644 --- a/components/Chat/Chat.tsx +++ b/components/Chat/Chat.tsx @@ -20,10 +20,13 @@ interface Props { onSend: (message: Message, isResend: boolean) => void; onUpdateConversation: (conversation: Conversation, data: KeyValuePair) => void; onAcceptEnv: (accept: boolean) => void; + onEditMessage: (message: Message, messageIndex: number) => void; + onDeleteMessage: (message: Message, messageIndex: number) => void; + onRegenerate: () => void; stopConversationRef: MutableRefObject; } -export const Chat: FC = ({ conversation, models, apiKey, isUsingEnv, messageIsStreaming, modelError, messageError, loading, lightMode, onSend, onUpdateConversation, onAcceptEnv, stopConversationRef }) => { +export const Chat: FC = ({ conversation, models, apiKey, isUsingEnv, messageIsStreaming, modelError, messageError, loading, lightMode, onSend, onUpdateConversation, onAcceptEnv, onEditMessage, onDeleteMessage, onRegenerate, stopConversationRef }) => { const [currentMessage, setCurrentMessage] = useState(); const [autoScrollEnabled, setAutoScrollEnabled] = useState(true); @@ -122,7 +125,10 @@ export const Chat: FC = ({ conversation, models, apiKey, isUsingEnv, mess ))} @@ -149,11 +155,12 @@ export const Chat: FC = ({ conversation, models, apiKey, isUsingEnv, mess stopConversationRef={stopConversationRef} textareaRef={textareaRef} messageIsStreaming={messageIsStreaming} + model={conversation.model} onSend={(message) => { setCurrentMessage(message); onSend(message, false); }} - model={conversation.model} + onRegenerate={onRegenerate} /> )} diff --git a/components/Chat/ChatInput.tsx b/components/Chat/ChatInput.tsx index ee223ec..f9c3474 100644 --- a/components/Chat/ChatInput.tsx +++ b/components/Chat/ChatInput.tsx @@ -1,11 +1,12 @@ import { Message, OpenAIModel, OpenAIModelID } from "@/types"; import { IconPlayerStop, IconSend } from "@tabler/icons-react"; -import { FC, KeyboardEvent, MutableRefObject, useEffect, useRef, useState } from "react"; +import { FC, KeyboardEvent, MutableRefObject, useEffect, useState } from "react"; interface Props { messageIsStreaming: boolean; - onSend: (message: Message) => void; model: OpenAIModel; + onSend: (message: Message) => void; + onRegenerate: () => void; stopConversationRef: MutableRefObject; textareaRef: MutableRefObject; } @@ -67,7 +68,6 @@ export const ChatInput: FC = ({ onSend, messageIsStreaming, model, stopCo } }, [content]); - function handleStopConversation() { stopConversationRef.current = true; setTimeout(() => { diff --git a/components/Chat/ChatMessage.tsx b/components/Chat/ChatMessage.tsx index 8e74e5d..2ec0065 100644 --- a/components/Chat/ChatMessage.tsx +++ b/components/Chat/ChatMessage.tsx @@ -1,26 +1,119 @@ import { Message } from "@/types"; -import { FC } from "react"; +import { IconEdit } from "@tabler/icons-react"; +import { FC, useEffect, useRef, useState } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { CodeBlock } from "../Markdown/CodeBlock"; interface Props { message: Message; + messageIndex: number; lightMode: "light" | "dark"; + onEditMessage: (message: Message, messageIndex: number) => void; + onDeleteMessage: (message: Message, messageIndex: number) => void; } -export const ChatMessage: FC = ({ message, lightMode }) => { +export const ChatMessage: FC = ({ message, messageIndex, lightMode, onEditMessage, onDeleteMessage }) => { + const [isEditing, setIsEditing] = useState(false); + const [isHovering, setIsHovering] = useState(false); + const [messageContent, setMessageContent] = useState(message.content); + + const textareaRef = useRef(null); + + const toggleEditing = () => { + setIsEditing(!isEditing); + }; + + const handleInputChange = (event: React.ChangeEvent) => { + setMessageContent(event.target.value); + if (textareaRef.current) { + textareaRef.current.style.height = "inherit"; + textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; + } + }; + + const handleEditMessage = () => { + onEditMessage({ ...message, content: messageContent }, messageIndex); + setIsEditing(false); + }; + + const handlePressEnter = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleEditMessage(); + } + }; + + useEffect(() => { + if (textareaRef.current) { + textareaRef.current.style.height = "inherit"; + textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; + } + }, [isEditing]); + return (
setIsHovering(true)} + onMouseLeave={() => setIsHovering(false)} > -
+
{message.role === "assistant" ? "AI:" : "You:"}
-
+
{message.role === "user" ? ( -
{message.content}
+
+ {isEditing ? ( +
+