From 8ba2e473cd819357f93f5daf6c7d2fe755570b7b Mon Sep 17 00:00:00 2001 From: Jing Hua Date: Tue, 7 Mar 2023 08:15:28 +0800 Subject: [PATCH] feat: customise free api endpoint --- src/api/freeApi.ts | 9 ++- src/components/ApiMenu/ApiMenu.tsx | 108 +++++++++++++++++++---------- src/hooks/useSubmit.ts | 1 + src/store/auth-slice.ts | 9 +++ src/store/store.ts | 2 + 5 files changed, 91 insertions(+), 38 deletions(-) diff --git a/src/api/freeApi.ts b/src/api/freeApi.ts index bb372ac..4deb249 100644 --- a/src/api/freeApi.ts +++ b/src/api/freeApi.ts @@ -1,8 +1,7 @@ import { ConfigInterface, MessageInterface } from '@type/chat'; -export const endpoint = 'https://chatgpt-api.shn.hk/v1/'; - export const getChatCompletion = async ( + endpoint: string, messages: MessageInterface[], config: ConfigInterface ) => { @@ -24,6 +23,7 @@ export const getChatCompletion = async ( }; export const getChatCompletionStream = async ( + endpoint: string, messages: MessageInterface[], config: ConfigInterface ) => { @@ -39,6 +39,11 @@ export const getChatCompletionStream = async ( stream: true, }), }); + if (response.status === 404) + throw new Error( + 'Message from freechatgpt.chat:\nInvalid API endpoint! We recommend you to check your free API endpoint.' + ); + const text = await response.text(); if (response.status === 429 && text.includes('insufficient_quota')) throw new Error( diff --git a/src/components/ApiMenu/ApiMenu.tsx b/src/components/ApiMenu/ApiMenu.tsx index 6f46804..a0b117c 100644 --- a/src/components/ApiMenu/ApiMenu.tsx +++ b/src/components/ApiMenu/ApiMenu.tsx @@ -15,26 +15,34 @@ const ApiMenu = ({ const setApiKey = useStore((state) => state.setApiKey); const apiFree = useStore((state) => state.apiFree); const setApiFree = useStore((state) => state.setApiFree); + const apiFreeEndpoint = useStore((state) => state.apiFreeEndpoint); + const setApiFreeEndpoint = useStore((state) => state.setApiFreeEndpoint); const [_apiFree, _setApiFree] = useState(apiFree); const [_apiKey, _setApiKey] = useState(apiKey || ''); - const [error, setError] = useState(false); + const [_apiFreeEndpoint, _setApiFreeEndpoint] = + useState(apiFreeEndpoint); + const [error, setError] = useState(''); const handleSave = async () => { if (_apiFree === true) { + setApiFreeEndpoint(_apiFreeEndpoint); setApiFree(true); + setError(''); setIsModalOpen(false); } else { const valid = await validateApiKey(_apiKey); if (valid) { setApiKey(_apiKey); setApiFree(false); - setError(false); + setError(''); setIsModalOpen(false); } else { - setError(true); + setError( + 'Error: Invalid API key or network blocked. Please check your API key and network settings for OpenAI API.' + ); setTimeout(() => { - setError(false); + setError(''); }, 10000); } } @@ -42,17 +50,24 @@ const ApiMenu = ({ useEffect(() => { if (apiKey) { - setApiFree(false); - _setApiFree(false); - _setApiKey(apiKey); - } + setApiFree(false); + _setApiFree(false); + _setApiKey(apiKey); + } }, []); + const handleClose = () => { + _setApiFree(apiFree); + _setApiFreeEndpoint(apiFreeEndpoint); + apiKey && _setApiKey(apiKey); + }; + return isModalOpen ? (
@@ -63,16 +78,40 @@ const ApiMenu = ({ onChange={() => _setApiFree(true)} />
+ + {_apiFree && ( +
+
+ Use free API endpoint from{' '} + + Ayaka + + : https://chatgpt-api.shn.hk/v1/ or enter your own API endpoint +
+
+
+ Free API Endpoint +
+ { + _setApiFreeEndpoint(e.target.value); + }} + /> +
+
+ )} +
{_apiFree === false && ( - <> -
-
- API Key -
- { - _setApiKey(e.target.value); - }} - /> +
+
+ API Key
- {error && ( -
- Error: Invalid API key or network blocked. Please check your API - key and network settings for OpenAI API. -
- )} - + { + _setApiKey(e.target.value); + }} + /> +
)}
@@ -126,6 +157,11 @@ const ApiMenu = ({ purpose of accessing the OpenAI API and not for any other unauthorised use.
+ {error !== '' && ( +
+ {error} +
+ )}
) : ( diff --git a/src/hooks/useSubmit.ts b/src/hooks/useSubmit.ts index a013d0b..e33f94a 100644 --- a/src/hooks/useSubmit.ts +++ b/src/hooks/useSubmit.ts @@ -40,6 +40,7 @@ const useSubmit = () => { if (apiFree) { stream = await getChatCompletionStreamFree( + useStore.getState().apiFreeEndpoint, messages, chats[currentChatIndex].config ); diff --git a/src/store/auth-slice.ts b/src/store/auth-slice.ts index 994cd59..e99f841 100644 --- a/src/store/auth-slice.ts +++ b/src/store/auth-slice.ts @@ -3,12 +3,15 @@ import { StoreSlice } from './store'; export interface AuthSlice { apiKey?: string; apiFree: boolean; + apiFreeEndpoint: string; setApiKey: (apiKey: string) => void; setApiFree: (apiFree: boolean) => void; + setApiFreeEndpoint: (apiFreeEndpoint: string) => void; } export const createAuthSlice: StoreSlice = (set, get) => ({ apiFree: true, + apiFreeEndpoint: 'https://chatgpt-api.shn.hk/v1/', setApiKey: (apiKey: string) => { set((prev: AuthSlice) => ({ ...prev, @@ -21,4 +24,10 @@ export const createAuthSlice: StoreSlice = (set, get) => ({ apiFree: apiFree, })); }, + setApiFreeEndpoint: (apiFreeEndpoint: string) => { + set((prev: AuthSlice) => ({ + ...prev, + apiFreeEndpoint: apiFreeEndpoint, + })); + }, }); diff --git a/src/store/store.ts b/src/store/store.ts index e548e29..ab5c587 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -26,6 +26,8 @@ const useStore = create()( chats: state.chats, currentChatIndex: state.currentChatIndex, apiKey: state.apiKey, + apiFree: state.apiFree, + apiFreeEndpoint: state.apiFreeEndpoint, theme: state.theme, }), }