Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui, worker): commercial license indicator for FLUX dev #6881

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions invokeai/frontend/web/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,12 @@
"paragraphs": [
"Structure controls how closely the output image will keep to the layout of the original. Low structure allows major changes, while high structure strictly maintains the original composition and layout."
]
},
"fluxDev": {
"heading": "Non-Commercial License",
"paragraphs": [
"FLUX.1 [dev] models are licensed under the FLUX.1 [dev] non-commercial license. To use this model type for commercial purposes in Invoke, we’ve partnered with Black Forest Labs to offer commercial licensing in the Professional Edition, available on all our subscription plans. Contact us to learn more."
]
}
},
"unifiedCanvas": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { OPEN_DELAY, POPOVER_DATA, POPPER_MODIFIERS } from './constants';
type Props = {
feature: Feature;
inPortal?: boolean;
hideDisable?: boolean;
children: ReactElement;
};

Expand All @@ -37,48 +38,51 @@ const selectShouldEnableInformationalPopovers = createSelector(
(system) => system.shouldEnableInformationalPopovers
);

export const InformationalPopover = memo(({ feature, children, inPortal = true, ...rest }: Props) => {
const shouldEnableInformationalPopovers = useAppSelector(selectShouldEnableInformationalPopovers);
export const InformationalPopover = memo(
({ feature, children, inPortal = true, hideDisable = false, ...rest }: Props) => {
const shouldEnableInformationalPopovers = useAppSelector(selectShouldEnableInformationalPopovers);

const data = useMemo(() => POPOVER_DATA[feature], [feature]);
const data = useMemo(() => POPOVER_DATA[feature], [feature]);

const popoverProps = useMemo(() => merge(omit(data, ['image', 'href', 'buttonLabel']), rest), [data, rest]);
const popoverProps = useMemo(() => merge(omit(data, ['image', 'href', 'buttonLabel']), rest), [data, rest]);

if (!shouldEnableInformationalPopovers) {
return children;
}
if (!hideDisable && !shouldEnableInformationalPopovers) {
return children;
}

return (
<Popover
isLazy
closeOnBlur={false}
trigger="hover"
variant="informational"
openDelay={OPEN_DELAY}
modifiers={POPPER_MODIFIERS}
placement="top"
{...popoverProps}
>
<PopoverTrigger>{children}</PopoverTrigger>
{inPortal ? (
<Portal>
<Content data={data} feature={feature} />
</Portal>
) : (
<Content data={data} feature={feature} />
)}
</Popover>
);
});
return (
<Popover
isLazy
closeOnBlur={false}
trigger="hover"
variant="informational"
openDelay={OPEN_DELAY}
modifiers={POPPER_MODIFIERS}
placement="top"
{...popoverProps}
>
<PopoverTrigger>{children}</PopoverTrigger>
{inPortal ? (
<Portal>
<Content data={data} feature={feature} hideDisable={hideDisable} />
</Portal>
) : (
<Content data={data} feature={feature} hideDisable={hideDisable} />
)}
</Popover>
);
}
);

InformationalPopover.displayName = 'InformationalPopover';

type ContentProps = {
data?: PopoverData;
feature: Feature;
hideDisable: boolean;
};

const Content = ({ data, feature }: ContentProps) => {
const Content = ({ data, feature, hideDisable }: ContentProps) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const heading = useMemo<string | undefined>(() => t(`popovers.${feature}.heading`), [feature, t]);
Expand Down Expand Up @@ -120,14 +124,7 @@ const Content = ({ data, feature }: ContentProps) => {
)}
{data?.image && (
<>
<Image
objectFit="contain"
maxW="60%"
maxH="60%"
backgroundColor="white"
src={data.image}
alt="Optional Image"
/>
<Image objectFit="contain" backgroundColor="white" src={data.image} alt="Optional Image" />
<Divider />
</>
)}
Expand All @@ -137,9 +134,11 @@ const Content = ({ data, feature }: ContentProps) => {

<Divider />
<Flex alignItems="center" justifyContent="space-between" w="full">
<Button onClick={onClickDontShowMeThese} variant="link" size="sm">
{t('common.dontShowMeThese')}
</Button>
{!hideDisable && (
<Button onClick={onClickDontShowMeThese} variant="link" size="sm">
{t('common.dontShowMeThese')}
</Button>
)}
<Spacer />
{data?.href && (
<Button onClick={onClickLearnMore} leftIcon={<PiArrowSquareOutBold />} variant="link" size="sm">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { PopoverProps } from '@invoke-ai/ui-library';

import invokeBflImage from '/assets/images/invoke-bfl.png';

export type Feature =
| 'clipSkip'
| 'hrf'
Expand Down Expand Up @@ -58,7 +60,8 @@ export type Feature =
| 'upscaleModel'
| 'scale'
| 'creativity'
| 'structure';
| 'structure'
| 'fluxDev';

export type PopoverData = PopoverProps & {
image?: string;
Expand Down Expand Up @@ -186,6 +189,10 @@ export const POPOVER_DATA: { [key in Feature]?: PopoverData } = {
seamlessTilingYAxis: {
href: 'https://support.invoke.ai/support/solutions/articles/151000178161-advanced-settings',
},
fluxDev: {
href: 'https://www.invoke.com/get-a-commercial-license-for-flux',
image: invokeBflImage,
},
} as const;

export const OPEN_DELAY = 1000; // in milliseconds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ export const StarterModelsResultItem = memo(({ result, modelList }: Props) => {
type: result.type,
base: result.base,
format: result.format,
variant: result.variant,
},
},
];
if (result.dependencies) {
for (const d of result.dependencies) {
_allSources.push({
source: d.source,
config: { name: d.name, description: d.description, type: d.type, base: d.base, format: d.format },
config: {
name: d.name,
description: d.description,
type: d.type,
base: d.base,
format: d.format,
variant: d.variant,
},
});
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
import { Box, Combobox, FormControl, FormLabel, Tooltip } from '@invoke-ai/ui-library';
import type { ComboboxOption } from '@invoke-ai/ui-library';
import { Box, Combobox, Flex, FormControl, FormLabel, Image, Tooltip } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { GroupBase, SingleValueProps } from 'chakra-react-select';
import { chakraComponents } from 'chakra-react-select';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox';
import { selectModel } from 'features/controlLayers/store/paramsSlice';
import { selectModelKey } from 'features/controlLayers/store/paramsSlice';
import { zModelIdentifierField } from 'features/nodes/types/common';
import { modelSelected } from 'features/parameters/store/actions';
import { selectActiveTab } from 'features/ui/store/uiSelectors';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useMainModels } from 'services/api/hooks/modelsByType';
import type { AnyModelConfig, MainModelConfig } from 'services/api/types';
const commercialLicenseIcon = 'assets/images/commercial-license-icon.svg';

const ParamMainModelSelect = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const activeTabName = useAppSelector(selectActiveTab);
const selectedModel = useAppSelector(selectModel);
const selectedModelKey = useAppSelector(selectModelKey);
const [modelConfigs, { isLoading }] = useMainModels();

const tooltipLabel = useMemo(() => {
if (!modelConfigs.length || !selectedModel) {
return;
const selectedModel = useMemo(() => {
if (!modelConfigs) {
return null;
}
return modelConfigs.find((m) => m.key === selectedModel?.key)?.description;
}, [modelConfigs, selectedModel]);
if (selectedModelKey === null) {
return null;
}
const modelConfig = modelConfigs.find((model) => model.key === selectedModelKey);

if (!modelConfig) {
return null;
}

return modelConfig;
}, [modelConfigs, selectedModelKey]);

const _onChange = useCallback(
(model: MainModelConfig | null) => {
Expand All @@ -46,6 +59,8 @@ const ParamMainModelSelect = () => {
[activeTabName]
);

const shouldShowCommercialLicenseNotice = useMemo(() => selectedModel?.variant === 'dev', [selectedModel]);

const { options, value, onChange, placeholder, noOptionsMessage } = useGroupedModelCombobox({
modelConfigs,
selectedModel,
Expand All @@ -54,23 +69,51 @@ const ParamMainModelSelect = () => {
getIsDisabled,
});

const SingleValue = ({ children, ...props }: SingleValueProps<ComboboxOption, false, GroupBase<ComboboxOption>>) => (
<chakraComponents.SingleValue {...props}>
<Flex gap={2}>
{shouldShowCommercialLicenseNotice && (
<Image src={commercialLicenseIcon} w={6} h={6} minW={6} minH={6} flexShrink={0} />
)}
{children}
</Flex>
</chakraComponents.SingleValue>
);

return (
<FormControl isDisabled={!modelConfigs.length} isInvalid={!value || !modelConfigs.length}>
<InformationalPopover feature="paramModel">
<FormLabel>{t('modelManager.model')}</FormLabel>
</InformationalPopover>
<Tooltip label={tooltipLabel}>
<Box w="full" minW={0}>
<Combobox
value={value}
placeholder={placeholder}
options={options}
onChange={onChange}
noOptionsMessage={noOptionsMessage}
isInvalid={value?.isDisabled}
/>
</Box>
</Tooltip>
{shouldShowCommercialLicenseNotice ? (
<InformationalPopover feature="fluxDev" hideDisable={true}>
<Box w="full" minW={0}>
<Combobox
value={value}
placeholder={placeholder}
options={options}
onChange={onChange}
noOptionsMessage={noOptionsMessage}
isInvalid={value?.isDisabled}
components={{ SingleValue }}
/>
</Box>
</InformationalPopover>
) : (
<Tooltip label={selectedModel?.description}>
<Box w="full" minW={0}>
<Combobox
value={value}
placeholder={placeholder}
options={options}
onChange={onChange}
noOptionsMessage={noOptionsMessage}
isInvalid={value?.isDisabled}
components={{ SingleValue }}
/>
</Box>
</Tooltip>
)}
</FormControl>
);
};
Expand Down
4 changes: 3 additions & 1 deletion invokeai/frontend/web/src/services/api/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12312,7 +12312,7 @@ export type components = {
* @description Variant type.
* @enum {string}
*/
ModelVariantType: "normal" | "inpaint" | "depth";
ModelVariantType: "normal" | "inpaint" | "depth" | "dev" | "schnell";
/**
* ModelsList
* @description Return list of configs.
Expand Down Expand Up @@ -14834,6 +14834,7 @@ export type components = {
* @default false
*/
is_installed?: boolean;
variant?: components["schemas"]["ModelVariantType"] | null;
/** Dependencies */
dependencies?: components["schemas"]["StarterModelWithoutDependencies"][] | null;
};
Expand All @@ -14853,6 +14854,7 @@ export type components = {
* @default false
*/
is_installed?: boolean;
variant?: components["schemas"]["ModelVariantType"] | null;
};
/**
* Step Param Easing
Expand Down
Loading