2024-01-26 20:02:48 +00:00
|
|
|
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
2024-03-09 08:51:15 +00:00
|
|
|
import type { ModelIdentifierField } from 'features/nodes/types/common';
|
2023-12-29 06:38:01 +00:00
|
|
|
import { useCallback, useMemo } from 'react';
|
|
|
|
import { useTranslation } from 'react-i18next';
|
2024-02-20 00:14:08 +00:00
|
|
|
import type { AnyModelConfig } from 'services/api/types';
|
2023-12-29 06:38:01 +00:00
|
|
|
|
2024-02-16 07:56:02 +00:00
|
|
|
type UseModelComboboxArg<T extends AnyModelConfig> = {
|
2024-03-14 12:37:40 +00:00
|
|
|
modelConfigs: T[];
|
2024-03-09 08:51:15 +00:00
|
|
|
selectedModel?: ModelIdentifierField | null;
|
2023-12-29 06:38:01 +00:00
|
|
|
onChange: (value: T | null) => void;
|
|
|
|
getIsDisabled?: (model: T) => boolean;
|
|
|
|
optionsFilter?: (model: T) => boolean;
|
|
|
|
isLoading?: boolean;
|
|
|
|
};
|
|
|
|
|
2024-01-20 00:04:19 +00:00
|
|
|
type UseModelComboboxReturn = {
|
|
|
|
value: ComboboxOption | undefined | null;
|
|
|
|
options: ComboboxOption[];
|
|
|
|
onChange: ComboboxOnChange;
|
2023-12-29 06:38:01 +00:00
|
|
|
placeholder: string;
|
|
|
|
noOptionsMessage: () => string;
|
|
|
|
};
|
|
|
|
|
2024-02-16 11:42:15 +00:00
|
|
|
export const useModelCombobox = <T extends AnyModelConfig>(arg: UseModelComboboxArg<T>): UseModelComboboxReturn => {
|
2023-12-29 06:38:01 +00:00
|
|
|
const { t } = useTranslation();
|
2024-03-14 12:37:40 +00:00
|
|
|
const { modelConfigs, selectedModel, getIsDisabled, onChange, isLoading, optionsFilter = () => true } = arg;
|
2024-01-20 00:04:19 +00:00
|
|
|
const options = useMemo<ComboboxOption[]>(() => {
|
2024-03-14 12:37:40 +00:00
|
|
|
return modelConfigs.filter(optionsFilter).map((model) => ({
|
|
|
|
label: model.name,
|
|
|
|
value: model.key,
|
|
|
|
isDisabled: getIsDisabled ? getIsDisabled(model) : false,
|
|
|
|
}));
|
|
|
|
}, [optionsFilter, getIsDisabled, modelConfigs]);
|
2023-12-29 06:38:01 +00:00
|
|
|
|
|
|
|
const value = useMemo(
|
2024-02-20 00:14:08 +00:00
|
|
|
() => options.find((m) => (selectedModel ? m.value === selectedModel.key : false)),
|
2023-12-29 06:38:01 +00:00
|
|
|
[options, selectedModel]
|
|
|
|
);
|
|
|
|
|
2024-01-20 00:04:19 +00:00
|
|
|
const _onChange = useCallback<ComboboxOnChange>(
|
2023-12-29 06:38:01 +00:00
|
|
|
(v) => {
|
|
|
|
if (!v) {
|
|
|
|
onChange(null);
|
|
|
|
return;
|
|
|
|
}
|
2024-03-14 12:37:40 +00:00
|
|
|
const model = modelConfigs.find((m) => m.key === v.value);
|
2023-12-29 06:38:01 +00:00
|
|
|
if (!model) {
|
|
|
|
onChange(null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
onChange(model);
|
|
|
|
},
|
2024-03-14 12:37:40 +00:00
|
|
|
[modelConfigs, onChange]
|
2023-12-29 06:38:01 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
const placeholder = useMemo(() => {
|
|
|
|
if (isLoading) {
|
|
|
|
return t('common.loading');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.length === 0) {
|
|
|
|
return t('models.noModelsAvailable');
|
|
|
|
}
|
|
|
|
|
|
|
|
return t('models.selectModel');
|
|
|
|
}, [isLoading, options, t]);
|
|
|
|
|
|
|
|
const noOptionsMessage = useCallback(() => t('models.noMatchingModels'), [t]);
|
|
|
|
|
|
|
|
return { options, value, onChange: _onChange, placeholder, noOptionsMessage };
|
|
|
|
};
|