fix literal strings in MM UI

This commit is contained in:
Mary Hipp 2024-02-26 14:40:38 -05:00 committed by Kent Keirsey
parent 49b04f7db8
commit 66f6013436
9 changed files with 90 additions and 63 deletions

View File

@ -692,6 +692,7 @@
"addDiffuserModel": "Add Diffusers", "addDiffuserModel": "Add Diffusers",
"addManually": "Add Manually", "addManually": "Add Manually",
"addModel": "Add Model", "addModel": "Add Model",
"addModels": "Add Models",
"addNew": "Add New", "addNew": "Add New",
"addNewModel": "Add New Model", "addNewModel": "Add New Model",
"addSelected": "Add Selected", "addSelected": "Add Selected",
@ -736,6 +737,7 @@
"descriptionValidationMsg": "Add a description for your model", "descriptionValidationMsg": "Add a description for your model",
"deselectAll": "Deselect All", "deselectAll": "Deselect All",
"diffusersModels": "Diffusers", "diffusersModels": "Diffusers",
"edit": "Edit",
"findModels": "Find Models", "findModels": "Find Models",
"formMessageDiffusersModelLocation": "Diffusers Model Location", "formMessageDiffusersModelLocation": "Diffusers Model Location",
"formMessageDiffusersModelLocationDesc": "Please enter at least one.", "formMessageDiffusersModelLocationDesc": "Please enter at least one.",
@ -744,6 +746,7 @@
"height": "Height", "height": "Height",
"heightValidationMsg": "Default height of your model.", "heightValidationMsg": "Default height of your model.",
"ignoreMismatch": "Ignore Mismatches Between Selected Models", "ignoreMismatch": "Ignore Mismatches Between Selected Models",
"imageEncoderModelId": "Image Encoder Model ID",
"importModels": "Import Models", "importModels": "Import Models",
"importQueue": "Import Queue", "importQueue": "Import Queue",
"inpainting": "v1 Inpainting", "inpainting": "v1 Inpainting",
@ -774,8 +777,11 @@
"modelMergeHeaderHelp1": "You can merge up to three different models to create a blend that suits your needs.", "modelMergeHeaderHelp1": "You can merge up to three different models to create a blend that suits your needs.",
"modelMergeHeaderHelp2": "Only Diffusers are available for merging. If you want to merge a checkpoint model, please convert it to Diffusers first.", "modelMergeHeaderHelp2": "Only Diffusers are available for merging. If you want to merge a checkpoint model, please convert it to Diffusers first.",
"modelMergeInterpAddDifferenceHelp": "In this mode, Model 3 is first subtracted from Model 2. The resulting version is blended with Model 1 with the alpha rate set above.", "modelMergeInterpAddDifferenceHelp": "In this mode, Model 3 is first subtracted from Model 2. The resulting version is blended with Model 1 with the alpha rate set above.",
"modelMetadata": "Model Metadata",
"modelName": "Model Name",
"modelOne": "Model 1", "modelOne": "Model 1",
"modelsFound": "Models Found", "modelsFound": "Models Found",
"modelSettings": "Model Settings",
"modelsMerged": "Models Merged", "modelsMerged": "Models Merged",
"modelsMergeFailed": "Model Merge Failed", "modelsMergeFailed": "Model Merge Failed",
"modelsSynced": "Models Synced", "modelsSynced": "Models Synced",
@ -795,20 +801,24 @@
"notLoaded": "not loaded", "notLoaded": "not loaded",
"oliveModels": "Olives", "oliveModels": "Olives",
"onnxModels": "Onnx", "onnxModels": "Onnx",
"path": "Path",
"pathToCustomConfig": "Path To Custom Config", "pathToCustomConfig": "Path To Custom Config",
"pickModelType": "Pick Model Type", "pickModelType": "Pick Model Type",
"predictionType": "Prediction Type (for Stable Diffusion 2.x Models and occasional Stable Diffusion 1.x Models)", "predictionType": "Prediction Type",
"prune": "Prune", "prune": "Prune",
"pruneTooltip": "Prune finished imports from queue", "pruneTooltip": "Prune finished imports from queue",
"quickAdd": "Quick Add", "quickAdd": "Quick Add",
"removeFromQueue": "Remove From Queue", "removeFromQueue": "Remove From Queue",
"repo_id": "Repo ID", "repo_id": "Repo ID",
"repoIDValidationMsg": "Online repository of your model", "repoIDValidationMsg": "Online repository of your model",
"repoVariant": "Repo Variant",
"safetensorModels": "SafeTensors", "safetensorModels": "SafeTensors",
"sameFolder": "Same folder", "sameFolder": "Same folder",
"scan": "Scan",
"scanFolder": "Scan folder", "scanFolder": "Scan folder",
"scanAgain": "Scan Again", "scanAgain": "Scan Again",
"scanForModels": "Scan For Models", "scanForModels": "Scan For Models",
"scanResults": "Scan Results",
"search": "Search", "search": "Search",
"selectAll": "Select All", "selectAll": "Select All",
"selectAndAdd": "Select and Add Models Listed Below", "selectAndAdd": "Select and Add Models Listed Below",
@ -819,9 +829,11 @@
"showExisting": "Show Existing", "showExisting": "Show Existing",
"sigmoid": "Sigmoid", "sigmoid": "Sigmoid",
"simpleModelDesc": "Provide a path to a local Diffusers model, local checkpoint / safetensors model a HuggingFace Repo ID, or a checkpoint/diffusers model URL.", "simpleModelDesc": "Provide a path to a local Diffusers model, local checkpoint / safetensors model a HuggingFace Repo ID, or a checkpoint/diffusers model URL.",
"source": "Source",
"statusConverting": "Converting", "statusConverting": "Converting",
"syncModels": "Sync Models", "syncModels": "Sync Models",
"syncModelsDesc": "If your models are out of sync with the backend, you can refresh them up using this option. This is generally handy in cases where you add models to the InvokeAI root folder or autoimport directory after the application has booted.", "syncModelsDesc": "If your models are out of sync with the backend, you can refresh them up using this option. This is generally handy in cases where you add models to the InvokeAI root folder or autoimport directory after the application has booted.",
"upcastAttention": "Upcast Attention",
"updateModel": "Update Model", "updateModel": "Update Model",
"useCustomConfig": "Use Custom Config", "useCustomConfig": "Use Custom Config",
"v1": "v1", "v1": "v1",
@ -836,7 +848,8 @@
"variant": "Variant", "variant": "Variant",
"weightedSum": "Weighted Sum", "weightedSum": "Weighted Sum",
"width": "Width", "width": "Width",
"widthValidationMsg": "Default width of your model." "widthValidationMsg": "Default width of your model.",
"ztsnrTraining": "ZTSNR Training"
}, },
"models": { "models": {
"addLora": "Add LoRA", "addLora": "Add LoRA",

View File

@ -20,7 +20,6 @@ import ControlAdapterShouldAutoConfig from './ControlAdapterShouldAutoConfig';
import ControlNetCanvasImageImports from './imports/ControlNetCanvasImageImports'; import ControlNetCanvasImageImports from './imports/ControlNetCanvasImageImports';
import { ParamControlAdapterBeginEnd } from './parameters/ParamControlAdapterBeginEnd'; import { ParamControlAdapterBeginEnd } from './parameters/ParamControlAdapterBeginEnd';
import ParamControlAdapterControlMode from './parameters/ParamControlAdapterControlMode'; import ParamControlAdapterControlMode from './parameters/ParamControlAdapterControlMode';
import ParamControlAdapterModel from './parameters/ParamControlAdapterModel';
import ParamControlAdapterProcessorSelect from './parameters/ParamControlAdapterProcessorSelect'; import ParamControlAdapterProcessorSelect from './parameters/ParamControlAdapterProcessorSelect';
import ParamControlAdapterResizeMode from './parameters/ParamControlAdapterResizeMode'; import ParamControlAdapterResizeMode from './parameters/ParamControlAdapterResizeMode';
import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight'; import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight';
@ -73,7 +72,7 @@ const ControlAdapterConfig = (props: { id: string; number: number }) => {
</Flex> </Flex>
<Flex gap={4} alignItems="center"> <Flex gap={4} alignItems="center">
<Box minW={0} w="full" transitionProperty="common" transitionDuration="0.1s"> <Box minW={0} w="full" transitionProperty="common" transitionDuration="0.1s">
<ParamControlAdapterModel id={id} /> {/* <ParamControlAdapterModel id={id} /> */}
</Box> </Box>
{activeTabName === 'unifiedCanvas' && <ControlNetCanvasImageImports id={id} />} {activeTabName === 'unifiedCanvas' && <ControlNetCanvasImageImports id={id} />}
<IconButton <IconButton

View File

@ -126,7 +126,7 @@ export const AdvancedImport = () => {
<Flex flexDirection="column" gap={4} width="100%" pb={10}> <Flex flexDirection="column" gap={4} width="100%" pb={10}>
<Flex alignItems="flex-end" gap="4"> <Flex alignItems="flex-end" gap="4">
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Model Type</FormLabel> <FormLabel>{t('modelManager.modelType')}</FormLabel>
<ModelTypeSelect<AnyModelConfig> control={control} name="type" /> <ModelTypeSelect<AnyModelConfig> control={control} name="type" />
</FormControl> </FormControl>
<Text px="2" fontSize="xs" textAlign="center"> <Text px="2" fontSize="xs" textAlign="center">
@ -157,17 +157,17 @@ export const AdvancedImport = () => {
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Base Model</FormLabel> <FormLabel>{t('modelManager.baseModel')}</FormLabel>
<BaseModelSelect<AnyModelConfig> control={control} name="base" /> <BaseModelSelect<AnyModelConfig> control={control} name="base" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Format</FormLabel> <FormLabel>{t('common.format')}</FormLabel>
<ModelFormatSelect<AnyModelConfig> control={control} name="format" /> <ModelFormatSelect<AnyModelConfig> control={control} name="format" />
</FormControl> </FormControl>
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1} isInvalid={Boolean(errors.path)}> <FormControl flexDir="column" alignItems="flex-start" gap={1} isInvalid={Boolean(errors.path)}>
<FormLabel>Path</FormLabel> <FormLabel>{t('modelManager.path')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
validate: (value) => value.trim().length > 0 || 'Must provide a path', validate: (value) => value.trim().length > 0 || 'Must provide a path',
@ -181,39 +181,39 @@ export const AdvancedImport = () => {
<Flex gap={4}> <Flex gap={4}>
{watchedModelFormat === 'diffusers' && ( {watchedModelFormat === 'diffusers' && (
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Repo Variant</FormLabel> <FormLabel>{t('modelManager.repoVariant')}</FormLabel>
<RepoVariantSelect<AnyModelConfig> control={control} name="repo_variant" /> <RepoVariantSelect<AnyModelConfig> control={control} name="repo_variant" />
</FormControl> </FormControl>
)} )}
{watchedModelFormat === 'checkpoint' && ( {watchedModelFormat === 'checkpoint' && (
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Config Path</FormLabel> <FormLabel>{t('modelManager.pathToConfig')}</FormLabel>
<Input {...register('config')} /> <Input {...register('config')} />
</FormControl> </FormControl>
)} )}
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Variant</FormLabel> <FormLabel>{t('modelManager.variant')}</FormLabel>
<ModelVariantSelect<AnyModelConfig> control={control} name="variant" /> <ModelVariantSelect<AnyModelConfig> control={control} name="variant" />
</FormControl> </FormControl>
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Prediction Type</FormLabel> <FormLabel>{t('modelManager.predictionType')}</FormLabel>
<PredictionTypeSelect<AnyModelConfig> control={control} name="prediction_type" /> <PredictionTypeSelect<AnyModelConfig> control={control} name="prediction_type" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Upcast Attention</FormLabel> <FormLabel>{t('modelManager.upcastAttention')}</FormLabel>
<BooleanSelect<AnyModelConfig> control={control} name="upcast_attention" /> <BooleanSelect<AnyModelConfig> control={control} name="upcast_attention" />
</FormControl> </FormControl>
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>ZTSNR Training</FormLabel> <FormLabel>{t('modelManager.ztsnrTraining')}</FormLabel>
<BooleanSelect<AnyModelConfig> control={control} name="ztsnr_training" /> <BooleanSelect<AnyModelConfig> control={control} name="ztsnr_training" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>VAE Path</FormLabel> <FormLabel>{t('modelManager.vaeLocation')}</FormLabel>
<Input {...register('vae')} /> <Input {...register('vae')} />
</FormControl> </FormControl>
</Flex> </Flex>
@ -222,7 +222,7 @@ export const AdvancedImport = () => {
{watchedModelType === 'ip_adapter' && ( {watchedModelType === 'ip_adapter' && (
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Image Encoder Model ID</FormLabel> <FormLabel>{t('modelManager.imageEncoderModelId')}</FormLabel>
<Input {...register('image_encoder_model_id')} /> <Input {...register('image_encoder_model_id')} />
</FormControl> </FormControl>
</Flex> </Flex>

View File

@ -1,8 +1,8 @@
import { Divider, Flex, Heading, IconButton, Input, InputGroup, InputRightElement } from '@invoke-ai/ui-library'; import { Divider, Flex, Heading, IconButton, Input, InputGroup, InputRightElement } from '@invoke-ai/ui-library';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { t } from 'i18next';
import type { ChangeEventHandler } from 'react'; import type { ChangeEventHandler } from 'react';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiXBold } from 'react-icons/pi'; import { PiXBold } from 'react-icons/pi';
import type { ScanFolderResponse } from 'services/api/endpoints/models'; import type { ScanFolderResponse } from 'services/api/endpoints/models';
@ -13,6 +13,7 @@ type ScanModelResultsProps = {
}; };
export const ScanModelsResults = ({ results }: ScanModelResultsProps) => { export const ScanModelsResults = ({ results }: ScanModelResultsProps) => {
const { t } = useTranslation();
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const filteredResults = useMemo(() => { const filteredResults = useMemo(() => {
@ -36,7 +37,7 @@ export const ScanModelsResults = ({ results }: ScanModelResultsProps) => {
<Flex flexDir="column" gap={2} mt={4} height="100%"> <Flex flexDir="column" gap={2} mt={4} height="100%">
<Flex justifyContent="space-between" alignItems="center"> <Flex justifyContent="space-between" alignItems="center">
<Heading fontSize="md" as="h4"> <Heading fontSize="md" as="h4">
Scan Results {t('modelManager.scanResults')}
</Heading> </Heading>
<InputGroup maxW="300px" size="xs"> <InputGroup maxW="300px" size="xs">
<Input <Input

View File

@ -1,4 +1,5 @@
import { Box, Flex, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library'; import { Box, Flex, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library';
import { useTranslation } from 'react-i18next';
import { AdvancedImport } from './AddModelPanel/AdvancedImport'; import { AdvancedImport } from './AddModelPanel/AdvancedImport';
import { ImportQueue } from './AddModelPanel/ImportQueue/ImportQueue'; import { ImportQueue } from './AddModelPanel/ImportQueue/ImportQueue';
@ -6,17 +7,18 @@ import { ScanModelsForm } from './AddModelPanel/ScanModels/ScanModelsForm';
import { SimpleImport } from './AddModelPanel/SimpleImport'; import { SimpleImport } from './AddModelPanel/SimpleImport';
export const ImportModels = () => { export const ImportModels = () => {
const { t } = useTranslation();
return ( return (
<Flex layerStyle="first" p={3} borderRadius="base" w="full" h="full" flexDir="column" gap={2}> <Flex layerStyle="first" p={3} borderRadius="base" w="full" h="full" flexDir="column" gap={2}>
<Box w="full" p={2}> <Box w="full" p={2}>
<Heading fontSize="xl">Add Model</Heading> <Heading fontSize="xl">{t('modelManager.addModel')}</Heading>
</Box> </Box>
<Box layerStyle="second" borderRadius="base" w="full" h="50%" overflow="hidden"> <Box layerStyle="second" borderRadius="base" w="full" h="50%" overflow="hidden">
<Tabs variant="collapse" height="100%"> <Tabs variant="collapse" height="100%">
<TabList> <TabList>
<Tab>Simple</Tab> <Tab>{t('common.simple')}</Tab>
<Tab>Advanced</Tab> <Tab>{t('modelManager.advanced')}</Tab>
<Tab>Scan</Tab> <Tab>{t('modelManager.scan')}</Tab>
</TabList> </TabList>
<TabPanels p={3} height="100%"> <TabPanels p={3} height="100%">
<TabPanel> <TabPanel>

View File

@ -3,11 +3,13 @@ import { useAppDispatch } from 'app/store/storeHooks';
import { SyncModelsIconButton } from 'features/modelManagerV2/components/SyncModels/SyncModelsIconButton'; import { SyncModelsIconButton } from 'features/modelManagerV2/components/SyncModels/SyncModelsIconButton';
import { setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice'; import { setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import ModelList from './ModelManagerPanel/ModelList'; import ModelList from './ModelManagerPanel/ModelList';
import { ModelListNavigation } from './ModelManagerPanel/ModelListNavigation'; import { ModelListNavigation } from './ModelManagerPanel/ModelListNavigation';
export const ModelManager = () => { export const ModelManager = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const handleClickAddModel = useCallback(() => { const handleClickAddModel = useCallback(() => {
dispatch(setSelectedModelKey(null)); dispatch(setSelectedModelKey(null));
@ -17,11 +19,11 @@ export const ModelManager = () => {
<Box layerStyle="first" p={3} borderRadius="base" w="50%" h="full"> <Box layerStyle="first" p={3} borderRadius="base" w="50%" h="full">
<Flex w="full" p={3} justifyContent="space-between" alignItems="center"> <Flex w="full" p={3} justifyContent="space-between" alignItems="center">
<Flex gap={2}> <Flex gap={2}>
<Heading fontSize="xl">Model Manager</Heading> <Heading fontSize="xl">{t('common.modelManager')}</Heading>
<SyncModelsIconButton /> <SyncModelsIconButton />
</Flex> </Flex>
<Button colorScheme="invokeYellow" onClick={handleClickAddModel}> <Button colorScheme="invokeYellow" onClick={handleClickAddModel}>
Add Models {t('modelManager.addModels')}
</Button> </Button>
</Flex> </Flex>
<Box layerStyle="second" p={3} borderRadius="base" w="full" h="full"> <Box layerStyle="second" p={3} borderRadius="base" w="full" h="full">

View File

@ -2,6 +2,7 @@ import { Button, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-libr
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setFilteredModelType } from 'features/modelManagerV2/store/modelManagerV2Slice'; import { setFilteredModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { IoFilter } from 'react-icons/io5'; import { IoFilter } from 'react-icons/io5';
export const MODEL_TYPE_LABELS: { [key: string]: string } = { export const MODEL_TYPE_LABELS: { [key: string]: string } = {
@ -17,6 +18,7 @@ export const MODEL_TYPE_LABELS: { [key: string]: string } = {
}; };
export const ModelTypeFilter = () => { export const ModelTypeFilter = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const filteredModelType = useAppSelector((s) => s.modelmanagerV2.filteredModelType); const filteredModelType = useAppSelector((s) => s.modelmanagerV2.filteredModelType);
@ -34,10 +36,10 @@ export const ModelTypeFilter = () => {
return ( return (
<Menu> <Menu>
<MenuButton as={Button} leftIcon={<IoFilter />}> <MenuButton as={Button} leftIcon={<IoFilter />}>
{filteredModelType ? MODEL_TYPE_LABELS[filteredModelType] : 'All Models'} {filteredModelType ? MODEL_TYPE_LABELS[filteredModelType] : t('modelManager.allModels')}
</MenuButton> </MenuButton>
<MenuList> <MenuList>
<MenuItem onClick={clearModelType}>All Models</MenuItem> <MenuItem onClick={clearModelType}>{t('modelManager.allModels')}</MenuItem>
{Object.keys(MODEL_TYPE_LABELS).map((option) => ( {Object.keys(MODEL_TYPE_LABELS).map((option) => (
<MenuItem <MenuItem
key={option} key={option}

View File

@ -143,18 +143,18 @@ export const ModelEdit = () => {
}, [dispatch]); }, [dispatch]);
if (isLoading) { if (isLoading) {
return <Text>Loading</Text>; return <Text>{t('common.loading')}</Text>;
} }
if (!modelData) { if (!modelData) {
return <Text>Something went wrong</Text>; return <Text>{t('common.somethingWentWrong')}</Text>;
} }
return ( return (
<Flex flexDir="column" h="full"> <Flex flexDir="column" h="full">
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<FormControl flexDir="column" alignItems="flex-start" gap={1} isInvalid={Boolean(errors.name)}> <FormControl flexDir="column" alignItems="flex-start" gap={1} isInvalid={Boolean(errors.name)}>
<Flex w="full" justifyContent="space-between" gap={4} alignItems="center"> <Flex w="full" justifyContent="space-between" gap={4} alignItems="center">
<FormLabel hidden={true}>Model Name</FormLabel> <FormLabel hidden={true}>{t('modelManager.modelName')}</FormLabel>
<Input <Input
{...register('name', { {...register('name', {
validate: (value) => value.trim().length > 3 || 'Must be at least 3 characters', validate: (value) => value.trim().length > 3 || 'Must be at least 3 characters',
@ -164,7 +164,7 @@ export const ModelEdit = () => {
<Flex gap={2}> <Flex gap={2}>
<Button size="sm" onClick={handleClickCancel}> <Button size="sm" onClick={handleClickCancel}>
Cancel {t('common.cancel')}
</Button> </Button>
<Button <Button
size="sm" size="sm"
@ -173,7 +173,7 @@ export const ModelEdit = () => {
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={Boolean(Object.keys(errors).length)} isDisabled={Boolean(Object.keys(errors).length)}
> >
Save {t('common.save')}
</Button> </Button>
</Flex> </Flex>
</Flex> </Flex>
@ -183,30 +183,30 @@ export const ModelEdit = () => {
<Flex flexDir="column" gap={3} mt="4"> <Flex flexDir="column" gap={3} mt="4">
<Flex> <Flex>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Description</FormLabel> <FormLabel>{t('modelManager.description')}</FormLabel>
<Textarea fontSize="md" resize="none" {...register('description')} /> <Textarea fontSize="md" resize="none" {...register('description')} />
</FormControl> </FormControl>
</Flex> </Flex>
<Heading as="h3" fontSize="md" mt="4"> <Heading as="h3" fontSize="md" mt="4">
Model Settings {t('modelManager.modelSettings')}
</Heading> </Heading>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Base Model</FormLabel> <FormLabel>{t('modelManager.baseModel')}</FormLabel>
<BaseModelSelect<AnyModelConfig> control={control} name="base" /> <BaseModelSelect<AnyModelConfig> control={control} name="base" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Model Type</FormLabel> <FormLabel>{t('modelManager.modelType')}</FormLabel>
<ModelTypeSelect<AnyModelConfig> control={control} name="type" /> <ModelTypeSelect<AnyModelConfig> control={control} name="type" />
</FormControl> </FormControl>
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Format</FormLabel> <FormLabel>{t('common.format')}</FormLabel>
<ModelFormatSelect<AnyModelConfig> control={control} name="format" /> <ModelFormatSelect<AnyModelConfig> control={control} name="format" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1} isInvalid={Boolean(errors.path)}> <FormControl flexDir="column" alignItems="flex-start" gap={1} isInvalid={Boolean(errors.path)}>
<FormLabel>Path</FormLabel> <FormLabel>{t('modelManager.path')}</FormLabel>
<Input <Input
{...register('path', { {...register('path', {
validate: (value) => value.trim().length > 0 || 'Must provide a path', validate: (value) => value.trim().length > 0 || 'Must provide a path',
@ -220,39 +220,39 @@ export const ModelEdit = () => {
<Flex gap={4}> <Flex gap={4}>
{watchedModelFormat === 'diffusers' && ( {watchedModelFormat === 'diffusers' && (
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Repo Variant</FormLabel> <FormLabel>{t('modelManager.repoVariant')}</FormLabel>
<RepoVariantSelect<AnyModelConfig> control={control} name="repo_variant" /> <RepoVariantSelect<AnyModelConfig> control={control} name="repo_variant" />
</FormControl> </FormControl>
)} )}
{watchedModelFormat === 'checkpoint' && ( {watchedModelFormat === 'checkpoint' && (
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Config Path</FormLabel> <FormLabel>{t('modelManager.pathToConfig')}</FormLabel>
<Input {...register('config')} /> <Input {...register('config')} />
</FormControl> </FormControl>
)} )}
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Variant</FormLabel> <FormLabel>{t('modelManager.variant')}</FormLabel>
<ModelVariantSelect<AnyModelConfig> control={control} name="variant" /> <ModelVariantSelect<AnyModelConfig> control={control} name="variant" />
</FormControl> </FormControl>
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Prediction Type</FormLabel> <FormLabel>{t('modelManager.predictionType')}</FormLabel>
<PredictionTypeSelect<AnyModelConfig> control={control} name="prediction_type" /> <PredictionTypeSelect<AnyModelConfig> control={control} name="prediction_type" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Upcast Attention</FormLabel> <FormLabel>{t('modelManager.upcastAttention')}</FormLabel>
<BooleanSelect<AnyModelConfig> control={control} name="upcast_attention" /> <BooleanSelect<AnyModelConfig> control={control} name="upcast_attention" />
</FormControl> </FormControl>
</Flex> </Flex>
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>ZTSNR Training</FormLabel> <FormLabel>{t('modelManager.ztsnrTraining')}</FormLabel>
<BooleanSelect<AnyModelConfig> control={control} name="ztsnr_training" /> <BooleanSelect<AnyModelConfig> control={control} name="ztsnr_training" />
</FormControl> </FormControl>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>VAE Path</FormLabel> <FormLabel>{t('modelManager.vaeLocation')}</FormLabel>
<Input {...register('vae')} /> <Input {...register('vae')} />
</FormControl> </FormControl>
</Flex> </Flex>
@ -261,7 +261,7 @@ export const ModelEdit = () => {
{watchedModelType === 'ip_adapter' && ( {watchedModelType === 'ip_adapter' && (
<Flex gap={4}> <Flex gap={4}>
<FormControl flexDir="column" alignItems="flex-start" gap={1}> <FormControl flexDir="column" alignItems="flex-start" gap={1}>
<FormLabel>Image Encoder Model ID</FormLabel> <FormLabel>{t('modelManager.imageEncoderModelId')}</FormLabel>
<Input {...register('image_encoder_model_id')} /> <Input {...register('image_encoder_model_id')} />
</FormControl> </FormControl>
</Flex> </Flex>

View File

@ -4,6 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer'; import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice'; import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { IoPencil } from 'react-icons/io5'; import { IoPencil } from 'react-icons/io5';
import { useGetModelConfigQuery, useGetModelMetadataQuery } from 'services/api/endpoints/models'; import { useGetModelConfigQuery, useGetModelMetadataQuery } from 'services/api/endpoints/models';
import type { import type {
@ -21,6 +22,7 @@ import { ModelAttrView } from './ModelAttrView';
import { ModelConvert } from './ModelConvert'; import { ModelConvert } from './ModelConvert';
export const ModelView = () => { export const ModelView = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey); const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
const { data, isLoading } = useGetModelConfigQuery(selectedModelKey ?? skipToken); const { data, isLoading } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
@ -64,11 +66,11 @@ export const ModelView = () => {
}, [dispatch]); }, [dispatch]);
if (isLoading) { if (isLoading) {
return <Text>Loading</Text>; return <Text>{t('common.loading')}</Text>;
} }
if (!modelData) { if (!modelData) {
return <Text>Something went wrong</Text>; return <Text>{t('common.somethingWentWrong')}</Text>;
} }
return ( return (
<Flex flexDir="column" h="full"> <Flex flexDir="column" h="full">
@ -78,11 +80,15 @@ export const ModelView = () => {
{modelData.name} {modelData.name}
</Heading> </Heading>
{modelData.source && <Text variant="subtext">Source: {modelData.source}</Text>} {modelData.source && (
<Text variant="subtext">
{t('modelManager.source')}: {modelData.source}
</Text>
)}
</Flex> </Flex>
<Flex gap={2}> <Flex gap={2}>
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}> <Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
Edit {t('modelManager.edit')}
</Button> </Button>
{modelData.type === 'main' && modelData.format === 'checkpoint' && <ModelConvert model={modelData} />} {modelData.type === 'main' && modelData.format === 'checkpoint' && <ModelConvert model={modelData} />}
</Flex> </Flex>
@ -93,41 +99,43 @@ export const ModelView = () => {
<ModelAttrView label="Description" value={modelData.description} /> <ModelAttrView label="Description" value={modelData.description} />
</Flex> </Flex>
<Heading as="h3" fontSize="md" mt="4"> <Heading as="h3" fontSize="md" mt="4">
Model Settings {t('modelManager.modelSettings')}
</Heading> </Heading>
<Box layerStyle="second" borderRadius="base" p={3}> <Box layerStyle="second" borderRadius="base" p={3}>
<Flex flexDir="column" gap={3}> <Flex flexDir="column" gap={3}>
<Flex gap={2}> <Flex gap={2}>
<ModelAttrView label="Base Model" value={modelData.base} /> <ModelAttrView label={t('modelManager.baseModel')} value={modelData.base} />
<ModelAttrView label="Model Type" value={modelData.type} /> <ModelAttrView label={t('modelManager.modelType')} value={modelData.type} />
</Flex> </Flex>
<Flex gap={2}> <Flex gap={2}>
<ModelAttrView label="Format" value={modelData.format} /> <ModelAttrView label={t('common.format')} value={modelData.format} />
<ModelAttrView label="Path" value={modelData.path} /> <ModelAttrView label={t('modelManager.path')} value={modelData.path} />
</Flex> </Flex>
{modelData.type === 'main' && ( {modelData.type === 'main' && (
<> <>
<Flex gap={2}> <Flex gap={2}>
{modelData.format === 'diffusers' && ( {modelData.format === 'diffusers' && (
<ModelAttrView label="Repo Variant" value={modelData.repo_variant} /> <ModelAttrView label={t('modelManager.repoVariant')} value={modelData.repo_variant} />
)}
{modelData.format === 'checkpoint' && (
<ModelAttrView label={t('modelManager.pathToConfig')} value={modelData.config} />
)} )}
{modelData.format === 'checkpoint' && <ModelAttrView label="Config Path" value={modelData.config} />}
<ModelAttrView label="Variant" value={modelData.variant} /> <ModelAttrView label={t('modelManager.variant')} value={modelData.variant} />
</Flex> </Flex>
<Flex gap={2}> <Flex gap={2}>
<ModelAttrView label="Prediction Type" value={modelData.prediction_type} /> <ModelAttrView label={t('modelManager.predictionType')} value={modelData.prediction_type} />
<ModelAttrView label="Upcast Attention" value={`${modelData.upcast_attention}`} /> <ModelAttrView label={t('modelManager.upcastAttention')} value={`${modelData.upcast_attention}`} />
</Flex> </Flex>
<Flex gap={2}> <Flex gap={2}>
<ModelAttrView label="ZTSNR Training" value={`${modelData.ztsnr_training}`} /> <ModelAttrView label={t('modelManager.ztsnrTraining')} value={`${modelData.ztsnr_training}`} />
<ModelAttrView label="VAE" value={modelData.vae} /> <ModelAttrView label={t('modelManager.vae')} value={modelData.vae} />
</Flex> </Flex>
</> </>
)} )}
{modelData.type === 'ip_adapter' && ( {modelData.type === 'ip_adapter' && (
<Flex gap={2}> <Flex gap={2}>
<ModelAttrView label="Image Encoder Model ID" value={modelData.image_encoder_model_id} /> <ModelAttrView label={t('modelManager.imageEncoderModelId')} value={modelData.image_encoder_model_id} />
</Flex> </Flex>
)} )}
</Flex> </Flex>
@ -137,7 +145,7 @@ export const ModelView = () => {
{metadata && ( {metadata && (
<> <>
<Heading as="h3" fontSize="md" mt="4"> <Heading as="h3" fontSize="md" mt="4">
Model Metadata {t('modelManager.modelMetadata')}
</Heading> </Heading>
<Flex h="full" w="full" p={2}> <Flex h="full" w="full" p={2}>
<DataViewer label="metadata" data={metadata} /> <DataViewer label="metadata" data={metadata} />