diff --git a/src/common/stores/llms/llms.hooks.ts b/src/common/stores/llms/llms.hooks.ts index b9f4eb231..e86b06ccc 100644 --- a/src/common/stores/llms/llms.hooks.ts +++ b/src/common/stores/llms/llms.hooks.ts @@ -1,7 +1,8 @@ import { useShallow } from 'zustand/react/shallow'; -import { DLLM, DLLMId, isLLMVisible } from './llms.types'; import type { DModelsServiceId } from './llms.service.types'; +import { DLLM, DLLMId, isLLMVisible } from './llms.types'; +import { isLLMChatFree_cached } from './llms.pricing'; import { useModelsStore } from './store-llms'; @@ -59,6 +60,14 @@ export function useHasLLMs(): boolean { return useModelsStore(state => !!state.llms.length); } +export function useHasFreeLLMs(serviceId: false | DModelsServiceId | null): boolean { + return useModelsStore(state => { + if (serviceId === null) return false; // explicitly no service, so no free llms + const llms = !serviceId ? state.llms : state.llms.filter(llm => llm.sId === serviceId); + return llms.some(isLLMChatFree_cached); + }); +} + export function useModelsServices() { return useModelsStore(useShallow(state => ({ modelsServices: state.sources, diff --git a/src/modules/llms/models-modal/ModelsConfiguratorModal.tsx b/src/modules/llms/models-modal/ModelsConfiguratorModal.tsx index 7068ba1b4..bb6503d0c 100644 --- a/src/modules/llms/models-modal/ModelsConfiguratorModal.tsx +++ b/src/modules/llms/models-modal/ModelsConfiguratorModal.tsx @@ -16,11 +16,13 @@ import type { DModelsService, DModelsServiceId } from '~/common/stores/llms/llms import { AppBreadcrumbs } from '~/common/components/AppBreadcrumbs'; import { ConfirmationModal } from '~/common/components/modals/ConfirmationModal'; import { GoodModal } from '~/common/components/modals/GoodModal'; -import { llmsStoreActions } from '~/common/stores/llms/store-llms'; +import { PhGift } from '~/common/components/icons/phosphor/PhGift'; +import { isLLMChatFree_cached } from '~/common/stores/llms/llms.pricing'; +import { llmsStoreActions, llmsStoreState } from '~/common/stores/llms/store-llms'; import { optimaActions } from '~/common/layout/optima/useOptima'; import { themeZIndexOverMobileDrawer } from '~/common/app.theme'; import { useAllServicesDCStatus } from '~/common/stores/llms/hooks/useModelServiceClientSideFetch'; -import { useHasLLMs } from '~/common/stores/llms/llms.hooks'; +import { useHasFreeLLMs, useHasLLMs } from '~/common/stores/llms/llms.hooks'; import { useIsMobile } from '~/common/components/useMatchMedia'; import { useModelsZeroState } from '~/common/stores/llms/hooks/useModelsZeroState'; import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents'; @@ -76,7 +78,7 @@ export function ModelsConfiguratorModal(props: { // active service with fallback to the last added service - const activeServiceId = confServiceId + const activeServiceId: string | null = confServiceId ?? modelsServices[modelsServices.length - 1]?.id ?? null; @@ -86,6 +88,7 @@ export function ModelsConfiguratorModal(props: { const hasAnyServices = !!modelsServices.length; const isTabWizard = tab === 'wizard'; const isTabSetup = tab === 'setup'; + const activeHasFreeLLMs = useHasFreeLLMs(activeServiceId); // const isTabDefaults = tab === 'defaults'; @@ -166,6 +169,20 @@ export function ModelsConfiguratorModal(props: { llmsStoreActions().setServiceModelsHidden(activeServiceId, false); }, [activeServiceId]); + const handleShowOnlyFree = React.useCallback(() => { + const updates = llmsStoreState().llms + .filter(llm => llm.sId === activeServiceId) + .map(llm => ({ id: llm.id, partial: { userHidden: !isLLMChatFree_cached(llm) } })); + llmsStoreActions().updateLLMs(updates); + }, [activeServiceId]); + + const handleShowOnlyPaid = React.useCallback(() => { + const updates = llmsStoreState().llms + .filter(llm => llm.sId === activeServiceId) + .map(llm => ({ id: llm.id, partial: { userHidden: isLLMChatFree_cached(llm) } })); + llmsStoreActions().updateLLMs(updates); + }, [activeServiceId]); + const handleRemoveClones = React.useCallback(() => { showPromisedOverlay('llms-remove-clones', {}, ({ onResolve, onUserReject }) => Hide All + {activeHasFreeLLMs && } + {activeHasFreeLLMs && + + Only Free + } + {activeHasFreeLLMs && + + Only Paid + } + Reset Default Visibility @@ -308,7 +335,7 @@ export function ModelsConfiguratorModal(props: { ); return undefined; - }, [activeService?.label, dcAllEnabled, dcHasEligible, dcMenuAnchor, dcNoneEnabled, dcStatus.eligible, dcStatus.enabled, handleDisableAllDC, handleEnableAllDC, handleHideAllModels, handleMainMenuOpenChange, handleRefreshModels, handleRemoveClones, handleResetAllParameters, handleResetVisibility, handleShowAllModels, handleShowWizard, hasAnyServices, hasLLMs, isMobile, isRefreshing, isTabSetup, isTabWizard, mainMenuOpen, setShowModelsHidden, setStarredOnTop, showModelsHidden, starredOnTop, visMenuAnchor]); + }, [activeHasFreeLLMs, activeService?.label, dcAllEnabled, dcHasEligible, dcMenuAnchor, dcNoneEnabled, dcStatus.eligible, dcStatus.enabled, handleDisableAllDC, handleEnableAllDC, handleHideAllModels, handleMainMenuOpenChange, handleRefreshModels, handleRemoveClones, handleResetAllParameters, handleResetVisibility, handleShowAllModels, handleShowOnlyFree, handleShowOnlyPaid, handleShowWizard, hasAnyServices, hasLLMs, isMobile, isRefreshing, isTabSetup, isTabWizard, mainMenuOpen, setShowModelsHidden, setStarredOnTop, showModelsHidden, starredOnTop, visMenuAnchor]); // custom done button for wizard mode (combines start and close buttons) @@ -359,7 +386,7 @@ export function ModelsConfiguratorModal(props: { setShowExplainer(true); }, []); - const handleDismissExplainer = React.useCallback((event: React.BaseSyntheticEvent, reason: 'backdropClick' | 'escapeKeyDown' | 'closeClick') => { + const handleDismissExplainer = React.useCallback((_event: React.BaseSyntheticEvent, reason: 'backdropClick' | 'escapeKeyDown' | 'closeClick') => { // hide for both the 'x' button and close setShowExplainer(false); diff --git a/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx b/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx index f8c7426e9..a9bb0c4ef 100644 --- a/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx +++ b/src/modules/llms/vendors/openrouter/OpenRouterServiceSetup.tsx @@ -2,13 +2,10 @@ import * as React from 'react'; import { Box, Button, Typography } from '@mui/joy'; import LaunchIcon from '@mui/icons-material/Launch'; -import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; -import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; import type { DModelsServiceId } from '~/common/stores/llms/llms.service.types'; import { AlreadySet } from '~/common/components/AlreadySet'; import { FormInputKey } from '~/common/components/forms/FormInputKey'; -import { isLLMChatFree_cached } from '~/common/stores/llms/llms.pricing'; import { InlineError } from '~/common/components/InlineError'; import { Link } from '~/common/components/Link'; import { PhGift } from '~/common/components/icons/phosphor/PhGift'; @@ -16,7 +13,6 @@ import { FormSwitchControl } from '~/common/components/forms/FormSwitchControl'; import { SetupFormClientSideToggle } from '~/common/components/forms/SetupFormClientSideToggle'; import { SetupFormRefetchButton } from '~/common/components/forms/SetupFormRefetchButton'; import { getCallbackUrl } from '~/common/app.routes'; -import { llmsStoreActions, llmsStoreState } from '~/common/stores/llms/store-llms'; import { useToggleableBoolean } from '~/common/util/hooks/useToggleableBoolean'; import { ApproximateCosts } from '../ApproximateCosts'; @@ -29,7 +25,7 @@ import { isValidOpenRouterKey, ModelVendorOpenRouter } from './openrouter.vendor export function OpenRouterServiceSetup(props: { serviceId: DModelsServiceId }) { // external state - const { service, serviceAccess, serviceHasCloudTenantConfig, serviceHasLLMs, serviceHasVisibleLLMs, updateSettings } = + const { service, serviceAccess, serviceHasCloudTenantConfig, serviceHasLLMs, updateSettings } = useServiceSetup(props.serviceId, ModelVendorOpenRouter); // derived state @@ -58,27 +54,6 @@ export function OpenRouterServiceSetup(props: { serviceId: DModelsServiceId }) { // ...bye / see you soon at the callback location... }; - const handleHIdeNonFreeLLMs = () => { - const { llms } = llmsStoreState(); - const { updateLLMs } = llmsStoreActions(); - const updates = llms - .filter(llm => llm.sId === props.serviceId) - .map(llm => { - const isFree = isLLMChatFree_cached(llm); - return { id: llm.id, partial: { userHidden: !isFree } }; - }); - updateLLMs(updates); - }; - - const handleSetVisibilityAll = React.useCallback((visible: boolean) => { - const { llms } = llmsStoreState(); - const { updateLLMs } = llmsStoreActions(); - const updates = llms - .filter(llm => llm.sId === props.serviceId) - .map(llm => ({ id: llm.id, partial: { userHidden: !visible } })); - updateLLMs(updates); - }, [props.serviceId]); - return <> @@ -148,23 +123,6 @@ export function OpenRouterServiceSetup(props: { serviceId: DModelsServiceId }) { - - - - } /> {isError && } diff --git a/src/modules/llms/vendors/useServiceSetup.ts b/src/modules/llms/vendors/useServiceSetup.ts index 3e738ee09..154050c4a 100644 --- a/src/modules/llms/vendors/useServiceSetup.ts +++ b/src/modules/llms/vendors/useServiceSetup.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import { useShallow } from 'zustand/react/shallow'; import type { DModelsService, DModelsServiceId } from '~/common/stores/llms/llms.service.types'; -import { DLLM, isLLMVisible } from '~/common/stores/llms/llms.types'; +import type { DLLM } from '~/common/stores/llms/llms.types'; import { useShallowStabilizer } from '~/common/util/hooks/useShallowObject'; import { useModelsStore } from '~/common/stores/llms/store-llms'; @@ -21,7 +21,6 @@ export function useServiceSetup(servic serviceHasCloudTenantConfig: boolean; serviceHasLLMs: boolean; - serviceHasVisibleLLMs: boolean; serviceSetupValid: boolean; updateLabel: (label: string, allowEmpty?: boolean) => void; @@ -50,7 +49,6 @@ export function useServiceSetup(servic serviceHasCloudTenantConfig: vendorHasBackendCap(vendor), serviceHasLLMs: !!serviceLLms.length, - serviceHasVisibleLLMs: serviceLLms.some(isLLMVisible), serviceSetupValid: serviceSetupValid, partialSettings: service?.setup ?? null, // NOTE: do not use - prefer ACCESS; only used in 1 edge case now