feat(app): lint & beautify

This commit is contained in:
ItzCrazyKns
2025-10-18 18:50:08 +05:30
parent d43ef9e43d
commit 2c9012e99c
7 changed files with 407 additions and 395 deletions

View File

@@ -2,118 +2,117 @@ import { Dialog, DialogPanel } from '@headlessui/react';
import { Loader2, Trash2 } from 'lucide-react'; import { Loader2, Trash2 } from 'lucide-react';
import { useState } from 'react'; import { useState } from 'react';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { import { ConfigModelProvider } from '@/lib/config/types';
ConfigModelProvider,
} from '@/lib/config/types';
import { toast } from 'sonner'; import { toast } from 'sonner';
const DeleteProvider = ({ const DeleteProvider = ({
modelProvider, modelProvider,
setProviders, setProviders,
}: { }: {
modelProvider: ConfigModelProvider; modelProvider: ConfigModelProvider;
setProviders: React.Dispatch<React.SetStateAction<ConfigModelProvider[]>>; setProviders: React.Dispatch<React.SetStateAction<ConfigModelProvider[]>>;
}) => { }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const handleDelete = async (e: React.FormEvent) => { const handleDelete = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
setLoading(true); setLoading(true);
try { try {
const res = await fetch(`/api/providers/${modelProvider.id}`, { const res = await fetch(`/api/providers/${modelProvider.id}`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}); });
if (!res.ok) { if (!res.ok) {
throw new Error('Failed to delete provider'); throw new Error('Failed to delete provider');
} }
setProviders((prev) => { setProviders((prev) => {
return prev.filter((p) => p.id !== modelProvider.id); return prev.filter((p) => p.id !== modelProvider.id);
}); });
toast.success('Provider deleted successfully.'); toast.success('Provider deleted successfully.');
} catch (error) { } catch (error) {
console.error('Error deleting provider:', error); console.error('Error deleting provider:', error);
toast.error('Failed to delete provider.'); toast.error('Failed to delete provider.');
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; };
return ( return (
<> <>
<button <button
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
setOpen(true); setOpen(true);
}} }}
className="group p-1.5 rounded-md hover:bg-light-200 hover:dark:bg-dark-200 transition-colors group" className="group p-1.5 rounded-md hover:bg-light-200 hover:dark:bg-dark-200 transition-colors group"
title="Delete provider" title="Delete provider"
>
<Trash2
size={14}
className="text-black/60 dark:text-white/60 group-hover:text-red-500 group-hover:dark:text-red-400"
/>
</button>
<AnimatePresence>
{open && (
<Dialog
static
open={open}
onClose={() => setOpen(false)}
className="relative z-[60]"
>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.1 }}
className="fixed inset-0 flex w-screen items-center justify-center p-4 bg-black/30 backdrop-blur-sm"
> >
<Trash2 <DialogPanel className="w-full mx-4 lg:w-[600px] max-h-[85vh] flex flex-col border bg-light-primary dark:bg-dark-primary border-light-secondary dark:border-dark-secondary rounded-lg">
size={14} <div className="px-6 pt-6 pb-4">
className="text-black/60 dark:text-white/60 group-hover:text-red-500 group-hover:dark:text-red-400" <h3 className="text-black/90 dark:text-white/90 font-medium">
/> Delete provider
</button> </h3>
<AnimatePresence> </div>
{open && ( <div className="border-t border-light-200 dark:border-dark-200" />
<Dialog <div className="flex-1 overflow-y-auto px-6 py-4">
static <p className="text-SM text-black/60 dark:text-white/60">
open={open} Are you sure you want to delete the provider &quot;
onClose={() => setOpen(false)} {modelProvider.name}&quot;? This action cannot be undone.
className="relative z-[60]" </p>
> </div>
<motion.div <div className="px-6 py-6 flex justify-end space-x-2">
initial={{ opacity: 0 }} <button
animate={{ opacity: 1 }} disabled={loading}
exit={{ opacity: 0 }} onClick={() => setOpen(false)}
transition={{ duration: 0.1 }} className="px-4 py-2 rounded-lg text-sm border border-light-200 dark:border-dark-200 text-black dark:text-white bg-light-secondary/50 dark:bg-dark-secondary/50 hover:bg-light-secondary hover:dark:bg-dark-secondary hover:border-light-300 hover:dark:border-dark-300 flex flex-row items-center space-x-1 active:scale-95 transition duration-200"
className="fixed inset-0 flex w-screen items-center justify-center p-4 bg-black/30 backdrop-blur-sm" >
> Cancel
<DialogPanel className="w-full mx-4 lg:w-[600px] max-h-[85vh] flex flex-col border bg-light-primary dark:bg-dark-primary border-light-secondary dark:border-dark-secondary rounded-lg"> </button>
<div className="px-6 pt-6 pb-4"> <button
<h3 className="text-black/90 dark:text-white/90 font-medium"> disabled={loading}
Delete provider onClick={handleDelete}
</h3> className="px-4 py-2 rounded-lg text-sm bg-red-500 text-white font-medium disabled:opacity-85 hover:opacity-85 active:scale-95 transition duration-200"
</div> >
<div className="border-t border-light-200 dark:border-dark-200" /> {loading ? (
<div className="flex-1 overflow-y-auto px-6 py-4"> <Loader2 className="animate-spin" size={16} />
<p className='text-SM text-black/60 dark:text-white/60'> ) : (
Are you sure you want to delete the provider &quot;{modelProvider.name}&quot;? This action cannot be undone. 'Delete'
</p> )}
</div> </button>
<div className="px-6 py-6 flex justify-end space-x-2"> </div>
<button </DialogPanel>
disabled={loading} </motion.div>
onClick={() => setOpen(false)} </Dialog>
className="px-4 py-2 rounded-lg text-sm border border-light-200 dark:border-dark-200 text-black dark:text-white bg-light-secondary/50 dark:bg-dark-secondary/50 hover:bg-light-secondary hover:dark:bg-dark-secondary hover:border-light-300 hover:dark:border-dark-300 flex flex-row items-center space-x-1 active:scale-95 transition duration-200" )}
> </AnimatePresence>
Cancel </>
</button> );
<button
disabled={loading}
onClick={handleDelete}
className="px-4 py-2 rounded-lg text-sm bg-red-500 text-white font-medium disabled:opacity-85 hover:opacity-85 active:scale-95 transition duration-200"
>
{loading ? (
<Loader2 className="animate-spin" size={16} />
) : (
'Delete'
)}
</button>
</div>
</DialogPanel>
</motion.div>
</Dialog>
)}
</AnimatePresence>
</>
);
}; };
export default DeleteProvider; export default DeleteProvider;

View File

@@ -9,199 +9,209 @@ import UpdateProvider from './UpdateProviderDialog';
import DeleteProvider from './DeleteProviderDialog'; import DeleteProvider from './DeleteProviderDialog';
const ModelProvider = ({ const ModelProvider = ({
modelProvider, modelProvider,
setProviders, setProviders,
fields, fields,
}: { }: {
modelProvider: ConfigModelProvider; modelProvider: ConfigModelProvider;
fields: UIConfigField[]; fields: UIConfigField[];
setProviders: React.Dispatch<React.SetStateAction<ConfigModelProvider[]>>; setProviders: React.Dispatch<React.SetStateAction<ConfigModelProvider[]>>;
}) => { }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const handleModelDelete = async ( const handleModelDelete = async (
type: 'chat' | 'embedding', type: 'chat' | 'embedding',
modelKey: string, modelKey: string,
) => { ) => {
try { try {
const res = await fetch(`/api/providers/${modelProvider.id}/models`, { const res = await fetch(`/api/providers/${modelProvider.id}/models`, {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ key: modelKey, type: type }), body: JSON.stringify({ key: modelKey, type: type }),
}); });
if (!res.ok) { if (!res.ok) {
throw new Error('Failed to delete model: ' + (await res.text())); throw new Error('Failed to delete model: ' + (await res.text()));
}
setProviders(
(prev) =>
prev.map((provider) => {
if (provider.id === modelProvider.id) {
return {
...provider,
...(type === 'chat'
? {
chatModels: provider.chatModels.filter(
(m) => m.key !== modelKey,
),
}
: {
embeddingModels: provider.embeddingModels.filter(
(m) => m.key !== modelKey,
),
}),
};
} }
return provider;
}) as ConfigModelProvider[],
);
setProviders( toast.success('Model deleted successfully.');
(prev) => } catch (err) {
prev.map((provider) => { console.error('Failed to delete model', err);
if (provider.id === modelProvider.id) { toast.error('Failed to delete model.');
return { }
...provider, };
...(type === 'chat'
? {
chatModels: provider.chatModels.filter(
(m) => m.key !== modelKey,
),
}
: {
embeddingModels: provider.embeddingModels.filter(
(m) => m.key !== modelKey,
),
}),
};
}
return provider;
}) as ConfigModelProvider[],
);
toast.success('Model deleted successfully.'); return (
} catch (err) { <div
console.error('Failed to delete model', err); key={modelProvider.id}
toast.error('Failed to delete model.'); className="border border-light-200 dark:border-dark-200 rounded-lg overflow-hidden"
} >
}; <div
className={cn(
return ( 'group px-5 py-4 flex flex-row justify-between w-full cursor-pointer hover:bg-light-secondary hover:dark:bg-dark-secondary transition duration-200 items-center',
<div !open && 'rounded-lg',
key={modelProvider.id} )}
className="border border-light-200 dark:border-dark-200 rounded-lg overflow-hidden" onClick={() => setOpen(!open)}
> >
<div <p className="text-black dark:text-white font-medium">
className={cn( {modelProvider.name}
'group px-5 py-4 flex flex-row justify-between w-full cursor-pointer hover:bg-light-secondary hover:dark:bg-dark-secondary transition duration-200 items-center', </p>
!open && 'rounded-lg', <div className="flex items-center gap-4">
)} <div className="flex flex-row items-center">
onClick={() => setOpen(!open)} <UpdateProvider
> fields={fields}
<p className="text-black dark:text-white font-medium"> modelProvider={modelProvider}
{modelProvider.name} setProviders={setProviders}
</p> />
<div className="flex items-center gap-4"> <DeleteProvider
<div className="flex flex-row items-center"> modelProvider={modelProvider}
<UpdateProvider setProviders={setProviders}
fields={fields} />
modelProvider={modelProvider} </div>
setProviders={setProviders} <ChevronDown
/> size={16}
<DeleteProvider className={cn(
modelProvider={modelProvider} open ? 'rotate-180' : '',
setProviders={setProviders} 'transition duration-200 text-black/70 dark:text-white/70 group-hover:text-sky-500',
/> )}
</div> />
<ChevronDown
size={16}
className={cn(
open ? 'rotate-180' : '',
'transition duration-200 text-black/70 dark:text-white/70 group-hover:text-sky-500',
)}
/>
</div>
</div>
<AnimatePresence>
{open && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.1 }}
>
<div className="border-t border-light-200 dark:border-dark-200" />
<div className="flex flex-col gap-y-4 px-5 py-4">
{modelProvider.chatModels.length > 0 && (
<div className="flex flex-col gap-y-2">
<div className="flex flex-row w-full justify-between items-center">
<p className="text-xs text-black/70 dark:text-white/70">
Chat models
</p>
<AddModel
providerId={modelProvider.id}
setProviders={setProviders}
type="chat"
/>
</div>
<div className="flex flex-col gap-2">
{modelProvider.chatModels.some((m) => m.key === 'error') ? (
<div className="flex flex-row items-center gap-2 text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<AlertCircle size={16} className="shrink-0" />
<span className="break-words">
{modelProvider.chatModels.find((m) => m.key === 'error')?.name}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.chatModels.map((model, index) => (
<div
key={`${modelProvider.id}-chat-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
>
<span>{model.name}</span>
<button
onClick={() => {
handleModelDelete('chat', model.key);
}}
>
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div>
)}
{modelProvider.embeddingModels.length > 0 && (
<div className="flex flex-col gap-y-2">
<div className="flex flex-row w-full justify-between items-center">
<p className="text-xs text-black/70 dark:text-white/70">
Embedding models
</p>
<AddModel
providerId={modelProvider.id}
setProviders={setProviders}
type="embedding"
/>
</div>
<div className="flex flex-col gap-2">
{modelProvider.embeddingModels.some((m) => m.key === 'error') ? (
<div className="flex flex-row items-center gap-2 text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<AlertCircle size={16} className="shrink-0" />
<span className="break-words">
{modelProvider.embeddingModels.find((m) => m.key === 'error')?.name}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.embeddingModels.map((model, index) => (
<div
key={`${modelProvider.id}-embedding-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
>
<span>{model.name}</span>
<button
onClick={() => {
handleModelDelete('embedding', model.key);
}}
>
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div>
)}
</div>
</motion.div>
)}
</AnimatePresence>
</div> </div>
); </div>
<AnimatePresence>
{open && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.1 }}
>
<div className="border-t border-light-200 dark:border-dark-200" />
<div className="flex flex-col gap-y-4 px-5 py-4">
{modelProvider.chatModels.length > 0 && (
<div className="flex flex-col gap-y-2">
<div className="flex flex-row w-full justify-between items-center">
<p className="text-xs text-black/70 dark:text-white/70">
Chat models
</p>
<AddModel
providerId={modelProvider.id}
setProviders={setProviders}
type="chat"
/>
</div>
<div className="flex flex-col gap-2">
{modelProvider.chatModels.some((m) => m.key === 'error') ? (
<div className="flex flex-row items-center gap-2 text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<AlertCircle size={16} className="shrink-0" />
<span className="break-words">
{
modelProvider.chatModels.find(
(m) => m.key === 'error',
)?.name
}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.chatModels.map((model, index) => (
<div
key={`${modelProvider.id}-chat-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
>
<span>{model.name}</span>
<button
onClick={() => {
handleModelDelete('chat', model.key);
}}
>
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div>
)}
{modelProvider.embeddingModels.length > 0 && (
<div className="flex flex-col gap-y-2">
<div className="flex flex-row w-full justify-between items-center">
<p className="text-xs text-black/70 dark:text-white/70">
Embedding models
</p>
<AddModel
providerId={modelProvider.id}
setProviders={setProviders}
type="embedding"
/>
</div>
<div className="flex flex-col gap-2">
{modelProvider.embeddingModels.some(
(m) => m.key === 'error',
) ? (
<div className="flex flex-row items-center gap-2 text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
<AlertCircle size={16} className="shrink-0" />
<span className="break-words">
{
modelProvider.embeddingModels.find(
(m) => m.key === 'error',
)?.name
}
</span>
</div>
) : (
<div className="flex flex-row flex-wrap gap-2">
{modelProvider.embeddingModels.map((model, index) => (
<div
key={`${modelProvider.id}-embedding-${model.key}-${index}`}
className="flex flex-row items-center space-x-1 text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
>
<span>{model.name}</span>
<button
onClick={() => {
handleModelDelete('embedding', model.key);
}}
>
<X size={12} />
</button>
</div>
))}
</div>
)}
</div>
</div>
)}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}; };
export default ModelProvider; export default ModelProvider;

View File

@@ -11,4 +11,5 @@ export const getConfiguredModelProviderById = (
return getConfiguredModelProviders().find((p) => p.id === id) ?? undefined; return getConfiguredModelProviders().find((p) => p.id === id) ?? undefined;
}; };
export const getSearxngURL = () => configManager.getConfig('search.searxngURL', '') export const getSearxngURL = () =>
configManager.getConfig('search.searxngURL', '');

View File

@@ -17,7 +17,6 @@ type StringUIConfigField = BaseUIConfigField & {
type SelectUIConfigFieldOptions = { type SelectUIConfigFieldOptions = {
name: string; name: string;
key: string;
value: string; value: string;
}; };
@@ -56,8 +55,8 @@ type Config = {
}; };
modelProviders: ConfigModelProvider[]; modelProviders: ConfigModelProvider[];
search: { search: {
[key: string]: any [key: string]: any;
} };
}; };
type EnvMap = { type EnvMap = {
@@ -76,7 +75,7 @@ type ModelProviderUISection = {
type UIConfigSections = { type UIConfigSections = {
general: UIConfigField[]; general: UIConfigField[];
modelProviders: ModelProviderUISection[]; modelProviders: ModelProviderUISection[];
search: UIConfigField[]; search: UIConfigField[];
}; };
export type { export type {
@@ -84,6 +83,8 @@ export type {
Config, Config,
EnvMap, EnvMap,
UIConfigSections, UIConfigSections,
SelectUIConfigField,
StringUIConfigField,
ModelProviderUISection, ModelProviderUISection,
ConfigModelProvider, ConfigModelProvider,
}; };

View File

@@ -5,7 +5,7 @@ import OllamaProvider from './ollama';
export const providers: Record<string, ProviderConstructor<any>> = { export const providers: Record<string, ProviderConstructor<any>> = {
openai: OpenAIProvider, openai: OpenAIProvider,
ollama: OllamaProvider ollama: OllamaProvider,
}; };
export const getModelProvidersUIConfigSection = export const getModelProvidersUIConfigSection =

View File

@@ -7,129 +7,131 @@ import { UIConfigField } from '@/lib/config/types';
import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry'; import { getConfiguredModelProviderById } from '@/lib/config/serverRegistry';
interface OllamaConfig { interface OllamaConfig {
baseURL: string; baseURL: string;
} }
const providerConfigFields: UIConfigField[] = [ const providerConfigFields: UIConfigField[] = [
{ {
type: 'string', type: 'string',
name: 'Base URL', name: 'Base URL',
key: 'baseURL', key: 'baseURL',
description: 'The base URL for the Ollama', description: 'The base URL for the Ollama',
required: true, required: true,
placeholder: 'Ollama Base URL', placeholder: 'Ollama Base URL',
default: process.env.DOCKER ? 'http://host.docker.internal:11434' : 'http://localhost:11434', default: process.env.DOCKER
env: 'OLLAMA_BASE_URL', ? 'http://host.docker.internal:11434'
scope: 'server', : 'http://localhost:11434',
}, env: 'OLLAMA_BASE_URL',
scope: 'server',
},
]; ];
class OllamaProvider extends BaseModelProvider<OllamaConfig> { class OllamaProvider extends BaseModelProvider<OllamaConfig> {
constructor(id: string, name: string, config: OllamaConfig) { constructor(id: string, name: string, config: OllamaConfig) {
super(id, name, config); super(id, name, config);
} }
async getDefaultModels(): Promise<ModelList> { async getDefaultModels(): Promise<ModelList> {
try { try {
const res = await fetch(`${this.config.baseURL}/api/tags`, { const res = await fetch(`${this.config.baseURL}/api/tags`, {
method: "GET", method: 'GET',
headers: { headers: {
'Content-type': 'application/json' 'Content-type': 'application/json',
} },
}) });
const data = await res.json() const data = await res.json();
const models: Model[] = data.models.map((m: any) => {
return {
name: m.name,
key: m.model
}
})
return {
embedding: models,
chat: models,
};
} catch (err) {
if (err instanceof TypeError) {
throw new Error('Error connecting to Ollama API. Please ensure the base URL is correct and the Ollama server is running.');
}
throw err;
}
}
async getModelList(): Promise<ModelList> {
const defaultModels = await this.getDefaultModels();
const configProvider = getConfiguredModelProviderById(this.id)!;
const models: Model[] = data.models.map((m: any) => {
return { return {
embedding: [ name: m.name,
...defaultModels.embedding, key: m.model,
...configProvider.embeddingModels,
],
chat: [...defaultModels.chat, ...configProvider.chatModels],
}; };
});
return {
embedding: models,
chat: models,
};
} catch (err) {
if (err instanceof TypeError) {
throw new Error(
'Error connecting to Ollama API. Please ensure the base URL is correct and the Ollama server is running.',
);
}
throw err;
}
}
async getModelList(): Promise<ModelList> {
const defaultModels = await this.getDefaultModels();
const configProvider = getConfiguredModelProviderById(this.id)!;
return {
embedding: [
...defaultModels.embedding,
...configProvider.embeddingModels,
],
chat: [...defaultModels.chat, ...configProvider.chatModels],
};
}
async loadChatModel(key: string): Promise<BaseChatModel> {
const modelList = await this.getModelList();
const exists = modelList.chat.find((m) => m.key === key);
if (!exists) {
throw new Error(
'Error Loading Ollama Chat Model. Invalid Model Selected',
);
} }
async loadChatModel(key: string): Promise<BaseChatModel> { return new ChatOllama({
const modelList = await this.getModelList(); temperature: 0.7,
model: key,
baseUrl: this.config.baseURL,
});
}
const exists = modelList.chat.find((m) => m.key === key); async loadEmbeddingModel(key: string): Promise<Embeddings> {
const modelList = await this.getModelList();
const exists = modelList.embedding.find((m) => m.key === key);
if (!exists) { if (!exists) {
throw new Error( throw new Error(
'Error Loading Ollama Chat Model. Invalid Model Selected', 'Error Loading Ollama Embedding Model. Invalid Model Selected.',
); );
}
return new ChatOllama({
temperature: 0.7,
model: key,
baseUrl: this.config.baseURL,
});
} }
async loadEmbeddingModel(key: string): Promise<Embeddings> { return new OllamaEmbeddings({
const modelList = await this.getModelList(); model: key,
const exists = modelList.embedding.find((m) => m.key === key); baseUrl: this.config.baseURL,
});
}
if (!exists) { static parseAndValidate(raw: any): OllamaConfig {
throw new Error( if (!raw || typeof raw !== 'object')
'Error Loading Ollama Embedding Model. Invalid Model Selected.', throw new Error('Invalid config provided. Expected object');
); if (!raw.baseURL)
} throw new Error('Invalid config provided. Base URL must be provided');
return new OllamaEmbeddings({ return {
model: key, baseURL: String(raw.baseURL),
baseUrl: this.config.baseURL, };
}); }
}
static parseAndValidate(raw: any): OllamaConfig { static getProviderConfigFields(): UIConfigField[] {
if (!raw || typeof raw !== 'object') return providerConfigFields;
throw new Error('Invalid config provided. Expected object'); }
if (!raw.baseURL)
throw new Error(
'Invalid config provided. Base URL must be provided',
);
return { static getProviderMetadata(): ProviderMetadata {
baseURL: String(raw.baseURL), return {
}; key: 'ollama',
} name: 'Ollama',
};
static getProviderConfigFields(): UIConfigField[] { }
return providerConfigFields;
}
static getProviderMetadata(): ProviderMetadata {
return {
key: 'ollama',
name: 'Ollama',
};
}
} }
export default OllamaProvider; export default OllamaProvider;

View File

@@ -67,7 +67,6 @@ class ModelRegistry {
chatModels: m.chat, chatModels: m.chat,
embeddingModels: m.embedding, embeddingModels: m.embedding,
}); });
}), }),
); );