import type { ModelProvider, } from './declarations' import { RiAlertFill, RiBrainLine, } from '@remixicon/react' import { useDebounce } from 'ahooks' import { useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { IS_CLOUD_EDITION } from '@/config' import { useAppContext } from '@/context/app-context' import { useGlobalPublicStore } from '@/context/global-public-context' import { useProviderContext } from '@/context/provider-context' import { cn } from '@/utils/classnames' import { CustomConfigurationStatusEnum, ModelTypeEnum, } from './declarations' import { useDefaultModel, } from './hooks' import InstallFromMarketplace from './install-from-marketplace' import ProviderAddedCard from './provider-added-card' import QuotaPanel from './provider-added-card/quota-panel' import SystemModelSelector from './system-model-selector' type Props = { searchText: string } const FixedModelProvider = ['langgenius/openai/openai', 'langgenius/anthropic/anthropic'] const ModelProviderPage = ({ searchText }: Props) => { const debouncedSearchText = useDebounce(searchText, { wait: 500 }) const { t } = useTranslation() const { mutateCurrentWorkspace, isValidatingCurrentWorkspace } = useAppContext() const { data: textGenerationDefaultModel, isLoading: isTextGenerationDefaultModelLoading } = useDefaultModel(ModelTypeEnum.textGeneration) const { data: embeddingsDefaultModel, isLoading: isEmbeddingsDefaultModelLoading } = useDefaultModel(ModelTypeEnum.textEmbedding) const { data: rerankDefaultModel, isLoading: isRerankDefaultModelLoading } = useDefaultModel(ModelTypeEnum.rerank) const { data: speech2textDefaultModel, isLoading: isSpeech2textDefaultModelLoading } = useDefaultModel(ModelTypeEnum.speech2text) const { data: ttsDefaultModel, isLoading: isTTSDefaultModelLoading } = useDefaultModel(ModelTypeEnum.tts) const { modelProviders: providers } = useProviderContext() const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures) const isDefaultModelLoading = isTextGenerationDefaultModelLoading || isEmbeddingsDefaultModelLoading || isRerankDefaultModelLoading || isSpeech2textDefaultModelLoading || isTTSDefaultModelLoading const defaultModelNotConfigured = !isDefaultModelLoading && !textGenerationDefaultModel && !embeddingsDefaultModel && !speech2textDefaultModel && !rerankDefaultModel && !ttsDefaultModel const [configuredProviders, notConfiguredProviders] = useMemo(() => { const configuredProviders: ModelProvider[] = [] const notConfiguredProviders: ModelProvider[] = [] providers.forEach((provider) => { if ( provider.custom_configuration.status === CustomConfigurationStatusEnum.active || ( provider.system_configuration.enabled === true && provider.system_configuration.quota_configurations.find(item => item.quota_type === provider.system_configuration.current_quota_type) ) ) { configuredProviders.push(provider) } else { notConfiguredProviders.push(provider) } }) configuredProviders.sort((a, b) => { if (FixedModelProvider.includes(a.provider) && FixedModelProvider.includes(b.provider)) return FixedModelProvider.indexOf(a.provider) - FixedModelProvider.indexOf(b.provider) > 0 ? 1 : -1 else if (FixedModelProvider.includes(a.provider)) return -1 else if (FixedModelProvider.includes(b.provider)) return 1 return 0 }) return [configuredProviders, notConfiguredProviders] }, [providers]) const [filteredConfiguredProviders, filteredNotConfiguredProviders] = useMemo(() => { const filteredConfiguredProviders = configuredProviders.filter( provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase()) || Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())), ) const filteredNotConfiguredProviders = notConfiguredProviders.filter( provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase()) || Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())), ) return [filteredConfiguredProviders, filteredNotConfiguredProviders] }, [configuredProviders, debouncedSearchText, notConfiguredProviders]) useEffect(() => { mutateCurrentWorkspace() }, [mutateCurrentWorkspace]) return (
{t('modelProvider.models', { ns: 'common' })}
{defaultModelNotConfigured &&
} {defaultModelNotConfigured && (
{t('modelProvider.notConfigured', { ns: 'common' })}
)}
{IS_CLOUD_EDITION && } {!filteredConfiguredProviders?.length && (
{t('modelProvider.emptyProviderTitle', { ns: 'common' })}
{t('modelProvider.emptyProviderTip', { ns: 'common' })}
)} {!!filteredConfiguredProviders?.length && (
{filteredConfiguredProviders?.map(provider => ( ))}
)} {!!filteredNotConfiguredProviders?.length && ( <>
{t('modelProvider.toBeConfigured', { ns: 'common' })}
{filteredNotConfiguredProviders?.map(provider => ( ))}
)} { enable_marketplace && ( ) }
) } export default ModelProviderPage