mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Models List: show free only
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 }) =>
|
||||
<ConfirmationModal
|
||||
@@ -298,6 +315,16 @@ export function ModelsConfiguratorModal(props: {
|
||||
<ListItemDecorator><VisibilityOffIcon /></ListItemDecorator>
|
||||
Hide All
|
||||
</MenuItem>
|
||||
{activeHasFreeLLMs && <ListDivider />}
|
||||
{activeHasFreeLLMs && <MenuItem onClick={handleShowOnlyFree}>
|
||||
<ListItemDecorator><PhGift /></ListItemDecorator>
|
||||
Only Free
|
||||
</MenuItem>}
|
||||
{activeHasFreeLLMs && <MenuItem onClick={handleShowOnlyPaid}>
|
||||
<ListItemDecorator />
|
||||
Only Paid
|
||||
</MenuItem>}
|
||||
<ListDivider />
|
||||
<MenuItem onClick={handleResetVisibility}>
|
||||
<ListItemDecorator><RestoreIcon /></ListItemDecorator>
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 <>
|
||||
|
||||
<ApproximateCosts serviceId={service?.id} />
|
||||
@@ -148,23 +123,6 @@ export function OpenRouterServiceSetup(props: { serviceId: DModelsServiceId }) {
|
||||
|
||||
<SetupFormRefetchButton
|
||||
refetch={refetch} disabled={!shallFetchSucceed || isFetching} loading={isFetching} error={isError} advanced={advanced}
|
||||
leftButton={
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
|
||||
<Button
|
||||
color='neutral' variant='outlined' size='sm'
|
||||
onClick={handleHIdeNonFreeLLMs}
|
||||
>
|
||||
Only Free <PhGift sx={{ ml: 1, color: 'success.softColor' }} />
|
||||
</Button>
|
||||
<Button
|
||||
color='neutral' variant='outlined' size='sm'
|
||||
onClick={() => handleSetVisibilityAll(!serviceHasVisibleLLMs)}
|
||||
endDecorator={serviceHasVisibleLLMs ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlinedIcon />}
|
||||
>
|
||||
{serviceHasVisibleLLMs ? 'Hide' : 'Show'} All
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
|
||||
{isError && <InlineError error={error} />}
|
||||
|
||||
+1
-3
@@ -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<TServiceSettings extends object, TAccess>(servic
|
||||
|
||||
serviceHasCloudTenantConfig: boolean;
|
||||
serviceHasLLMs: boolean;
|
||||
serviceHasVisibleLLMs: boolean;
|
||||
serviceSetupValid: boolean;
|
||||
|
||||
updateLabel: (label: string, allowEmpty?: boolean) => void;
|
||||
@@ -50,7 +49,6 @@ export function useServiceSetup<TServiceSettings extends object, TAccess>(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
|
||||
|
||||
Reference in New Issue
Block a user