regenerate button (#138)
This commit is contained in:
parent
d7fdcd0dfe
commit
d27326125b
|
@ -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 ? (
|
<ChatInput
|
||||||
<Regenerate
|
stopConversationRef={stopConversationRef}
|
||||||
onRegenerate={() => {
|
textareaRef={textareaRef}
|
||||||
if (currentMessage) {
|
messageIsStreaming={messageIsStreaming}
|
||||||
onSend(currentMessage, true);
|
messages={conversation.messages}
|
||||||
}
|
model={conversation.model}
|
||||||
}}
|
onSend={(message) => {
|
||||||
/>
|
setCurrentMessage(message);
|
||||||
) : (
|
onSend(message);
|
||||||
<ChatInput
|
}}
|
||||||
stopConversationRef={stopConversationRef}
|
onRegenerate={() => {
|
||||||
textareaRef={textareaRef}
|
if (currentMessage) {
|
||||||
messageIsStreaming={messageIsStreaming}
|
onSend(currentMessage, true, 2);
|
||||||
model={conversation.model}
|
}
|
||||||
onSend={(message) => {
|
}}
|
||||||
setCurrentMessage(message);
|
/>
|
||||||
onSend(message, false);
|
|
||||||
}}
|
|
||||||
onRegenerate={onRegenerate}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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];
|
||||||
updatedMessages.pop();
|
for (let i = 0; i < deleteCount; i++) {
|
||||||
|
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>
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue