From bb6a2d66a5b7499873ec0ce4f3cceffba2a37bdb Mon Sep 17 00:00:00 2001 From: Enrico Ros Date: Fri, 12 May 2023 03:24:41 -0700 Subject: [PATCH] Add Vendors to Sources (ok). Configure Sources (bad) --- src/modules/models/AddVendor.tsx | 110 ++++++++++++++++++++++++ src/modules/models/ConfigureSources.tsx | 96 +++++++++++++++++++++ src/modules/models/Modeling.tsx | 12 --- 3 files changed, 206 insertions(+), 12 deletions(-) create mode 100644 src/modules/models/AddVendor.tsx create mode 100644 src/modules/models/ConfigureSources.tsx delete mode 100644 src/modules/models/Modeling.tsx diff --git a/src/modules/models/AddVendor.tsx b/src/modules/models/AddVendor.tsx new file mode 100644 index 000000000..5202f7095 --- /dev/null +++ b/src/modules/models/AddVendor.tsx @@ -0,0 +1,110 @@ +import * as React from 'react'; + +import { Box, Button, Option, Select, Typography } from '@mui/joy'; +import AddIcon from '@mui/icons-material/Add'; +import CloudOutlinedIcon from '@mui/icons-material/CloudOutlined'; +import ComputerIcon from '@mui/icons-material/Computer'; + +import { hideOnMobile } from '@/common/theme'; + +import { DModelSource, DModelSourceId, ModelVendorId } from './store-models'; + + +interface ModelVendorDescription { + id: ModelVendorId; + name: string; + multiple: boolean; + icon: React.ReactNode; +} + +const MODEL_VENDOR_DESCRIPTIONS: ModelVendorDescription[] = [ + { id: 'openai', name: 'OpenAI', multiple: false, icon: }, + { id: 'localai', name: 'LocalAI', multiple: true, icon: }, + { id: 'google_vertex', name: 'Google Vertex', multiple: false, icon: }, + { id: 'azure_openai', name: 'Azure OpenAI', multiple: false, icon: }, + { id: 'anthropic', name: 'Anthropic', multiple: false, icon: }, +]; + +const DEFAULT_MODEL_VENDOR_ID: ModelVendorId = 'openai'; + + +export function AddVendor(props: { llmSources: DModelSource[], onAddSource: (llmSource: DModelSource) => void }) { + // state + const [selectedVendorId, setSelectedVendorId] = React.useState(DEFAULT_MODEL_VENDOR_ID); + + const vendorItems = React.useMemo(() => MODEL_VENDOR_DESCRIPTIONS.map(vendor => { + const existingCount = props.llmSources.filter(source => source.vendorId === vendor.id).length; + const disabled = !vendor.multiple && existingCount >= 1 || existingCount >= 2; + return { + vendor, + disabled, + component: , + existingCount, + }; + }), [props.llmSources]); + + const selectedVendor = vendorItems.find(item => item.vendor.id === selectedVendorId); + + const handleAddSource = () => { + if (!selectedVendor || selectedVendor.disabled) + return; + + // create a unique DModelSourceId + const vendorId = selectedVendor.vendor.id; + let sourceId: DModelSourceId = vendorId; + let suffix = 0; + if (selectedVendor.existingCount > 0) { + suffix += 2; + while (props.llmSources.find(source => source.sourceId === `${sourceId}-${suffix}`)) + suffix++; + sourceId = `${sourceId}-${suffix}`; + } + + // add the new configuration + props.onAddSource({ + sourceId, + label: selectedVendor.vendor.name + (suffix > 0 ? ` #${suffix}` : ''), + vendorId, + }); + }; + + // if there are no configs, add the default one + React.useEffect(() => { + if (!props.llmSources.length) { + const vendorId = DEFAULT_MODEL_VENDOR_ID; + props.onAddSource({ + sourceId: vendorId, + label: MODEL_VENDOR_DESCRIPTIONS.find(vendor => vendor.id === vendorId)?.name || '', + vendorId, + }); + } + }, [props, selectedVendorId]); + + return ( + + + + Source + + + + + + + + ); +} \ No newline at end of file diff --git a/src/modules/models/ConfigureSources.tsx b/src/modules/models/ConfigureSources.tsx new file mode 100644 index 000000000..4bc36e87d --- /dev/null +++ b/src/modules/models/ConfigureSources.tsx @@ -0,0 +1,96 @@ +import * as React from 'react'; + +import { Chip, IconButton, Radio, RadioGroup } from '@mui/joy'; +import CheckIcon from '@mui/icons-material/Check'; +import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; + +import { DModelSource, DModelSourceId } from '@/modules/models/store-models'; +import { LocalAISource } from '@/modules/models/localai/LocalAISource'; +import { OpenAISource } from '@/modules/models/openai/OpenAISource'; + + +export function ConfigureSources(props: { + llmSources: DModelSource[], + selectedSourceId: DModelSourceId | null, + setSelectedSourceId: (sourceId: DModelSourceId | null) => void, + onDeleteSourceId: (sourceId: DModelSourceId) => void, +}) { + + const sourceItems = React.useMemo(() => props.llmSources.map(source => { + const checked = source.sourceId === props.selectedSourceId; + return { + source, + component: ( + + // configured + // ? + // : + } + > + + + ), + }; + }), [props.llmSources, props.selectedSourceId]); + + const selectedSource = sourceItems.find(item => item.source.sourceId === props.selectedSourceId); + + let vendorConfigComponent: React.JSX.Element | null = null; + if (selectedSource) { + switch (selectedSource.source.sourceId) { + case 'openai': + vendorConfigComponent = ; + break; + case 'google_vertex': + break; + case 'anthropic': + break; + case 'localai': + vendorConfigComponent = ; + break; + } + } + + const enableDeleteButton = !!props.setSelectedSourceId && sourceItems.length >= 2; + + return <> + + {/* Configuration Items */} + props.setSelectedSourceId(event.target.value)} + sx={{ display: 'flex', flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', gap: 1 }} + > + {sourceItems.map(item => item.component)} + + {/* Delete Configuration Button */} + props.onDeleteSourceId(props.selectedSourceId!)} + sx={{ ml: 'auto' }} + > + + + + + {/* Selected Item Configuration */} + {vendorConfigComponent} + + ; +} \ No newline at end of file diff --git a/src/modules/models/Modeling.tsx b/src/modules/models/Modeling.tsx deleted file mode 100644 index 9f5ff38f9..000000000 --- a/src/modules/models/Modeling.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Box, Typography } from '@mui/joy'; -import * as React from 'react'; - -export function Modeling() { - return <> - - - Test - - - ; -} \ No newline at end of file