diff --git a/config/examples/train_lora_chroma_24gb.yaml b/config/examples/train_lora_chroma_24gb.yaml index f3110652..807f2bba 100644 --- a/config/examples/train_lora_chroma_24gb.yaml +++ b/config/examples/train_lora_chroma_24gb.yaml @@ -65,7 +65,14 @@ config: # Download the whichever model you prefer from the Chroma repo # https://huggingface.co/lodestones/Chroma/tree/main # point to it here. - name_or_path: "/path/to/chroma/chroma-unlocked-vVERSION.safetensors" + # name_or_path: "/path/to/chroma/chroma-unlocked-vVERSION.safetensors" + + # using lodestones/Chroma will automatically use the latest version + name_or_path: "lodestones/Chroma" + + # # You can also select a version of Chroma like so + # name_or_path: "lodestones/Chroma/v28" + arch: "chroma" quantize: true # run 8bit mixed precision sample: diff --git a/extensions_built_in/diffusion_models/chroma/chroma_model.py b/extensions_built_in/diffusion_models/chroma/chroma_model.py index 35be1ac5..0072e2e5 100644 --- a/extensions_built_in/diffusion_models/chroma/chroma_model.py +++ b/extensions_built_in/diffusion_models/chroma/chroma_model.py @@ -22,6 +22,7 @@ import torch.nn.functional as F from .src.model import Chroma, chroma_params from safetensors.torch import load_file, save_file from toolkit.metadata import get_meta_for_safetensors +import huggingface_hub if TYPE_CHECKING: from toolkit.data_transfer_object.data_loader import DataLoaderBatchDTO @@ -100,7 +101,44 @@ class ChromaModel(BaseModel): # will be updated if we detect a existing checkpoint in training folder model_path = self.model_config.name_or_path - extras_path = 'black-forest-labs/FLUX.1-schnell' + if model_path == "lodestones/Chroma": + print("Looking for latest Chroma checkpoint") + # get the latest checkpoint + files_list = huggingface_hub.list_repo_files(model_path) + print(files_list) + latest_version = 28 # current latest version at time of writing + while True: + if f"chroma-unlocked-v{latest_version}.safetensors" not in files_list: + latest_version -= 1 + break + else: + latest_version += 1 + print(f"Using latest Chroma version: v{latest_version}") + + # make sure we have it + model_path = huggingface_hub.hf_hub_download( + repo_id=model_path, + filename=f"chroma-unlocked-v{latest_version}.safetensors", + ) + elif model_path.startswith("lodestones/Chroma/v"): + # get the version number + version = model_path.split("/")[-1].split("v")[-1] + print(f"Using Chroma version: v{version}") + # make sure we have it + model_path = huggingface_hub.hf_hub_download( + repo_id='lodestones/Chroma', + filename=f"chroma-unlocked-v{version}.safetensors", + ) + else: + # check if the model path is a local file + if os.path.exists(model_path): + print(f"Using local model: {model_path}") + else: + raise ValueError(f"Model path {model_path} does not exist") + + # extras_path = 'black-forest-labs/FLUX.1-schnell' + # schnell model is gated now, use flex instead + extras_path = 'ostris/Flex.1-alpha' self.print_and_status_update("Loading transformer") diff --git a/jobs/process/TrainSliderProcess.py b/jobs/process/TrainSliderProcess.py index 38dc40c3..eddc9838 100644 --- a/jobs/process/TrainSliderProcess.py +++ b/jobs/process/TrainSliderProcess.py @@ -363,7 +363,8 @@ class TrainSliderProcess(BaseSDTrainProcess): ] pred_kwargs['down_block_additional_residuals'] = down_block_additional_residuals - denoised_latents = torch.cat([noisy_latents] * self.prompt_chunk_size, dim=0) + # denoised_latents = torch.cat([noisy_latents] * self.prompt_chunk_size, dim=0) + denoised_latents = noisy_latents current_timestep = timesteps else: if self.train_config.noise_scheduler == 'flowmatch': @@ -417,25 +418,24 @@ class TrainSliderProcess(BaseSDTrainProcess): self.network.multiplier = prompt_pair.multiplier_list + prompt_pair.multiplier_list denoised_latents = self.sd.diffuse_some_steps( latents, # pass simple noise latents - train_tools.concat_prompt_embeddings( - prompt_pair.positive_target, # unconditional - prompt_pair.target_class, # target - self.train_config.batch_size, - ), + prompt_pair.target_class, start_timesteps=0, total_timesteps=timesteps_to, guidance_scale=3, + bypass_guidance_embedding=False ) - - - noise_scheduler.set_timesteps(1000) + if hasattr(self.sd.noise_scheduler, 'set_train_timesteps'): + noise_scheduler.set_train_timesteps(1000, device=self.device_torch) + else: + noise_scheduler.set_timesteps(1000) current_timestep_index = int(timesteps_to * 1000 / self.train_config.max_denoising_steps) current_timestep = noise_scheduler.timesteps[current_timestep_index] # split the latents into out prompt pair chunks - denoised_latent_chunks = torch.chunk(denoised_latents, self.prompt_chunk_size, dim=0) - denoised_latent_chunks = [x.detach() for x in denoised_latent_chunks] + # denoised_latent_chunks = torch.chunk(denoised_latents, self.prompt_chunk_size, dim=0) + # denoised_latent_chunks = [x.detach() for x in denoised_latent_chunks] + denoised_latent_chunks = [denoised_latents] # flush() # 4.2GB to 3GB on 512x512 mask_multiplier = torch.ones((denoised_latents.shape[0], 1, 1, 1), device=self.device_torch, dtype=dtype) @@ -467,35 +467,62 @@ class TrainSliderProcess(BaseSDTrainProcess): unmasked_target = None # 4.20 GB RAM for 512x512 - positive_latents = get_noise_pred( - prompt_pair.positive_target, # negative prompt - prompt_pair.negative_target, # positive prompt - 1, - current_timestep, - denoised_latents - ) - positive_latents = positive_latents.detach() - positive_latents.requires_grad = False + # positive_latents = get_noise_pred( + # prompt_pair.positive_target, # negative prompt + # prompt_pair.negative_target, # positive prompt + # 1, + # current_timestep, + # denoised_latents + # ) + # positive_latents = positive_latents.detach() + # positive_latents.requires_grad = False - neutral_latents = get_noise_pred( - prompt_pair.positive_target, # negative prompt - prompt_pair.empty_prompt, # positive prompt (normally neutral - 1, - current_timestep, - denoised_latents - ) - neutral_latents = neutral_latents.detach() - neutral_latents.requires_grad = False + # neutral_latents = get_noise_pred( + # prompt_pair.positive_target, # negative prompt + # prompt_pair.empty_prompt, # positive prompt (normally neutral + # 1, + # current_timestep, + # denoised_latents + # ) + # neutral_latents = neutral_latents.detach() + # neutral_latents.requires_grad = False - unconditional_latents = get_noise_pred( - prompt_pair.positive_target, # negative prompt - prompt_pair.positive_target, # positive prompt - 1, - current_timestep, - denoised_latents + # unconditional_latents = get_noise_pred( + # prompt_pair.positive_target, # negative prompt + # prompt_pair.positive_target, # positive prompt + # 1, + # current_timestep, + # denoised_latents + # ) + # unconditional_latents = unconditional_latents.detach() + # unconditional_latents.requires_grad = False + + # we just need positive target, negative target, and empty prompt to calculate all + # since we are in no grad, we can easily do it in a single step + embeddings = train_tools.concat_prompt_embeddings( + prompt_pair.positive_target, + prompt_pair.empty_prompt, + 1 ) - unconditional_latents = unconditional_latents.detach() - unconditional_latents.requires_grad = False + embeddings = train_tools.concat_prompt_embeddings( + embeddings, + prompt_pair.negative_target, + 1 + ) + all_pred = self.sd.predict_noise( + latents=torch.cat([denoised_latents] * 3, dim=0), + text_embeddings=embeddings, + timestep=torch.cat([current_timestep] * 3, dim=0), + ) + all_pred = all_pred.detach() + all_pred.requires_grad = False + positive_pred, neutral_pred, unconditional_pred = torch.chunk(all_pred, 3, dim=0) + + # doing them backward here as it was originally for erasing + positive_latents = unconditional_pred + neutral_latents = neutral_pred + unconditional_latents = positive_pred + denoised_latents = denoised_latents.detach() @@ -505,60 +532,7 @@ class TrainSliderProcess(BaseSDTrainProcess): self.optimizer.zero_grad(set_to_none=True) anchor_loss_float = None - if len(self.anchor_pairs) > 0: - with torch.no_grad(): - # get a random anchor pair - anchor: EncodedAnchor = self.anchor_pairs[ - torch.randint(0, len(self.anchor_pairs), (1,)).item() - ] - anchor.to(self.device_torch, dtype=dtype) - - # first we get the target prediction without network active - anchor_target_noise = get_noise_pred( - anchor.neg_prompt, anchor.prompt, 1, current_timestep, denoised_latents - # ).to("cpu", dtype=torch.float32) - ).requires_grad_(False) - - # to save vram, we will run these through separately while tracking grads - # otherwise it consumes a ton of vram and this isn't our speed bottleneck - anchor_chunks = split_anchors(anchor, self.prompt_chunk_size) - anchor_target_noise_chunks = torch.chunk(anchor_target_noise, self.prompt_chunk_size, dim=0) - assert len(anchor_chunks) == len(denoised_latent_chunks) - - # 4.32 GB RAM for 512x512 - with self.network: - assert self.network.is_active - anchor_float_losses = [] - for anchor_chunk, denoised_latent_chunk, anchor_target_noise_chunk in zip( - anchor_chunks, denoised_latent_chunks, anchor_target_noise_chunks - ): - self.network.multiplier = anchor_chunk.multiplier_list + anchor_chunk.multiplier_list - - anchor_pred_noise = get_noise_pred( - anchor_chunk.neg_prompt, anchor_chunk.prompt, 1, current_timestep, denoised_latent_chunk - ) - # 9.42 GB RAM for 512x512 -> 4.20 GB RAM for 512x512 with new grad_checkpointing - anchor_loss = loss_function( - anchor_target_noise_chunk, - anchor_pred_noise, - ) - anchor_float_losses.append(anchor_loss.item()) - # compute anchor loss gradients - # we will accumulate them later - # this saves a ton of memory doing them separately - anchor_loss.backward() - del anchor_pred_noise - del anchor_target_noise_chunk - del anchor_loss - flush() - - anchor_loss_float = sum(anchor_float_losses) / len(anchor_float_losses) - del anchor_chunks - del anchor_target_noise_chunks - del anchor_target_noise - # move anchor back to cpu - anchor.to("cpu") - + with torch.no_grad(): if self.slider_config.low_ram: prompt_pair_chunks = split_prompt_pairs(prompt_pair.detach(), self.prompt_chunk_size) @@ -607,13 +581,12 @@ class TrainSliderProcess(BaseSDTrainProcess): mask_multiplier_chunks, unmasked_target_chunks ): - self.network.multiplier = prompt_pair_chunk.multiplier_list + prompt_pair_chunk.multiplier_list - target_latents = get_noise_pred( - prompt_pair_chunk.positive_target, - prompt_pair_chunk.target_class, - 1, - current_timestep, - denoised_latent_chunk + self.network.multiplier = prompt_pair_chunk.multiplier_list + + target_latents = self.sd.predict_noise( + latents=denoised_latent_chunk.detach(), + text_embeddings=prompt_pair_chunk.target_class, + timestep=current_timestep, ) guidance_scale = 1.0 diff --git a/toolkit/config_modules.py b/toolkit/config_modules.py index 0f9ef88e..e3f80ae3 100644 --- a/toolkit/config_modules.py +++ b/toolkit/config_modules.py @@ -463,7 +463,7 @@ class TrainConfig: self.blended_blur_noise = kwargs.get('blended_blur_noise', False) -ModelArch = Literal['sd1', 'sd2', 'sd3', 'sdxl', 'pixart', 'pixart_sigma', 'auraflow', 'flux', 'flex2', 'lumina2', 'vega', 'ssd', 'wan21'] +ModelArch = Literal['sd1', 'sd2', 'sd3', 'sdxl', 'pixart', 'pixart_sigma', 'auraflow', 'flux', 'flex1', 'flex2', 'lumina2', 'vega', 'ssd', 'wan21'] class ModelConfig: @@ -553,6 +553,15 @@ class ModelConfig: # kwargs to pass to the model self.model_kwargs = kwargs.get("model_kwargs", {}) + # allow frontend to pass arch with a color like arch:tag + # but remove the tag + if self.arch is not None: + if ':' in self.arch: + self.arch = self.arch.split(':')[0] + + if self.arch == "flex1": + self.arch = "flux" + # handle migrating to new model arch if self.arch is not None: # reverse the arch to the old style diff --git a/ui/package-lock.json b/ui/package-lock.json index 2ff2e530..f20ef7a4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -22,6 +22,7 @@ "react-dropzone": "^14.3.5", "react-global-hooks": "^1.3.5", "react-icons": "^5.5.0", + "react-select": "^5.10.1", "sqlite3": "^5.1.7", "yaml": "^2.7.0" }, @@ -48,6 +49,126 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "dependencies": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", @@ -57,6 +178,109 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, "node_modules/@floating-ui/core": { "version": "1.6.9", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", @@ -493,7 +717,6 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -507,7 +730,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -516,7 +738,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -524,14 +745,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -958,11 +1177,15 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, "node_modules/@types/react": { "version": "19.0.10", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", - "dev": true, "dependencies": { "csstype": "^3.0.2" } @@ -976,6 +1199,14 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1117,6 +1348,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1345,6 +1590,14 @@ "node": ">= 0.4" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -1539,6 +1792,34 @@ "license": "ISC", "optional": true }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1568,15 +1849,13 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", - "optional": true, "dependencies": { "ms": "^2.1.3" }, @@ -1648,6 +1927,15 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1709,6 +1997,19 @@ "license": "MIT", "optional": true }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -1750,6 +2051,17 @@ "node": ">= 0.4" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -1825,6 +2137,11 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -2078,6 +2395,14 @@ "node": ">=10.13.0" } }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2139,6 +2464,14 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -2218,6 +2551,21 @@ ], "license": "BSD-3-Clause" }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2305,7 +2653,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "dependencies": { "hasown": "^2.0.2" }, @@ -2404,6 +2751,22 @@ "license": "MIT", "optional": true }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -2419,8 +2782,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -2510,6 +2872,11 @@ "node": ">= 0.4" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2784,8 +3151,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", @@ -3101,6 +3467,34 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3123,8 +3517,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -3142,6 +3535,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -3533,6 +3934,41 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-select": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.1.tgz", + "integrity": "sha512-roPEZUL4aRZDx6DcsD+ZNreVl+fM8VsKn0Wtex1v4IazH60ILp5xhdlp464IsEAlJdXeD+BhDAFsBVMfvLQueA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3572,7 +4008,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", @@ -3588,6 +4023,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -3911,6 +4354,14 @@ "node": ">= 10" } }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4125,6 +4576,11 @@ } } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -4151,7 +4607,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -4356,6 +4811,19 @@ "imurmurhash": "^0.1.4" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", + "integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/ui/package.json b/ui/package.json index 6775b5ba..43e0d861 100644 --- a/ui/package.json +++ b/ui/package.json @@ -26,6 +26,7 @@ "react-dropzone": "^14.3.5", "react-global-hooks": "^1.3.5", "react-icons": "^5.5.0", + "react-select": "^5.10.1", "sqlite3": "^5.1.7", "yaml": "^2.7.0" }, diff --git a/ui/src/app/globals.css b/ui/src/app/globals.css index 6b717ad3..890dc5bc 100644 --- a/ui/src/app/globals.css +++ b/ui/src/app/globals.css @@ -19,3 +19,54 @@ body { background: var(--background); font-family: Arial, Helvetica, sans-serif; } + +@layer components { + /* control */ + .aitk-react-select-container .aitk-react-select__control { + @apply flex w-full h-8 min-h-0 px-0 text-sm bg-gray-800 border border-gray-700 rounded-sm hover:border-gray-600 items-center; + } + + /* selected label */ + .aitk-react-select-container .aitk-react-select__single-value { + @apply flex-1 min-w-0 truncate text-sm text-neutral-200; + } + + /* invisible input (keeps focus & typing, never wraps) */ + .aitk-react-select-container .aitk-react-select__input-container { + @apply text-neutral-200; + } + + /* focus */ + .aitk-react-select-container .aitk-react-select__control--is-focused { + @apply ring-2 ring-gray-600 border-transparent hover:border-transparent shadow-none; + } + + /* menu */ + .aitk-react-select-container .aitk-react-select__menu { + @apply bg-gray-800 border border-gray-700; + } + + /* options */ + .aitk-react-select-container .aitk-react-select__option { + @apply text-sm text-neutral-200 bg-gray-800 hover:bg-gray-700; + } + + /* indicator separator */ + .aitk-react-select-container .aitk-react-select__indicator-separator { + @apply bg-gray-600; + } + + /* indicators */ + .aitk-react-select-container .aitk-react-select__indicators, + .aitk-react-select-container .aitk-react-select__indicator { + @apply py-0 flex items-center; + } + + /* placeholder */ + .aitk-react-select-container .aitk-react-select__placeholder { + @apply text-sm text-neutral-200; + } +} + + + diff --git a/ui/src/app/jobs/new/SimpleJob.tsx b/ui/src/app/jobs/new/SimpleJob.tsx index 84d98330..bb422e43 100644 --- a/ui/src/app/jobs/new/SimpleJob.tsx +++ b/ui/src/app/jobs/new/SimpleJob.tsx @@ -69,46 +69,6 @@ export default function SimpleJob({ {/* Model Configuration Section */} - { - // see if model changed - const currentModel = options.model.find( - model => model.name_or_path === jobConfig.config.process[0].model.name_or_path, - ); - if (!currentModel || currentModel.name_or_path === value) { - // model has not changed - return; - } - // revert defaults from previous model - for (const key in currentModel.defaults) { - setJobConfig(currentModel.defaults[key][1], key); - } - // set new model - setJobConfig(value, 'config.process[0].model.name_or_path'); - // update the defaults when a model is selected - const model = options.model.find(model => model.name_or_path === value); - if (model?.defaults) { - for (const key in model.defaults) { - setJobConfig(model.defaults[key][0], key); - } - } - }} - options={ - options.model - .map(model => { - if (model.dev_only && !isDev) { - return null; - } - return { - value: model.name_or_path, - label: model.name_or_path, - }; - }) - .filter(x => x) as { value: string; label: string }[] - } - /> model.name === value); + if (newArch?.defaults) { + for (const key in newArch.defaults) { + setJobConfig(newArch.defaults[key][0], key); + } + } // set new model setJobConfig(value, 'config.process[0].model.arch'); }} @@ -131,6 +103,18 @@ export default function SimpleJob({ .filter(x => x) as { value: string; label: string }[] } /> + { + if (value?.trim() === '') { + value = null; + } + setJobConfig(value, 'config.process[0].model.name_or_path'); + }} + placeholder="" + required + />
{ @@ -22,15 +120,15 @@ export const isVideoModelFromArch = (arch: string) => { const defaultModelArch = 'flux'; -export const options = { +export const options: Option = { model: [ { name_or_path: 'ostris/Flex.1-alpha', + arch: 'flex1', defaults: { // default updates when [selected, unselected] in the UI 'config.process[0].model.quantize': [true, false], 'config.process[0].model.quantize_te': [true, false], - 'config.process[0].model.arch': ['flux', defaultModelArch], 'config.process[0].train.bypass_guidance_embedding': [true, false], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], @@ -38,22 +136,33 @@ export const options = { }, { name_or_path: 'black-forest-labs/FLUX.1-dev', + arch: 'flux', + defaults: { + // default updates when [selected, unselected] in the UI + 'config.process[0].model.quantize': [true, false], + 'config.process[0].model.quantize_te': [true, false], + 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], + 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], + }, + }, + { + name_or_path: 'lodestones/Chroma', + arch: 'chroma', defaults: { // default updates when [selected, unselected] in the UI 'config.process[0].model.quantize': [true, false], 'config.process[0].model.quantize_te': [true, false], - 'config.process[0].model.arch': ['flux', defaultModelArch], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, }, { name_or_path: 'Wan-AI/Wan2.1-T2V-1.3B-Diffusers', + arch: 'wan21', defaults: { // default updates when [selected, unselected] in the UI 'config.process[0].model.quantize': [false, false], 'config.process[0].model.quantize_te': [true, false], - 'config.process[0].model.arch': ['wan21', defaultModelArch], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], 'config.process[0].sample.num_frames': [40, 1], @@ -62,11 +171,11 @@ export const options = { }, { name_or_path: 'Wan-AI/Wan2.1-T2V-14B-Diffusers', + arch: 'wan21', defaults: { // default updates when [selected, unselected] in the UI 'config.process[0].model.quantize': [true, false], 'config.process[0].model.quantize_te': [true, false], - 'config.process[0].model.arch': ['wan21', defaultModelArch], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], 'config.process[0].sample.num_frames': [40, 1], @@ -75,22 +184,22 @@ export const options = { }, { name_or_path: 'Alpha-VLLM/Lumina-Image-2.0', + arch: 'lumina2', defaults: { // default updates when [selected, unselected] in the UI 'config.process[0].model.quantize': [false, false], 'config.process[0].model.quantize_te': [true, false], - 'config.process[0].model.arch': ['lumina2', defaultModelArch], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], }, }, { name_or_path: 'HiDream-ai/HiDream-I1-Full', + arch: 'hidream', defaults: { // default updates when [selected, unselected] in the UI 'config.process[0].model.quantize': [true, false], 'config.process[0].model.quantize_te': [true, false], - 'config.process[0].model.arch': ['hidream', defaultModelArch], 'config.process[0].sample.sampler': ['flowmatch', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['flowmatch', 'flowmatch'], 'config.process[0].train.lr': [0.0002, 0.0001], @@ -100,11 +209,11 @@ export const options = { }, { name_or_path: 'ostris/objective-reality', + arch: 'sd1', dev_only: true, defaults: { 'config.process[0].sample.sampler': ['ddpm', 'flowmatch'], 'config.process[0].train.noise_scheduler': ['ddpm', 'flowmatch'], - 'config.process[0].model.arch': ['sd1', defaultModelArch], }, }, ], diff --git a/ui/src/components/formInputs.tsx b/ui/src/components/formInputs.tsx index 60d3fc60..7f53e681 100644 --- a/ui/src/components/formInputs.tsx +++ b/ui/src/components/formInputs.tsx @@ -1,5 +1,9 @@ +'use client'; + import React, { forwardRef } from 'react'; import classNames from 'classnames'; +import dynamic from "next/dynamic"; +const Select = dynamic(() => import("react-select"), { ssr: false }); const labelClasses = 'block text-xs mb-1 mt-2 text-gray-300'; const inputClasses = @@ -116,16 +120,21 @@ export interface SelectInputProps extends InputProps { export const SelectInput = (props: SelectInputProps) => { const { label, value, onChange, options } = props; + const selectedOption = options.find(option => option.value === value); return (
{label && } - +