Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
8341a4f
feat(nodes): add dataURL to image node
psychedelicious May 2, 2023
b473f66
chore(ui): regen api client
psychedelicious May 2, 2023
9955b74
feat(ui): wip canvas nodes migration
psychedelicious May 2, 2023
0a93c80
feat(ui): wip canvas nodes migration 2
psychedelicious May 2, 2023
5e65ac5
feat(ui): wip canvas nodes migration 3
psychedelicious May 3, 2023
318ce40
feat(nodes): free gpu mem after invocation
psychedelicious May 3, 2023
255d5b6
feat(ui): wip canvas migration, createListenerMiddleware
psychedelicious May 3, 2023
dfdf741
feat(ui): wip canvas migration 4
psychedelicious May 3, 2023
aaacbec
feat(ui): fix generation mode logic
psychedelicious May 4, 2023
c5eadcb
Revert "feat(nodes): free gpu mem after invocation"
psychedelicious May 4, 2023
f8fd4b0
feat(nodes): allow uploaded images to be any ImageType (eg intermedia…
psychedelicious May 4, 2023
f7925d9
fix(nodes): fix cfg scale min value
psychedelicious May 4, 2023
b375017
feat(nodes): wip inpaint node
psychedelicious May 4, 2023
18f70b0
feat(ui): wip canvas
psychedelicious May 4, 2023
9cd3783
fix(ui): fix currentimagepreview not working for uploads
psychedelicious May 5, 2023
848a9c7
feat(ui): endless gallery scroll
psychedelicious May 5, 2023
d19d49e
feat(ui): tweak gallery loading indicator
psychedelicious May 5, 2023
f1413d3
fix(nodes): add MetadataColorField
psychedelicious May 5, 2023
c458746
fix(nodes): fix trivial typing issues
psychedelicious May 5, 2023
a9595be
feat(ui): fix endless gallery scroll for single col layout
psychedelicious May 5, 2023
1e896ad
feat(nodes): add LatentsToImage node (VAE encode)
psychedelicious May 5, 2023
7c6a0b9
feat(nodes): add InfillInvocation
psychedelicious May 5, 2023
eaa9951
feat(ui): update for InfillInvocation
psychedelicious May 5, 2023
6daae2e
feat(ui): migrate to redux-remember
psychedelicious May 5, 2023
fc406ba
chore(ui): bump redux-remember
psychedelicious May 5, 2023
7abe6c1
chore(ui): remove unused babelrc & npm script
psychedelicious May 5, 2023
06043a0
fix(ui): use `lodash-es` instead of lodash
psychedelicious May 5, 2023
c59e39d
feat(nodes): cleanup unused params, seed generation
psychedelicious May 6, 2023
ce70dd6
feat(nodes): add infill nodes
psychedelicious May 6, 2023
7e7c996
fix(nodes): restore seamless to TextToLatents
psychedelicious May 6, 2023
d297ef3
fix(ui): fix types bug
psychedelicious May 6, 2023
add9313
chore(ui): regen api client
psychedelicious May 6, 2023
66b5fd9
fix(nodes): remove dataURL invocation
psychedelicious May 6, 2023
79b6d47
fix(nodes): fix infill docstrings
psychedelicious May 6, 2023
bf64751
fix(nodes): fix ImageOutput Config
psychedelicious May 6, 2023
d78cd6d
feat(nodes): improve default model choosing output
psychedelicious May 6, 2023
f665916
fix(ui): default node model selection
psychedelicious May 6, 2023
a434397
feat(ui): support collect nodes
psychedelicious May 7, 2023
47928c6
feat(ui): wip layouting
psychedelicious May 7, 2023
4ce20c8
feat(ui): wip img2img layouting
psychedelicious May 8, 2023
1f36267
feat(ui): add IAICollapse for parameters
psychedelicious May 8, 2023
e6e0f04
feat(ui): revert tabs to txt2img/img2img
psychedelicious May 8, 2023
89ef32e
fix(ui): remove duplicate gallery
psychedelicious May 8, 2023
910deb3
feat(ui): wip layout
psychedelicious May 9, 2023
67e2876
feat(ui): organize parameters panels
psychedelicious May 9, 2023
d9f6f39
feat(ui): restore tab names
psychedelicious May 9, 2023
d042ffd
fix(ui): duplicate gallery in nodes editor
psychedelicious May 9, 2023
d1991bf
cleanup(ui): Remove unused vars + minor bug fixes
blessedcoolant May 9, 2023
75b41d0
fix(ui): fix copying image link
psychedelicious May 9, 2023
e3eb311
fix(ui): fix metadataviewer styling
psychedelicious May 9, 2023
d90bba3
feat(ui): half-baked use all parameters
psychedelicious May 9, 2023
5bf0201
fix(ui): fix missing images on reload issue
psychedelicious May 9, 2023
c9b8ea1
fix(ui): disable invoke button as soon as pressed
psychedelicious May 10, 2023
b7a8441
fix(ui): fix janky gallery image delete
psychedelicious May 10, 2023
addd4ae
feat(ui): progress images in gallery and viewer
psychedelicious May 10, 2023
5d1e405
feat(ui): canvas antialiasing
psychedelicious May 10, 2023
2dbf9d9
fix(ui): h/w disabled bug
psychedelicious May 10, 2023
661fa82
feat(ui): antialias progress images
psychedelicious May 10, 2023
4035304
build(ui): add yalc to gitignore
psychedelicious May 10, 2023
98ccb5d
fix(nodes): fix usage of Optional
psychedelicious May 11, 2023
4c13ad2
fix(ui): fix canvas img2img if no init image selected
psychedelicious May 11, 2023
600c40a
fix(ui): rescale canvas on gallery resize
psychedelicious May 11, 2023
0e1fa74
fix(ui): change tab to img2img when selected initial image
psychedelicious May 11, 2023
83cb5bb
fix(nodes): fix metadata test
psychedelicious May 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 5 additions & 5 deletions invokeai/app/api/routers/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ async def get_thumbnail(
status_code=201,
)
async def upload_image(
file: UploadFile, request: Request, response: Response
file: UploadFile, image_type: ImageType, request: Request, response: Response
) -> ImageResponse:
if not file.content_type.startswith("image"):
raise HTTPException(status_code=415, detail="Not an image")
Expand All @@ -99,21 +99,21 @@ async def upload_image(
filename = f"{uuid.uuid4()}_{str(int(datetime.now(timezone.utc).timestamp()))}.png"

saved_image = ApiDependencies.invoker.services.images.save(
ImageType.UPLOAD, filename, img
image_type, filename, img
)

invokeai_metadata = ApiDependencies.invoker.services.metadata.get_metadata(img)

image_url = ApiDependencies.invoker.services.images.get_uri(
ImageType.UPLOAD, saved_image.image_name
image_type, saved_image.image_name
)

thumbnail_url = ApiDependencies.invoker.services.images.get_uri(
ImageType.UPLOAD, saved_image.image_name, True
image_type, saved_image.image_name, True
)

res = ImageResponse(
image_type=ImageType.UPLOAD,
image_type=image_type,
image_name=saved_image.image_name,
image_url=image_url,
thumbnail_url=thumbnail_url,
Expand Down
12 changes: 6 additions & 6 deletions invokeai/app/invocations/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from typing import Literal, Optional

import numpy as np
import numpy.random
from pydantic import Field

from invokeai.app.util.misc import SEED_MAX, get_random_seed

from .baseinvocation import (
BaseInvocation,
InvocationConfig,
InvocationContext,
BaseInvocationOutput,
)
Expand Down Expand Up @@ -50,11 +50,11 @@ class RandomRangeInvocation(BaseInvocation):
default=np.iinfo(np.int32).max, description="The exclusive high value"
)
size: int = Field(default=1, description="The number of values to generate")
seed: Optional[int] = Field(
seed: int = Field(
ge=0,
le=np.iinfo(np.int32).max,
description="The seed for the RNG",
default_factory=lambda: numpy.random.randint(0, np.iinfo(np.int32).max),
le=SEED_MAX,
description="The seed for the RNG (omit for random)",
default_factory=get_random_seed,
)

def invoke(self, context: InvocationContext) -> IntCollectionOutput:
Expand Down
31 changes: 20 additions & 11 deletions invokeai/app/invocations/generate.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654)

from functools import partial
from typing import Literal, Optional, Union
from typing import Literal, Optional, Union, get_args

import numpy as np
from torch import Tensor

from pydantic import BaseModel, Field

from invokeai.app.models.image import ImageField, ImageType
from invokeai.app.models.image import ColorField, ImageField, ImageType
from invokeai.app.invocations.util.choose_model import choose_model
from invokeai.app.util.misc import SEED_MAX, get_random_seed
from invokeai.backend.generator.inpaint import infill_methods
from .baseinvocation import BaseInvocation, InvocationContext, InvocationConfig
from .image import ImageOutput, build_image_output
from ...backend.generator import Txt2Img, Img2Img, Inpaint, InvokeAIGenerator
from ...backend.stable_diffusion import PipelineIntermediateState
from ..util.step_callback import stable_diffusion_step_callback

SAMPLER_NAME_VALUES = Literal[tuple(InvokeAIGenerator.schedulers())]

INFILL_METHODS = Literal[tuple(infill_methods())]
DEFAULT_INFILL_METHOD = 'patchmatch' if 'patchmatch' in get_args(INFILL_METHODS) else 'tile'

class SDImageInvocation(BaseModel):
"""Helper class to provide all Stable Diffusion raster image invocations with additional config"""
Expand All @@ -44,15 +47,13 @@ class TextToImageInvocation(BaseInvocation, SDImageInvocation):
# TODO: consider making prompt optional to enable providing prompt through a link
# fmt: off
prompt: Optional[str] = Field(description="The prompt to generate an image from")
seed: int = Field(default=-1,ge=-1, le=np.iinfo(np.uint32).max, description="The seed to use (-1 for a random seed)", )
steps: int = Field(default=10, gt=0, description="The number of steps to use to generate the image")
seed: int = Field(ge=0, le=SEED_MAX, description="The seed to use (omit for random)", default_factory=get_random_seed)
steps: int = Field(default=30, gt=0, description="The number of steps to use to generate the image")
width: int = Field(default=512, multiple_of=8, gt=0, description="The width of the resulting image", )
height: int = Field(default=512, multiple_of=8, gt=0, description="The height of the resulting image", )
cfg_scale: float = Field(default=7.5, gt=0, description="The Classifier-Free Guidance, higher values may result in a result closer to the prompt", )
cfg_scale: float = Field(default=7.5, ge=1, description="The Classifier-Free Guidance, higher values may result in a result closer to the prompt", )
scheduler: SAMPLER_NAME_VALUES = Field(default="k_lms", description="The scheduler to use" )
seamless: bool = Field(default=False, description="Whether or not to generate an image that can tile without seams", )
model: str = Field(default="", description="The model to use (currently ignored)")
progress_images: bool = Field(default=False, description="Whether or not to produce progress images during generation", )
# fmt: on

# TODO: pass this an emitter method or something? or a session for dispatching?
Expand Down Expand Up @@ -148,7 +149,6 @@ def invoke(self, context: InvocationContext) -> ImageOutput:
self.image.image_type, self.image.image_name
)
)
mask = None

if self.fit:
image = image.resize((self.width, self.height))
Expand All @@ -165,7 +165,6 @@ def invoke(self, context: InvocationContext) -> ImageOutput:
outputs = Img2Img(model).generate(
prompt=self.prompt,
init_image=image,
init_mask=mask,
step_callback=partial(self.dispatch_progress, context, source_node_id),
**self.dict(
exclude={"prompt", "image", "mask"}
Expand Down Expand Up @@ -197,14 +196,24 @@ def invoke(self, context: InvocationContext) -> ImageOutput:
image=result_image,
)


class InpaintInvocation(ImageToImageInvocation):
"""Generates an image using inpaint."""

type: Literal["inpaint"] = "inpaint"

# Inputs
mask: Union[ImageField, None] = Field(description="The mask")
seam_size: int = Field(default=96, ge=1, description="The seam inpaint size (px)")
seam_blur: int = Field(default=16, ge=0, description="The seam inpaint blur radius (px)")
seam_strength: float = Field(
default=0.75, gt=0, le=1, description="The seam inpaint strength"
)
seam_steps: int = Field(default=30, ge=1, description="The number of steps to use for seam inpaint")
tile_size: int = Field(default=32, ge=1, description="The tile infill method size (px)")
infill_method: INFILL_METHODS = Field(default=DEFAULT_INFILL_METHOD, description="The method used to infill empty regions (px)")
inpaint_width: Optional[int] = Field(default=None, multiple_of=8, gt=0, description="The width of the inpaint region (px)")
inpaint_height: Optional[int] = Field(default=None, multiple_of=8, gt=0, description="The height of the inpaint region (px)")
inpaint_fill: Optional[ColorField] = Field(default=ColorField(r=127, g=127, b=127, a=255), description="The solid infill method color")
inpaint_replace: float = Field(
default=0.0,
ge=0.0,
Expand Down
10 changes: 4 additions & 6 deletions invokeai/app/invocations/image.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654)

import io
from typing import Literal, Optional

import numpy
Expand Down Expand Up @@ -37,9 +38,7 @@ class ImageOutput(BaseInvocationOutput):
# fmt: on

class Config:
schema_extra = {
"required": ["type", "image", "width", "height", "mode"]
}
schema_extra = {"required": ["type", "image", "width", "height"]}


def build_image_output(
Expand All @@ -54,7 +53,6 @@ def build_image_output(
image=image_field,
width=image.width,
height=image.height,
mode=image.mode,
)


Expand Down Expand Up @@ -151,7 +149,7 @@ def invoke(self, context: InvocationContext) -> ImageOutput:
metadata = context.services.metadata.build_metadata(
session_id=context.graph_execution_state_id, node=self
)

context.services.images.save(image_type, image_name, image_crop, metadata)
return build_image_output(
image_type=image_type,
Expand Down Expand Up @@ -209,7 +207,7 @@ def invoke(self, context: InvocationContext) -> ImageOutput:
metadata = context.services.metadata.build_metadata(
session_id=context.graph_execution_state_id, node=self
)

context.services.images.save(image_type, image_name, new_image, metadata)
return build_image_output(
image_type=image_type,
Expand Down
Loading