mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into lstein/config-management-fixes
This commit is contained in:
commit
951900a86a
@ -1,5 +1,6 @@
|
|||||||
import io
|
import io
|
||||||
from fastapi import HTTPException, Path, Query, Request, Response, UploadFile
|
from typing import Optional
|
||||||
|
from fastapi import Body, HTTPException, Path, Query, Request, Response, UploadFile
|
||||||
from fastapi.routing import APIRouter
|
from fastapi.routing import APIRouter
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@ -7,7 +8,11 @@ from invokeai.app.models.image import (
|
|||||||
ImageCategory,
|
ImageCategory,
|
||||||
ImageType,
|
ImageType,
|
||||||
)
|
)
|
||||||
from invokeai.app.services.models.image_record import ImageDTO, ImageUrlsDTO
|
from invokeai.app.services.models.image_record import (
|
||||||
|
ImageDTO,
|
||||||
|
ImageRecordChanges,
|
||||||
|
ImageUrlsDTO,
|
||||||
|
)
|
||||||
from invokeai.app.services.item_storage import PaginatedResults
|
from invokeai.app.services.item_storage import PaginatedResults
|
||||||
|
|
||||||
from ..dependencies import ApiDependencies
|
from ..dependencies import ApiDependencies
|
||||||
@ -27,10 +32,17 @@ images_router = APIRouter(prefix="/v1/images", tags=["images"])
|
|||||||
)
|
)
|
||||||
async def upload_image(
|
async def upload_image(
|
||||||
file: UploadFile,
|
file: UploadFile,
|
||||||
image_type: ImageType,
|
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
image_category: ImageCategory = ImageCategory.GENERAL,
|
image_category: ImageCategory = Query(
|
||||||
|
default=ImageCategory.GENERAL, description="The category of the image"
|
||||||
|
),
|
||||||
|
is_intermediate: bool = Query(
|
||||||
|
default=False, description="Whether this is an intermediate image"
|
||||||
|
),
|
||||||
|
session_id: Optional[str] = Query(
|
||||||
|
default=None, description="The session ID associated with this upload, if any"
|
||||||
|
),
|
||||||
) -> ImageDTO:
|
) -> ImageDTO:
|
||||||
"""Uploads an image"""
|
"""Uploads an image"""
|
||||||
if not file.content_type.startswith("image"):
|
if not file.content_type.startswith("image"):
|
||||||
@ -46,9 +58,11 @@ async def upload_image(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
image_dto = ApiDependencies.invoker.services.images.create(
|
image_dto = ApiDependencies.invoker.services.images.create(
|
||||||
pil_image,
|
image=pil_image,
|
||||||
image_type,
|
image_type=ImageType.UPLOAD,
|
||||||
image_category,
|
image_category=image_category,
|
||||||
|
session_id=session_id,
|
||||||
|
is_intermediate=is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
response.status_code = 201
|
response.status_code = 201
|
||||||
@ -61,7 +75,7 @@ async def upload_image(
|
|||||||
|
|
||||||
@images_router.delete("/{image_type}/{image_name}", operation_id="delete_image")
|
@images_router.delete("/{image_type}/{image_name}", operation_id="delete_image")
|
||||||
async def delete_image(
|
async def delete_image(
|
||||||
image_type: ImageType = Query(description="The type of image to delete"),
|
image_type: ImageType = Path(description="The type of image to delete"),
|
||||||
image_name: str = Path(description="The name of the image to delete"),
|
image_name: str = Path(description="The name of the image to delete"),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Deletes an image"""
|
"""Deletes an image"""
|
||||||
@ -73,6 +87,28 @@ async def delete_image(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@images_router.patch(
|
||||||
|
"/{image_type}/{image_name}",
|
||||||
|
operation_id="update_image",
|
||||||
|
response_model=ImageDTO,
|
||||||
|
)
|
||||||
|
async def update_image(
|
||||||
|
image_type: ImageType = Path(description="The type of image to update"),
|
||||||
|
image_name: str = Path(description="The name of the image to update"),
|
||||||
|
image_changes: ImageRecordChanges = Body(
|
||||||
|
description="The changes to apply to the image"
|
||||||
|
),
|
||||||
|
) -> ImageDTO:
|
||||||
|
"""Updates an image"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
return ApiDependencies.invoker.services.images.update(
|
||||||
|
image_type, image_name, image_changes
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=400, detail="Failed to update image")
|
||||||
|
|
||||||
|
|
||||||
@images_router.get(
|
@images_router.get(
|
||||||
"/{image_type}/{image_name}/metadata",
|
"/{image_type}/{image_name}/metadata",
|
||||||
operation_id="get_image_metadata",
|
operation_id="get_image_metadata",
|
||||||
@ -85,9 +121,7 @@ async def get_image_metadata(
|
|||||||
"""Gets an image's metadata"""
|
"""Gets an image's metadata"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return ApiDependencies.invoker.services.images.get_dto(
|
return ApiDependencies.invoker.services.images.get_dto(image_type, image_name)
|
||||||
image_type, image_name
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=404)
|
raise HTTPException(status_code=404)
|
||||||
|
|
||||||
@ -113,9 +147,7 @@ async def get_image_full(
|
|||||||
"""Gets a full-resolution image file"""
|
"""Gets a full-resolution image file"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
path = ApiDependencies.invoker.services.images.get_path(
|
path = ApiDependencies.invoker.services.images.get_path(image_type, image_name)
|
||||||
image_type, image_name
|
|
||||||
)
|
|
||||||
|
|
||||||
if not ApiDependencies.invoker.services.images.validate_path(path):
|
if not ApiDependencies.invoker.services.images.validate_path(path):
|
||||||
raise HTTPException(status_code=404)
|
raise HTTPException(status_code=404)
|
||||||
|
@ -78,6 +78,7 @@ class BaseInvocation(ABC, BaseModel):
|
|||||||
|
|
||||||
#fmt: off
|
#fmt: off
|
||||||
id: str = Field(description="The id of this node. Must be unique among all nodes.")
|
id: str = Field(description="The id of this node. Must be unique among all nodes.")
|
||||||
|
is_intermediate: bool = Field(default=False, description="Whether or not this node is an intermediate node.")
|
||||||
#fmt: on
|
#fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,10 +57,11 @@ class CvInpaintInvocation(BaseInvocation, CvInvocationConfig):
|
|||||||
|
|
||||||
image_dto = context.services.images.create(
|
image_dto = context.services.images.create(
|
||||||
image=image_inpainted,
|
image=image_inpainted,
|
||||||
image_type=ImageType.INTERMEDIATE,
|
image_type=ImageType.RESULT,
|
||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -101,6 +101,7 @@ class TextToImageInvocation(BaseInvocation, SDImageInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -181,6 +182,7 @@ class ImageToImageInvocation(TextToImageInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -296,6 +298,7 @@ class InpaintInvocation(ImageToImageInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -143,6 +143,7 @@ class ImageCropInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -204,6 +205,7 @@ class ImagePasteInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -242,6 +244,7 @@ class MaskFromAlphaInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.MASK,
|
image_category=ImageCategory.MASK,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return MaskOutput(
|
return MaskOutput(
|
||||||
@ -280,6 +283,7 @@ class ImageMultiplyInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -318,6 +322,7 @@ class ImageChannelInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -356,6 +361,7 @@ class ImageConvertInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -397,6 +403,7 @@ class ImageBlurInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -437,6 +444,7 @@ class ImageLerpInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -482,6 +490,7 @@ class ImageInverseLerpInvocation(BaseInvocation, PILInvocationConfig):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -149,6 +149,7 @@ class InfillColorInvocation(BaseInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -193,6 +194,7 @@ class InfillTileInvocation(BaseInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
@ -230,6 +232,7 @@ class InfillPatchMatchInvocation(BaseInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -370,6 +370,7 @@ class LatentsToImageInvocation(BaseInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
|
is_intermediate=self.is_intermediate
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -43,10 +43,11 @@ class RestoreFaceInvocation(BaseInvocation):
|
|||||||
# TODO: can this return multiple results?
|
# TODO: can this return multiple results?
|
||||||
image_dto = context.services.images.create(
|
image_dto = context.services.images.create(
|
||||||
image=results[0][0],
|
image=results[0][0],
|
||||||
image_type=ImageType.INTERMEDIATE,
|
image_type=ImageType.RESULT,
|
||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -49,6 +49,7 @@ class UpscaleInvocation(BaseInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -10,7 +10,6 @@ class ImageType(str, Enum, metaclass=MetaEnum):
|
|||||||
|
|
||||||
RESULT = "results"
|
RESULT = "results"
|
||||||
UPLOAD = "uploads"
|
UPLOAD = "uploads"
|
||||||
INTERMEDIATE = "intermediates"
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidImageTypeException(ValueError):
|
class InvalidImageTypeException(ValueError):
|
||||||
|
@ -12,6 +12,7 @@ from invokeai.app.models.image import (
|
|||||||
)
|
)
|
||||||
from invokeai.app.services.models.image_record import (
|
from invokeai.app.services.models.image_record import (
|
||||||
ImageRecord,
|
ImageRecord,
|
||||||
|
ImageRecordChanges,
|
||||||
deserialize_image_record,
|
deserialize_image_record,
|
||||||
)
|
)
|
||||||
from invokeai.app.services.item_storage import PaginatedResults
|
from invokeai.app.services.item_storage import PaginatedResults
|
||||||
@ -49,6 +50,16 @@ class ImageRecordStorageBase(ABC):
|
|||||||
"""Gets an image record."""
|
"""Gets an image record."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(
|
||||||
|
self,
|
||||||
|
image_name: str,
|
||||||
|
image_type: ImageType,
|
||||||
|
changes: ImageRecordChanges,
|
||||||
|
) -> None:
|
||||||
|
"""Updates an image record."""
|
||||||
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_many(
|
def get_many(
|
||||||
self,
|
self,
|
||||||
@ -78,6 +89,7 @@ class ImageRecordStorageBase(ABC):
|
|||||||
session_id: Optional[str],
|
session_id: Optional[str],
|
||||||
node_id: Optional[str],
|
node_id: Optional[str],
|
||||||
metadata: Optional[ImageMetadata],
|
metadata: Optional[ImageMetadata],
|
||||||
|
is_intermediate: bool = False,
|
||||||
) -> datetime:
|
) -> datetime:
|
||||||
"""Saves an image record."""
|
"""Saves an image record."""
|
||||||
pass
|
pass
|
||||||
@ -125,6 +137,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
|
|||||||
session_id TEXT,
|
session_id TEXT,
|
||||||
node_id TEXT,
|
node_id TEXT,
|
||||||
metadata TEXT,
|
metadata TEXT,
|
||||||
|
is_intermediate BOOLEAN DEFAULT FALSE,
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
-- Updated via trigger
|
-- Updated via trigger
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
@ -193,6 +206,42 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
|
|||||||
|
|
||||||
return deserialize_image_record(dict(result))
|
return deserialize_image_record(dict(result))
|
||||||
|
|
||||||
|
def update(
|
||||||
|
self,
|
||||||
|
image_name: str,
|
||||||
|
image_type: ImageType,
|
||||||
|
changes: ImageRecordChanges,
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
self._lock.acquire()
|
||||||
|
# Change the category of the image
|
||||||
|
if changes.image_category is not None:
|
||||||
|
self._cursor.execute(
|
||||||
|
f"""--sql
|
||||||
|
UPDATE images
|
||||||
|
SET image_category = ?
|
||||||
|
WHERE image_name = ?;
|
||||||
|
""",
|
||||||
|
(changes.image_category, image_name),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Change the session associated with the image
|
||||||
|
if changes.session_id is not None:
|
||||||
|
self._cursor.execute(
|
||||||
|
f"""--sql
|
||||||
|
UPDATE images
|
||||||
|
SET session_id = ?
|
||||||
|
WHERE image_name = ?;
|
||||||
|
""",
|
||||||
|
(changes.session_id, image_name),
|
||||||
|
)
|
||||||
|
self._conn.commit()
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
self._conn.rollback()
|
||||||
|
raise ImageRecordSaveException from e
|
||||||
|
finally:
|
||||||
|
self._lock.release()
|
||||||
|
|
||||||
def get_many(
|
def get_many(
|
||||||
self,
|
self,
|
||||||
image_type: ImageType,
|
image_type: ImageType,
|
||||||
@ -265,6 +314,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
|
|||||||
height: int,
|
height: int,
|
||||||
node_id: Optional[str],
|
node_id: Optional[str],
|
||||||
metadata: Optional[ImageMetadata],
|
metadata: Optional[ImageMetadata],
|
||||||
|
is_intermediate: bool = False,
|
||||||
) -> datetime:
|
) -> datetime:
|
||||||
try:
|
try:
|
||||||
metadata_json = (
|
metadata_json = (
|
||||||
@ -281,9 +331,10 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
|
|||||||
height,
|
height,
|
||||||
node_id,
|
node_id,
|
||||||
session_id,
|
session_id,
|
||||||
metadata
|
metadata,
|
||||||
|
is_intermediate
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
image_name,
|
image_name,
|
||||||
@ -294,6 +345,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
|
|||||||
node_id,
|
node_id,
|
||||||
session_id,
|
session_id,
|
||||||
metadata_json,
|
metadata_json,
|
||||||
|
is_intermediate,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self._conn.commit()
|
self._conn.commit()
|
||||||
|
@ -20,6 +20,7 @@ from invokeai.app.services.image_record_storage import (
|
|||||||
from invokeai.app.services.models.image_record import (
|
from invokeai.app.services.models.image_record import (
|
||||||
ImageRecord,
|
ImageRecord,
|
||||||
ImageDTO,
|
ImageDTO,
|
||||||
|
ImageRecordChanges,
|
||||||
image_record_to_dto,
|
image_record_to_dto,
|
||||||
)
|
)
|
||||||
from invokeai.app.services.image_file_storage import (
|
from invokeai.app.services.image_file_storage import (
|
||||||
@ -31,7 +32,6 @@ from invokeai.app.services.image_file_storage import (
|
|||||||
from invokeai.app.services.item_storage import ItemStorageABC, PaginatedResults
|
from invokeai.app.services.item_storage import ItemStorageABC, PaginatedResults
|
||||||
from invokeai.app.services.metadata import MetadataServiceBase
|
from invokeai.app.services.metadata import MetadataServiceBase
|
||||||
from invokeai.app.services.urls import UrlServiceBase
|
from invokeai.app.services.urls import UrlServiceBase
|
||||||
from invokeai.app.util.misc import get_iso_timestamp
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from invokeai.app.services.graph import GraphExecutionState
|
from invokeai.app.services.graph import GraphExecutionState
|
||||||
@ -48,11 +48,21 @@ class ImageServiceABC(ABC):
|
|||||||
image_category: ImageCategory,
|
image_category: ImageCategory,
|
||||||
node_id: Optional[str] = None,
|
node_id: Optional[str] = None,
|
||||||
session_id: Optional[str] = None,
|
session_id: Optional[str] = None,
|
||||||
metadata: Optional[ImageMetadata] = None,
|
intermediate: bool = False,
|
||||||
) -> ImageDTO:
|
) -> ImageDTO:
|
||||||
"""Creates an image, storing the file and its metadata."""
|
"""Creates an image, storing the file and its metadata."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(
|
||||||
|
self,
|
||||||
|
image_type: ImageType,
|
||||||
|
image_name: str,
|
||||||
|
changes: ImageRecordChanges,
|
||||||
|
) -> ImageDTO:
|
||||||
|
"""Updates an image."""
|
||||||
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_pil_image(self, image_type: ImageType, image_name: str) -> PILImageType:
|
def get_pil_image(self, image_type: ImageType, image_name: str) -> PILImageType:
|
||||||
"""Gets an image as a PIL image."""
|
"""Gets an image as a PIL image."""
|
||||||
@ -157,6 +167,7 @@ class ImageService(ImageServiceABC):
|
|||||||
image_category: ImageCategory,
|
image_category: ImageCategory,
|
||||||
node_id: Optional[str] = None,
|
node_id: Optional[str] = None,
|
||||||
session_id: Optional[str] = None,
|
session_id: Optional[str] = None,
|
||||||
|
is_intermediate: bool = False,
|
||||||
) -> ImageDTO:
|
) -> ImageDTO:
|
||||||
if image_type not in ImageType:
|
if image_type not in ImageType:
|
||||||
raise InvalidImageTypeException
|
raise InvalidImageTypeException
|
||||||
@ -184,6 +195,8 @@ class ImageService(ImageServiceABC):
|
|||||||
image_category=image_category,
|
image_category=image_category,
|
||||||
width=width,
|
width=width,
|
||||||
height=height,
|
height=height,
|
||||||
|
# Meta fields
|
||||||
|
is_intermediate=is_intermediate,
|
||||||
# Nullable fields
|
# Nullable fields
|
||||||
node_id=node_id,
|
node_id=node_id,
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
@ -217,6 +230,7 @@ class ImageService(ImageServiceABC):
|
|||||||
created_at=created_at,
|
created_at=created_at,
|
||||||
updated_at=created_at, # this is always the same as the created_at at this time
|
updated_at=created_at, # this is always the same as the created_at at this time
|
||||||
deleted_at=None,
|
deleted_at=None,
|
||||||
|
is_intermediate=is_intermediate,
|
||||||
# Extra non-nullable fields for DTO
|
# Extra non-nullable fields for DTO
|
||||||
image_url=image_url,
|
image_url=image_url,
|
||||||
thumbnail_url=thumbnail_url,
|
thumbnail_url=thumbnail_url,
|
||||||
@ -231,6 +245,23 @@ class ImageService(ImageServiceABC):
|
|||||||
self._services.logger.error("Problem saving image record and file")
|
self._services.logger.error("Problem saving image record and file")
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
def update(
|
||||||
|
self,
|
||||||
|
image_type: ImageType,
|
||||||
|
image_name: str,
|
||||||
|
changes: ImageRecordChanges,
|
||||||
|
) -> ImageDTO:
|
||||||
|
try:
|
||||||
|
self._services.records.update(image_name, image_type, changes)
|
||||||
|
return self.get_dto(image_type, image_name)
|
||||||
|
except ImageRecordSaveException:
|
||||||
|
self._services.logger.error("Failed to update image record")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
self._services.logger.error("Problem updating image record")
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def get_pil_image(self, image_type: ImageType, image_name: str) -> PILImageType:
|
def get_pil_image(self, image_type: ImageType, image_name: str) -> PILImageType:
|
||||||
try:
|
try:
|
||||||
return self._services.files.get(image_type, image_name)
|
return self._services.files.get(image_type, image_name)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Extra, Field, StrictStr
|
||||||
from invokeai.app.models.image import ImageCategory, ImageType
|
from invokeai.app.models.image import ImageCategory, ImageType
|
||||||
from invokeai.app.models.metadata import ImageMetadata
|
from invokeai.app.models.metadata import ImageMetadata
|
||||||
from invokeai.app.util.misc import get_iso_timestamp
|
from invokeai.app.util.misc import get_iso_timestamp
|
||||||
@ -31,6 +31,8 @@ class ImageRecord(BaseModel):
|
|||||||
description="The deleted timestamp of the image."
|
description="The deleted timestamp of the image."
|
||||||
)
|
)
|
||||||
"""The deleted timestamp of the image."""
|
"""The deleted timestamp of the image."""
|
||||||
|
is_intermediate: bool = Field(description="Whether this is an intermediate image.")
|
||||||
|
"""Whether this is an intermediate image."""
|
||||||
session_id: Optional[str] = Field(
|
session_id: Optional[str] = Field(
|
||||||
default=None,
|
default=None,
|
||||||
description="The session ID that generated this image, if it is a generated image.",
|
description="The session ID that generated this image, if it is a generated image.",
|
||||||
@ -48,6 +50,25 @@ class ImageRecord(BaseModel):
|
|||||||
"""A limited subset of the image's generation metadata. Retrieve the image's session for full metadata."""
|
"""A limited subset of the image's generation metadata. Retrieve the image's session for full metadata."""
|
||||||
|
|
||||||
|
|
||||||
|
class ImageRecordChanges(BaseModel, extra=Extra.forbid):
|
||||||
|
"""A set of changes to apply to an image record.
|
||||||
|
|
||||||
|
Only limited changes are valid:
|
||||||
|
- `image_category`: change the category of an image
|
||||||
|
- `session_id`: change the session associated with an image
|
||||||
|
"""
|
||||||
|
|
||||||
|
image_category: Optional[ImageCategory] = Field(
|
||||||
|
description="The image's new category."
|
||||||
|
)
|
||||||
|
"""The image's new category."""
|
||||||
|
session_id: Optional[StrictStr] = Field(
|
||||||
|
default=None,
|
||||||
|
description="The image's new session ID.",
|
||||||
|
)
|
||||||
|
"""The image's new session ID."""
|
||||||
|
|
||||||
|
|
||||||
class ImageUrlsDTO(BaseModel):
|
class ImageUrlsDTO(BaseModel):
|
||||||
"""The URLs for an image and its thumbnail."""
|
"""The URLs for an image and its thumbnail."""
|
||||||
|
|
||||||
@ -95,6 +116,7 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord:
|
|||||||
created_at = image_dict.get("created_at", get_iso_timestamp())
|
created_at = image_dict.get("created_at", get_iso_timestamp())
|
||||||
updated_at = image_dict.get("updated_at", get_iso_timestamp())
|
updated_at = image_dict.get("updated_at", get_iso_timestamp())
|
||||||
deleted_at = image_dict.get("deleted_at", get_iso_timestamp())
|
deleted_at = image_dict.get("deleted_at", get_iso_timestamp())
|
||||||
|
is_intermediate = image_dict.get("is_intermediate", False)
|
||||||
|
|
||||||
raw_metadata = image_dict.get("metadata")
|
raw_metadata = image_dict.get("metadata")
|
||||||
|
|
||||||
@ -115,4 +137,5 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord:
|
|||||||
created_at=created_at,
|
created_at=created_at,
|
||||||
updated_at=updated_at,
|
updated_at=updated_at,
|
||||||
deleted_at=deleted_at,
|
deleted_at=deleted_at,
|
||||||
|
is_intermediate=is_intermediate,
|
||||||
)
|
)
|
||||||
|
@ -8,9 +8,16 @@ import type { TypedStartListening, TypedAddListener } from '@reduxjs/toolkit';
|
|||||||
|
|
||||||
import type { RootState, AppDispatch } from '../../store';
|
import type { RootState, AppDispatch } from '../../store';
|
||||||
import { addInitialImageSelectedListener } from './listeners/initialImageSelected';
|
import { addInitialImageSelectedListener } from './listeners/initialImageSelected';
|
||||||
import { addImageResultReceivedListener } from './listeners/invocationComplete';
|
import {
|
||||||
import { addImageUploadedListener } from './listeners/imageUploaded';
|
addImageUploadedFulfilledListener,
|
||||||
import { addRequestedImageDeletionListener } from './listeners/imageDeleted';
|
addImageUploadedRejectedListener,
|
||||||
|
} from './listeners/imageUploaded';
|
||||||
|
import {
|
||||||
|
addImageDeletedFulfilledListener,
|
||||||
|
addImageDeletedPendingListener,
|
||||||
|
addImageDeletedRejectedListener,
|
||||||
|
addRequestedImageDeletionListener,
|
||||||
|
} from './listeners/imageDeleted';
|
||||||
import { addUserInvokedCanvasListener } from './listeners/userInvokedCanvas';
|
import { addUserInvokedCanvasListener } from './listeners/userInvokedCanvas';
|
||||||
import { addUserInvokedNodesListener } from './listeners/userInvokedNodes';
|
import { addUserInvokedNodesListener } from './listeners/userInvokedNodes';
|
||||||
import { addUserInvokedTextToImageListener } from './listeners/userInvokedTextToImage';
|
import { addUserInvokedTextToImageListener } from './listeners/userInvokedTextToImage';
|
||||||
@ -19,6 +26,47 @@ import { addCanvasSavedToGalleryListener } from './listeners/canvasSavedToGaller
|
|||||||
import { addCanvasDownloadedAsImageListener } from './listeners/canvasDownloadedAsImage';
|
import { addCanvasDownloadedAsImageListener } from './listeners/canvasDownloadedAsImage';
|
||||||
import { addCanvasCopiedToClipboardListener } from './listeners/canvasCopiedToClipboard';
|
import { addCanvasCopiedToClipboardListener } from './listeners/canvasCopiedToClipboard';
|
||||||
import { addCanvasMergedListener } from './listeners/canvasMerged';
|
import { addCanvasMergedListener } from './listeners/canvasMerged';
|
||||||
|
import { addGeneratorProgressListener } from './listeners/socketio/generatorProgress';
|
||||||
|
import { addGraphExecutionStateCompleteListener } from './listeners/socketio/graphExecutionStateComplete';
|
||||||
|
import { addInvocationCompleteListener } from './listeners/socketio/invocationComplete';
|
||||||
|
import { addInvocationErrorListener } from './listeners/socketio/invocationError';
|
||||||
|
import { addInvocationStartedListener } from './listeners/socketio/invocationStarted';
|
||||||
|
import { addSocketConnectedListener } from './listeners/socketio/socketConnected';
|
||||||
|
import { addSocketDisconnectedListener } from './listeners/socketio/socketDisconnected';
|
||||||
|
import { addSocketSubscribedListener } from './listeners/socketio/socketSubscribed';
|
||||||
|
import { addSocketUnsubscribedListener } from './listeners/socketio/socketUnsubscribed';
|
||||||
|
import { addSessionReadyToInvokeListener } from './listeners/sessionReadyToInvoke';
|
||||||
|
import {
|
||||||
|
addImageMetadataReceivedFulfilledListener,
|
||||||
|
addImageMetadataReceivedRejectedListener,
|
||||||
|
} from './listeners/imageMetadataReceived';
|
||||||
|
import {
|
||||||
|
addImageUrlsReceivedFulfilledListener,
|
||||||
|
addImageUrlsReceivedRejectedListener,
|
||||||
|
} from './listeners/imageUrlsReceived';
|
||||||
|
import {
|
||||||
|
addSessionCreatedFulfilledListener,
|
||||||
|
addSessionCreatedPendingListener,
|
||||||
|
addSessionCreatedRejectedListener,
|
||||||
|
} from './listeners/sessionCreated';
|
||||||
|
import {
|
||||||
|
addSessionInvokedFulfilledListener,
|
||||||
|
addSessionInvokedPendingListener,
|
||||||
|
addSessionInvokedRejectedListener,
|
||||||
|
} from './listeners/sessionInvoked';
|
||||||
|
import {
|
||||||
|
addSessionCanceledFulfilledListener,
|
||||||
|
addSessionCanceledPendingListener,
|
||||||
|
addSessionCanceledRejectedListener,
|
||||||
|
} from './listeners/sessionCanceled';
|
||||||
|
import {
|
||||||
|
addReceivedResultImagesPageFulfilledListener,
|
||||||
|
addReceivedResultImagesPageRejectedListener,
|
||||||
|
} from './listeners/receivedResultImagesPage';
|
||||||
|
import {
|
||||||
|
addReceivedUploadImagesPageFulfilledListener,
|
||||||
|
addReceivedUploadImagesPageRejectedListener,
|
||||||
|
} from './listeners/receivedUploadImagesPage';
|
||||||
|
|
||||||
export const listenerMiddleware = createListenerMiddleware();
|
export const listenerMiddleware = createListenerMiddleware();
|
||||||
|
|
||||||
@ -38,17 +86,67 @@ export type AppListenerEffect = ListenerEffect<
|
|||||||
AppDispatch
|
AppDispatch
|
||||||
>;
|
>;
|
||||||
|
|
||||||
addImageUploadedListener();
|
// Image uploaded
|
||||||
addInitialImageSelectedListener();
|
addImageUploadedFulfilledListener();
|
||||||
addImageResultReceivedListener();
|
addImageUploadedRejectedListener();
|
||||||
addRequestedImageDeletionListener();
|
|
||||||
|
|
||||||
|
addInitialImageSelectedListener();
|
||||||
|
|
||||||
|
// Image deleted
|
||||||
|
addRequestedImageDeletionListener();
|
||||||
|
addImageDeletedPendingListener();
|
||||||
|
addImageDeletedFulfilledListener();
|
||||||
|
addImageDeletedRejectedListener();
|
||||||
|
|
||||||
|
// Image metadata
|
||||||
|
addImageMetadataReceivedFulfilledListener();
|
||||||
|
addImageMetadataReceivedRejectedListener();
|
||||||
|
|
||||||
|
// Image URLs
|
||||||
|
addImageUrlsReceivedFulfilledListener();
|
||||||
|
addImageUrlsReceivedRejectedListener();
|
||||||
|
|
||||||
|
// User Invoked
|
||||||
addUserInvokedCanvasListener();
|
addUserInvokedCanvasListener();
|
||||||
addUserInvokedNodesListener();
|
addUserInvokedNodesListener();
|
||||||
addUserInvokedTextToImageListener();
|
addUserInvokedTextToImageListener();
|
||||||
addUserInvokedImageToImageListener();
|
addUserInvokedImageToImageListener();
|
||||||
|
addSessionReadyToInvokeListener();
|
||||||
|
|
||||||
|
// Canvas actions
|
||||||
addCanvasSavedToGalleryListener();
|
addCanvasSavedToGalleryListener();
|
||||||
addCanvasDownloadedAsImageListener();
|
addCanvasDownloadedAsImageListener();
|
||||||
addCanvasCopiedToClipboardListener();
|
addCanvasCopiedToClipboardListener();
|
||||||
addCanvasMergedListener();
|
addCanvasMergedListener();
|
||||||
|
|
||||||
|
// socketio
|
||||||
|
addGeneratorProgressListener();
|
||||||
|
addGraphExecutionStateCompleteListener();
|
||||||
|
addInvocationCompleteListener();
|
||||||
|
addInvocationErrorListener();
|
||||||
|
addInvocationStartedListener();
|
||||||
|
addSocketConnectedListener();
|
||||||
|
addSocketDisconnectedListener();
|
||||||
|
addSocketSubscribedListener();
|
||||||
|
addSocketUnsubscribedListener();
|
||||||
|
|
||||||
|
// Session Created
|
||||||
|
addSessionCreatedPendingListener();
|
||||||
|
addSessionCreatedFulfilledListener();
|
||||||
|
addSessionCreatedRejectedListener();
|
||||||
|
|
||||||
|
// Session Invoked
|
||||||
|
addSessionInvokedPendingListener();
|
||||||
|
addSessionInvokedFulfilledListener();
|
||||||
|
addSessionInvokedRejectedListener();
|
||||||
|
|
||||||
|
// Session Canceled
|
||||||
|
addSessionCanceledPendingListener();
|
||||||
|
addSessionCanceledFulfilledListener();
|
||||||
|
addSessionCanceledRejectedListener();
|
||||||
|
|
||||||
|
// Gallery pages
|
||||||
|
addReceivedResultImagesPageFulfilledListener();
|
||||||
|
addReceivedResultImagesPageRejectedListener();
|
||||||
|
addReceivedUploadImagesPageFulfilledListener();
|
||||||
|
addReceivedUploadImagesPageRejectedListener();
|
||||||
|
@ -52,7 +52,6 @@ export const addCanvasMergedListener = () => {
|
|||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
imageType: 'intermediates',
|
|
||||||
formData: {
|
formData: {
|
||||||
file: new File([blob], filename, { type: 'image/png' }),
|
file: new File([blob], filename, { type: 'image/png' }),
|
||||||
},
|
},
|
||||||
@ -65,7 +64,7 @@ export const addCanvasMergedListener = () => {
|
|||||||
action.meta.arg.formData.file.name === filename
|
action.meta.arg.formData.file.name === filename
|
||||||
);
|
);
|
||||||
|
|
||||||
const mergedCanvasImage = payload.response;
|
const mergedCanvasImage = payload;
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setMergedCanvas({
|
setMergedCanvas({
|
||||||
|
@ -29,7 +29,6 @@ export const addCanvasSavedToGalleryListener = () => {
|
|||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
imageType: 'results',
|
|
||||||
formData: {
|
formData: {
|
||||||
file: new File([blob], 'mergedCanvas.png', { type: 'image/png' }),
|
file: new File([blob], 'mergedCanvas.png', { type: 'image/png' }),
|
||||||
},
|
},
|
||||||
|
@ -4,9 +4,14 @@ import { imageDeleted } from 'services/thunks/image';
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
|
import { uploadsAdapter } from 'features/gallery/store/uploadsSlice';
|
||||||
|
import { resultsAdapter } from 'features/gallery/store/resultsSlice';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'addRequestedImageDeletionListener' });
|
const moduleLog = log.child({ namespace: 'addRequestedImageDeletionListener' });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the user requests an image deletion
|
||||||
|
*/
|
||||||
export const addRequestedImageDeletionListener = () => {
|
export const addRequestedImageDeletionListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: requestedImageDeletion,
|
actionCreator: requestedImageDeletion,
|
||||||
@ -19,11 +24,6 @@ export const addRequestedImageDeletionListener = () => {
|
|||||||
|
|
||||||
const { image_name, image_type } = image;
|
const { image_name, image_type } = image;
|
||||||
|
|
||||||
if (image_type !== 'uploads' && image_type !== 'results') {
|
|
||||||
moduleLog.warn({ data: image }, `Invalid image type ${image_type}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedImageName = getState().gallery.selectedImage?.image_name;
|
const selectedImageName = getState().gallery.selectedImage?.image_name;
|
||||||
|
|
||||||
if (selectedImageName === image_name) {
|
if (selectedImageName === image_name) {
|
||||||
@ -57,3 +57,49 @@ export const addRequestedImageDeletionListener = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the actual delete request is sent to the server
|
||||||
|
*/
|
||||||
|
export const addImageDeletedPendingListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageDeleted.pending,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
const { imageName, imageType } = action.meta.arg;
|
||||||
|
// Preemptively remove the image from the gallery
|
||||||
|
if (imageType === 'uploads') {
|
||||||
|
uploadsAdapter.removeOne(getState().uploads, imageName);
|
||||||
|
}
|
||||||
|
if (imageType === 'results') {
|
||||||
|
resultsAdapter.removeOne(getState().results, imageName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on successful delete
|
||||||
|
*/
|
||||||
|
export const addImageDeletedFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageDeleted.fulfilled,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.debug({ data: { image: action.meta.arg } }, 'Image deleted');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on failed delete
|
||||||
|
*/
|
||||||
|
export const addImageDeletedRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageDeleted.rejected,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { image: action.meta.arg } },
|
||||||
|
'Unable to delete image'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { imageMetadataReceived } from 'services/thunks/image';
|
||||||
|
import {
|
||||||
|
ResultsImageDTO,
|
||||||
|
resultUpserted,
|
||||||
|
} from 'features/gallery/store/resultsSlice';
|
||||||
|
import {
|
||||||
|
UploadsImageDTO,
|
||||||
|
uploadUpserted,
|
||||||
|
} from 'features/gallery/store/uploadsSlice';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
|
|
||||||
|
export const addImageMetadataReceivedFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageMetadataReceived.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const image = action.payload;
|
||||||
|
moduleLog.debug({ data: { image } }, 'Image metadata received');
|
||||||
|
|
||||||
|
if (image.image_type === 'results') {
|
||||||
|
dispatch(resultUpserted(action.payload as ResultsImageDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.image_type === 'uploads') {
|
||||||
|
dispatch(uploadUpserted(action.payload as UploadsImageDTO));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addImageMetadataReceivedRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageMetadataReceived.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { image: action.meta.arg } },
|
||||||
|
'Problem receiving image metadata'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -1,25 +1,31 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { uploadAdded } from 'features/gallery/store/uploadsSlice';
|
import { uploadUpserted } from 'features/gallery/store/uploadsSlice';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
import { imageUploaded } from 'services/thunks/image';
|
import { imageUploaded } from 'services/thunks/image';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||||
import { resultAdded } from 'features/gallery/store/resultsSlice';
|
import { resultUpserted } from 'features/gallery/store/resultsSlice';
|
||||||
import { isResultsImageDTO, isUploadsImageDTO } from 'services/types/guards';
|
import { isResultsImageDTO, isUploadsImageDTO } from 'services/types/guards';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
|
||||||
export const addImageUploadedListener = () => {
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
|
|
||||||
|
export const addImageUploadedFulfilledListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
predicate: (action): action is ReturnType<typeof imageUploaded.fulfilled> =>
|
predicate: (action): action is ReturnType<typeof imageUploaded.fulfilled> =>
|
||||||
imageUploaded.fulfilled.match(action) &&
|
imageUploaded.fulfilled.match(action) &&
|
||||||
action.payload.response.image_type !== 'intermediates',
|
action.payload.is_intermediate === false,
|
||||||
effect: (action, { dispatch, getState }) => {
|
effect: (action, { dispatch, getState }) => {
|
||||||
const { response: image } = action.payload;
|
const image = action.payload;
|
||||||
|
|
||||||
|
moduleLog.debug({ arg: '<Blob>', image }, 'Image uploaded');
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
|
// Handle uploads
|
||||||
if (isUploadsImageDTO(image)) {
|
if (isUploadsImageDTO(image)) {
|
||||||
dispatch(uploadAdded(image));
|
dispatch(uploadUpserted(image));
|
||||||
|
|
||||||
dispatch(addToast({ title: 'Image Uploaded', status: 'success' }));
|
dispatch(addToast({ title: 'Image Uploaded', status: 'success' }));
|
||||||
|
|
||||||
@ -36,9 +42,26 @@ export const addImageUploadedListener = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle results
|
||||||
|
// TODO: Can this ever happen? I don't think so...
|
||||||
if (isResultsImageDTO(image)) {
|
if (isResultsImageDTO(image)) {
|
||||||
dispatch(resultAdded(image));
|
dispatch(resultUpserted(image));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const addImageUploadedRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageUploaded.rejected,
|
||||||
|
effect: (action, { dispatch }) => {
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
title: 'Image Upload Failed',
|
||||||
|
description: action.error.message,
|
||||||
|
status: 'error',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { imageUrlsReceived } from 'services/thunks/image';
|
||||||
|
import { resultsAdapter } from 'features/gallery/store/resultsSlice';
|
||||||
|
import { uploadsAdapter } from 'features/gallery/store/uploadsSlice';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
|
|
||||||
|
export const addImageUrlsReceivedFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageUrlsReceived.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const image = action.payload;
|
||||||
|
moduleLog.debug({ data: { image } }, 'Image URLs received');
|
||||||
|
|
||||||
|
const { image_type, image_name, image_url, thumbnail_url } = image;
|
||||||
|
|
||||||
|
if (image_type === 'results') {
|
||||||
|
resultsAdapter.updateOne(getState().results, {
|
||||||
|
id: image_name,
|
||||||
|
changes: {
|
||||||
|
image_url,
|
||||||
|
thumbnail_url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image_type === 'uploads') {
|
||||||
|
uploadsAdapter.updateOne(getState().uploads, {
|
||||||
|
id: image_name,
|
||||||
|
changes: {
|
||||||
|
image_url,
|
||||||
|
thumbnail_url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addImageUrlsReceivedRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: imageUrlsReceived.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { image: action.meta.arg } },
|
||||||
|
'Problem getting image URLs'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -1,62 +0,0 @@
|
|||||||
import { invocationComplete } from 'services/events/actions';
|
|
||||||
import { isImageOutput } from 'services/types/guards';
|
|
||||||
import {
|
|
||||||
imageMetadataReceived,
|
|
||||||
imageUrlsReceived,
|
|
||||||
} from 'services/thunks/image';
|
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
|
|
||||||
|
|
||||||
const nodeDenylist = ['dataURL_image'];
|
|
||||||
|
|
||||||
export const addImageResultReceivedListener = () => {
|
|
||||||
startAppListening({
|
|
||||||
predicate: (action) => {
|
|
||||||
if (
|
|
||||||
invocationComplete.match(action) &&
|
|
||||||
isImageOutput(action.payload.data.result)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
effect: async (action, { getState, dispatch, take }) => {
|
|
||||||
if (!invocationComplete.match(action)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data } = action.payload;
|
|
||||||
const { result, node, graph_execution_state_id } = data;
|
|
||||||
|
|
||||||
if (isImageOutput(result) && !nodeDenylist.includes(node.type)) {
|
|
||||||
const { image_name, image_type } = result.image;
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
imageUrlsReceived({ imageName: image_name, imageType: image_type })
|
|
||||||
);
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
imageMetadataReceived({
|
|
||||||
imageName: image_name,
|
|
||||||
imageType: image_type,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle canvas image
|
|
||||||
if (
|
|
||||||
graph_execution_state_id ===
|
|
||||||
getState().canvas.layerState.stagingArea.sessionId
|
|
||||||
) {
|
|
||||||
const [{ payload: image }] = await take(
|
|
||||||
(
|
|
||||||
action
|
|
||||||
): action is ReturnType<typeof imageMetadataReceived.fulfilled> =>
|
|
||||||
imageMetadataReceived.fulfilled.match(action) &&
|
|
||||||
action.payload.image_name === image_name
|
|
||||||
);
|
|
||||||
dispatch(addImageToStagingArea(image));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
@ -0,0 +1,33 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { receivedResultImagesPage } from 'services/thunks/gallery';
|
||||||
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'gallery' });
|
||||||
|
|
||||||
|
export const addReceivedResultImagesPageFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: receivedResultImagesPage.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const page = action.payload;
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { page } },
|
||||||
|
`Received ${page.items.length} results`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addReceivedResultImagesPageRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: receivedResultImagesPage.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
if (action.payload) {
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { error: serializeError(action.payload.error) } },
|
||||||
|
'Problem receiving results'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,33 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { receivedUploadImagesPage } from 'services/thunks/gallery';
|
||||||
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'gallery' });
|
||||||
|
|
||||||
|
export const addReceivedUploadImagesPageFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: receivedUploadImagesPage.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const page = action.payload;
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { page } },
|
||||||
|
`Received ${page.items.length} uploads`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addReceivedUploadImagesPageRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: receivedUploadImagesPage.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
if (action.payload) {
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { error: serializeError(action.payload.error) } },
|
||||||
|
'Problem receiving uploads'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,48 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { sessionCanceled } from 'services/thunks/session';
|
||||||
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
|
|
||||||
|
export const addSessionCanceledPendingListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionCanceled.pending,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addSessionCanceledFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionCanceled.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const { sessionId } = action.meta.arg;
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { sessionId } },
|
||||||
|
`Session canceled (${sessionId})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addSessionCanceledRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionCanceled.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
if (action.payload) {
|
||||||
|
const { arg, error } = action.payload;
|
||||||
|
moduleLog.error(
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
arg,
|
||||||
|
error: serializeError(error),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`Problem canceling session`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,45 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { sessionCreated } from 'services/thunks/session';
|
||||||
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
|
|
||||||
|
export const addSessionCreatedPendingListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionCreated.pending,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addSessionCreatedFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionCreated.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const session = action.payload;
|
||||||
|
moduleLog.debug({ data: { session } }, `Session created (${session.id})`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addSessionCreatedRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionCreated.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
if (action.payload) {
|
||||||
|
const { arg, error } = action.payload;
|
||||||
|
moduleLog.error(
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
arg,
|
||||||
|
error: serializeError(error),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`Problem creating session`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,48 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
import { sessionInvoked } from 'services/thunks/session';
|
||||||
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
|
|
||||||
|
export const addSessionInvokedPendingListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionInvoked.pending,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addSessionInvokedFulfilledListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionInvoked.fulfilled,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const { sessionId } = action.meta.arg;
|
||||||
|
moduleLog.debug(
|
||||||
|
{ data: { sessionId } },
|
||||||
|
`Session invoked (${sessionId})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addSessionInvokedRejectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionInvoked.rejected,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
if (action.payload) {
|
||||||
|
const { arg, error } = action.payload;
|
||||||
|
moduleLog.error(
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
arg,
|
||||||
|
error: serializeError(error),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`Problem invoking session`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
import { startAppListening } from '..';
|
||||||
|
import { sessionInvoked } from 'services/thunks/session';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
|
|
||||||
|
export const addSessionReadyToInvokeListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: sessionReadyToInvoke,
|
||||||
|
effect: (action, { getState, dispatch }) => {
|
||||||
|
const { sessionId } = getState().system;
|
||||||
|
if (sessionId) {
|
||||||
|
moduleLog.debug(
|
||||||
|
{ sessionId },
|
||||||
|
`Session ready to invoke (${sessionId})})`
|
||||||
|
);
|
||||||
|
dispatch(sessionInvoked({ sessionId }));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { generatorProgress } from 'services/events/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addGeneratorProgressListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: generatorProgress,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
if (
|
||||||
|
getState().system.canceledSession ===
|
||||||
|
action.payload.data.graph_execution_state_id
|
||||||
|
) {
|
||||||
|
moduleLog.trace(
|
||||||
|
action.payload,
|
||||||
|
'Ignored generator progress for canceled session'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleLog.trace(
|
||||||
|
action.payload,
|
||||||
|
`Generator progress (${action.payload.data.node.type})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { graphExecutionStateComplete } from 'services/events/actions';
|
||||||
|
import { startAppListening } from '../..';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addGraphExecutionStateCompleteListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: graphExecutionStateComplete,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
action.payload,
|
||||||
|
`Session invocation complete (${action.payload.data.graph_execution_state_id})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,74 @@
|
|||||||
|
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
|
||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { invocationComplete } from 'services/events/actions';
|
||||||
|
import { imageMetadataReceived } from 'services/thunks/image';
|
||||||
|
import { sessionCanceled } from 'services/thunks/session';
|
||||||
|
import { isImageOutput } from 'services/types/guards';
|
||||||
|
import { progressImageSet } from 'features/system/store/systemSlice';
|
||||||
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
const nodeDenylist = ['dataURL_image'];
|
||||||
|
|
||||||
|
export const addInvocationCompleteListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: invocationComplete,
|
||||||
|
effect: async (action, { dispatch, getState, take }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
action.payload,
|
||||||
|
`Invocation complete (${action.payload.data.node.type})`
|
||||||
|
);
|
||||||
|
|
||||||
|
const sessionId = action.payload.data.graph_execution_state_id;
|
||||||
|
|
||||||
|
const { cancelType, isCancelScheduled } = getState().system;
|
||||||
|
|
||||||
|
// Handle scheduled cancelation
|
||||||
|
if (cancelType === 'scheduled' && isCancelScheduled) {
|
||||||
|
dispatch(sessionCanceled({ sessionId }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = action.payload;
|
||||||
|
const { result, node, graph_execution_state_id } = data;
|
||||||
|
|
||||||
|
// This complete event has an associated image output
|
||||||
|
if (isImageOutput(result) && !nodeDenylist.includes(node.type)) {
|
||||||
|
const { image_name, image_type } = result.image;
|
||||||
|
|
||||||
|
// Get its metadata
|
||||||
|
dispatch(
|
||||||
|
imageMetadataReceived({
|
||||||
|
imageName: image_name,
|
||||||
|
imageType: image_type,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const [{ payload: imageDTO }] = await take(
|
||||||
|
imageMetadataReceived.fulfilled.match
|
||||||
|
);
|
||||||
|
|
||||||
|
if (getState().gallery.shouldAutoSwitchToNewImages) {
|
||||||
|
dispatch(imageSelected(imageDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle canvas image
|
||||||
|
if (
|
||||||
|
graph_execution_state_id ===
|
||||||
|
getState().canvas.layerState.stagingArea.sessionId
|
||||||
|
) {
|
||||||
|
const [{ payload: image }] = await take(
|
||||||
|
(
|
||||||
|
action
|
||||||
|
): action is ReturnType<typeof imageMetadataReceived.fulfilled> =>
|
||||||
|
imageMetadataReceived.fulfilled.match(action) &&
|
||||||
|
action.payload.image_name === image_name
|
||||||
|
);
|
||||||
|
dispatch(addImageToStagingArea(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(progressImageSet(null));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { invocationError } from 'services/events/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addInvocationErrorListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: invocationError,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.error(
|
||||||
|
action.payload,
|
||||||
|
`Invocation error (${action.payload.data.node.type})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { invocationStarted } from 'services/events/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addInvocationStartedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: invocationStarted,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
if (
|
||||||
|
getState().system.canceledSession ===
|
||||||
|
action.payload.data.graph_execution_state_id
|
||||||
|
) {
|
||||||
|
moduleLog.trace(
|
||||||
|
action.payload,
|
||||||
|
'Ignored invocation started for canceled session'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleLog.debug(
|
||||||
|
action.payload,
|
||||||
|
`Invocation started (${action.payload.data.node.type})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,43 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { socketConnected } from 'services/events/actions';
|
||||||
|
import {
|
||||||
|
receivedResultImagesPage,
|
||||||
|
receivedUploadImagesPage,
|
||||||
|
} from 'services/thunks/gallery';
|
||||||
|
import { receivedModels } from 'services/thunks/model';
|
||||||
|
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addSocketConnectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: socketConnected,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
const { timestamp } = action.payload;
|
||||||
|
|
||||||
|
moduleLog.debug({ timestamp }, 'Connected');
|
||||||
|
|
||||||
|
const { results, uploads, models, nodes, config } = getState();
|
||||||
|
|
||||||
|
const { disabledTabs } = config;
|
||||||
|
|
||||||
|
// These thunks need to be dispatch in middleware; cannot handle in a reducer
|
||||||
|
if (!results.ids.length) {
|
||||||
|
dispatch(receivedResultImagesPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uploads.ids.length) {
|
||||||
|
dispatch(receivedUploadImagesPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!models.ids.length) {
|
||||||
|
dispatch(receivedModels());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodes.schema && !disabledTabs.includes('nodes')) {
|
||||||
|
dispatch(receivedOpenAPISchema());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { socketDisconnected } from 'services/events/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addSocketDisconnectedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: socketDisconnected,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.debug(action.payload, 'Disconnected');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { socketSubscribed } from 'services/events/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addSocketSubscribedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: socketSubscribed,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
action.payload,
|
||||||
|
`Subscribed (${action.payload.sessionId}))`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
import { startAppListening } from '../..';
|
||||||
|
import { log } from 'app/logging/useLogger';
|
||||||
|
import { socketUnsubscribed } from 'services/events/actions';
|
||||||
|
|
||||||
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
|
|
||||||
|
export const addSocketUnsubscribedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: socketUnsubscribed,
|
||||||
|
effect: (action, { dispatch, getState }) => {
|
||||||
|
moduleLog.debug(
|
||||||
|
action.payload,
|
||||||
|
`Unsubscribed (${action.payload.sessionId})`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -1,9 +1,9 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionCreated, sessionInvoked } from 'services/thunks/session';
|
import { sessionCreated } from 'services/thunks/session';
|
||||||
import { buildCanvasGraphComponents } from 'features/nodes/util/graphBuilders/buildCanvasGraph';
|
import { buildCanvasGraphComponents } from 'features/nodes/util/graphBuilders/buildCanvasGraph';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { canvasGraphBuilt } from 'features/nodes/store/actions';
|
import { canvasGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { imageUploaded } from 'services/thunks/image';
|
import { imageUpdated, imageUploaded } from 'services/thunks/image';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { Graph } from 'services/api';
|
import { Graph } from 'services/api';
|
||||||
import {
|
import {
|
||||||
@ -15,12 +15,22 @@ import { getCanvasData } from 'features/canvas/util/getCanvasData';
|
|||||||
import { getCanvasGenerationMode } from 'features/canvas/util/getCanvasGenerationMode';
|
import { getCanvasGenerationMode } from 'features/canvas/util/getCanvasGenerationMode';
|
||||||
import { blobToDataURL } from 'features/canvas/util/blobToDataURL';
|
import { blobToDataURL } from 'features/canvas/util/blobToDataURL';
|
||||||
import openBase64ImageInTab from 'common/util/openBase64ImageInTab';
|
import openBase64ImageInTab from 'common/util/openBase64ImageInTab';
|
||||||
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'invoke' });
|
const moduleLog = log.child({ namespace: 'invoke' });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This listener is responsible for building the canvas graph and blobs when the user invokes the canvas.
|
* This listener is responsible invoking the canvas. This involves a number of steps:
|
||||||
* It is also responsible for uploading the base and mask layers to the server.
|
*
|
||||||
|
* 1. Generate image blobs from the canvas layers
|
||||||
|
* 2. Determine the generation mode from the layers (txt2img, img2img, inpaint)
|
||||||
|
* 3. Build the canvas graph
|
||||||
|
* 4. Create the session with the graph
|
||||||
|
* 5. Upload the init image if necessary
|
||||||
|
* 6. Upload the mask image if necessary
|
||||||
|
* 7. Update the init and mask images with the session ID
|
||||||
|
* 8. Initialize the staging area if not yet initialized
|
||||||
|
* 9. Dispatch the sessionReadyToInvoke action to invoke the session
|
||||||
*/
|
*/
|
||||||
export const addUserInvokedCanvasListener = () => {
|
export const addUserInvokedCanvasListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
@ -70,63 +80,7 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
|
|
||||||
const { rangeNode, iterateNode, baseNode, edges } = graphComponents;
|
const { rangeNode, iterateNode, baseNode, edges } = graphComponents;
|
||||||
|
|
||||||
// Upload the base layer, to be used as init image
|
// Assemble! Note that this graph *does not have the init or mask image set yet!*
|
||||||
const baseFilename = `${uuidv4()}.png`;
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
imageUploaded({
|
|
||||||
imageType: 'intermediates',
|
|
||||||
formData: {
|
|
||||||
file: new File([baseBlob], baseFilename, { type: 'image/png' }),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (baseNode.type === 'img2img' || baseNode.type === 'inpaint') {
|
|
||||||
const [{ payload: basePayload }] = await take(
|
|
||||||
(action): action is ReturnType<typeof imageUploaded.fulfilled> =>
|
|
||||||
imageUploaded.fulfilled.match(action) &&
|
|
||||||
action.meta.arg.formData.file.name === baseFilename
|
|
||||||
);
|
|
||||||
|
|
||||||
const { image_name: baseName, image_type: baseType } =
|
|
||||||
basePayload.response;
|
|
||||||
|
|
||||||
baseNode.image = {
|
|
||||||
image_name: baseName,
|
|
||||||
image_type: baseType,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload the mask layer image
|
|
||||||
const maskFilename = `${uuidv4()}.png`;
|
|
||||||
|
|
||||||
if (baseNode.type === 'inpaint') {
|
|
||||||
dispatch(
|
|
||||||
imageUploaded({
|
|
||||||
imageType: 'intermediates',
|
|
||||||
formData: {
|
|
||||||
file: new File([maskBlob], maskFilename, { type: 'image/png' }),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const [{ payload: maskPayload }] = await take(
|
|
||||||
(action): action is ReturnType<typeof imageUploaded.fulfilled> =>
|
|
||||||
imageUploaded.fulfilled.match(action) &&
|
|
||||||
action.meta.arg.formData.file.name === maskFilename
|
|
||||||
);
|
|
||||||
|
|
||||||
const { image_name: maskName, image_type: maskType } =
|
|
||||||
maskPayload.response;
|
|
||||||
|
|
||||||
baseNode.mask = {
|
|
||||||
image_name: maskName,
|
|
||||||
image_type: maskType,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble!
|
|
||||||
const nodes: Graph['nodes'] = {
|
const nodes: Graph['nodes'] = {
|
||||||
[rangeNode.id]: rangeNode,
|
[rangeNode.id]: rangeNode,
|
||||||
[iterateNode.id]: iterateNode,
|
[iterateNode.id]: iterateNode,
|
||||||
@ -136,15 +90,90 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
const graph = { nodes, edges };
|
const graph = { nodes, edges };
|
||||||
|
|
||||||
dispatch(canvasGraphBuilt(graph));
|
dispatch(canvasGraphBuilt(graph));
|
||||||
moduleLog({ data: graph }, 'Canvas graph built');
|
|
||||||
|
|
||||||
// Actually create the session
|
moduleLog.debug({ data: graph }, 'Canvas graph built');
|
||||||
|
|
||||||
|
// If we are generating img2img or inpaint, we need to upload the init images
|
||||||
|
if (baseNode.type === 'img2img' || baseNode.type === 'inpaint') {
|
||||||
|
const baseFilename = `${uuidv4()}.png`;
|
||||||
|
dispatch(
|
||||||
|
imageUploaded({
|
||||||
|
formData: {
|
||||||
|
file: new File([baseBlob], baseFilename, { type: 'image/png' }),
|
||||||
|
},
|
||||||
|
isIntermediate: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for the image to be uploaded
|
||||||
|
const [{ payload: baseImageDTO }] = await take(
|
||||||
|
(action): action is ReturnType<typeof imageUploaded.fulfilled> =>
|
||||||
|
imageUploaded.fulfilled.match(action) &&
|
||||||
|
action.meta.arg.formData.file.name === baseFilename
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the base node with the image name and type
|
||||||
|
baseNode.image = {
|
||||||
|
image_name: baseImageDTO.image_name,
|
||||||
|
image_type: baseImageDTO.image_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// For inpaint, we also need to upload the mask layer
|
||||||
|
if (baseNode.type === 'inpaint') {
|
||||||
|
const maskFilename = `${uuidv4()}.png`;
|
||||||
|
dispatch(
|
||||||
|
imageUploaded({
|
||||||
|
formData: {
|
||||||
|
file: new File([maskBlob], maskFilename, { type: 'image/png' }),
|
||||||
|
},
|
||||||
|
isIntermediate: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for the mask to be uploaded
|
||||||
|
const [{ payload: maskImageDTO }] = await take(
|
||||||
|
(action): action is ReturnType<typeof imageUploaded.fulfilled> =>
|
||||||
|
imageUploaded.fulfilled.match(action) &&
|
||||||
|
action.meta.arg.formData.file.name === maskFilename
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the base node with the image name and type
|
||||||
|
baseNode.mask = {
|
||||||
|
image_name: maskImageDTO.image_name,
|
||||||
|
image_type: maskImageDTO.image_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the session and wait for response
|
||||||
dispatch(sessionCreated({ graph }));
|
dispatch(sessionCreated({ graph }));
|
||||||
|
const [sessionCreatedAction] = await take(sessionCreated.fulfilled.match);
|
||||||
|
const sessionId = sessionCreatedAction.payload.id;
|
||||||
|
|
||||||
// Wait for the session to be invoked (this is just the HTTP request to start processing)
|
// Associate the init image with the session, now that we have the session ID
|
||||||
const [{ meta }] = await take(sessionInvoked.fulfilled.match);
|
if (
|
||||||
|
(baseNode.type === 'img2img' || baseNode.type === 'inpaint') &&
|
||||||
|
baseNode.image
|
||||||
|
) {
|
||||||
|
dispatch(
|
||||||
|
imageUpdated({
|
||||||
|
imageName: baseNode.image.image_name,
|
||||||
|
imageType: baseNode.image.image_type,
|
||||||
|
requestBody: { session_id: sessionId },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const { sessionId } = meta.arg;
|
// Associate the mask image with the session, now that we have the session ID
|
||||||
|
if (baseNode.type === 'inpaint' && baseNode.mask) {
|
||||||
|
dispatch(
|
||||||
|
imageUpdated({
|
||||||
|
imageName: baseNode.mask.image_name,
|
||||||
|
imageType: baseNode.mask.image_type,
|
||||||
|
requestBody: { session_id: sessionId },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!state.canvas.layerState.stagingArea.boundingBox) {
|
if (!state.canvas.layerState.stagingArea.boundingBox) {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -158,7 +187,11 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flag the session with the canvas session ID
|
||||||
dispatch(canvasSessionIdChanged(sessionId));
|
dispatch(canvasSessionIdChanged(sessionId));
|
||||||
|
|
||||||
|
// We are ready to invoke the session!
|
||||||
|
dispatch(sessionReadyToInvoke());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { sessionCreated } from 'services/thunks/session';
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { imageToImageGraphBuilt } from 'features/nodes/store/actions';
|
import { imageToImageGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'invoke' });
|
const moduleLog = log.child({ namespace: 'invoke' });
|
||||||
|
|
||||||
@ -11,14 +12,18 @@ export const addUserInvokedImageToImageListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
predicate: (action): action is ReturnType<typeof userInvoked> =>
|
predicate: (action): action is ReturnType<typeof userInvoked> =>
|
||||||
userInvoked.match(action) && action.payload === 'img2img',
|
userInvoked.match(action) && action.payload === 'img2img',
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: async (action, { getState, dispatch, take }) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const graph = buildImageToImageGraph(state);
|
const graph = buildImageToImageGraph(state);
|
||||||
dispatch(imageToImageGraphBuilt(graph));
|
dispatch(imageToImageGraphBuilt(graph));
|
||||||
moduleLog({ data: graph }, 'Image to Image graph built');
|
moduleLog.debug({ data: graph }, 'Image to Image graph built');
|
||||||
|
|
||||||
dispatch(sessionCreated({ graph }));
|
dispatch(sessionCreated({ graph }));
|
||||||
|
|
||||||
|
await take(sessionCreated.fulfilled.match);
|
||||||
|
|
||||||
|
dispatch(sessionReadyToInvoke());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { buildNodesGraph } from 'features/nodes/util/graphBuilders/buildNodesGra
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { nodesGraphBuilt } from 'features/nodes/store/actions';
|
import { nodesGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'invoke' });
|
const moduleLog = log.child({ namespace: 'invoke' });
|
||||||
|
|
||||||
@ -11,14 +12,18 @@ export const addUserInvokedNodesListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
predicate: (action): action is ReturnType<typeof userInvoked> =>
|
predicate: (action): action is ReturnType<typeof userInvoked> =>
|
||||||
userInvoked.match(action) && action.payload === 'nodes',
|
userInvoked.match(action) && action.payload === 'nodes',
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: async (action, { getState, dispatch, take }) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const graph = buildNodesGraph(state);
|
const graph = buildNodesGraph(state);
|
||||||
dispatch(nodesGraphBuilt(graph));
|
dispatch(nodesGraphBuilt(graph));
|
||||||
moduleLog({ data: graph }, 'Nodes graph built');
|
moduleLog.debug({ data: graph }, 'Nodes graph built');
|
||||||
|
|
||||||
dispatch(sessionCreated({ graph }));
|
dispatch(sessionCreated({ graph }));
|
||||||
|
|
||||||
|
await take(sessionCreated.fulfilled.match);
|
||||||
|
|
||||||
|
dispatch(sessionReadyToInvoke());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { sessionCreated } from 'services/thunks/session';
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { textToImageGraphBuilt } from 'features/nodes/store/actions';
|
import { textToImageGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'invoke' });
|
const moduleLog = log.child({ namespace: 'invoke' });
|
||||||
|
|
||||||
@ -11,14 +12,20 @@ export const addUserInvokedTextToImageListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
predicate: (action): action is ReturnType<typeof userInvoked> =>
|
predicate: (action): action is ReturnType<typeof userInvoked> =>
|
||||||
userInvoked.match(action) && action.payload === 'txt2img',
|
userInvoked.match(action) && action.payload === 'txt2img',
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: async (action, { getState, dispatch, take }) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const graph = buildTextToImageGraph(state);
|
const graph = buildTextToImageGraph(state);
|
||||||
|
|
||||||
dispatch(textToImageGraphBuilt(graph));
|
dispatch(textToImageGraphBuilt(graph));
|
||||||
moduleLog({ data: graph }, 'Text to Image graph built');
|
|
||||||
|
moduleLog.debug({ data: graph }, 'Text to Image graph built');
|
||||||
|
|
||||||
dispatch(sessionCreated({ graph }));
|
dispatch(sessionCreated({ graph }));
|
||||||
|
|
||||||
|
await take(sessionCreated.fulfilled.match);
|
||||||
|
|
||||||
|
dispatch(sessionReadyToInvoke());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,7 @@ import lightboxReducer from 'features/lightbox/store/lightboxSlice';
|
|||||||
import generationReducer from 'features/parameters/store/generationSlice';
|
import generationReducer from 'features/parameters/store/generationSlice';
|
||||||
import postprocessingReducer from 'features/parameters/store/postprocessingSlice';
|
import postprocessingReducer from 'features/parameters/store/postprocessingSlice';
|
||||||
import systemReducer from 'features/system/store/systemSlice';
|
import systemReducer from 'features/system/store/systemSlice';
|
||||||
|
// import sessionReducer from 'features/system/store/sessionSlice';
|
||||||
import configReducer from 'features/system/store/configSlice';
|
import configReducer from 'features/system/store/configSlice';
|
||||||
import uiReducer from 'features/ui/store/uiSlice';
|
import uiReducer from 'features/ui/store/uiSlice';
|
||||||
import hotkeysReducer from 'features/ui/store/hotkeysSlice';
|
import hotkeysReducer from 'features/ui/store/hotkeysSlice';
|
||||||
@ -46,6 +47,7 @@ const allReducers = {
|
|||||||
ui: uiReducer,
|
ui: uiReducer,
|
||||||
uploads: uploadsReducer,
|
uploads: uploadsReducer,
|
||||||
hotkeys: hotkeysReducer,
|
hotkeys: hotkeysReducer,
|
||||||
|
// session: sessionReducer,
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootReducer = combineReducers(allReducers);
|
const rootReducer = combineReducers(allReducers);
|
||||||
|
@ -68,7 +68,6 @@ const ImageUploader = (props: ImageUploaderProps) => {
|
|||||||
async (file: File) => {
|
async (file: File) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
imageType: 'uploads',
|
|
||||||
formData: { file },
|
formData: { file },
|
||||||
activeTabName,
|
activeTabName,
|
||||||
})
|
})
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
|
import {
|
||||||
|
PayloadAction,
|
||||||
|
createEntityAdapter,
|
||||||
|
createSlice,
|
||||||
|
} from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import {
|
import {
|
||||||
receivedResultImagesPage,
|
receivedResultImagesPage,
|
||||||
IMAGES_PER_PAGE,
|
IMAGES_PER_PAGE,
|
||||||
} from 'services/thunks/gallery';
|
} from 'services/thunks/gallery';
|
||||||
import {
|
|
||||||
imageDeleted,
|
|
||||||
imageMetadataReceived,
|
|
||||||
imageUrlsReceived,
|
|
||||||
} from 'services/thunks/image';
|
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
import { dateComparator } from 'common/util/dateComparator';
|
import { dateComparator } from 'common/util/dateComparator';
|
||||||
|
|
||||||
@ -26,6 +25,7 @@ type AdditionalResultsState = {
|
|||||||
pages: number;
|
pages: number;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
nextPage: number;
|
nextPage: number;
|
||||||
|
upsertedImageCount: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initialResultsState =
|
export const initialResultsState =
|
||||||
@ -34,6 +34,7 @@ export const initialResultsState =
|
|||||||
pages: 0,
|
pages: 0,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
nextPage: 0,
|
nextPage: 0,
|
||||||
|
upsertedImageCount: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ResultsState = typeof initialResultsState;
|
export type ResultsState = typeof initialResultsState;
|
||||||
@ -42,7 +43,10 @@ const resultsSlice = createSlice({
|
|||||||
name: 'results',
|
name: 'results',
|
||||||
initialState: initialResultsState,
|
initialState: initialResultsState,
|
||||||
reducers: {
|
reducers: {
|
||||||
resultAdded: resultsAdapter.upsertOne,
|
resultUpserted: (state, action: PayloadAction<ResultsImageDTO>) => {
|
||||||
|
resultsAdapter.upsertOne(state, action.payload);
|
||||||
|
state.upsertedImageCount += 1;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
/**
|
/**
|
||||||
@ -68,47 +72,6 @@ const resultsSlice = createSlice({
|
|||||||
state.nextPage = items.length < IMAGES_PER_PAGE ? page : page + 1;
|
state.nextPage = items.length < IMAGES_PER_PAGE ? page : page + 1;
|
||||||
state.isLoading = false;
|
state.isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Image Metadata Received - FULFILLED
|
|
||||||
*/
|
|
||||||
builder.addCase(imageMetadataReceived.fulfilled, (state, action) => {
|
|
||||||
const { image_type } = action.payload;
|
|
||||||
|
|
||||||
if (image_type === 'results') {
|
|
||||||
resultsAdapter.upsertOne(state, action.payload as ResultsImageDTO);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Image URLs Received - FULFILLED
|
|
||||||
*/
|
|
||||||
builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
|
|
||||||
const { image_name, image_type, image_url, thumbnail_url } =
|
|
||||||
action.payload;
|
|
||||||
|
|
||||||
if (image_type === 'results') {
|
|
||||||
resultsAdapter.updateOne(state, {
|
|
||||||
id: image_name,
|
|
||||||
changes: {
|
|
||||||
image_url: image_url,
|
|
||||||
thumbnail_url: thumbnail_url,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete Image - PENDING
|
|
||||||
* Pre-emptively remove the image from the gallery
|
|
||||||
*/
|
|
||||||
builder.addCase(imageDeleted.pending, (state, action) => {
|
|
||||||
const { imageType, imageName } = action.meta.arg;
|
|
||||||
|
|
||||||
if (imageType === 'results') {
|
|
||||||
resultsAdapter.removeOne(state, imageName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -120,6 +83,6 @@ export const {
|
|||||||
selectTotal: selectResultsTotal,
|
selectTotal: selectResultsTotal,
|
||||||
} = resultsAdapter.getSelectors<RootState>((state) => state.results);
|
} = resultsAdapter.getSelectors<RootState>((state) => state.results);
|
||||||
|
|
||||||
export const { resultAdded } = resultsSlice.actions;
|
export const { resultUpserted } = resultsSlice.actions;
|
||||||
|
|
||||||
export default resultsSlice.reducer;
|
export default resultsSlice.reducer;
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
|
import {
|
||||||
|
PayloadAction,
|
||||||
|
createEntityAdapter,
|
||||||
|
createSlice,
|
||||||
|
} from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import {
|
import {
|
||||||
receivedUploadImagesPage,
|
receivedUploadImagesPage,
|
||||||
IMAGES_PER_PAGE,
|
IMAGES_PER_PAGE,
|
||||||
} from 'services/thunks/gallery';
|
} from 'services/thunks/gallery';
|
||||||
import { imageDeleted, imageUrlsReceived } from 'services/thunks/image';
|
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api';
|
||||||
import { dateComparator } from 'common/util/dateComparator';
|
import { dateComparator } from 'common/util/dateComparator';
|
||||||
|
|
||||||
@ -23,6 +26,7 @@ type AdditionalUploadsState = {
|
|||||||
pages: number;
|
pages: number;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
nextPage: number;
|
nextPage: number;
|
||||||
|
upsertedImageCount: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initialUploadsState =
|
export const initialUploadsState =
|
||||||
@ -31,6 +35,7 @@ export const initialUploadsState =
|
|||||||
pages: 0,
|
pages: 0,
|
||||||
nextPage: 0,
|
nextPage: 0,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
upsertedImageCount: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type UploadsState = typeof initialUploadsState;
|
export type UploadsState = typeof initialUploadsState;
|
||||||
@ -39,7 +44,10 @@ const uploadsSlice = createSlice({
|
|||||||
name: 'uploads',
|
name: 'uploads',
|
||||||
initialState: initialUploadsState,
|
initialState: initialUploadsState,
|
||||||
reducers: {
|
reducers: {
|
||||||
uploadAdded: uploadsAdapter.upsertOne,
|
uploadUpserted: (state, action: PayloadAction<UploadsImageDTO>) => {
|
||||||
|
uploadsAdapter.upsertOne(state, action.payload);
|
||||||
|
state.upsertedImageCount += 1;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
/**
|
/**
|
||||||
@ -65,36 +73,6 @@ const uploadsSlice = createSlice({
|
|||||||
state.nextPage = items.length < IMAGES_PER_PAGE ? page : page + 1;
|
state.nextPage = items.length < IMAGES_PER_PAGE ? page : page + 1;
|
||||||
state.isLoading = false;
|
state.isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Image URLs Received - FULFILLED
|
|
||||||
*/
|
|
||||||
builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
|
|
||||||
const { image_name, image_type, image_url, thumbnail_url } =
|
|
||||||
action.payload;
|
|
||||||
|
|
||||||
if (image_type === 'uploads') {
|
|
||||||
uploadsAdapter.updateOne(state, {
|
|
||||||
id: image_name,
|
|
||||||
changes: {
|
|
||||||
image_url: image_url,
|
|
||||||
thumbnail_url: thumbnail_url,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete Image - pending
|
|
||||||
* Pre-emptively remove the image from the gallery
|
|
||||||
*/
|
|
||||||
builder.addCase(imageDeleted.pending, (state, action) => {
|
|
||||||
const { imageType, imageName } = action.meta.arg;
|
|
||||||
|
|
||||||
if (imageType === 'uploads') {
|
|
||||||
uploadsAdapter.removeOne(state, imageName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -106,6 +84,6 @@ export const {
|
|||||||
selectTotal: selectUploadsTotal,
|
selectTotal: selectUploadsTotal,
|
||||||
} = uploadsAdapter.getSelectors<RootState>((state) => state.uploads);
|
} = uploadsAdapter.getSelectors<RootState>((state) => state.uploads);
|
||||||
|
|
||||||
export const { uploadAdded } = uploadsSlice.actions;
|
export const { uploadUpserted } = uploadsSlice.actions;
|
||||||
|
|
||||||
export default uploadsSlice.reducer;
|
export default uploadsSlice.reducer;
|
||||||
|
@ -13,7 +13,9 @@ import {
|
|||||||
buildOutputFieldTemplates,
|
buildOutputFieldTemplates,
|
||||||
} from './fieldTemplateBuilders';
|
} from './fieldTemplateBuilders';
|
||||||
|
|
||||||
const invocationDenylist = ['Graph'];
|
const RESERVED_FIELD_NAMES = ['id', 'type', 'meta'];
|
||||||
|
|
||||||
|
const invocationDenylist = ['Graph', 'InvocationMeta'];
|
||||||
|
|
||||||
export const parseSchema = (openAPI: OpenAPIV3.Document) => {
|
export const parseSchema = (openAPI: OpenAPIV3.Document) => {
|
||||||
// filter out non-invocation schemas, plus some tricky invocations for now
|
// filter out non-invocation schemas, plus some tricky invocations for now
|
||||||
@ -73,7 +75,7 @@ export const parseSchema = (openAPI: OpenAPIV3.Document) => {
|
|||||||
(inputsAccumulator, property, propertyName) => {
|
(inputsAccumulator, property, propertyName) => {
|
||||||
if (
|
if (
|
||||||
// `type` and `id` are not valid inputs/outputs
|
// `type` and `id` are not valid inputs/outputs
|
||||||
!['type', 'id'].includes(propertyName) &&
|
!RESERVED_FIELD_NAMES.includes(propertyName) &&
|
||||||
isSchemaObject(property)
|
isSchemaObject(property)
|
||||||
) {
|
) {
|
||||||
const field: InputFieldTemplate | undefined =
|
const field: InputFieldTemplate | undefined =
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
export const sessionReadyToInvoke = createAction('system/sessionReadyToInvoke');
|
@ -0,0 +1,62 @@
|
|||||||
|
// TODO: split system slice inot this
|
||||||
|
|
||||||
|
// import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
// import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
// import { socketSubscribed, socketUnsubscribed } from 'services/events/actions';
|
||||||
|
|
||||||
|
// export type SessionState = {
|
||||||
|
// /**
|
||||||
|
// * The current socket session id
|
||||||
|
// */
|
||||||
|
// sessionId: string;
|
||||||
|
// /**
|
||||||
|
// * Whether the current session is a canvas session. Needed to manage the staging area.
|
||||||
|
// */
|
||||||
|
// isCanvasSession: boolean;
|
||||||
|
// /**
|
||||||
|
// * When a session is canceled, its ID is stored here until a new session is created.
|
||||||
|
// */
|
||||||
|
// canceledSessionId: string;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export const initialSessionState: SessionState = {
|
||||||
|
// sessionId: '',
|
||||||
|
// isCanvasSession: false,
|
||||||
|
// canceledSessionId: '',
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export const sessionSlice = createSlice({
|
||||||
|
// name: 'session',
|
||||||
|
// initialState: initialSessionState,
|
||||||
|
// reducers: {
|
||||||
|
// sessionIdChanged: (state, action: PayloadAction<string>) => {
|
||||||
|
// state.sessionId = action.payload;
|
||||||
|
// },
|
||||||
|
// isCanvasSessionChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
|
// state.isCanvasSession = action.payload;
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// extraReducers: (builder) => {
|
||||||
|
// /**
|
||||||
|
// * Socket Subscribed
|
||||||
|
// */
|
||||||
|
// builder.addCase(socketSubscribed, (state, action) => {
|
||||||
|
// state.sessionId = action.payload.sessionId;
|
||||||
|
// state.canceledSessionId = '';
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Socket Unsubscribed
|
||||||
|
// */
|
||||||
|
// builder.addCase(socketUnsubscribed, (state) => {
|
||||||
|
// state.sessionId = '';
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// export const { sessionIdChanged, isCanvasSessionChanged } =
|
||||||
|
// sessionSlice.actions;
|
||||||
|
|
||||||
|
// export default sessionSlice.reducer;
|
||||||
|
|
||||||
|
export default {};
|
@ -1,5 +1,5 @@
|
|||||||
import { UseToastOptions } from '@chakra-ui/react';
|
import { UseToastOptions } from '@chakra-ui/react';
|
||||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
import { PayloadAction, isAnyOf } from '@reduxjs/toolkit';
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import * as InvokeAI from 'app/types/invokeai';
|
import * as InvokeAI from 'app/types/invokeai';
|
||||||
import {
|
import {
|
||||||
@ -16,7 +16,11 @@ import {
|
|||||||
|
|
||||||
import { ProgressImage } from 'services/events/types';
|
import { ProgressImage } from 'services/events/types';
|
||||||
import { makeToast } from '../../../app/components/Toaster';
|
import { makeToast } from '../../../app/components/Toaster';
|
||||||
import { sessionCanceled, sessionInvoked } from 'services/thunks/session';
|
import {
|
||||||
|
sessionCanceled,
|
||||||
|
sessionCreated,
|
||||||
|
sessionInvoked,
|
||||||
|
} from 'services/thunks/session';
|
||||||
import { receivedModels } from 'services/thunks/model';
|
import { receivedModels } from 'services/thunks/model';
|
||||||
import { parsedOpenAPISchema } from 'features/nodes/store/nodesSlice';
|
import { parsedOpenAPISchema } from 'features/nodes/store/nodesSlice';
|
||||||
import { LogLevelName } from 'roarr';
|
import { LogLevelName } from 'roarr';
|
||||||
@ -215,6 +219,9 @@ export const systemSlice = createSlice({
|
|||||||
languageChanged: (state, action: PayloadAction<keyof typeof LANGUAGES>) => {
|
languageChanged: (state, action: PayloadAction<keyof typeof LANGUAGES>) => {
|
||||||
state.language = action.payload;
|
state.language = action.payload;
|
||||||
},
|
},
|
||||||
|
progressImageSet(state, action: PayloadAction<ProgressImage | null>) {
|
||||||
|
state.progressImage = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers(builder) {
|
extraReducers(builder) {
|
||||||
/**
|
/**
|
||||||
@ -305,7 +312,6 @@ export const systemSlice = createSlice({
|
|||||||
state.currentStep = 0;
|
state.currentStep = 0;
|
||||||
state.totalSteps = 0;
|
state.totalSteps = 0;
|
||||||
state.statusTranslationKey = 'common.statusProcessingComplete';
|
state.statusTranslationKey = 'common.statusProcessingComplete';
|
||||||
state.progressImage = null;
|
|
||||||
|
|
||||||
if (state.canceledSession === data.graph_execution_state_id) {
|
if (state.canceledSession === data.graph_execution_state_id) {
|
||||||
state.isProcessing = false;
|
state.isProcessing = false;
|
||||||
@ -343,15 +349,8 @@ export const systemSlice = createSlice({
|
|||||||
state.statusTranslationKey = 'common.statusPreparing';
|
state.statusTranslationKey = 'common.statusPreparing';
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.addCase(sessionInvoked.rejected, (state, action) => {
|
|
||||||
const error = action.payload as string | undefined;
|
|
||||||
state.toastQueue.push(
|
|
||||||
makeToast({ title: error || t('toast.serverError'), status: 'error' })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session Canceled
|
* Session Canceled - FULFILLED
|
||||||
*/
|
*/
|
||||||
builder.addCase(sessionCanceled.fulfilled, (state, action) => {
|
builder.addCase(sessionCanceled.fulfilled, (state, action) => {
|
||||||
state.canceledSession = action.meta.arg.sessionId;
|
state.canceledSession = action.meta.arg.sessionId;
|
||||||
@ -414,6 +413,26 @@ export const systemSlice = createSlice({
|
|||||||
builder.addCase(imageUploaded.fulfilled, (state) => {
|
builder.addCase(imageUploaded.fulfilled, (state) => {
|
||||||
state.isUploading = false;
|
state.isUploading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// *** Matchers - must be after all cases ***
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session Invoked - REJECTED
|
||||||
|
* Session Created - REJECTED
|
||||||
|
*/
|
||||||
|
builder.addMatcher(isAnySessionRejected, (state, action) => {
|
||||||
|
state.isProcessing = false;
|
||||||
|
state.isCancelable = false;
|
||||||
|
state.isCancelScheduled = false;
|
||||||
|
state.currentStep = 0;
|
||||||
|
state.totalSteps = 0;
|
||||||
|
state.statusTranslationKey = 'common.statusConnected';
|
||||||
|
state.progressImage = null;
|
||||||
|
|
||||||
|
state.toastQueue.push(
|
||||||
|
makeToast({ title: t('toast.serverError'), status: 'error' })
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -438,6 +457,12 @@ export const {
|
|||||||
isPersistedChanged,
|
isPersistedChanged,
|
||||||
shouldAntialiasProgressImageChanged,
|
shouldAntialiasProgressImageChanged,
|
||||||
languageChanged,
|
languageChanged,
|
||||||
|
progressImageSet,
|
||||||
} = systemSlice.actions;
|
} = systemSlice.actions;
|
||||||
|
|
||||||
export default systemSlice.reducer;
|
export default systemSlice.reducer;
|
||||||
|
|
||||||
|
const isAnySessionRejected = isAnyOf(
|
||||||
|
sessionCreated.rejected,
|
||||||
|
sessionInvoked.rejected
|
||||||
|
);
|
||||||
|
@ -7,7 +7,6 @@ export { OpenAPI } from './core/OpenAPI';
|
|||||||
export type { OpenAPIConfig } from './core/OpenAPI';
|
export type { OpenAPIConfig } from './core/OpenAPI';
|
||||||
|
|
||||||
export type { AddInvocation } from './models/AddInvocation';
|
export type { AddInvocation } from './models/AddInvocation';
|
||||||
export type { BlurInvocation } from './models/BlurInvocation';
|
|
||||||
export type { Body_upload_image } from './models/Body_upload_image';
|
export type { Body_upload_image } from './models/Body_upload_image';
|
||||||
export type { CkptModelInfo } from './models/CkptModelInfo';
|
export type { CkptModelInfo } from './models/CkptModelInfo';
|
||||||
export type { CollectInvocation } from './models/CollectInvocation';
|
export type { CollectInvocation } from './models/CollectInvocation';
|
||||||
@ -17,7 +16,6 @@ export type { CompelInvocation } from './models/CompelInvocation';
|
|||||||
export type { CompelOutput } from './models/CompelOutput';
|
export type { CompelOutput } from './models/CompelOutput';
|
||||||
export type { ConditioningField } from './models/ConditioningField';
|
export type { ConditioningField } from './models/ConditioningField';
|
||||||
export type { CreateModelRequest } from './models/CreateModelRequest';
|
export type { CreateModelRequest } from './models/CreateModelRequest';
|
||||||
export type { CropImageInvocation } from './models/CropImageInvocation';
|
|
||||||
export type { CvInpaintInvocation } from './models/CvInpaintInvocation';
|
export type { CvInpaintInvocation } from './models/CvInpaintInvocation';
|
||||||
export type { DiffusersModelInfo } from './models/DiffusersModelInfo';
|
export type { DiffusersModelInfo } from './models/DiffusersModelInfo';
|
||||||
export type { DivideInvocation } from './models/DivideInvocation';
|
export type { DivideInvocation } from './models/DivideInvocation';
|
||||||
@ -28,11 +26,20 @@ export type { GraphExecutionState } from './models/GraphExecutionState';
|
|||||||
export type { GraphInvocation } from './models/GraphInvocation';
|
export type { GraphInvocation } from './models/GraphInvocation';
|
||||||
export type { GraphInvocationOutput } from './models/GraphInvocationOutput';
|
export type { GraphInvocationOutput } from './models/GraphInvocationOutput';
|
||||||
export type { HTTPValidationError } from './models/HTTPValidationError';
|
export type { HTTPValidationError } from './models/HTTPValidationError';
|
||||||
|
export type { ImageBlurInvocation } from './models/ImageBlurInvocation';
|
||||||
export type { ImageCategory } from './models/ImageCategory';
|
export type { ImageCategory } from './models/ImageCategory';
|
||||||
|
export type { ImageChannelInvocation } from './models/ImageChannelInvocation';
|
||||||
|
export type { ImageConvertInvocation } from './models/ImageConvertInvocation';
|
||||||
|
export type { ImageCropInvocation } from './models/ImageCropInvocation';
|
||||||
export type { ImageDTO } from './models/ImageDTO';
|
export type { ImageDTO } from './models/ImageDTO';
|
||||||
export type { ImageField } from './models/ImageField';
|
export type { ImageField } from './models/ImageField';
|
||||||
|
export type { ImageInverseLerpInvocation } from './models/ImageInverseLerpInvocation';
|
||||||
|
export type { ImageLerpInvocation } from './models/ImageLerpInvocation';
|
||||||
export type { ImageMetadata } from './models/ImageMetadata';
|
export type { ImageMetadata } from './models/ImageMetadata';
|
||||||
|
export type { ImageMultiplyInvocation } from './models/ImageMultiplyInvocation';
|
||||||
export type { ImageOutput } from './models/ImageOutput';
|
export type { ImageOutput } from './models/ImageOutput';
|
||||||
|
export type { ImagePasteInvocation } from './models/ImagePasteInvocation';
|
||||||
|
export type { ImageRecordChanges } from './models/ImageRecordChanges';
|
||||||
export type { ImageToImageInvocation } from './models/ImageToImageInvocation';
|
export type { ImageToImageInvocation } from './models/ImageToImageInvocation';
|
||||||
export type { ImageToLatentsInvocation } from './models/ImageToLatentsInvocation';
|
export type { ImageToLatentsInvocation } from './models/ImageToLatentsInvocation';
|
||||||
export type { ImageType } from './models/ImageType';
|
export type { ImageType } from './models/ImageType';
|
||||||
@ -43,14 +50,12 @@ export type { InfillTileInvocation } from './models/InfillTileInvocation';
|
|||||||
export type { InpaintInvocation } from './models/InpaintInvocation';
|
export type { InpaintInvocation } from './models/InpaintInvocation';
|
||||||
export type { IntCollectionOutput } from './models/IntCollectionOutput';
|
export type { IntCollectionOutput } from './models/IntCollectionOutput';
|
||||||
export type { IntOutput } from './models/IntOutput';
|
export type { IntOutput } from './models/IntOutput';
|
||||||
export type { InverseLerpInvocation } from './models/InverseLerpInvocation';
|
|
||||||
export type { IterateInvocation } from './models/IterateInvocation';
|
export type { IterateInvocation } from './models/IterateInvocation';
|
||||||
export type { IterateInvocationOutput } from './models/IterateInvocationOutput';
|
export type { IterateInvocationOutput } from './models/IterateInvocationOutput';
|
||||||
export type { LatentsField } from './models/LatentsField';
|
export type { LatentsField } from './models/LatentsField';
|
||||||
export type { LatentsOutput } from './models/LatentsOutput';
|
export type { LatentsOutput } from './models/LatentsOutput';
|
||||||
export type { LatentsToImageInvocation } from './models/LatentsToImageInvocation';
|
export type { LatentsToImageInvocation } from './models/LatentsToImageInvocation';
|
||||||
export type { LatentsToLatentsInvocation } from './models/LatentsToLatentsInvocation';
|
export type { LatentsToLatentsInvocation } from './models/LatentsToLatentsInvocation';
|
||||||
export type { LerpInvocation } from './models/LerpInvocation';
|
|
||||||
export type { LoadImageInvocation } from './models/LoadImageInvocation';
|
export type { LoadImageInvocation } from './models/LoadImageInvocation';
|
||||||
export type { MaskFromAlphaInvocation } from './models/MaskFromAlphaInvocation';
|
export type { MaskFromAlphaInvocation } from './models/MaskFromAlphaInvocation';
|
||||||
export type { MaskOutput } from './models/MaskOutput';
|
export type { MaskOutput } from './models/MaskOutput';
|
||||||
@ -61,7 +66,6 @@ export type { NoiseOutput } from './models/NoiseOutput';
|
|||||||
export type { PaginatedResults_GraphExecutionState_ } from './models/PaginatedResults_GraphExecutionState_';
|
export type { PaginatedResults_GraphExecutionState_ } from './models/PaginatedResults_GraphExecutionState_';
|
||||||
export type { PaginatedResults_ImageDTO_ } from './models/PaginatedResults_ImageDTO_';
|
export type { PaginatedResults_ImageDTO_ } from './models/PaginatedResults_ImageDTO_';
|
||||||
export type { ParamIntInvocation } from './models/ParamIntInvocation';
|
export type { ParamIntInvocation } from './models/ParamIntInvocation';
|
||||||
export type { PasteImageInvocation } from './models/PasteImageInvocation';
|
|
||||||
export type { PromptOutput } from './models/PromptOutput';
|
export type { PromptOutput } from './models/PromptOutput';
|
||||||
export type { RandomIntInvocation } from './models/RandomIntInvocation';
|
export type { RandomIntInvocation } from './models/RandomIntInvocation';
|
||||||
export type { RandomRangeInvocation } from './models/RandomRangeInvocation';
|
export type { RandomRangeInvocation } from './models/RandomRangeInvocation';
|
||||||
|
@ -10,6 +10,10 @@ export type AddInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'add';
|
type?: 'add';
|
||||||
/**
|
/**
|
||||||
* The first number
|
* The first number
|
||||||
|
@ -10,6 +10,10 @@ export type CollectInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'collect';
|
type?: 'collect';
|
||||||
/**
|
/**
|
||||||
* The item to collect (all inputs must be of the same type)
|
* The item to collect (all inputs must be of the same type)
|
||||||
|
@ -10,6 +10,10 @@ export type CompelInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'compel';
|
type?: 'compel';
|
||||||
/**
|
/**
|
||||||
* Prompt
|
* Prompt
|
||||||
|
@ -12,6 +12,10 @@ export type CvInpaintInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'cv_inpaint';
|
type?: 'cv_inpaint';
|
||||||
/**
|
/**
|
||||||
* The image to inpaint
|
* The image to inpaint
|
||||||
|
@ -10,6 +10,10 @@ export type DivideInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'div';
|
type?: 'div';
|
||||||
/**
|
/**
|
||||||
* The first number
|
* The first number
|
||||||
|
@ -3,31 +3,34 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
import type { AddInvocation } from './AddInvocation';
|
import type { AddInvocation } from './AddInvocation';
|
||||||
import type { BlurInvocation } from './BlurInvocation';
|
|
||||||
import type { CollectInvocation } from './CollectInvocation';
|
import type { CollectInvocation } from './CollectInvocation';
|
||||||
import type { CompelInvocation } from './CompelInvocation';
|
import type { CompelInvocation } from './CompelInvocation';
|
||||||
import type { CropImageInvocation } from './CropImageInvocation';
|
|
||||||
import type { CvInpaintInvocation } from './CvInpaintInvocation';
|
import type { CvInpaintInvocation } from './CvInpaintInvocation';
|
||||||
import type { DivideInvocation } from './DivideInvocation';
|
import type { DivideInvocation } from './DivideInvocation';
|
||||||
import type { Edge } from './Edge';
|
import type { Edge } from './Edge';
|
||||||
import type { GraphInvocation } from './GraphInvocation';
|
import type { GraphInvocation } from './GraphInvocation';
|
||||||
|
import type { ImageBlurInvocation } from './ImageBlurInvocation';
|
||||||
|
import type { ImageChannelInvocation } from './ImageChannelInvocation';
|
||||||
|
import type { ImageConvertInvocation } from './ImageConvertInvocation';
|
||||||
|
import type { ImageCropInvocation } from './ImageCropInvocation';
|
||||||
|
import type { ImageInverseLerpInvocation } from './ImageInverseLerpInvocation';
|
||||||
|
import type { ImageLerpInvocation } from './ImageLerpInvocation';
|
||||||
|
import type { ImageMultiplyInvocation } from './ImageMultiplyInvocation';
|
||||||
|
import type { ImagePasteInvocation } from './ImagePasteInvocation';
|
||||||
import type { ImageToImageInvocation } from './ImageToImageInvocation';
|
import type { ImageToImageInvocation } from './ImageToImageInvocation';
|
||||||
import type { ImageToLatentsInvocation } from './ImageToLatentsInvocation';
|
import type { ImageToLatentsInvocation } from './ImageToLatentsInvocation';
|
||||||
import type { InfillColorInvocation } from './InfillColorInvocation';
|
import type { InfillColorInvocation } from './InfillColorInvocation';
|
||||||
import type { InfillPatchMatchInvocation } from './InfillPatchMatchInvocation';
|
import type { InfillPatchMatchInvocation } from './InfillPatchMatchInvocation';
|
||||||
import type { InfillTileInvocation } from './InfillTileInvocation';
|
import type { InfillTileInvocation } from './InfillTileInvocation';
|
||||||
import type { InpaintInvocation } from './InpaintInvocation';
|
import type { InpaintInvocation } from './InpaintInvocation';
|
||||||
import type { InverseLerpInvocation } from './InverseLerpInvocation';
|
|
||||||
import type { IterateInvocation } from './IterateInvocation';
|
import type { IterateInvocation } from './IterateInvocation';
|
||||||
import type { LatentsToImageInvocation } from './LatentsToImageInvocation';
|
import type { LatentsToImageInvocation } from './LatentsToImageInvocation';
|
||||||
import type { LatentsToLatentsInvocation } from './LatentsToLatentsInvocation';
|
import type { LatentsToLatentsInvocation } from './LatentsToLatentsInvocation';
|
||||||
import type { LerpInvocation } from './LerpInvocation';
|
|
||||||
import type { LoadImageInvocation } from './LoadImageInvocation';
|
import type { LoadImageInvocation } from './LoadImageInvocation';
|
||||||
import type { MaskFromAlphaInvocation } from './MaskFromAlphaInvocation';
|
import type { MaskFromAlphaInvocation } from './MaskFromAlphaInvocation';
|
||||||
import type { MultiplyInvocation } from './MultiplyInvocation';
|
import type { MultiplyInvocation } from './MultiplyInvocation';
|
||||||
import type { NoiseInvocation } from './NoiseInvocation';
|
import type { NoiseInvocation } from './NoiseInvocation';
|
||||||
import type { ParamIntInvocation } from './ParamIntInvocation';
|
import type { ParamIntInvocation } from './ParamIntInvocation';
|
||||||
import type { PasteImageInvocation } from './PasteImageInvocation';
|
|
||||||
import type { RandomIntInvocation } from './RandomIntInvocation';
|
import type { RandomIntInvocation } from './RandomIntInvocation';
|
||||||
import type { RandomRangeInvocation } from './RandomRangeInvocation';
|
import type { RandomRangeInvocation } from './RandomRangeInvocation';
|
||||||
import type { RangeInvocation } from './RangeInvocation';
|
import type { RangeInvocation } from './RangeInvocation';
|
||||||
@ -49,7 +52,7 @@ export type Graph = {
|
|||||||
/**
|
/**
|
||||||
* The nodes in this graph
|
* The nodes in this graph
|
||||||
*/
|
*/
|
||||||
nodes?: Record<string, (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | CompelInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | RandomIntInvocation | ParamIntInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | ImageToLatentsInvocation | CvInpaintInvocation | RangeInvocation | RangeOfSizeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | InfillColorInvocation | InfillTileInvocation | InfillPatchMatchInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation)>;
|
nodes?: Record<string, (LoadImageInvocation | ShowImageInvocation | ImageCropInvocation | ImagePasteInvocation | MaskFromAlphaInvocation | ImageMultiplyInvocation | ImageChannelInvocation | ImageConvertInvocation | ImageBlurInvocation | ImageLerpInvocation | ImageInverseLerpInvocation | CompelInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | RandomIntInvocation | ParamIntInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | ImageToLatentsInvocation | CvInpaintInvocation | RangeInvocation | RangeOfSizeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | InfillColorInvocation | InfillTileInvocation | InfillPatchMatchInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation)>;
|
||||||
/**
|
/**
|
||||||
* The connections between nodes and their fields in this graph
|
* The connections between nodes and their fields in this graph
|
||||||
*/
|
*/
|
||||||
|
@ -5,14 +5,17 @@
|
|||||||
import type { Graph } from './Graph';
|
import type { Graph } from './Graph';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node to process inputs and produce outputs.
|
* Execute a graph
|
||||||
* May use dependency injection in __init__ to receive providers.
|
|
||||||
*/
|
*/
|
||||||
export type GraphInvocation = {
|
export type GraphInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'graph';
|
type?: 'graph';
|
||||||
/**
|
/**
|
||||||
* The graph to run
|
* The graph to run
|
||||||
|
@ -7,12 +7,16 @@ import type { ImageField } from './ImageField';
|
|||||||
/**
|
/**
|
||||||
* Blurs an image
|
* Blurs an image
|
||||||
*/
|
*/
|
||||||
export type BlurInvocation = {
|
export type ImageBlurInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
type?: 'blur';
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_blur';
|
||||||
/**
|
/**
|
||||||
* The image to blur
|
* The image to blur
|
||||||
*/
|
*/
|
@ -5,4 +5,4 @@
|
|||||||
/**
|
/**
|
||||||
* The category of an image. Use ImageCategory.OTHER for non-default categories.
|
* The category of an image. Use ImageCategory.OTHER for non-default categories.
|
||||||
*/
|
*/
|
||||||
export type ImageCategory = 'general' | 'control' | 'other';
|
export type ImageCategory = 'general' | 'control' | 'mask' | 'other';
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { ImageField } from './ImageField';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a channel from an image.
|
||||||
|
*/
|
||||||
|
export type ImageChannelInvocation = {
|
||||||
|
/**
|
||||||
|
* The id of this node. Must be unique among all nodes.
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_chan';
|
||||||
|
/**
|
||||||
|
* The image to get the channel from
|
||||||
|
*/
|
||||||
|
image?: ImageField;
|
||||||
|
/**
|
||||||
|
* The channel to get
|
||||||
|
*/
|
||||||
|
channel?: 'A' | 'R' | 'G' | 'B';
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,29 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { ImageField } from './ImageField';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an image to a different mode.
|
||||||
|
*/
|
||||||
|
export type ImageConvertInvocation = {
|
||||||
|
/**
|
||||||
|
* The id of this node. Must be unique among all nodes.
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_conv';
|
||||||
|
/**
|
||||||
|
* The image to convert
|
||||||
|
*/
|
||||||
|
image?: ImageField;
|
||||||
|
/**
|
||||||
|
* The mode to convert to
|
||||||
|
*/
|
||||||
|
mode?: 'L' | 'RGB' | 'RGBA' | 'CMYK' | 'YCbCr' | 'LAB' | 'HSV' | 'I' | 'F';
|
||||||
|
};
|
||||||
|
|
@ -7,12 +7,16 @@ import type { ImageField } from './ImageField';
|
|||||||
/**
|
/**
|
||||||
* Crops an image to a specified box. The box can be outside of the image.
|
* Crops an image to a specified box. The box can be outside of the image.
|
||||||
*/
|
*/
|
||||||
export type CropImageInvocation = {
|
export type ImageCropInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
type?: 'crop';
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_crop';
|
||||||
/**
|
/**
|
||||||
* The image to crop
|
* The image to crop
|
||||||
*/
|
*/
|
@ -50,6 +50,10 @@ export type ImageDTO = {
|
|||||||
* The deleted timestamp of the image.
|
* The deleted timestamp of the image.
|
||||||
*/
|
*/
|
||||||
deleted_at?: string;
|
deleted_at?: string;
|
||||||
|
/**
|
||||||
|
* Whether this is an intermediate image.
|
||||||
|
*/
|
||||||
|
is_intermediate: boolean;
|
||||||
/**
|
/**
|
||||||
* The session ID that generated this image, if it is a generated image.
|
* The session ID that generated this image, if it is a generated image.
|
||||||
*/
|
*/
|
||||||
|
@ -7,12 +7,16 @@ import type { ImageField } from './ImageField';
|
|||||||
/**
|
/**
|
||||||
* Inverse linear interpolation of all pixels of an image
|
* Inverse linear interpolation of all pixels of an image
|
||||||
*/
|
*/
|
||||||
export type InverseLerpInvocation = {
|
export type ImageInverseLerpInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
type?: 'ilerp';
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_ilerp';
|
||||||
/**
|
/**
|
||||||
* The image to lerp
|
* The image to lerp
|
||||||
*/
|
*/
|
@ -7,12 +7,16 @@ import type { ImageField } from './ImageField';
|
|||||||
/**
|
/**
|
||||||
* Linear interpolation of all pixels of an image
|
* Linear interpolation of all pixels of an image
|
||||||
*/
|
*/
|
||||||
export type LerpInvocation = {
|
export type ImageLerpInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
type?: 'lerp';
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_lerp';
|
||||||
/**
|
/**
|
||||||
* The image to lerp
|
* The image to lerp
|
||||||
*/
|
*/
|
@ -0,0 +1,29 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { ImageField } from './ImageField';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies two images together using `PIL.ImageChops.multiply()`.
|
||||||
|
*/
|
||||||
|
export type ImageMultiplyInvocation = {
|
||||||
|
/**
|
||||||
|
* The id of this node. Must be unique among all nodes.
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_mul';
|
||||||
|
/**
|
||||||
|
* The first image to multiply
|
||||||
|
*/
|
||||||
|
image1?: ImageField;
|
||||||
|
/**
|
||||||
|
* The second image to multiply
|
||||||
|
*/
|
||||||
|
image2?: ImageField;
|
||||||
|
};
|
||||||
|
|
@ -7,12 +7,16 @@ import type { ImageField } from './ImageField';
|
|||||||
/**
|
/**
|
||||||
* Pastes an image into another image.
|
* Pastes an image into another image.
|
||||||
*/
|
*/
|
||||||
export type PasteImageInvocation = {
|
export type ImagePasteInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
type?: 'paste';
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
|
type?: 'img_paste';
|
||||||
/**
|
/**
|
||||||
* The base image
|
* The base image
|
||||||
*/
|
*/
|
@ -0,0 +1,24 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { ImageCategory } from './ImageCategory';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of changes to apply to an image record.
|
||||||
|
*
|
||||||
|
* Only limited changes are valid:
|
||||||
|
* - `image_category`: change the category of an image
|
||||||
|
* - `session_id`: change the session associated with an image
|
||||||
|
*/
|
||||||
|
export type ImageRecordChanges = {
|
||||||
|
/**
|
||||||
|
* The image's new category.
|
||||||
|
*/
|
||||||
|
image_category?: ImageCategory;
|
||||||
|
/**
|
||||||
|
* The image's new session ID.
|
||||||
|
*/
|
||||||
|
session_id?: string;
|
||||||
|
};
|
||||||
|
|
@ -12,6 +12,10 @@ export type ImageToImageInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'img2img';
|
type?: 'img2img';
|
||||||
/**
|
/**
|
||||||
* The prompt to generate an image from
|
* The prompt to generate an image from
|
||||||
|
@ -12,6 +12,10 @@ export type ImageToLatentsInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'i2l';
|
type?: 'i2l';
|
||||||
/**
|
/**
|
||||||
* The image to encode
|
* The image to encode
|
||||||
|
@ -5,4 +5,4 @@
|
|||||||
/**
|
/**
|
||||||
* The type of an image.
|
* The type of an image.
|
||||||
*/
|
*/
|
||||||
export type ImageType = 'results' | 'uploads' | 'intermediates';
|
export type ImageType = 'results' | 'uploads';
|
||||||
|
@ -13,6 +13,10 @@ export type InfillColorInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'infill_rgba';
|
type?: 'infill_rgba';
|
||||||
/**
|
/**
|
||||||
* The image to infill
|
* The image to infill
|
||||||
|
@ -12,6 +12,10 @@ export type InfillPatchMatchInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'infill_patchmatch';
|
type?: 'infill_patchmatch';
|
||||||
/**
|
/**
|
||||||
* The image to infill
|
* The image to infill
|
||||||
|
@ -12,6 +12,10 @@ export type InfillTileInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'infill_tile';
|
type?: 'infill_tile';
|
||||||
/**
|
/**
|
||||||
* The image to infill
|
* The image to infill
|
||||||
|
@ -13,6 +13,10 @@ export type InpaintInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'inpaint';
|
type?: 'inpaint';
|
||||||
/**
|
/**
|
||||||
* The prompt to generate an image from
|
* The prompt to generate an image from
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node to process inputs and produce outputs.
|
* Iterates over a list of items
|
||||||
* May use dependency injection in __init__ to receive providers.
|
|
||||||
*/
|
*/
|
||||||
export type IterateInvocation = {
|
export type IterateInvocation = {
|
||||||
/**
|
/**
|
||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'iterate';
|
type?: 'iterate';
|
||||||
/**
|
/**
|
||||||
* The list of items to iterate over
|
* The list of items to iterate over
|
||||||
|
@ -12,6 +12,10 @@ export type LatentsToImageInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'l2i';
|
type?: 'l2i';
|
||||||
/**
|
/**
|
||||||
* The latents to generate an image from
|
* The latents to generate an image from
|
||||||
|
@ -13,6 +13,10 @@ export type LatentsToLatentsInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'l2l';
|
type?: 'l2l';
|
||||||
/**
|
/**
|
||||||
* Positive conditioning for generation
|
* Positive conditioning for generation
|
||||||
@ -42,14 +46,6 @@ export type LatentsToLatentsInvocation = {
|
|||||||
* The model to use (currently ignored)
|
* The model to use (currently ignored)
|
||||||
*/
|
*/
|
||||||
model?: string;
|
model?: string;
|
||||||
/**
|
|
||||||
* Whether or not to generate an image that can tile without seams
|
|
||||||
*/
|
|
||||||
seamless?: boolean;
|
|
||||||
/**
|
|
||||||
* The axes to tile the image on, 'x' and/or 'y'
|
|
||||||
*/
|
|
||||||
seamless_axes?: string;
|
|
||||||
/**
|
/**
|
||||||
* The latents to use as a base image
|
* The latents to use as a base image
|
||||||
*/
|
*/
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
import type { ImageType } from './ImageType';
|
import type { ImageField } from './ImageField';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an image and provide it as output.
|
* Load an image and provide it as output.
|
||||||
@ -12,14 +12,14 @@ export type LoadImageInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'load_image';
|
type?: 'load_image';
|
||||||
/**
|
/**
|
||||||
* The type of the image
|
* The image to load
|
||||||
*/
|
*/
|
||||||
image_type: ImageType;
|
image?: ImageField;
|
||||||
/**
|
|
||||||
* The name of the image
|
|
||||||
*/
|
|
||||||
image_name: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ export type MaskFromAlphaInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'tomask';
|
type?: 'tomask';
|
||||||
/**
|
/**
|
||||||
* The image to create the mask from
|
* The image to create the mask from
|
||||||
|
@ -10,6 +10,10 @@ export type MultiplyInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'mul';
|
type?: 'mul';
|
||||||
/**
|
/**
|
||||||
* The first number
|
* The first number
|
||||||
|
@ -10,6 +10,10 @@ export type NoiseInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'noise';
|
type?: 'noise';
|
||||||
/**
|
/**
|
||||||
* The seed to use
|
* The seed to use
|
||||||
|
@ -10,6 +10,10 @@ export type ParamIntInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'param_int';
|
type?: 'param_int';
|
||||||
/**
|
/**
|
||||||
* The integer value
|
* The integer value
|
||||||
|
@ -10,6 +10,10 @@ export type RandomIntInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'rand_int';
|
type?: 'rand_int';
|
||||||
/**
|
/**
|
||||||
* The inclusive low value
|
* The inclusive low value
|
||||||
|
@ -10,6 +10,10 @@ export type RandomRangeInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'random_range';
|
type?: 'random_range';
|
||||||
/**
|
/**
|
||||||
* The inclusive low value
|
* The inclusive low value
|
||||||
|
@ -10,6 +10,10 @@ export type RangeInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'range';
|
type?: 'range';
|
||||||
/**
|
/**
|
||||||
* The start of the range
|
* The start of the range
|
||||||
|
@ -10,6 +10,10 @@ export type RangeOfSizeInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'range_of_size';
|
type?: 'range_of_size';
|
||||||
/**
|
/**
|
||||||
* The start of the range
|
* The start of the range
|
||||||
|
@ -12,6 +12,10 @@ export type ResizeLatentsInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'lresize';
|
type?: 'lresize';
|
||||||
/**
|
/**
|
||||||
* The latents to resize
|
* The latents to resize
|
||||||
|
@ -12,6 +12,10 @@ export type RestoreFaceInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'restore_face';
|
type?: 'restore_face';
|
||||||
/**
|
/**
|
||||||
* The input image
|
* The input image
|
||||||
|
@ -12,6 +12,10 @@ export type ScaleLatentsInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'lscale';
|
type?: 'lscale';
|
||||||
/**
|
/**
|
||||||
* The latents to scale
|
* The latents to scale
|
||||||
|
@ -12,6 +12,10 @@ export type ShowImageInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'show_image';
|
type?: 'show_image';
|
||||||
/**
|
/**
|
||||||
* The image to show
|
* The image to show
|
||||||
|
@ -10,6 +10,10 @@ export type SubtractInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'sub';
|
type?: 'sub';
|
||||||
/**
|
/**
|
||||||
* The first number
|
* The first number
|
||||||
|
@ -10,6 +10,10 @@ export type TextToImageInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'txt2img';
|
type?: 'txt2img';
|
||||||
/**
|
/**
|
||||||
* The prompt to generate an image from
|
* The prompt to generate an image from
|
||||||
|
@ -13,6 +13,10 @@ export type TextToLatentsInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 't2l';
|
type?: 't2l';
|
||||||
/**
|
/**
|
||||||
* Positive conditioning for generation
|
* Positive conditioning for generation
|
||||||
@ -42,13 +46,5 @@ export type TextToLatentsInvocation = {
|
|||||||
* The model to use (currently ignored)
|
* The model to use (currently ignored)
|
||||||
*/
|
*/
|
||||||
model?: string;
|
model?: string;
|
||||||
/**
|
|
||||||
* Whether or not to generate an image that can tile without seams
|
|
||||||
*/
|
|
||||||
seamless?: boolean;
|
|
||||||
/**
|
|
||||||
* The axes to tile the image on, 'x' and/or 'y'
|
|
||||||
*/
|
|
||||||
seamless_axes?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ export type UpscaleInvocation = {
|
|||||||
* The id of this node. Must be unique among all nodes.
|
* The id of this node. Must be unique among all nodes.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Whether or not this node is an intermediate node.
|
||||||
|
*/
|
||||||
|
is_intermediate?: boolean;
|
||||||
type?: 'upscale';
|
type?: 'upscale';
|
||||||
/**
|
/**
|
||||||
* The input image
|
* The input image
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import type { Body_upload_image } from '../models/Body_upload_image';
|
import type { Body_upload_image } from '../models/Body_upload_image';
|
||||||
import type { ImageCategory } from '../models/ImageCategory';
|
import type { ImageCategory } from '../models/ImageCategory';
|
||||||
import type { ImageDTO } from '../models/ImageDTO';
|
import type { ImageDTO } from '../models/ImageDTO';
|
||||||
|
import type { ImageRecordChanges } from '../models/ImageRecordChanges';
|
||||||
import type { ImageType } from '../models/ImageType';
|
import type { ImageType } from '../models/ImageType';
|
||||||
import type { ImageUrlsDTO } from '../models/ImageUrlsDTO';
|
import type { ImageUrlsDTO } from '../models/ImageUrlsDTO';
|
||||||
import type { PaginatedResults_ImageDTO_ } from '../models/PaginatedResults_ImageDTO_';
|
import type { PaginatedResults_ImageDTO_ } from '../models/PaginatedResults_ImageDTO_';
|
||||||
@ -65,20 +66,32 @@ export class ImagesService {
|
|||||||
* @throws ApiError
|
* @throws ApiError
|
||||||
*/
|
*/
|
||||||
public static uploadImage({
|
public static uploadImage({
|
||||||
imageType,
|
|
||||||
formData,
|
formData,
|
||||||
imageCategory,
|
imageCategory,
|
||||||
|
isIntermediate = false,
|
||||||
|
sessionId,
|
||||||
}: {
|
}: {
|
||||||
imageType: ImageType,
|
|
||||||
formData: Body_upload_image,
|
formData: Body_upload_image,
|
||||||
|
/**
|
||||||
|
* The category of the image
|
||||||
|
*/
|
||||||
imageCategory?: ImageCategory,
|
imageCategory?: ImageCategory,
|
||||||
|
/**
|
||||||
|
* Whether this is an intermediate image
|
||||||
|
*/
|
||||||
|
isIntermediate?: boolean,
|
||||||
|
/**
|
||||||
|
* The session ID associated with this upload, if any
|
||||||
|
*/
|
||||||
|
sessionId?: string,
|
||||||
}): CancelablePromise<ImageDTO> {
|
}): CancelablePromise<ImageDTO> {
|
||||||
return __request(OpenAPI, {
|
return __request(OpenAPI, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/api/v1/images/',
|
url: '/api/v1/images/',
|
||||||
query: {
|
query: {
|
||||||
'image_type': imageType,
|
|
||||||
'image_category': imageCategory,
|
'image_category': imageCategory,
|
||||||
|
'is_intermediate': isIntermediate,
|
||||||
|
'session_id': sessionId,
|
||||||
},
|
},
|
||||||
formData: formData,
|
formData: formData,
|
||||||
mediaType: 'multipart/form-data',
|
mediaType: 'multipart/form-data',
|
||||||
@ -132,6 +145,9 @@ export class ImagesService {
|
|||||||
imageType,
|
imageType,
|
||||||
imageName,
|
imageName,
|
||||||
}: {
|
}: {
|
||||||
|
/**
|
||||||
|
* The type of image to delete
|
||||||
|
*/
|
||||||
imageType: ImageType,
|
imageType: ImageType,
|
||||||
/**
|
/**
|
||||||
* The name of the image to delete
|
* The name of the image to delete
|
||||||
@ -151,6 +167,42 @@ export class ImagesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Image
|
||||||
|
* Updates an image
|
||||||
|
* @returns ImageDTO Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static updateImage({
|
||||||
|
imageType,
|
||||||
|
imageName,
|
||||||
|
requestBody,
|
||||||
|
}: {
|
||||||
|
/**
|
||||||
|
* The type of image to update
|
||||||
|
*/
|
||||||
|
imageType: ImageType,
|
||||||
|
/**
|
||||||
|
* The name of the image to update
|
||||||
|
*/
|
||||||
|
imageName: string,
|
||||||
|
requestBody: ImageRecordChanges,
|
||||||
|
}): CancelablePromise<ImageDTO> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'PATCH',
|
||||||
|
url: '/api/v1/images/{image_type}/{image_name}',
|
||||||
|
path: {
|
||||||
|
'image_type': imageType,
|
||||||
|
'image_name': imageName,
|
||||||
|
},
|
||||||
|
body: requestBody,
|
||||||
|
mediaType: 'application/json',
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Image Metadata
|
* Get Image Metadata
|
||||||
* Gets an image's metadata
|
* Gets an image's metadata
|
||||||
|
@ -2,34 +2,37 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import type { AddInvocation } from '../models/AddInvocation';
|
import type { AddInvocation } from '../models/AddInvocation';
|
||||||
import type { BlurInvocation } from '../models/BlurInvocation';
|
|
||||||
import type { CollectInvocation } from '../models/CollectInvocation';
|
import type { CollectInvocation } from '../models/CollectInvocation';
|
||||||
import type { CompelInvocation } from '../models/CompelInvocation';
|
import type { CompelInvocation } from '../models/CompelInvocation';
|
||||||
import type { CropImageInvocation } from '../models/CropImageInvocation';
|
|
||||||
import type { CvInpaintInvocation } from '../models/CvInpaintInvocation';
|
import type { CvInpaintInvocation } from '../models/CvInpaintInvocation';
|
||||||
import type { DivideInvocation } from '../models/DivideInvocation';
|
import type { DivideInvocation } from '../models/DivideInvocation';
|
||||||
import type { Edge } from '../models/Edge';
|
import type { Edge } from '../models/Edge';
|
||||||
import type { Graph } from '../models/Graph';
|
import type { Graph } from '../models/Graph';
|
||||||
import type { GraphExecutionState } from '../models/GraphExecutionState';
|
import type { GraphExecutionState } from '../models/GraphExecutionState';
|
||||||
import type { GraphInvocation } from '../models/GraphInvocation';
|
import type { GraphInvocation } from '../models/GraphInvocation';
|
||||||
|
import type { ImageBlurInvocation } from '../models/ImageBlurInvocation';
|
||||||
|
import type { ImageChannelInvocation } from '../models/ImageChannelInvocation';
|
||||||
|
import type { ImageConvertInvocation } from '../models/ImageConvertInvocation';
|
||||||
|
import type { ImageCropInvocation } from '../models/ImageCropInvocation';
|
||||||
|
import type { ImageInverseLerpInvocation } from '../models/ImageInverseLerpInvocation';
|
||||||
|
import type { ImageLerpInvocation } from '../models/ImageLerpInvocation';
|
||||||
|
import type { ImageMultiplyInvocation } from '../models/ImageMultiplyInvocation';
|
||||||
|
import type { ImagePasteInvocation } from '../models/ImagePasteInvocation';
|
||||||
import type { ImageToImageInvocation } from '../models/ImageToImageInvocation';
|
import type { ImageToImageInvocation } from '../models/ImageToImageInvocation';
|
||||||
import type { ImageToLatentsInvocation } from '../models/ImageToLatentsInvocation';
|
import type { ImageToLatentsInvocation } from '../models/ImageToLatentsInvocation';
|
||||||
import type { InfillColorInvocation } from '../models/InfillColorInvocation';
|
import type { InfillColorInvocation } from '../models/InfillColorInvocation';
|
||||||
import type { InfillPatchMatchInvocation } from '../models/InfillPatchMatchInvocation';
|
import type { InfillPatchMatchInvocation } from '../models/InfillPatchMatchInvocation';
|
||||||
import type { InfillTileInvocation } from '../models/InfillTileInvocation';
|
import type { InfillTileInvocation } from '../models/InfillTileInvocation';
|
||||||
import type { InpaintInvocation } from '../models/InpaintInvocation';
|
import type { InpaintInvocation } from '../models/InpaintInvocation';
|
||||||
import type { InverseLerpInvocation } from '../models/InverseLerpInvocation';
|
|
||||||
import type { IterateInvocation } from '../models/IterateInvocation';
|
import type { IterateInvocation } from '../models/IterateInvocation';
|
||||||
import type { LatentsToImageInvocation } from '../models/LatentsToImageInvocation';
|
import type { LatentsToImageInvocation } from '../models/LatentsToImageInvocation';
|
||||||
import type { LatentsToLatentsInvocation } from '../models/LatentsToLatentsInvocation';
|
import type { LatentsToLatentsInvocation } from '../models/LatentsToLatentsInvocation';
|
||||||
import type { LerpInvocation } from '../models/LerpInvocation';
|
|
||||||
import type { LoadImageInvocation } from '../models/LoadImageInvocation';
|
import type { LoadImageInvocation } from '../models/LoadImageInvocation';
|
||||||
import type { MaskFromAlphaInvocation } from '../models/MaskFromAlphaInvocation';
|
import type { MaskFromAlphaInvocation } from '../models/MaskFromAlphaInvocation';
|
||||||
import type { MultiplyInvocation } from '../models/MultiplyInvocation';
|
import type { MultiplyInvocation } from '../models/MultiplyInvocation';
|
||||||
import type { NoiseInvocation } from '../models/NoiseInvocation';
|
import type { NoiseInvocation } from '../models/NoiseInvocation';
|
||||||
import type { PaginatedResults_GraphExecutionState_ } from '../models/PaginatedResults_GraphExecutionState_';
|
import type { PaginatedResults_GraphExecutionState_ } from '../models/PaginatedResults_GraphExecutionState_';
|
||||||
import type { ParamIntInvocation } from '../models/ParamIntInvocation';
|
import type { ParamIntInvocation } from '../models/ParamIntInvocation';
|
||||||
import type { PasteImageInvocation } from '../models/PasteImageInvocation';
|
|
||||||
import type { RandomIntInvocation } from '../models/RandomIntInvocation';
|
import type { RandomIntInvocation } from '../models/RandomIntInvocation';
|
||||||
import type { RandomRangeInvocation } from '../models/RandomRangeInvocation';
|
import type { RandomRangeInvocation } from '../models/RandomRangeInvocation';
|
||||||
import type { RangeInvocation } from '../models/RangeInvocation';
|
import type { RangeInvocation } from '../models/RangeInvocation';
|
||||||
@ -151,7 +154,7 @@ export class SessionsService {
|
|||||||
* The id of the session
|
* The id of the session
|
||||||
*/
|
*/
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
requestBody: (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | CompelInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | RandomIntInvocation | ParamIntInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | ImageToLatentsInvocation | CvInpaintInvocation | RangeInvocation | RangeOfSizeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | InfillColorInvocation | InfillTileInvocation | InfillPatchMatchInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation),
|
requestBody: (LoadImageInvocation | ShowImageInvocation | ImageCropInvocation | ImagePasteInvocation | MaskFromAlphaInvocation | ImageMultiplyInvocation | ImageChannelInvocation | ImageConvertInvocation | ImageBlurInvocation | ImageLerpInvocation | ImageInverseLerpInvocation | CompelInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | RandomIntInvocation | ParamIntInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | ImageToLatentsInvocation | CvInpaintInvocation | RangeInvocation | RangeOfSizeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | InfillColorInvocation | InfillTileInvocation | InfillPatchMatchInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation),
|
||||||
}): CancelablePromise<string> {
|
}): CancelablePromise<string> {
|
||||||
return __request(OpenAPI, {
|
return __request(OpenAPI, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -188,7 +191,7 @@ export class SessionsService {
|
|||||||
* The path to the node in the graph
|
* The path to the node in the graph
|
||||||
*/
|
*/
|
||||||
nodePath: string,
|
nodePath: string,
|
||||||
requestBody: (LoadImageInvocation | ShowImageInvocation | CropImageInvocation | PasteImageInvocation | MaskFromAlphaInvocation | BlurInvocation | LerpInvocation | InverseLerpInvocation | CompelInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | RandomIntInvocation | ParamIntInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | ImageToLatentsInvocation | CvInpaintInvocation | RangeInvocation | RangeOfSizeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | InfillColorInvocation | InfillTileInvocation | InfillPatchMatchInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation),
|
requestBody: (LoadImageInvocation | ShowImageInvocation | ImageCropInvocation | ImagePasteInvocation | MaskFromAlphaInvocation | ImageMultiplyInvocation | ImageChannelInvocation | ImageConvertInvocation | ImageBlurInvocation | ImageLerpInvocation | ImageInverseLerpInvocation | CompelInvocation | AddInvocation | SubtractInvocation | MultiplyInvocation | DivideInvocation | RandomIntInvocation | ParamIntInvocation | NoiseInvocation | TextToLatentsInvocation | LatentsToImageInvocation | ResizeLatentsInvocation | ScaleLatentsInvocation | ImageToLatentsInvocation | CvInpaintInvocation | RangeInvocation | RangeOfSizeInvocation | RandomRangeInvocation | UpscaleInvocation | RestoreFaceInvocation | TextToImageInvocation | InfillColorInvocation | InfillTileInvocation | InfillPatchMatchInvocation | GraphInvocation | IterateInvocation | CollectInvocation | LatentsToLatentsInvocation | ImageToImageInvocation | InpaintInvocation),
|
||||||
}): CancelablePromise<GraphExecutionState> {
|
}): CancelablePromise<GraphExecutionState> {
|
||||||
return __request(OpenAPI, {
|
return __request(OpenAPI, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
import { socketSubscribed, socketUnsubscribed } from './actions';
|
import { socketSubscribed, socketUnsubscribed } from './actions';
|
||||||
import { AppThunkDispatch, RootState } from 'app/store/store';
|
import { AppThunkDispatch, RootState } from 'app/store/store';
|
||||||
import { getTimestamp } from 'common/util/getTimestamp';
|
import { getTimestamp } from 'common/util/getTimestamp';
|
||||||
import { sessionInvoked, sessionCreated } from 'services/thunks/session';
|
import { sessionCreated } from 'services/thunks/session';
|
||||||
import { OpenAPI } from 'services/api';
|
import { OpenAPI } from 'services/api';
|
||||||
import { setEventListeners } from 'services/events/util/setEventListeners';
|
import { setEventListeners } from 'services/events/util/setEventListeners';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
@ -64,15 +64,9 @@ export const socketMiddleware = () => {
|
|||||||
|
|
||||||
if (sessionCreated.fulfilled.match(action)) {
|
if (sessionCreated.fulfilled.match(action)) {
|
||||||
const sessionId = action.payload.id;
|
const sessionId = action.payload.id;
|
||||||
const sessionLog = socketioLog.child({ sessionId });
|
|
||||||
const oldSessionId = getState().system.sessionId;
|
const oldSessionId = getState().system.sessionId;
|
||||||
|
|
||||||
if (oldSessionId) {
|
if (oldSessionId) {
|
||||||
sessionLog.debug(
|
|
||||||
{ oldSessionId },
|
|
||||||
`Unsubscribed from old session (${oldSessionId})`
|
|
||||||
);
|
|
||||||
|
|
||||||
socket.emit('unsubscribe', {
|
socket.emit('unsubscribe', {
|
||||||
session: oldSessionId,
|
session: oldSessionId,
|
||||||
});
|
});
|
||||||
@ -85,8 +79,6 @@ export const socketMiddleware = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionLog.debug(`Subscribe to new session (${sessionId})`);
|
|
||||||
|
|
||||||
socket.emit('subscribe', { session: sessionId });
|
socket.emit('subscribe', { session: sessionId });
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -95,9 +87,6 @@ export const socketMiddleware = () => {
|
|||||||
timestamp: getTimestamp(),
|
timestamp: getTimestamp(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Finally we actually invoke the session, starting processing
|
|
||||||
dispatch(sessionInvoked({ sessionId }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next(action);
|
next(action);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { MiddlewareAPI } from '@reduxjs/toolkit';
|
import { MiddlewareAPI } from '@reduxjs/toolkit';
|
||||||
import { AppDispatch, RootState } from 'app/store/store';
|
import { AppDispatch, RootState } from 'app/store/store';
|
||||||
import { getTimestamp } from 'common/util/getTimestamp';
|
import { getTimestamp } from 'common/util/getTimestamp';
|
||||||
import { sessionCanceled } from 'services/thunks/session';
|
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import {
|
import {
|
||||||
generatorProgress,
|
generatorProgress,
|
||||||
@ -16,12 +15,6 @@ import {
|
|||||||
import { ClientToServerEvents, ServerToClientEvents } from '../types';
|
import { ClientToServerEvents, ServerToClientEvents } from '../types';
|
||||||
import { Logger } from 'roarr';
|
import { Logger } from 'roarr';
|
||||||
import { JsonObject } from 'roarr/dist/types';
|
import { JsonObject } from 'roarr/dist/types';
|
||||||
import {
|
|
||||||
receivedResultImagesPage,
|
|
||||||
receivedUploadImagesPage,
|
|
||||||
} from 'services/thunks/gallery';
|
|
||||||
import { receivedModels } from 'services/thunks/model';
|
|
||||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
|
||||||
import { makeToast } from '../../../app/components/Toaster';
|
import { makeToast } from '../../../app/components/Toaster';
|
||||||
import { addToast } from '../../../features/system/store/systemSlice';
|
import { addToast } from '../../../features/system/store/systemSlice';
|
||||||
|
|
||||||
@ -43,37 +36,13 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
|
|
||||||
dispatch(socketConnected({ timestamp: getTimestamp() }));
|
dispatch(socketConnected({ timestamp: getTimestamp() }));
|
||||||
|
|
||||||
const { results, uploads, models, nodes, config, system } = getState();
|
const { sessionId } = getState().system;
|
||||||
|
|
||||||
const { disabledTabs } = config;
|
if (sessionId) {
|
||||||
|
socket.emit('subscribe', { session: sessionId });
|
||||||
// These thunks need to be dispatch in middleware; cannot handle in a reducer
|
|
||||||
if (!results.ids.length) {
|
|
||||||
dispatch(receivedResultImagesPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!uploads.ids.length) {
|
|
||||||
dispatch(receivedUploadImagesPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!models.ids.length) {
|
|
||||||
dispatch(receivedModels());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nodes.schema && !disabledTabs.includes('nodes')) {
|
|
||||||
dispatch(receivedOpenAPISchema());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (system.sessionId) {
|
|
||||||
log.debug(
|
|
||||||
{ sessionId: system.sessionId },
|
|
||||||
`Subscribed to existing session (${system.sessionId})`
|
|
||||||
);
|
|
||||||
|
|
||||||
socket.emit('subscribe', { session: system.sessionId });
|
|
||||||
dispatch(
|
dispatch(
|
||||||
socketSubscribed({
|
socketSubscribed({
|
||||||
sessionId: system.sessionId,
|
sessionId,
|
||||||
timestamp: getTimestamp(),
|
timestamp: getTimestamp(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -101,7 +70,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
* Disconnect
|
* Disconnect
|
||||||
*/
|
*/
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
log.debug('Disconnected');
|
|
||||||
dispatch(socketDisconnected({ timestamp: getTimestamp() }));
|
dispatch(socketDisconnected({ timestamp: getTimestamp() }));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -109,18 +77,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
* Invocation started
|
* Invocation started
|
||||||
*/
|
*/
|
||||||
socket.on('invocation_started', (data) => {
|
socket.on('invocation_started', (data) => {
|
||||||
if (getState().system.canceledSession === data.graph_execution_state_id) {
|
|
||||||
log.trace(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Ignored invocation started (${data.node.type}) for canceled session (${data.graph_execution_state_id})`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Invocation started (${data.node.type})`
|
|
||||||
);
|
|
||||||
dispatch(invocationStarted({ data, timestamp: getTimestamp() }));
|
dispatch(invocationStarted({ data, timestamp: getTimestamp() }));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -128,18 +84,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
* Generator progress
|
* Generator progress
|
||||||
*/
|
*/
|
||||||
socket.on('generator_progress', (data) => {
|
socket.on('generator_progress', (data) => {
|
||||||
if (getState().system.canceledSession === data.graph_execution_state_id) {
|
|
||||||
log.trace(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Ignored generator progress (${data.node.type}) for canceled session (${data.graph_execution_state_id})`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.trace(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Generator progress (${data.node.type})`
|
|
||||||
);
|
|
||||||
dispatch(generatorProgress({ data, timestamp: getTimestamp() }));
|
dispatch(generatorProgress({ data, timestamp: getTimestamp() }));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -147,10 +91,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
* Invocation error
|
* Invocation error
|
||||||
*/
|
*/
|
||||||
socket.on('invocation_error', (data) => {
|
socket.on('invocation_error', (data) => {
|
||||||
log.error(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Invocation error (${data.node.type})`
|
|
||||||
);
|
|
||||||
dispatch(invocationError({ data, timestamp: getTimestamp() }));
|
dispatch(invocationError({ data, timestamp: getTimestamp() }));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -158,19 +98,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
* Invocation complete
|
* Invocation complete
|
||||||
*/
|
*/
|
||||||
socket.on('invocation_complete', (data) => {
|
socket.on('invocation_complete', (data) => {
|
||||||
log.info(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Invocation complete (${data.node.type})`
|
|
||||||
);
|
|
||||||
const sessionId = data.graph_execution_state_id;
|
|
||||||
|
|
||||||
const { cancelType, isCancelScheduled } = getState().system;
|
|
||||||
|
|
||||||
// Handle scheduled cancelation
|
|
||||||
if (cancelType === 'scheduled' && isCancelScheduled) {
|
|
||||||
dispatch(sessionCanceled({ sessionId }));
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
invocationComplete({
|
invocationComplete({
|
||||||
data,
|
data,
|
||||||
@ -183,10 +110,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
|
|||||||
* Graph complete
|
* Graph complete
|
||||||
*/
|
*/
|
||||||
socket.on('graph_execution_state_complete', (data) => {
|
socket.on('graph_execution_state_complete', (data) => {
|
||||||
log.info(
|
|
||||||
{ data, sessionId: data.graph_execution_state_id },
|
|
||||||
`Graph execution state complete (${data.graph_execution_state_id})`
|
|
||||||
);
|
|
||||||
dispatch(graphExecutionStateComplete({ data, timestamp: getTimestamp() }));
|
dispatch(graphExecutionStateComplete({ data, timestamp: getTimestamp() }));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,45 +1,64 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
|
||||||
import { createAppAsyncThunk } from 'app/store/storeUtils';
|
import { createAppAsyncThunk } from 'app/store/storeUtils';
|
||||||
import { ImagesService } from 'services/api';
|
import { ImagesService, PaginatedResults_ImageDTO_ } from 'services/api';
|
||||||
|
|
||||||
export const IMAGES_PER_PAGE = 20;
|
export const IMAGES_PER_PAGE = 20;
|
||||||
|
|
||||||
const galleryLog = log.child({ namespace: 'gallery' });
|
type ReceivedResultImagesPageThunkConfig = {
|
||||||
|
rejectValue: {
|
||||||
|
error: unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const receivedResultImagesPage = createAppAsyncThunk(
|
export const receivedResultImagesPage = createAppAsyncThunk<
|
||||||
|
PaginatedResults_ImageDTO_,
|
||||||
|
void,
|
||||||
|
ReceivedResultImagesPageThunkConfig
|
||||||
|
>(
|
||||||
'results/receivedResultImagesPage',
|
'results/receivedResultImagesPage',
|
||||||
async (_arg, { getState, rejectWithValue }) => {
|
async (_arg, { getState, rejectWithValue }) => {
|
||||||
const { page, pages, nextPage } = getState().results;
|
const { page, pages, nextPage, upsertedImageCount } = getState().results;
|
||||||
|
|
||||||
if (nextPage === page) {
|
// If many images have been upserted, we need to offset the page number
|
||||||
rejectWithValue([]);
|
// TODO: add an offset param to the list images endpoint
|
||||||
}
|
const pageOffset = Math.floor(upsertedImageCount / IMAGES_PER_PAGE);
|
||||||
|
|
||||||
const response = await ImagesService.listImagesWithMetadata({
|
const response = await ImagesService.listImagesWithMetadata({
|
||||||
imageType: 'results',
|
imageType: 'results',
|
||||||
imageCategory: 'general',
|
imageCategory: 'general',
|
||||||
page: getState().results.nextPage,
|
page: nextPage + pageOffset,
|
||||||
perPage: IMAGES_PER_PAGE,
|
perPage: IMAGES_PER_PAGE,
|
||||||
});
|
});
|
||||||
|
|
||||||
galleryLog.info({ response }, `Received ${response.items.length} results`);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const receivedUploadImagesPage = createAppAsyncThunk(
|
type ReceivedUploadImagesPageThunkConfig = {
|
||||||
|
rejectValue: {
|
||||||
|
error: unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const receivedUploadImagesPage = createAppAsyncThunk<
|
||||||
|
PaginatedResults_ImageDTO_,
|
||||||
|
void,
|
||||||
|
ReceivedUploadImagesPageThunkConfig
|
||||||
|
>(
|
||||||
'uploads/receivedUploadImagesPage',
|
'uploads/receivedUploadImagesPage',
|
||||||
async (_arg, { getState }) => {
|
async (_arg, { getState, rejectWithValue }) => {
|
||||||
|
const { page, pages, nextPage, upsertedImageCount } = getState().uploads;
|
||||||
|
|
||||||
|
// If many images have been upserted, we need to offset the page number
|
||||||
|
// TODO: add an offset param to the list images endpoint
|
||||||
|
const pageOffset = Math.floor(upsertedImageCount / IMAGES_PER_PAGE);
|
||||||
|
|
||||||
const response = await ImagesService.listImagesWithMetadata({
|
const response = await ImagesService.listImagesWithMetadata({
|
||||||
imageType: 'uploads',
|
imageType: 'uploads',
|
||||||
imageCategory: 'general',
|
imageCategory: 'general',
|
||||||
page: getState().uploads.nextPage,
|
page: nextPage + pageOffset,
|
||||||
perPage: IMAGES_PER_PAGE,
|
perPage: IMAGES_PER_PAGE,
|
||||||
});
|
});
|
||||||
|
|
||||||
galleryLog.info({ response }, `Received ${response.items.length} uploads`);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
|
||||||
import { createAppAsyncThunk } from 'app/store/storeUtils';
|
import { createAppAsyncThunk } from 'app/store/storeUtils';
|
||||||
import { InvokeTabName } from 'features/ui/store/tabMap';
|
import { InvokeTabName } from 'features/ui/store/tabMap';
|
||||||
import { ImagesService } from 'services/api';
|
import { ImagesService } from 'services/api';
|
||||||
import { getHeaders } from 'services/util/getHeaders';
|
|
||||||
|
|
||||||
const imagesLog = log.child({ namespace: 'image' });
|
|
||||||
|
|
||||||
type imageUrlsReceivedArg = Parameters<
|
type imageUrlsReceivedArg = Parameters<
|
||||||
(typeof ImagesService)['getImageUrls']
|
(typeof ImagesService)['getImageUrls']
|
||||||
@ -17,7 +13,6 @@ export const imageUrlsReceived = createAppAsyncThunk(
|
|||||||
'api/imageUrlsReceived',
|
'api/imageUrlsReceived',
|
||||||
async (arg: imageUrlsReceivedArg) => {
|
async (arg: imageUrlsReceivedArg) => {
|
||||||
const response = await ImagesService.getImageUrls(arg);
|
const response = await ImagesService.getImageUrls(arg);
|
||||||
imagesLog.info({ arg, response }, 'Received image urls');
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -33,7 +28,6 @@ export const imageMetadataReceived = createAppAsyncThunk(
|
|||||||
'api/imageMetadataReceived',
|
'api/imageMetadataReceived',
|
||||||
async (arg: imageMetadataReceivedArg) => {
|
async (arg: imageMetadataReceivedArg) => {
|
||||||
const response = await ImagesService.getImageMetadata(arg);
|
const response = await ImagesService.getImageMetadata(arg);
|
||||||
imagesLog.info({ arg, response }, 'Received image record');
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -53,11 +47,7 @@ export const imageUploaded = createAppAsyncThunk(
|
|||||||
// strip out `activeTabName` from arg - the route does not need it
|
// strip out `activeTabName` from arg - the route does not need it
|
||||||
const { activeTabName, ...rest } = arg;
|
const { activeTabName, ...rest } = arg;
|
||||||
const response = await ImagesService.uploadImage(rest);
|
const response = await ImagesService.uploadImage(rest);
|
||||||
const { location } = getHeaders(response);
|
return response;
|
||||||
|
|
||||||
imagesLog.debug({ arg: '<Blob>', response, location }, 'Image uploaded');
|
|
||||||
|
|
||||||
return { response, location };
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -70,9 +60,19 @@ export const imageDeleted = createAppAsyncThunk(
|
|||||||
'api/imageDeleted',
|
'api/imageDeleted',
|
||||||
async (arg: ImageDeletedArg) => {
|
async (arg: ImageDeletedArg) => {
|
||||||
const response = await ImagesService.deleteImage(arg);
|
const response = await ImagesService.deleteImage(arg);
|
||||||
|
return response;
|
||||||
imagesLog.debug({ arg, response }, 'Image deleted');
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type ImageUpdatedArg = Parameters<(typeof ImagesService)['updateImage']>[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `ImagesService.updateImage()` thunk
|
||||||
|
*/
|
||||||
|
export const imageUpdated = createAppAsyncThunk(
|
||||||
|
'api/imageUpdated',
|
||||||
|
async (arg: ImageUpdatedArg) => {
|
||||||
|
const response = await ImagesService.updateImage(arg);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user