mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-22 03:10:15 +01:00
Added functionality to allow users to set custom api keys (#276)
* Added functionality to allow users to set custom api keys * Added error handling * Changed token to apiKey * Changed apiKey to oaiApiKey * added azure openai ui * Removed logging * Changed configure to Use * Made checked position more rounded * Made setting api key optional if it is openai * Modified error handling * Add support for insufficient_quota errors * Fixed faulty error detection * removed logging
This commit is contained in:
parent
08f3a77d58
commit
14104b276f
11 changed files with 207 additions and 32 deletions
|
|
@ -0,0 +1,34 @@
|
|||
import React from 'react';
|
||||
import { Input } from '../../ui/Input.tsx';
|
||||
import { Label } from '../../ui/Label.tsx';
|
||||
import { cn } from '~/utils/';
|
||||
|
||||
function InputWithLabel({ value, onChange, label, id }) {
|
||||
const defaultTextProps =
|
||||
'rounded-md border border-gray-300 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.10)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-400 dark:bg-gray-700 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
|
||||
|
||||
return (
|
||||
<>
|
||||
<Label
|
||||
htmlFor={id}
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
{label}
|
||||
<br />
|
||||
</Label>
|
||||
|
||||
<Input
|
||||
id={id}
|
||||
value={value || ''}
|
||||
onChange={onChange}
|
||||
placeholder={`Enter ${label}`}
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0'
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default InputWithLabel;
|
||||
|
|
@ -4,11 +4,24 @@ import { Dialog } from '../../ui/Dialog.tsx';
|
|||
import { Input } from '../../ui/Input.tsx';
|
||||
import { Label } from '../../ui/Label.tsx';
|
||||
import { cn } from '~/utils/';
|
||||
import * as Checkbox from '@radix-ui/react-checkbox';
|
||||
import { CheckIcon } from '@radix-ui/react-icons';
|
||||
import FileUpload from '../NewConversationMenu/FileUpload';
|
||||
import store from '~/store';
|
||||
import InputWithLabel from './InputWithLabel';
|
||||
|
||||
function isJson(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const SetTokenDialog = ({ open, onOpenChange, endpoint }) => {
|
||||
const [token, setToken] = useState('');
|
||||
const [showPanel, setShowPanel] = useState(false);
|
||||
const { getToken, saveToken } = store.useToken(endpoint);
|
||||
|
||||
const defaultTextProps =
|
||||
|
|
@ -20,9 +33,19 @@ const SetTokenDialog = ({ open, onOpenChange, endpoint }) => {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
setToken(getToken() ?? '');
|
||||
let oldToken = getToken();
|
||||
if (isJson(token)) {
|
||||
setShowPanel(true);
|
||||
}
|
||||
setToken(oldToken ?? '');
|
||||
}, [open]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!showPanel && isJson(token)) {
|
||||
setToken('');
|
||||
}
|
||||
}, [showPanel]);
|
||||
|
||||
const helpText = {
|
||||
bingAI: (
|
||||
<small className="break-all text-gray-600">
|
||||
|
|
@ -79,6 +102,25 @@ const SetTokenDialog = ({ open, onOpenChange, endpoint }) => {
|
|||
)
|
||||
};
|
||||
|
||||
function getAzure(name) {
|
||||
if (isJson(token)) {
|
||||
let newToken = JSON.parse(token);
|
||||
return newToken[name];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function setAzure(name, value) {
|
||||
let newToken = {};
|
||||
if (isJson(token)) {
|
||||
newToken = JSON.parse(token);
|
||||
}
|
||||
newToken[name] = value;
|
||||
|
||||
setToken(JSON.stringify(newToken));
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
|
|
@ -88,16 +130,9 @@ const SetTokenDialog = ({ open, onOpenChange, endpoint }) => {
|
|||
title={`Set Token of ${endpoint}`}
|
||||
main={
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="chatGptLabel"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
Token Name
|
||||
<br />
|
||||
</Label>
|
||||
{endpoint === 'google' ? (
|
||||
<FileUpload
|
||||
id="googleKey"
|
||||
id="googleKey"
|
||||
className="w-full"
|
||||
text="Import Service Account JSON Key"
|
||||
successText="Successfully Imported Service Account JSON Key"
|
||||
|
|
@ -137,17 +172,77 @@ const SetTokenDialog = ({ open, onOpenChange, endpoint }) => {
|
|||
setToken(JSON.stringify(data));
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
id="chatGptLabel"
|
||||
value={token || ''}
|
||||
onChange={e => setToken(e.target.value || '')}
|
||||
placeholder="Set the token."
|
||||
className={cn(
|
||||
defaultTextProps,
|
||||
'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0'
|
||||
) : endpoint === 'openAI' ? (
|
||||
<>
|
||||
{!showPanel ? (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'chatGPTLabel'}
|
||||
value={token || ''}
|
||||
onChange={e => setToken(e.target.value || '')}
|
||||
label={'OpenAI API Key'}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'instanceNameLabel'}
|
||||
value={getAzure('instanceName') || ''}
|
||||
onChange={e => setAzure('instanceName', e.target.value || '')}
|
||||
label={'Azure OpenAI Instance Name'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'deploymentNameLabel'}
|
||||
value={getAzure('deploymentName') || ''}
|
||||
onChange={e => setAzure('deploymentName', e.target.value || '')}
|
||||
label={'Azure OpenAI Deployment Name'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'versionLabel'}
|
||||
value={getAzure('version') || ''}
|
||||
onChange={e => setAzure('version', e.target.value || '')}
|
||||
label={'Azure OpenAI API Version'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'apiKeyLabel'}
|
||||
value={getAzure('apiKey') || ''}
|
||||
onChange={e => setAzure('apiKey', e.target.value || '')}
|
||||
label={'Azure OpenAI API Key'}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<div className="flex items-center">
|
||||
<Checkbox.Root
|
||||
className="flex h-[20px] w-[20px] appearance-none items-center justify-center rounded-[4px] bg-gray-100 text-white outline-none hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-900"
|
||||
id="azureOpenAI"
|
||||
checked={showPanel}
|
||||
onCheckedChange={() => setShowPanel(!showPanel)}
|
||||
>
|
||||
<Checkbox.Indicator className="flex h-[20px] w-[20px] items-center justify-center rounded-[3.5px] bg-green-600">
|
||||
<CheckIcon />
|
||||
</Checkbox.Indicator>
|
||||
</Checkbox.Root>
|
||||
|
||||
<label
|
||||
className="pl-[8px] text-[15px] leading-none dark:text-white"
|
||||
htmlFor="azureOpenAI"
|
||||
>
|
||||
Use Azure OpenAI.
|
||||
</label>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'chatGPTLabel'}
|
||||
value={token || ''}
|
||||
onChange={e => setToken(e.target.value || '')}
|
||||
label={'Token Name'}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<small className="text-red-600">Your token will be sent to the server, but not saved.</small>
|
||||
{helpText?.[endpoint]}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue