Add OpenaiURL

This commit is contained in:
blue-eyed 2024-06-17 21:03:56 +08:00
parent 476303f52b
commit e980945d59
4 changed files with 159 additions and 168 deletions

View file

@ -16,6 +16,7 @@ interface Config {
API_ENDPOINTS: {
SEARXNG: string;
OLLAMA: string;
OPENAI: string;
};
}
@ -41,6 +42,8 @@ export const getSearxngApiEndpoint = () => loadConfig().API_ENDPOINTS.SEARXNG;
export const getOllamaApiEndpoint = () => loadConfig().API_ENDPOINTS.OLLAMA;
export const getOpenaiApiEndpoint = () => loadConfig().API_ENDPOINTS.OPENAI;
export const updateConfig = (config: RecursivePartial<Config>) => {
const currentConfig = loadConfig();

View file

@ -6,6 +6,7 @@ import {
getGroqApiKey,
getOllamaApiEndpoint,
getOpenaiApiKey,
getOpenaiApiEndpoint,
} from '../config';
import logger from '../utils/logger';
@ -13,6 +14,7 @@ export const getAvailableChatModelProviders = async () => {
const openAIApiKey = getOpenaiApiKey();
const groqApiKey = getGroqApiKey();
const ollamaEndpoint = getOllamaApiEndpoint();
const openAIEndpoint = getOpenaiApiEndpoint();
const models = {};
@ -23,22 +25,38 @@ export const getAvailableChatModelProviders = async () => {
openAIApiKey,
modelName: 'gpt-3.5-turbo',
temperature: 0.7,
}),
},
{
baseURL:openAIEndpoint,
},
),
'GPT-4': new ChatOpenAI({
openAIApiKey,
modelName: 'gpt-4',
temperature: 0.7,
}),
},
{
baseURL:openAIEndpoint,
},
),
'GPT-4 turbo': new ChatOpenAI({
openAIApiKey,
modelName: 'gpt-4-turbo',
temperature: 0.7,
}),
},
{
baseURL:openAIEndpoint,
},
),
'GPT-4 omni': new ChatOpenAI({
openAIApiKey,
modelName: 'gpt-4o',
temperature: 0.7,
}),
},
{
baseURL:openAIEndpoint,
},
),
};
} catch (err) {
logger.error(`Error loading OpenAI models: ${err}`);
@ -117,6 +135,8 @@ export const getAvailableChatModelProviders = async () => {
}
}
models['custom_openai'] = {};
return models;
@ -125,6 +145,7 @@ export const getAvailableChatModelProviders = async () => {
export const getAvailableEmbeddingModelProviders = async () => {
const openAIApiKey = getOpenaiApiKey();
const ollamaEndpoint = getOllamaApiEndpoint();
const openAIEndpoint = getOpenaiApiEndpoint();
const models = {};
@ -134,11 +155,19 @@ export const getAvailableEmbeddingModelProviders = async () => {
'Text embedding 3 small': new OpenAIEmbeddings({
openAIApiKey,
modelName: 'text-embedding-3-small',
}),
},
{
baseURL:openAIEndpoint,
},
),
'Text embedding 3 large': new OpenAIEmbeddings({
openAIApiKey,
modelName: 'text-embedding-3-large',
}),
},
{
baseURL:openAIEndpoint,
},
),
};
} catch (err) {
logger.error(`Error loading OpenAI embeddings: ${err}`);
@ -167,6 +196,7 @@ export const getAvailableEmbeddingModelProviders = async () => {
}
}
try {
models['local'] = {
'BGE Small': new HuggingFaceTransformersEmbeddings({

View file

@ -7,6 +7,7 @@ import {
getGroqApiKey,
getOllamaApiEndpoint,
getOpenaiApiKey,
getOpenaiApiEndpoint,
updateConfig,
} from '../config';
@ -38,7 +39,7 @@ router.get('/', async (_, res) => {
config['openaiApiKey'] = getOpenaiApiKey();
config['ollamaApiUrl'] = getOllamaApiEndpoint();
config['groqApiKey'] = getGroqApiKey();
config['openaiApiUrl'] = getOpenaiApiEndpoint();
res.status(200).json(config);
});
@ -52,6 +53,7 @@ router.post('/', async (req, res) => {
},
API_ENDPOINTS: {
OLLAMA: config.ollamaApiUrl,
OPENAI: config.openaiApiUrl,
},
};

View file

@ -1,52 +1,6 @@
import { cn } from '@/lib/utils';
import { Dialog, Transition } from '@headlessui/react';
import { CloudUpload, RefreshCcw, RefreshCw } from 'lucide-react';
import React, {
Fragment,
useEffect,
useMemo,
useState,
type SelectHTMLAttributes,
} from 'react';
import ThemeSwitcher from './theme/Switcher';
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = ({ className, ...restProps }: InputProps) => {
return (
<input
{...restProps}
className={cn(
'bg-light-secondary dark:bg-dark-secondary px-3 py-2 flex items-center overflow-hidden border border-light-200 dark:border-dark-200 dark:text-white rounded-lg text-sm',
className,
)}
/>
);
};
interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
options: { value: string; label: string; disabled?: boolean }[];
}
export const Select = ({ className, options, ...restProps }: SelectProps) => {
return (
<select
{...restProps}
className={cn(
'bg-light-secondary dark:bg-dark-secondary px-3 py-2 flex items-center overflow-hidden border border-light-200 dark:border-dark-200 dark:text-white rounded-lg text-sm',
className,
)}
>
{options.map(({ label, value, disabled }) => {
return (
<option key={value} value={value} disabled={disabled}>
{label}
</option>
);
})}
</select>
);
};
import React, { Fragment, useEffect, useState } from 'react';
interface SettingsType {
chatModelProviders: {
@ -58,6 +12,7 @@ interface SettingsType {
openaiApiKey: string;
groqApiKey: string;
ollamaApiUrl: string;
openaiApiUrl: string;
}
const SettingsDialog = ({
@ -191,7 +146,7 @@ const SettingsDialog = ({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-white/50 dark:bg-black/50" />
<div className="fixed inset-0 bg-black/50" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
@ -204,24 +159,18 @@ const SettingsDialog = ({
leaveFrom="opacity-100 scale-200"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-md transform rounded-2xl bg-light-secondary dark:bg-dark-secondary border border-light-200 dark:border-dark-200 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title className="text-xl font-medium leading-6 dark:text-white">
<Dialog.Panel className="w-full max-w-md transform rounded-2xl bg-[#111111] border border-[#1c1c1c] p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title className="text-xl font-medium leading-6 text-white">
Settings
</Dialog.Title>
{config && !isLoading && (
<div className="flex flex-col space-y-4 mt-6">
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Theme
</p>
<ThemeSwitcher />
</div>
{config.chatModelProviders && (
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
<p className="text-white/70 text-sm">
Chat model Provider
</p>
<Select
<select
value={selectedChatModelProvider ?? undefined}
onChange={(e) => {
setSelectedChatModelProvider(e.target.value);
@ -229,99 +178,97 @@ const SettingsDialog = ({
config.chatModelProviders[e.target.value][0],
);
}}
options={Object.keys(config.chatModelProviders).map(
(provider) => ({
value: provider,
label:
provider.charAt(0).toUpperCase() +
provider.slice(1),
}),
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
>
{Object.keys(config.chatModelProviders).map(
(provider) => (
<option key={provider} value={provider}>
{provider.charAt(0).toUpperCase() +
provider.slice(1)}
</option>
),
)}
/>
</select>
</div>
)}
{selectedChatModelProvider &&
selectedChatModelProvider != 'custom_openai' && (
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Chat Model
</p>
<Select
<p className="text-white/70 text-sm">Chat Model</p>
<select
value={selectedChatModel ?? undefined}
onChange={(e) =>
setSelectedChatModel(e.target.value)
}
options={(() => {
const chatModelProvider =
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
>
{config.chatModelProviders[
selectedChatModelProvider
] ? (
config.chatModelProviders[
selectedChatModelProvider
].length > 0 ? (
config.chatModelProviders[
selectedChatModelProvider
];
return chatModelProvider
? chatModelProvider.length > 0
? chatModelProvider.map((model) => ({
value: model,
label: model,
}))
: [
{
value: '',
label: 'No models available',
disabled: true,
},
]
: [
{
value: '',
label:
'Invalid provider, please check backend logs',
disabled: true,
},
];
})()}
/>
].map((model) => (
<option key={model} value={model}>
{model}
</option>
))
) : (
<option value="" disabled>
No models available
</option>
)
) : (
<option value="" disabled>
Invalid provider, please check backend logs
</option>
)}
</select>
</div>
)}
{selectedChatModelProvider &&
selectedChatModelProvider === 'custom_openai' && (
<>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Model name
</p>
<Input
<p className="text-white/70 text-sm">Model name</p>
<input
type="text"
placeholder="Model name"
defaultValue={selectedChatModel!}
onChange={(e) =>
setSelectedChatModel(e.target.value)
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
<p className="text-white/70 text-sm">
Custom OpenAI API Key
</p>
<Input
<input
type="text"
placeholder="Custom OpenAI API Key"
defaultValue={customOpenAIApiKey!}
onChange={(e) =>
setCustomOpenAIApiKey(e.target.value)
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
<p className="text-white/70 text-sm">
Custom OpenAI Base URL
</p>
<Input
<input
type="text"
placeholder="Custom OpenAI Base URL"
defaultValue={customOpenAIBaseURL!}
onChange={(e) =>
setCustomOpenAIBaseURL(e.target.value)
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
</>
@ -329,10 +276,10 @@ const SettingsDialog = ({
{/* Embedding models */}
{config.embeddingModelProviders && (
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
<p className="text-white/70 text-sm">
Embedding model Provider
</p>
<Select
<select
value={selectedEmbeddingModelProvider ?? undefined}
onChange={(e) => {
setSelectedEmbeddingModelProvider(e.target.value);
@ -340,63 +287,58 @@ const SettingsDialog = ({
config.embeddingModelProviders[e.target.value][0],
);
}}
options={Object.keys(
config.embeddingModelProviders,
).map((provider) => ({
label:
provider.charAt(0).toUpperCase() +
provider.slice(1),
value: provider,
}))}
/>
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
>
{Object.keys(config.embeddingModelProviders).map(
(provider) => (
<option key={provider} value={provider}>
{provider.charAt(0).toUpperCase() +
provider.slice(1)}
</option>
),
)}
</select>
</div>
)}
{selectedEmbeddingModelProvider && (
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Embedding Model
</p>
<Select
<p className="text-white/70 text-sm">Embedding Model</p>
<select
value={selectedEmbeddingModel ?? undefined}
onChange={(e) =>
setSelectedEmbeddingModel(e.target.value)
}
options={(() => {
const embeddingModelProvider =
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
>
{config.embeddingModelProviders[
selectedEmbeddingModelProvider
] ? (
config.embeddingModelProviders[
selectedEmbeddingModelProvider
].length > 0 ? (
config.embeddingModelProviders[
selectedEmbeddingModelProvider
];
return embeddingModelProvider
? embeddingModelProvider.length > 0
? embeddingModelProvider.map((model) => ({
label: model,
value: model,
}))
: [
{
label: 'No embedding models available',
value: '',
disabled: true,
},
]
: [
{
label:
'Invalid provider, please check backend logs',
value: '',
disabled: true,
},
];
})()}
/>
].map((model) => (
<option key={model} value={model}>
{model}
</option>
))
) : (
<option value="" disabled selected>
No embedding models available
</option>
)
) : (
<option value="" disabled selected>
Invalid provider, please check backend logs
</option>
)}
</select>
</div>
)}
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
OpenAI API Key
</p>
<Input
<p className="text-white/70 text-sm">OpenAI API Key</p>
<input
type="text"
placeholder="OpenAI API Key"
defaultValue={config.openaiApiKey}
@ -406,13 +348,12 @@ const SettingsDialog = ({
openaiApiKey: e.target.value,
})
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Ollama API URL
</p>
<Input
<p className="text-white/70 text-sm">Ollama API URL</p>
<input
type="text"
placeholder="Ollama API URL"
defaultValue={config.ollamaApiUrl}
@ -422,13 +363,27 @@ const SettingsDialog = ({
ollamaApiUrl: e.target.value,
})
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
GROQ API Key
</p>
<Input
<p className="text-white/70 text-sm">OpenAI API URL</p>
<input
type="text"
placeholder="OpenAI API URL"
defaultValue={config.openaiApiUrl}
onChange={(e) =>
setConfig({
...config,
openaiApiUrl: e.target.value,
})
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
<div className="flex flex-col space-y-1">
<p className="text-white/70 text-sm">GROQ API Key</p>
<input
type="text"
placeholder="GROQ API Key"
defaultValue={config.groqApiKey}
@ -438,17 +393,18 @@ const SettingsDialog = ({
groqApiKey: e.target.value,
})
}
className="bg-[#111111] px-3 py-2 flex items-center overflow-hidden border border-[#1C1C1C] text-white rounded-lg text-sm"
/>
</div>
</div>
)}
{isLoading && (
<div className="w-full flex items-center justify-center mt-6 text-black/70 dark:text-white/70 py-6">
<div className="w-full flex items-center justify-center mt-6 text-white/70 py-6">
<RefreshCcw className="animate-spin" />
</div>
)}
<div className="w-full mt-6 space-y-2">
<p className="text-xs text-black/50 dark:text-white/50">
<p className="text-xs text-white/50">
We&apos;ll refresh the page after updating the settings.
</p>
<button