mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-25 22:43:59 +01:00
feat: customise free api endpoint
This commit is contained in:
parent
98729351e0
commit
8ba2e473cd
|
@ -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(
|
||||
|
|
|
@ -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<boolean>(apiFree);
|
||||
const [_apiKey, _setApiKey] = useState<string>(apiKey || '');
|
||||
const [error, setError] = useState<boolean>(false);
|
||||
const [_apiFreeEndpoint, _setApiFreeEndpoint] =
|
||||
useState<string>(apiFreeEndpoint);
|
||||
const [error, setError] = useState<string>('');
|
||||
|
||||
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 ? (
|
||||
<PopupModal
|
||||
title='API'
|
||||
setIsModalOpen={setIsModalOpen}
|
||||
handleConfirm={handleSave}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
<div className='p-6 border-b border-gray-200 dark:border-gray-600'>
|
||||
<div className='flex items-center mb-2'>
|
||||
|
@ -63,16 +78,40 @@ const ApiMenu = ({
|
|||
onChange={() => _setApiFree(true)}
|
||||
/>
|
||||
<label className='ml-2 text-sm font-medium text-gray-900 dark:text-gray-300'>
|
||||
Use free API from{' '}
|
||||
<a
|
||||
href='https://github.com/ayaka14732/ChatGPTAPIFree'
|
||||
className='underline dark:hover:text-white hover:text-black'
|
||||
target='_blank'
|
||||
>
|
||||
Ayaka
|
||||
</a>
|
||||
Use free API endpoint
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{_apiFree && (
|
||||
<div className='mt-2 mb-6'>
|
||||
<div className='text-sm font-medium text-gray-900 dark:text-gray-300 mb-2'>
|
||||
Use free API endpoint from{' '}
|
||||
<a
|
||||
href='https://github.com/ayaka14732/ChatGPTAPIFree'
|
||||
className='underline dark:hover:text-white hover:text-black'
|
||||
target='_blank'
|
||||
>
|
||||
Ayaka
|
||||
</a>
|
||||
: https://chatgpt-api.shn.hk/v1/ or enter your own API endpoint
|
||||
</div>
|
||||
<div className='flex gap-2 items-center justify-center'>
|
||||
<div className='min-w-fit text-gray-900 dark:text-gray-300 text-sm'>
|
||||
Free API Endpoint
|
||||
</div>
|
||||
<input
|
||||
type='text'
|
||||
className='text-gray-800 dark:text-white p-3 text-sm border-none bg-gray-200 dark:bg-gray-600 rounded-md m-0 w-full mr-0 h-8 focus:outline-none'
|
||||
value={_apiFreeEndpoint}
|
||||
placeholder='https://chatgpt-api.shn.hk/v1/'
|
||||
onChange={(e) => {
|
||||
_setApiFreeEndpoint(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='flex items-center'>
|
||||
<input
|
||||
type='radio'
|
||||
|
@ -86,27 +125,19 @@ const ApiMenu = ({
|
|||
</div>
|
||||
|
||||
{_apiFree === false && (
|
||||
<>
|
||||
<div className='flex gap-2 items-center justify-center mt-2'>
|
||||
<div className='min-w-fit text-gray-900 dark:text-gray-300 text-sm'>
|
||||
API Key
|
||||
</div>
|
||||
<input
|
||||
type='text'
|
||||
className='text-gray-800 dark:text-white p-3 text-sm border-none bg-gray-200 dark:bg-gray-600 rounded-md m-0 w-full mr-0 h-8 focus:outline-none'
|
||||
value={_apiKey}
|
||||
onChange={(e) => {
|
||||
_setApiKey(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<div className='flex gap-2 items-center justify-center mt-2'>
|
||||
<div className='min-w-fit text-gray-900 dark:text-gray-300 text-sm'>
|
||||
API Key
|
||||
</div>
|
||||
{error && (
|
||||
<div className='bg-red-600/50 p-2 rounded-sm mt-3 text-gray-900 dark:text-gray-300 text-sm'>
|
||||
Error: Invalid API key or network blocked. Please check your API
|
||||
key and network settings for OpenAI API.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
<input
|
||||
type='text'
|
||||
className='text-gray-800 dark:text-white p-3 text-sm border-none bg-gray-200 dark:bg-gray-600 rounded-md m-0 w-full mr-0 h-8 focus:outline-none'
|
||||
value={_apiKey}
|
||||
onChange={(e) => {
|
||||
_setApiKey(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='min-w-fit text-gray-900 dark:text-gray-300 text-sm mt-4 text-center'>
|
||||
|
@ -126,6 +157,11 @@ const ApiMenu = ({
|
|||
purpose of accessing the OpenAI API and not for any other unauthorised
|
||||
use.
|
||||
</div>
|
||||
{error !== '' && (
|
||||
<div className='bg-red-600/50 p-2 rounded-sm mt-3 text-gray-900 dark:text-gray-300 text-sm'>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PopupModal>
|
||||
) : (
|
||||
|
|
|
@ -40,6 +40,7 @@ const useSubmit = () => {
|
|||
|
||||
if (apiFree) {
|
||||
stream = await getChatCompletionStreamFree(
|
||||
useStore.getState().apiFreeEndpoint,
|
||||
messages,
|
||||
chats[currentChatIndex].config
|
||||
);
|
||||
|
|
|
@ -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<AuthSlice> = (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<AuthSlice> = (set, get) => ({
|
|||
apiFree: apiFree,
|
||||
}));
|
||||
},
|
||||
setApiFreeEndpoint: (apiFreeEndpoint: string) => {
|
||||
set((prev: AuthSlice) => ({
|
||||
...prev,
|
||||
apiFreeEndpoint: apiFreeEndpoint,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
|
|
@ -26,6 +26,8 @@ const useStore = create<StoreState>()(
|
|||
chats: state.chats,
|
||||
currentChatIndex: state.currentChatIndex,
|
||||
apiKey: state.apiKey,
|
||||
apiFree: state.apiFree,
|
||||
apiFreeEndpoint: state.apiFreeEndpoint,
|
||||
theme: state.theme,
|
||||
}),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue