mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
refactor(SetTokenDialog): refactor to TS, modularize config logic into separate components
This commit is contained in:
parent
b6f21af69b
commit
8b91145953
15 changed files with 385 additions and 306 deletions
|
|
@ -31,7 +31,7 @@ router.get('/', async function (req, res) {
|
|||
key = require('../../data/auth.json');
|
||||
} catch (e) {
|
||||
if (i === 0) {
|
||||
console.log("No 'auth.json' file (service account key) found in /api/data/ for PaLM models");
|
||||
console.log('No \'auth.json\' file (service account key) found in /api/data/ for PaLM models');
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,7 @@ router.get('/', async function (req, res) {
|
|||
: false;
|
||||
const openAIApiKey = process.env.OPENAI_API_KEY;
|
||||
const azureOpenAIApiKey = process.env.AZURE_API_KEY;
|
||||
const userProvidedOpenAI = openAIApiKey ? openAIApiKey === 'user_provided' : azureOpenAIApiKey === 'user_provided';
|
||||
const openAI = openAIApiKey
|
||||
? { availableModels: getOpenAIModels(), userProvide: openAIApiKey === 'user_provided' }
|
||||
: false;
|
||||
|
|
@ -57,7 +58,7 @@ router.get('/', async function (req, res) {
|
|||
? { availableModels: getOpenAIModels({ azure: true}), userProvide: azureOpenAIApiKey === 'user_provided' }
|
||||
: false;
|
||||
const gptPlugins = openAIApiKey || azureOpenAIApiKey
|
||||
? { availableModels: getPluginModels(), availableTools, availableAgents: ['classic', 'functions'] }
|
||||
? { availableModels: getPluginModels(), availableTools, availableAgents: ['classic', 'functions'], userProvide: userProvidedOpenAI }
|
||||
: false;
|
||||
const bingAI = process.env.BINGAI_TOKEN
|
||||
? { userProvide: process.env.BINGAI_TOKEN == 'user_provided' }
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
import { useState } from 'react';
|
||||
import { DropdownMenuRadioItem } from '../../ui/DropdownMenu.tsx';
|
||||
import { DropdownMenuRadioItem } from '~/components';
|
||||
import { Settings } from 'lucide-react';
|
||||
import getIcon from '~/utils/getIcon';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import SetTokenDialog from '../SetTokenDialog';
|
||||
import { SetTokenDialog } from '../SetTokenDialog';
|
||||
|
||||
import store from '../../../store';
|
||||
import { cn } from '~/utils/index.jsx';
|
||||
|
||||
const alternateName = {
|
||||
openAI: 'OpenAI',
|
||||
azureOpenAI: 'Azure OpenAI',
|
||||
bingAI: 'Bing',
|
||||
chatGPTBrowser: 'ChatGPT',
|
||||
gptPlugins: 'Plugins',
|
||||
google: 'PaLM'
|
||||
};
|
||||
import store from '~/store';
|
||||
import { cn, alternateName } from '~/utils';
|
||||
|
||||
export default function ModelItem({ endpoint, value, isSelected }) {
|
||||
const [setTokenDialogOpen, setSetTokenDialogOpen] = useState(false);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,36 @@
|
|||
import { useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { FileUp } from 'lucide-react';
|
||||
import { cn } from '~/utils/';
|
||||
|
||||
const FileUpload = ({
|
||||
type FileUploadProps = {
|
||||
onFileSelected: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
className?: string;
|
||||
successText?: string;
|
||||
invalidText?: string;
|
||||
validator?: ((data: any) => boolean) | null;
|
||||
text?: string;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
const FileUpload: React.FC<FileUploadProps> = ({
|
||||
onFileSelected,
|
||||
className = '',
|
||||
successText = null,
|
||||
invalidText = null,
|
||||
validator = null,
|
||||
text = null,
|
||||
id = '1'
|
||||
}) => {
|
||||
const [statusColor, setStatusColor] = useState('text-gray-600');
|
||||
const [status, setStatus] = useState(null);
|
||||
const [statusColor, setStatusColor] = useState<string>('text-gray-600');
|
||||
const [status, setStatus] = useState<null | string>(null);
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
const file = event.target.files[0];
|
||||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const jsonData = JSON.parse(e.target.result);
|
||||
const jsonData = JSON.parse(e.target?.result as string);
|
||||
if (validator && !validator(jsonData)) {
|
||||
setStatus('invalid');
|
||||
setStatusColor('text-red-600');
|
||||
|
|
@ -52,7 +63,7 @@ const FileUpload = ({
|
|||
id={`file-upload-${id}`}
|
||||
value=""
|
||||
type="file"
|
||||
className="hidden "
|
||||
className={cn('hidden ', className)}
|
||||
accept=".json"
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
50
client/src/components/Input/SetTokenDialog/GoogleConfig.tsx
Normal file
50
client/src/components/Input/SetTokenDialog/GoogleConfig.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import React from 'react';
|
||||
import FileUpload from '../NewConversationMenu/FileUpload';
|
||||
|
||||
const GoogleConfig = ({ setToken } : { setToken: React.Dispatch<React.SetStateAction<string>> }) => {
|
||||
return (
|
||||
<FileUpload
|
||||
id="googleKey"
|
||||
className="w-full"
|
||||
text="Import Service Account JSON Key"
|
||||
successText="Successfully Imported Service Account JSON Key"
|
||||
invalidText="Invalid Service Account JSON Key, Did you import the correct file?"
|
||||
validator={(credentials) => {
|
||||
if (!credentials) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!credentials.client_email ||
|
||||
typeof credentials.client_email !== 'string' ||
|
||||
credentials.client_email.length <= 2
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!credentials.project_id ||
|
||||
typeof credentials.project_id !== 'string' ||
|
||||
credentials.project_id.length <= 2
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!credentials.private_key ||
|
||||
typeof credentials.private_key !== 'string' ||
|
||||
credentials.private_key.length <= 600
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}}
|
||||
onFileSelected={(data) => {
|
||||
setToken(JSON.stringify(data));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoogleConfig;
|
||||
82
client/src/components/Input/SetTokenDialog/HelpText.tsx
Normal file
82
client/src/components/Input/SetTokenDialog/HelpText.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import React from 'react';
|
||||
|
||||
function HelpText({ endpoint } : { endpoint: string }) {
|
||||
const textMap = {
|
||||
bingAI: (
|
||||
<small className="break-all text-gray-600">
|
||||
{'To get your Access token for Bing, login to '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://www.bing.com"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
https://www.bing.com
|
||||
</a>
|
||||
{`. Use dev tools or an extension while logged into the site to copy the content of the _U cookie.
|
||||
If this fails, follow these `}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://github.com/waylaidwanderer/node-chatgpt-api/issues/378#issuecomment-1559868368"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
instructions
|
||||
</a>
|
||||
{' to provide the full cookie strings.'}
|
||||
</small>
|
||||
),
|
||||
chatGPTBrowser: (
|
||||
<small className="break-all text-gray-600">
|
||||
{'To get your Access token For ChatGPT \'Free Version\', login to '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chat.openai.com"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
https://chat.openai.com
|
||||
</a>
|
||||
, then visit{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chat.openai.com/api/auth/session"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
https://chat.openai.com/api/auth/session
|
||||
</a>
|
||||
. Copy access token.
|
||||
</small>
|
||||
),
|
||||
google: (
|
||||
<small className="break-all text-gray-600">
|
||||
You need to{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://console.cloud.google.com/vertex-ai"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
Enable Vertex AI
|
||||
</a>{' '}
|
||||
API on Google Cloud, then{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts/create?walkthrough_id=iam--create-service-account#step_index=1"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
Create a Service Account
|
||||
</a>
|
||||
{`. Make sure to click 'Create and Continue' to give at least the 'Vertex AI User' role.
|
||||
Lastly, create a JSON key to import here.`}
|
||||
</small>
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
return textMap[endpoint] || null;
|
||||
};
|
||||
|
||||
export default React.memo(HelpText);
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
import React from 'react';
|
||||
import { Input } from '../../ui/Input.tsx';
|
||||
import { Label } from '../../ui/Label.tsx';
|
||||
import React, { ChangeEvent, FC } from 'react';
|
||||
import { Input, Label } from '~/components';
|
||||
import { cn } from '~/utils/';
|
||||
|
||||
function InputWithLabel({ value, onChange, label, id }) {
|
||||
interface InputWithLabelProps {
|
||||
value: string;
|
||||
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
label: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const InputWithLabel: FC<InputWithLabelProps> = ({ 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';
|
||||
|
||||
126
client/src/components/Input/SetTokenDialog/OpenAIConfig.tsx
Normal file
126
client/src/components/Input/SetTokenDialog/OpenAIConfig.tsx
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import * as Checkbox from '@radix-ui/react-checkbox';
|
||||
import { CheckIcon } from '@radix-ui/react-icons';
|
||||
import InputWithLabel from './InputWithLabel';
|
||||
import store from '~/store';
|
||||
|
||||
function isJson(str: string) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
type OpenAIConfigProps = {
|
||||
token: string;
|
||||
setToken: React.Dispatch<React.SetStateAction<string>>;
|
||||
endpoint: string;
|
||||
};
|
||||
|
||||
const OpenAIConfig = ({ token, setToken, endpoint } : OpenAIConfigProps) => {
|
||||
const [showPanel, setShowPanel] = useState(endpoint === 'azureOpenAI');
|
||||
const { getToken } = store.useToken(endpoint);
|
||||
|
||||
useEffect(() => {
|
||||
let oldToken = getToken();
|
||||
if (isJson(token)) {
|
||||
setShowPanel(true);
|
||||
}
|
||||
setToken(oldToken ?? '');
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!showPanel && isJson(token)) {
|
||||
setToken('');
|
||||
}
|
||||
}, [showPanel]);
|
||||
|
||||
function getAzure(name: string) {
|
||||
if (isJson(token)) {
|
||||
let newToken = JSON.parse(token);
|
||||
return newToken[name];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function setAzure(name: string, value: any) {
|
||||
let newToken = {};
|
||||
if (isJson(token)) {
|
||||
newToken = JSON.parse(token);
|
||||
}
|
||||
newToken[name] = value;
|
||||
|
||||
setToken(JSON.stringify(newToken));
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{!showPanel ? (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'chatGPTLabel'}
|
||||
value={token || ''}
|
||||
onChange={(e: { target: { value: any; }; }) => setToken(e.target.value || '')}
|
||||
label={'OpenAI API Key'}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'instanceNameLabel'}
|
||||
value={getAzure('azureOpenAIApiInstanceName') || ''}
|
||||
onChange={(e: { target: { value: any; }; }) => setAzure('azureOpenAIApiInstanceName', e.target.value || '')}
|
||||
label={'Azure OpenAI Instance Name'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'deploymentNameLabel'}
|
||||
value={getAzure('azureOpenAIApiDeploymentName') || ''}
|
||||
onChange={(e: { target: { value: any; }; }) => setAzure('azureOpenAIApiDeploymentName', e.target.value || '')}
|
||||
label={'Azure OpenAI Deployment Name'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'versionLabel'}
|
||||
value={getAzure('azureOpenAIApiVersion') || ''}
|
||||
onChange={(e: { target: { value: any; }; }) => setAzure('azureOpenAIApiVersion', e.target.value || '')}
|
||||
label={'Azure OpenAI API Version'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'apiKeyLabel'}
|
||||
value={getAzure('azureOpenAIApiKey') || ''}
|
||||
onChange={(e: { target: { value: any; }; }) => setAzure('azureOpenAIApiKey', e.target.value || '')}
|
||||
label={'Azure OpenAI API Key'}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{ endpoint === 'gptPlugins' && (
|
||||
<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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default OpenAIConfig;
|
||||
20
client/src/components/Input/SetTokenDialog/OtherConfig.tsx
Normal file
20
client/src/components/Input/SetTokenDialog/OtherConfig.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
import InputWithLabel from './InputWithLabel';
|
||||
|
||||
type ConfigProps = {
|
||||
token: string;
|
||||
setToken: React.Dispatch<React.SetStateAction<string>>;
|
||||
};
|
||||
|
||||
const OtherConfig = ({ token, setToken } : ConfigProps) => {
|
||||
return (
|
||||
<InputWithLabel
|
||||
id={'chatGPTLabel'}
|
||||
value={token || ''}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setToken(e.target.value || '')}
|
||||
label={'Token Name'}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default OtherConfig;
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import React, { useState }from 'react';
|
||||
import HelpText from './HelpText';
|
||||
import GoogleConfig from './GoogleConfig';
|
||||
import OpenAIConfig from './OpenAIConfig';
|
||||
import OtherConfig from './OtherConfig';
|
||||
import { Dialog, DialogTemplate } from '~/components';
|
||||
import { alternateName } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
const SetTokenDialog = ({ open, onOpenChange, endpoint }) => {
|
||||
const [token, setToken] = useState('');
|
||||
const { saveToken } = store.useToken(endpoint);
|
||||
|
||||
const submit = () => {
|
||||
saveToken(token);
|
||||
onOpenChange(false);
|
||||
};
|
||||
|
||||
const endpointComponents = {
|
||||
'google': GoogleConfig,
|
||||
'openAI': OpenAIConfig,
|
||||
'azureOpenAI': OpenAIConfig,
|
||||
'gptPlugins': OpenAIConfig,
|
||||
'default': OtherConfig
|
||||
};
|
||||
|
||||
const EndpointComponent = endpointComponents[endpoint] || endpointComponents['default'];
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogTemplate
|
||||
title={`Set Token for ${alternateName[endpoint] ?? endpoint}`}
|
||||
main={
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<EndpointComponent token={token} setToken={setToken} endpoint={endpoint}/>
|
||||
<small className="text-red-600">
|
||||
Your token will be sent to the server, but not saved.
|
||||
</small>
|
||||
<HelpText endpoint={endpoint}/>
|
||||
</div>
|
||||
}
|
||||
selection={{
|
||||
selectHandler: submit,
|
||||
selectClasses: 'bg-green-600 hover:bg-green-700 dark:hover:bg-green-800 text-white',
|
||||
selectText: 'Submit'
|
||||
}}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default SetTokenDialog;
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Dialog, DialogTemplate } from '../../ui';
|
||||
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 submit = () => {
|
||||
saveToken(token);
|
||||
onOpenChange(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
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">
|
||||
{`To get your Access token for Bing, login to `}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://www.bing.com"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
https://www.bing.com
|
||||
</a>
|
||||
{`. Use dev tools or an extension while logged into the site to copy the content of the _U cookie.
|
||||
If this fails, follow these `}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://github.com/waylaidwanderer/node-chatgpt-api/issues/378#issuecomment-1559868368"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
instructions
|
||||
</a>
|
||||
{` to provide the full cookie strings.`}
|
||||
</small>
|
||||
),
|
||||
chatGPTBrowser: (
|
||||
<small className="break-all text-gray-600">
|
||||
{`To get your Access token For ChatGPT 'Free Version', login to `}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chat.openai.com"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
https://chat.openai.com
|
||||
</a>
|
||||
, then visit{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://chat.openai.com/api/auth/session"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
https://chat.openai.com/api/auth/session
|
||||
</a>
|
||||
. Copy access token.
|
||||
</small>
|
||||
),
|
||||
google: (
|
||||
<small className="break-all text-gray-600">
|
||||
You need to{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://console.cloud.google.com/vertex-ai"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
Enable Vertex AI
|
||||
</a>{' '}
|
||||
API on Google Cloud, then{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts/create?walkthrough_id=iam--create-service-account#step_index=1"
|
||||
rel="noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
Create a Service Account
|
||||
</a>
|
||||
{`. Make sure to click 'Create and Continue' to give at least the 'Vertex AI User' role.
|
||||
Lastly, create a JSON key to import here.`}
|
||||
</small>
|
||||
)
|
||||
};
|
||||
|
||||
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} onOpenChange={onOpenChange}>
|
||||
<DialogTemplate
|
||||
title={`Set Token of ${endpoint}`}
|
||||
main={
|
||||
<div className="grid w-full items-center gap-2">
|
||||
{endpoint === 'google' ? (
|
||||
<FileUpload
|
||||
id="googleKey"
|
||||
className="w-full"
|
||||
text="Import Service Account JSON Key"
|
||||
successText="Successfully Imported Service Account JSON Key"
|
||||
invalidText="Invalid Service Account JSON Key, Did you import the correct file?"
|
||||
validator={(credentials) => {
|
||||
if (!credentials) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!credentials.client_email ||
|
||||
typeof credentials.client_email !== 'string' ||
|
||||
credentials.client_email.length <= 2
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!credentials.project_id ||
|
||||
typeof credentials.project_id !== 'string' ||
|
||||
credentials.project_id.length <= 2
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!credentials.private_key ||
|
||||
typeof credentials.private_key !== 'string' ||
|
||||
credentials.private_key.length <= 600
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}}
|
||||
onFileSelected={(data) => {
|
||||
setToken(JSON.stringify(data));
|
||||
}}
|
||||
/>
|
||||
) : endpoint === 'openAI' || endpoint === 'azureOpenAI' ? (
|
||||
<>
|
||||
{!showPanel ? (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'chatGPTLabel'}
|
||||
value={token || ''}
|
||||
onChange={(e) => setToken(e.target.value || '')}
|
||||
label={'OpenAI API Key'}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<InputWithLabel
|
||||
id={'instanceNameLabel'}
|
||||
value={getAzure('azureOpenAIApiInstanceName') || ''}
|
||||
onChange={(e) => setAzure('azureOpenAIApiInstanceName', e.target.value || '')}
|
||||
label={'Azure OpenAI Instance Name'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'deploymentNameLabel'}
|
||||
value={getAzure('azureOpenAIApiDeploymentName') || ''}
|
||||
onChange={(e) => setAzure('azureOpenAIApiDeploymentName', e.target.value || '')}
|
||||
label={'Azure OpenAI Deployment Name'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'versionLabel'}
|
||||
value={getAzure('azureOpenAIApiVersion') || ''}
|
||||
onChange={(e) => setAzure('azureOpenAIApiVersion', e.target.value || '')}
|
||||
label={'Azure OpenAI API Version'}
|
||||
/>
|
||||
|
||||
<InputWithLabel
|
||||
id={'apiKeyLabel'}
|
||||
value={getAzure('azureOpenAIApiKey') || ''}
|
||||
onChange={(e) => setAzure('azureOpenAIApiKey', 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 && endpoint === 'azureOpenAI'}
|
||||
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]}
|
||||
</div>
|
||||
}
|
||||
selection={{
|
||||
selectHandler: submit,
|
||||
selectClasses: 'bg-green-600 hover:bg-green-700 dark:hover:bg-green-800 text-white',
|
||||
selectText: 'Submit'
|
||||
}}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default SetTokenDialog;
|
||||
1
client/src/components/Input/SetTokenDialog/index.ts
Normal file
1
client/src/components/Input/SetTokenDialog/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as SetTokenDialog } from './SetTokenDialog';
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useState } from 'react';
|
||||
import StopGeneratingIcon from '../svg/StopGeneratingIcon';
|
||||
import { StopGeneratingIcon } from '~/components';
|
||||
import { Settings } from 'lucide-react';
|
||||
import SetTokenDialog from './SetTokenDialog';
|
||||
import store from '../../store';
|
||||
import { SetTokenDialog } from './SetTokenDialog';
|
||||
import store from '~/store';
|
||||
|
||||
export default function SubmitButton({
|
||||
endpoint,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useState } from 'react';
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { Plugin } from '~/components/svg';
|
||||
import EndpointOptionsDialog from '../Endpoints/EndpointOptionsDialog';
|
||||
import { cn } from '~/utils/';
|
||||
import { cn, alternateName } from '~/utils/';
|
||||
|
||||
import store from '~/store';
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ const MessageHeader = ({ isSearchView = false }) => {
|
|||
const getConversationTitle = () => {
|
||||
if (isSearchView) return `Search: ${searchQuery}`;
|
||||
else {
|
||||
let _title = `${endpoint}`;
|
||||
let _title = `${alternateName[endpoint] ?? endpoint}`;
|
||||
|
||||
if (endpoint === 'azureOpenAI' || endpoint === 'openAI') {
|
||||
const { chatGptLabel } = conversation;
|
||||
|
|
@ -42,7 +42,7 @@ const MessageHeader = ({ isSearchView = false }) => {
|
|||
} else if (endpoint === 'bingAI') {
|
||||
const { jailbreak, toneStyle } = conversation;
|
||||
if (toneStyle) _title += `: ${toneStyle}`;
|
||||
if (jailbreak) _title += ` as Sydney`;
|
||||
if (jailbreak) _title += ' as Sydney';
|
||||
} else if (endpoint === 'chatGPTBrowser') {
|
||||
if (model) _title += `: ${model}`;
|
||||
} else if (endpoint === 'gptPlugins') {
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ export { default as GPTIcon } from './GPTIcon';
|
|||
export { default as BingIcon } from './BingIcon';
|
||||
export { default as CogIcon } from './CogIcon';
|
||||
export { default as Spinner } from './Spinner';
|
||||
export { default as MessagesSquared } from './MessagesSquared';
|
||||
export { default as MessagesSquared } from './MessagesSquared';
|
||||
export { default as StopGeneratingIcon } from './StopGeneratingIcon';
|
||||
|
|
@ -34,3 +34,13 @@ export const languages = [
|
|||
'perl',
|
||||
'pascal'
|
||||
];
|
||||
|
||||
export const alternateName = {
|
||||
openAI: 'OpenAI',
|
||||
azureOpenAI: 'Azure OpenAI',
|
||||
bingAI: 'Bing',
|
||||
chatGPTBrowser: 'ChatGPT',
|
||||
gptPlugins: 'Plugins',
|
||||
google: 'PaLM'
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue