Precise error messages (#150)

* Introduce a component to display error messages

* precise error message when api key is invalid
This commit is contained in:
Thomas LÉVEIL 2023-03-25 17:32:59 +01:00 committed by GitHub
parent 3f09a4c355
commit b89ca2082e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 15 deletions

View File

@ -1,9 +1,10 @@
import { Conversation, KeyValuePair, Message, OpenAIModel } from "@/types"; import { Conversation, ErrorMessage, KeyValuePair, Message, OpenAIModel } from "@/types";
import { FC, MutableRefObject, useCallback, useEffect, useRef, useState } from "react"; import { FC, MutableRefObject, useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { ChatInput } from "./ChatInput"; import { ChatInput } from "./ChatInput";
import { ChatLoader } from "./ChatLoader"; import { ChatLoader } from "./ChatLoader";
import { ChatMessage } from "./ChatMessage"; import { ChatMessage } from "./ChatMessage";
import { ErrorMessageDiv } from "./ErrorMessageDiv";
import { ModelSelect } from "./ModelSelect"; import { ModelSelect } from "./ModelSelect";
import { SystemPrompt } from "./SystemPrompt"; import { SystemPrompt } from "./SystemPrompt";
@ -13,7 +14,7 @@ interface Props {
apiKey: string; apiKey: string;
serverSideApiKeyIsSet: boolean; serverSideApiKeyIsSet: boolean;
messageIsStreaming: boolean; messageIsStreaming: boolean;
modelError: boolean; modelError: ErrorMessage | null;
messageError: boolean; messageError: boolean;
loading: boolean; loading: boolean;
lightMode: "light" | "dark"; lightMode: "light" | "dark";
@ -76,13 +77,7 @@ export const Chat: FC<Props> = ({ conversation, models, apiKey, serverSideApiKey
<div className="text-2xl font-semibold text-center text-gray-800 dark:text-gray-100">{t('OpenAI API Key Required')}</div> <div className="text-2xl font-semibold text-center text-gray-800 dark:text-gray-100">{t('OpenAI API Key Required')}</div>
<div className="text-center text-gray-500 dark:text-gray-400">{t('Please set your OpenAI API key in the bottom left of the sidebar.')}</div> <div className="text-center text-gray-500 dark:text-gray-400">{t('Please set your OpenAI API key in the bottom left of the sidebar.')}</div>
</div> </div>
) : modelError ? ( ) : modelError ? <ErrorMessageDiv error={modelError} /> : (
<div className="flex flex-col justify-center mx-auto h-full w-[300px] sm:w-[500px] space-y-6">
<div className="text-center text-red-500">{t('Error fetching models.')}</div>
<div className="text-center text-red-500">{t('Make sure your OpenAI API key is set in the bottom left of the sidebar.')}</div>
<div className="text-center text-red-500">{t('If you completed this step, OpenAI may be experiencing issues.')}</div>
</div>
) : (
<> <>
<div <div
className="overflow-scroll max-h-full" className="overflow-scroll max-h-full"

View File

@ -0,0 +1,17 @@
import { ErrorMessage } from "@/types";
import { FC } from "react";
interface Props {
error: ErrorMessage
}
export const ErrorMessageDiv: FC<Props> = ({ error }) => {
return (
<div className= "flex flex-col justify-center mx-auto h-full w-[300px] sm:w-[500px] space-y-6" >
<div className="text-center text-red-500" >{error.title} {error.code ? <i>({error.code}) </i> : "" }</div >
{ error.messageLines.map((line, index) => (
<div key={index} className="text-center text-red-500" > {line} </div>
)) }
</div>
);
};

View File

@ -17,7 +17,16 @@ const handler = async (req: Request): Promise<Response> => {
} }
}); });
if (response.status !== 200) { if (response.status === 401) {
return new Response(
response.body,
{
status: 500,
headers: response.headers
}
);
} else if (response.status !== 200) {
console.error(`OpenAI API returned an error ${response.status}: ${await response.text()}`)
throw new Error("OpenAI API returned an error"); throw new Error("OpenAI API returned an error");
} }

View File

@ -1,7 +1,7 @@
import { Chat } from "@/components/Chat/Chat"; import { Chat } from "@/components/Chat/Chat";
import { Navbar } from "@/components/Mobile/Navbar"; import { Navbar } from "@/components/Mobile/Navbar";
import { Sidebar } from "@/components/Sidebar/Sidebar"; import { Sidebar } from "@/components/Sidebar/Sidebar";
import { ChatBody, ChatFolder, Conversation, KeyValuePair, Message, OpenAIModel, OpenAIModelID, OpenAIModels } from "@/types"; import { ChatBody, ChatFolder, Conversation, ErrorMessage, KeyValuePair, Message, OpenAIModel, OpenAIModelID, OpenAIModels } from "@/types";
import { cleanConversationHistory, cleanSelectedConversation } from "@/utils/app/clean"; import { cleanConversationHistory, cleanSelectedConversation } from "@/utils/app/clean";
import { DEFAULT_SYSTEM_PROMPT } from "@/utils/app/const"; import { DEFAULT_SYSTEM_PROMPT } from "@/utils/app/const";
import { saveConversation, saveConversations, updateConversation } from "@/utils/app/conversation"; import { saveConversation, saveConversations, updateConversation } from "@/utils/app/conversation";
@ -18,6 +18,7 @@ interface HomeProps {
serverSideApiKeyIsSet: boolean; serverSideApiKeyIsSet: boolean;
} }
const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => { const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
const { t } = useTranslation('chat') const { t } = useTranslation('chat')
const [folders, setFolders] = useState<ChatFolder[]>([]); const [folders, setFolders] = useState<ChatFolder[]>([]);
@ -30,7 +31,7 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
const [showSidebar, setShowSidebar] = useState<boolean>(true); const [showSidebar, setShowSidebar] = useState<boolean>(true);
const [apiKey, setApiKey] = useState<string>(""); const [apiKey, setApiKey] = useState<string>("");
const [messageError, setMessageError] = useState<boolean>(false); const [messageError, setMessageError] = useState<boolean>(false);
const [modelError, setModelError] = useState<boolean>(false); const [modelError, setModelError] = useState<ErrorMessage | null>(null);
const [currentMessage, setCurrentMessage] = useState<Message>(); const [currentMessage, setCurrentMessage] = useState<Message>();
const stopConversationRef = useRef<boolean>(false); const stopConversationRef = useRef<boolean>(false);
@ -179,6 +180,15 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
}; };
const fetchModels = async (key: string) => { const fetchModels = async (key: string) => {
const error = {
title: t('Error fetching models.'),
code: null,
messageLines: [
t('Make sure your OpenAI API key is set in the bottom left of the sidebar.'),
t('If you completed this step, OpenAI may be experiencing issues.')
]
} as ErrorMessage;
const response = await fetch("/api/models", { const response = await fetch("/api/models", {
method: "POST", method: "POST",
headers: { headers: {
@ -190,19 +200,26 @@ const Home: React.FC<HomeProps> = ({ serverSideApiKeyIsSet }) => {
}); });
if (!response.ok) { if (!response.ok) {
setModelError(true); try {
const data = await response.json();
Object.assign(error, {
code: data.error?.code,
messageLines: [data.error?.message]
})
} catch (e) { }
setModelError(error);
return; return;
} }
const data = await response.json(); const data = await response.json();
if (!data) { if (!data) {
setModelError(true); setModelError(error);
return; return;
} }
setModels(data); setModels(data);
setModelError(false); setModelError(null);
}; };
const handleLightMode = (mode: "dark" | "light") => { const handleLightMode = (mode: "dark" | "light") => {

View File

@ -61,3 +61,9 @@ export interface LocalStorage {
// added folders (3/23/23) // added folders (3/23/23)
folders: ChatFolder[]; folders: ChatFolder[];
} }
export interface ErrorMessage {
code: String | null,
title: String,
messageLines: String[]
}