mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-26 00:34:00 +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';
|
import { ConfigInterface, MessageInterface } from '@type/chat';
|
||||||
|
|
||||||
export const endpoint = 'https://chatgpt-api.shn.hk/v1/';
|
|
||||||
|
|
||||||
export const getChatCompletion = async (
|
export const getChatCompletion = async (
|
||||||
|
endpoint: string,
|
||||||
messages: MessageInterface[],
|
messages: MessageInterface[],
|
||||||
config: ConfigInterface
|
config: ConfigInterface
|
||||||
) => {
|
) => {
|
||||||
|
@ -24,6 +23,7 @@ export const getChatCompletion = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getChatCompletionStream = async (
|
export const getChatCompletionStream = async (
|
||||||
|
endpoint: string,
|
||||||
messages: MessageInterface[],
|
messages: MessageInterface[],
|
||||||
config: ConfigInterface
|
config: ConfigInterface
|
||||||
) => {
|
) => {
|
||||||
|
@ -39,6 +39,11 @@ export const getChatCompletionStream = async (
|
||||||
stream: true,
|
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();
|
const text = await response.text();
|
||||||
if (response.status === 429 && text.includes('insufficient_quota'))
|
if (response.status === 429 && text.includes('insufficient_quota'))
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
@ -15,26 +15,34 @@ const ApiMenu = ({
|
||||||
const setApiKey = useStore((state) => state.setApiKey);
|
const setApiKey = useStore((state) => state.setApiKey);
|
||||||
const apiFree = useStore((state) => state.apiFree);
|
const apiFree = useStore((state) => state.apiFree);
|
||||||
const setApiFree = useStore((state) => state.setApiFree);
|
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 [_apiFree, _setApiFree] = useState<boolean>(apiFree);
|
||||||
const [_apiKey, _setApiKey] = useState<string>(apiKey || '');
|
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 () => {
|
const handleSave = async () => {
|
||||||
if (_apiFree === true) {
|
if (_apiFree === true) {
|
||||||
|
setApiFreeEndpoint(_apiFreeEndpoint);
|
||||||
setApiFree(true);
|
setApiFree(true);
|
||||||
|
setError('');
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
} else {
|
} else {
|
||||||
const valid = await validateApiKey(_apiKey);
|
const valid = await validateApiKey(_apiKey);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
setApiKey(_apiKey);
|
setApiKey(_apiKey);
|
||||||
setApiFree(false);
|
setApiFree(false);
|
||||||
setError(false);
|
setError('');
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
} else {
|
} else {
|
||||||
setError(true);
|
setError(
|
||||||
|
'Error: Invalid API key or network blocked. Please check your API key and network settings for OpenAI API.'
|
||||||
|
);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setError(false);
|
setError('');
|
||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,11 +56,18 @@ const ApiMenu = ({
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
_setApiFree(apiFree);
|
||||||
|
_setApiFreeEndpoint(apiFreeEndpoint);
|
||||||
|
apiKey && _setApiKey(apiKey);
|
||||||
|
};
|
||||||
|
|
||||||
return isModalOpen ? (
|
return isModalOpen ? (
|
||||||
<PopupModal
|
<PopupModal
|
||||||
title='API'
|
title='API'
|
||||||
setIsModalOpen={setIsModalOpen}
|
setIsModalOpen={setIsModalOpen}
|
||||||
handleConfirm={handleSave}
|
handleConfirm={handleSave}
|
||||||
|
handleClose={handleClose}
|
||||||
>
|
>
|
||||||
<div className='p-6 border-b border-gray-200 dark:border-gray-600'>
|
<div className='p-6 border-b border-gray-200 dark:border-gray-600'>
|
||||||
<div className='flex items-center mb-2'>
|
<div className='flex items-center mb-2'>
|
||||||
|
@ -63,7 +78,14 @@ const ApiMenu = ({
|
||||||
onChange={() => _setApiFree(true)}
|
onChange={() => _setApiFree(true)}
|
||||||
/>
|
/>
|
||||||
<label className='ml-2 text-sm font-medium text-gray-900 dark:text-gray-300'>
|
<label className='ml-2 text-sm font-medium text-gray-900 dark:text-gray-300'>
|
||||||
Use free API from{' '}
|
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
|
<a
|
||||||
href='https://github.com/ayaka14732/ChatGPTAPIFree'
|
href='https://github.com/ayaka14732/ChatGPTAPIFree'
|
||||||
className='underline dark:hover:text-white hover:text-black'
|
className='underline dark:hover:text-white hover:text-black'
|
||||||
|
@ -71,8 +93,25 @@ const ApiMenu = ({
|
||||||
>
|
>
|
||||||
Ayaka
|
Ayaka
|
||||||
</a>
|
</a>
|
||||||
</label>
|
: https://chatgpt-api.shn.hk/v1/ or enter your own API endpoint
|
||||||
</div>
|
</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'>
|
<div className='flex items-center'>
|
||||||
<input
|
<input
|
||||||
type='radio'
|
type='radio'
|
||||||
|
@ -86,7 +125,6 @@ const ApiMenu = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{_apiFree === false && (
|
{_apiFree === false && (
|
||||||
<>
|
|
||||||
<div className='flex gap-2 items-center justify-center mt-2'>
|
<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'>
|
<div className='min-w-fit text-gray-900 dark:text-gray-300 text-sm'>
|
||||||
API Key
|
API Key
|
||||||
|
@ -100,13 +138,6 @@ const ApiMenu = ({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='min-w-fit text-gray-900 dark:text-gray-300 text-sm mt-4 text-center'>
|
<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
|
purpose of accessing the OpenAI API and not for any other unauthorised
|
||||||
use.
|
use.
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</PopupModal>
|
</PopupModal>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -40,6 +40,7 @@ const useSubmit = () => {
|
||||||
|
|
||||||
if (apiFree) {
|
if (apiFree) {
|
||||||
stream = await getChatCompletionStreamFree(
|
stream = await getChatCompletionStreamFree(
|
||||||
|
useStore.getState().apiFreeEndpoint,
|
||||||
messages,
|
messages,
|
||||||
chats[currentChatIndex].config
|
chats[currentChatIndex].config
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,12 +3,15 @@ import { StoreSlice } from './store';
|
||||||
export interface AuthSlice {
|
export interface AuthSlice {
|
||||||
apiKey?: string;
|
apiKey?: string;
|
||||||
apiFree: boolean;
|
apiFree: boolean;
|
||||||
|
apiFreeEndpoint: string;
|
||||||
setApiKey: (apiKey: string) => void;
|
setApiKey: (apiKey: string) => void;
|
||||||
setApiFree: (apiFree: boolean) => void;
|
setApiFree: (apiFree: boolean) => void;
|
||||||
|
setApiFreeEndpoint: (apiFreeEndpoint: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createAuthSlice: StoreSlice<AuthSlice> = (set, get) => ({
|
export const createAuthSlice: StoreSlice<AuthSlice> = (set, get) => ({
|
||||||
apiFree: true,
|
apiFree: true,
|
||||||
|
apiFreeEndpoint: 'https://chatgpt-api.shn.hk/v1/',
|
||||||
setApiKey: (apiKey: string) => {
|
setApiKey: (apiKey: string) => {
|
||||||
set((prev: AuthSlice) => ({
|
set((prev: AuthSlice) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
@ -21,4 +24,10 @@ export const createAuthSlice: StoreSlice<AuthSlice> = (set, get) => ({
|
||||||
apiFree: apiFree,
|
apiFree: apiFree,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
setApiFreeEndpoint: (apiFreeEndpoint: string) => {
|
||||||
|
set((prev: AuthSlice) => ({
|
||||||
|
...prev,
|
||||||
|
apiFreeEndpoint: apiFreeEndpoint,
|
||||||
|
}));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,6 +26,8 @@ const useStore = create<StoreState>()(
|
||||||
chats: state.chats,
|
chats: state.chats,
|
||||||
currentChatIndex: state.currentChatIndex,
|
currentChatIndex: state.currentChatIndex,
|
||||||
apiKey: state.apiKey,
|
apiKey: state.apiKey,
|
||||||
|
apiFree: state.apiFree,
|
||||||
|
apiFreeEndpoint: state.apiFreeEndpoint,
|
||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue