import type { FC } from 'react' import type { ModelProvider } from '../declarations' import { useBoolean } from 'ahooks' import * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { AnthropicShortLight, Deepseek, Gemini, Grok, OpenaiSmall, Tongyi } from '@/app/components/base/icons/src/public/llm' import Loading from '@/app/components/base/loading' import Tooltip from '@/app/components/base/tooltip' import InstallFromMarketplace from '@/app/components/plugins/install-plugin/install-from-marketplace' import { useAppContext } from '@/context/app-context' import useTimestamp from '@/hooks/use-timestamp' import { cn } from '@/utils/classnames' import { formatNumber } from '@/utils/format' import { PreferredProviderTypeEnum } from '../declarations' import { useMarketplaceAllPlugins } from '../hooks' import { modelNameMap, ModelProviderQuotaGetPaid } from '../utils' const allProviders = [ { key: ModelProviderQuotaGetPaid.OPENAI, Icon: OpenaiSmall }, { key: ModelProviderQuotaGetPaid.ANTHROPIC, Icon: AnthropicShortLight }, { key: ModelProviderQuotaGetPaid.GEMINI, Icon: Gemini }, { key: ModelProviderQuotaGetPaid.X, Icon: Grok }, { key: ModelProviderQuotaGetPaid.DEEPSEEK, Icon: Deepseek }, { key: ModelProviderQuotaGetPaid.TONGYI, Icon: Tongyi }, ] as const // Map provider key to plugin ID // provider key format: langgenius/provider/model, plugin ID format: langgenius/provider const providerKeyToPluginId: Record = { [ModelProviderQuotaGetPaid.OPENAI]: 'langgenius/openai', [ModelProviderQuotaGetPaid.ANTHROPIC]: 'langgenius/anthropic', [ModelProviderQuotaGetPaid.GEMINI]: 'langgenius/gemini', [ModelProviderQuotaGetPaid.X]: 'langgenius/x', [ModelProviderQuotaGetPaid.DEEPSEEK]: 'langgenius/deepseek', [ModelProviderQuotaGetPaid.TONGYI]: 'langgenius/tongyi', } type QuotaPanelProps = { providers: ModelProvider[] isLoading?: boolean } const QuotaPanel: FC = ({ providers, isLoading = false, }) => { const { t } = useTranslation() const { currentWorkspace } = useAppContext() const credits = Math.max(currentWorkspace.trial_credits - currentWorkspace.trial_credits_used || 0, 0) const providerMap = useMemo(() => new Map( providers.map(p => [p.provider, p.preferred_provider_type]), ), [providers]) const { formatTime } = useTimestamp() const { plugins: allPlugins, } = useMarketplaceAllPlugins(providers, '') const [selectedPlugin, setSelectedPlugin] = useState(null) const [isShowInstallModal, { setTrue: showInstallFromMarketplace, setFalse: hideInstallFromMarketplace, }] = useBoolean(false) const selectedPluginIdRef = useRef(null) const handleIconClick = useCallback((key: string) => { const providerType = providerMap.get(key) if (!providerType && allPlugins) { const pluginId = providerKeyToPluginId[key] const plugin = allPlugins.find(p => p.plugin_id === pluginId) if (plugin) { setSelectedPlugin(plugin) selectedPluginIdRef.current = pluginId showInstallFromMarketplace() } } }, [allPlugins, providerMap, showInstallFromMarketplace]) useEffect(() => { if (isShowInstallModal && selectedPluginIdRef.current) { const isInstalled = providers.some(p => p.provider.startsWith(selectedPluginIdRef.current!)) if (isInstalled) { hideInstallFromMarketplace() selectedPluginIdRef.current = null } } }, [providers, isShowInstallModal, hideInstallFromMarketplace]) if (isLoading) { return (
) } return (
{t('common.modelProvider.quota')}
{formatNumber(credits)} {t('common.modelProvider.credits')} {currentWorkspace.next_credit_reset_date ? ( <> ยท {t('common.modelProvider.resetDate', { date: formatTime(currentWorkspace.next_credit_reset_date, t('appLog.dateFormat') as string), interpolation: { escapeValue: false }, })} ) : null}
{allProviders.map(({ key, Icon }) => { const providerType = providerMap.get(key) const usingQuota = providerType === PreferredProviderTypeEnum.system const getTooltipKey = () => { if (usingQuota) return 'common.modelProvider.card.modelSupported' if (providerType === PreferredProviderTypeEnum.custom) return 'common.modelProvider.card.modelAPI' return 'common.modelProvider.card.modelNotSupported' } return (
handleIconClick(key)} > {!usingQuota && (
)}
) })}
{isShowInstallModal && ( )}
) } export default React.memo(QuotaPanel)