regenerate button (#138)

This commit is contained in:
Mckay Wrigley 2023-03-25 07:12:51 -06:00 committed by GitHub
parent d7fdcd0dfe
commit d27326125b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 43 deletions

View File

@ -4,7 +4,6 @@ import { ChatInput } from "./ChatInput";
import { ChatLoader } from "./ChatLoader"; import { ChatLoader } from "./ChatLoader";
import { ChatMessage } from "./ChatMessage"; import { ChatMessage } from "./ChatMessage";
import { ModelSelect } from "./ModelSelect"; import { ModelSelect } from "./ModelSelect";
import { Regenerate } from "./Regenerate";
import { SystemPrompt } from "./SystemPrompt"; import { SystemPrompt } from "./SystemPrompt";
interface Props { interface Props {
@ -17,15 +16,13 @@ interface Props {
messageError: boolean; messageError: boolean;
loading: boolean; loading: boolean;
lightMode: "light" | "dark"; lightMode: "light" | "dark";
onSend: (message: Message, isResend: boolean) => void; onSend: (message: Message, isResend?: boolean, deleteCount?: number) => void;
onUpdateConversation: (conversation: Conversation, data: KeyValuePair) => void; onUpdateConversation: (conversation: Conversation, data: KeyValuePair) => void;
onEditMessage: (message: Message, messageIndex: number) => void; onEditMessage: (message: Message, messageIndex: number) => void;
onDeleteMessage: (message: Message, messageIndex: number) => void;
onRegenerate: () => void;
stopConversationRef: MutableRefObject<boolean>; stopConversationRef: MutableRefObject<boolean>;
} }
export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKeyIsSet, messageIsStreaming, modelError, messageError, loading, lightMode, onSend, onUpdateConversation, onEditMessage, onDeleteMessage, onRegenerate, stopConversationRef }) => { export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKeyIsSet, messageIsStreaming, modelError, messageError, loading, lightMode, onSend, onUpdateConversation, onEditMessage, stopConversationRef }) => {
const [currentMessage, setCurrentMessage] = useState<Message>(); const [currentMessage, setCurrentMessage] = useState<Message>();
const [autoScrollEnabled, setAutoScrollEnabled] = useState(true); const [autoScrollEnabled, setAutoScrollEnabled] = useState(true);
@ -55,6 +52,7 @@ export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKey
useEffect(() => { useEffect(() => {
scrollToBottom(); scrollToBottom();
textareaRef.current?.focus(); textareaRef.current?.focus();
setCurrentMessage(conversation.messages[conversation.messages.length - 2]);
}, [conversation.messages]); }, [conversation.messages]);
useEffect(() => { useEffect(() => {
@ -69,6 +67,8 @@ export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKey
} }
}, []); }, []);
console.log("currentMessage", currentMessage);
return ( return (
<div className="relative flex-1 overflow-none dark:bg-[#343541] bg-white"> <div className="relative flex-1 overflow-none dark:bg-[#343541] bg-white">
{!(apiKey || serverSideApiKeyIsSet) ? ( {!(apiKey || serverSideApiKeyIsSet) ? (
@ -120,7 +120,6 @@ export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKey
messageIndex={index} messageIndex={index}
lightMode={lightMode} lightMode={lightMode}
onEditMessage={onEditMessage} onEditMessage={onEditMessage}
onDeleteMessage={onDeleteMessage}
/> />
))} ))}
@ -134,27 +133,22 @@ export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKey
)} )}
</div> </div>
{messageError ? (
<Regenerate
onRegenerate={() => {
if (currentMessage) {
onSend(currentMessage, true);
}
}}
/>
) : (
<ChatInput <ChatInput
stopConversationRef={stopConversationRef} stopConversationRef={stopConversationRef}
textareaRef={textareaRef} textareaRef={textareaRef}
messageIsStreaming={messageIsStreaming} messageIsStreaming={messageIsStreaming}
messages={conversation.messages}
model={conversation.model} model={conversation.model}
onSend={(message) => { onSend={(message) => {
setCurrentMessage(message); setCurrentMessage(message);
onSend(message, false); onSend(message);
}}
onRegenerate={() => {
if (currentMessage) {
onSend(currentMessage, true, 2);
}
}} }}
onRegenerate={onRegenerate}
/> />
)}
</> </>
)} )}
</div> </div>

View File

@ -1,17 +1,18 @@
import { Message, OpenAIModel, OpenAIModelID } from "@/types"; import { Message, OpenAIModel, OpenAIModelID } from "@/types";
import { IconPlayerStop, IconSend } from "@tabler/icons-react"; import { IconPlayerStop, IconRepeat, IconSend } from "@tabler/icons-react";
import { FC, KeyboardEvent, MutableRefObject, useEffect, useState } from "react"; import { FC, KeyboardEvent, MutableRefObject, useEffect, useState } from "react";
interface Props { interface Props {
messageIsStreaming: boolean; messageIsStreaming: boolean;
model: OpenAIModel; model: OpenAIModel;
messages: Message[];
onSend: (message: Message) => void; onSend: (message: Message) => void;
onRegenerate: () => void; onRegenerate: () => void;
stopConversationRef: MutableRefObject<boolean>; stopConversationRef: MutableRefObject<boolean>;
textareaRef: MutableRefObject<HTMLTextAreaElement | null>; textareaRef: MutableRefObject<HTMLTextAreaElement | null>;
} }
export const ChatInput: FC<Props> = ({ onSend, messageIsStreaming, model, stopConversationRef, textareaRef }) => { export const ChatInput: FC<Props> = ({ messageIsStreaming, model, messages, onSend, onRegenerate, stopConversationRef, textareaRef }) => {
const [content, setContent] = useState<string>(); const [content, setContent] = useState<string>();
const [isTyping, setIsTyping] = useState<boolean>(false); const [isTyping, setIsTyping] = useState<boolean>(false);
@ -90,6 +91,20 @@ export const ChatInput: FC<Props> = ({ onSend, messageIsStreaming, model, stopCo
Stop Generating Stop Generating
</button> </button>
)} )}
{!messageIsStreaming && messages.length > 0 && (
<button
className="absolute -top-2 md:top-0 left-0 right-0 mx-auto dark:bg-[#343541] border w-fit border-gray-500 py-2 px-4 rounded text-black dark:text-white hover:opacity-50"
onClick={onRegenerate}
>
<IconRepeat
size={16}
className="inline-block mb-[2px]"
/>{" "}
Regenerate response
</button>
)}
<div className="flex flex-col w-full py-2 flex-grow md:py-3 md:pl-4 relative border border-black/10 bg-white dark:border-gray-900/50 dark:text-white dark:bg-[#40414F] rounded-md shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:shadow-[0_0_15px_rgba(0,0,0,0.10)]"> <div className="flex flex-col w-full py-2 flex-grow md:py-3 md:pl-4 relative border border-black/10 bg-white dark:border-gray-900/50 dark:text-white dark:bg-[#40414F] rounded-md shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:shadow-[0_0_15px_rgba(0,0,0,0.10)]">
<textarea <textarea
ref={textareaRef} ref={textareaRef}

View File

@ -10,10 +10,9 @@ interface Props {
messageIndex: number; messageIndex: number;
lightMode: "light" | "dark"; lightMode: "light" | "dark";
onEditMessage: (message: Message, messageIndex: number) => void; onEditMessage: (message: Message, messageIndex: number) => void;
onDeleteMessage: (message: Message, messageIndex: number) => void;
} }
export const ChatMessage: FC<Props> = ({ message, messageIndex, lightMode, onEditMessage, onDeleteMessage }) => { export const ChatMessage: FC<Props> = ({ message, messageIndex, lightMode, onEditMessage }) => {
const [isEditing, setIsEditing] = useState<boolean>(false); const [isEditing, setIsEditing] = useState<boolean>(false);
const [isHovering, setIsHovering] = useState<boolean>(false); const [isHovering, setIsHovering] = useState<boolean>(false);
const [messageContent, setMessageContent] = useState(message.content); const [messageContent, setMessageContent] = useState(message.content);
@ -106,7 +105,7 @@ export const ChatMessage: FC<Props> = ({ message, messageIndex, lightMode, onEdi
)} )}
{(isHovering || window.innerWidth < 640) && !isEditing && ( {(isHovering || window.innerWidth < 640) && !isEditing && (
<button className={`absolute ${window.innerWidth < 640 ? "right-1 bottom-1" : "right-[-20px] top-[26px]"}`}> <button className={`absolute ${window.innerWidth < 640 ? "right-3 bottom-1" : "right-[-20px] top-[26px]"}`}>
<IconEdit <IconEdit
size={20} size={20}
className="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300" className="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"

View File

@ -32,13 +32,15 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
const stopConversationRef = useRef<boolean>(false); const stopConversationRef = useRef<boolean>(false);
const handleSend = async (message: Message, isResend: boolean) => { const handleSend = async (message: Message, isResend = false, deleteCount = 0) => {
if (selectedConversation) { if (selectedConversation) {
let updatedConversation: Conversation; let updatedConversation: Conversation;
if (isResend) { if (isResend) {
const updatedMessages = [...selectedConversation.messages]; const updatedMessages = [...selectedConversation.messages];
for (let i = 0; i < deleteCount; i++) {
updatedMessages.pop(); updatedMessages.pop();
}
updatedConversation = { updatedConversation = {
...selectedConversation, ...selectedConversation,
@ -373,13 +375,9 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
} }
}; };
const handleDeleteMessage = (message: Message, messageIndex: number) => {};
const handleRegenerate = () => {};
useEffect(() => { useEffect(() => {
if (currentMessage) { if (currentMessage) {
handleSend(currentMessage, false); handleSend(currentMessage);
setCurrentMessage(undefined); setCurrentMessage(undefined);
} }
}, [currentMessage]); }, [currentMessage]);
@ -524,8 +522,6 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
onSend={handleSend} onSend={handleSend}
onUpdateConversation={handleUpdateConversation} onUpdateConversation={handleUpdateConversation}
onEditMessage={handleEditMessage} onEditMessage={handleEditMessage}
onDeleteMessage={handleDeleteMessage}
onRegenerate={handleRegenerate}
stopConversationRef={stopConversationRef} stopConversationRef={stopConversationRef}
/> />
</div> </div>

View File

@ -18,7 +18,7 @@ export const OpenAIStream = async (model: OpenAIModel, systemPrompt: string, key
...messages ...messages
], ],
max_tokens: 1000, max_tokens: 1000,
temperature: 0.0, temperature: 1,
stream: true stream: true
}) })
}); });