Merge branch 'main' into fix/ui/control-adapter-translation-string

This commit is contained in:
blessedcoolant 2023-10-15 18:16:48 +05:30 committed by GitHub
commit 3ad1226d1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 847 additions and 714 deletions

View File

@ -152,6 +152,7 @@ async def import_model(
) -> ImportModelResponse: ) -> ImportModelResponse:
"""Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically""" """Add a model using its local path, repo_id, or remote URL. Model characteristics will be probed and configured automatically"""
location = location.strip("\"' ")
items_to_import = {location} items_to_import = {location}
prediction_types = {x.value: x for x in SchedulerPredictionType} prediction_types = {x.value: x for x in SchedulerPredictionType}
logger = ApiDependencies.invoker.services.logger logger = ApiDependencies.invoker.services.logger

View File

@ -46,6 +46,8 @@ class FaceResultData(TypedDict):
y_center: float y_center: float
mesh_width: int mesh_width: int
mesh_height: int mesh_height: int
chunk_x_offset: int
chunk_y_offset: int
class FaceResultDataWithId(FaceResultData): class FaceResultDataWithId(FaceResultData):
@ -78,6 +80,48 @@ FONT_SIZE = 32
FONT_STROKE_WIDTH = 4 FONT_STROKE_WIDTH = 4
def coalesce_faces(face1: FaceResultData, face2: FaceResultData) -> FaceResultData:
face1_x_offset = face1["chunk_x_offset"] - min(face1["chunk_x_offset"], face2["chunk_x_offset"])
face2_x_offset = face2["chunk_x_offset"] - min(face1["chunk_x_offset"], face2["chunk_x_offset"])
face1_y_offset = face1["chunk_y_offset"] - min(face1["chunk_y_offset"], face2["chunk_y_offset"])
face2_y_offset = face2["chunk_y_offset"] - min(face1["chunk_y_offset"], face2["chunk_y_offset"])
new_im_width = (
max(face1["image"].width, face2["image"].width)
+ max(face1["chunk_x_offset"], face2["chunk_x_offset"])
- min(face1["chunk_x_offset"], face2["chunk_x_offset"])
)
new_im_height = (
max(face1["image"].height, face2["image"].height)
+ max(face1["chunk_y_offset"], face2["chunk_y_offset"])
- min(face1["chunk_y_offset"], face2["chunk_y_offset"])
)
pil_image = Image.new(mode=face1["image"].mode, size=(new_im_width, new_im_height))
pil_image.paste(face1["image"], (face1_x_offset, face1_y_offset))
pil_image.paste(face2["image"], (face2_x_offset, face2_y_offset))
# Mask images are always from the origin
new_mask_im_width = max(face1["mask"].width, face2["mask"].width)
new_mask_im_height = max(face1["mask"].height, face2["mask"].height)
mask_pil = create_white_image(new_mask_im_width, new_mask_im_height)
black_image = create_black_image(face1["mask"].width, face1["mask"].height)
mask_pil.paste(black_image, (0, 0), ImageOps.invert(face1["mask"]))
black_image = create_black_image(face2["mask"].width, face2["mask"].height)
mask_pil.paste(black_image, (0, 0), ImageOps.invert(face2["mask"]))
new_face = FaceResultData(
image=pil_image,
mask=mask_pil,
x_center=max(face1["x_center"], face2["x_center"]),
y_center=max(face1["y_center"], face2["y_center"]),
mesh_width=max(face1["mesh_width"], face2["mesh_width"]),
mesh_height=max(face1["mesh_height"], face2["mesh_height"]),
chunk_x_offset=max(face1["chunk_x_offset"], face2["chunk_x_offset"]),
chunk_y_offset=max(face2["chunk_y_offset"], face2["chunk_y_offset"]),
)
return new_face
def prepare_faces_list( def prepare_faces_list(
face_result_list: list[FaceResultData], face_result_list: list[FaceResultData],
) -> list[FaceResultDataWithId]: ) -> list[FaceResultDataWithId]:
@ -91,7 +135,7 @@ def prepare_faces_list(
should_add = True should_add = True
candidate_x_center = candidate["x_center"] candidate_x_center = candidate["x_center"]
candidate_y_center = candidate["y_center"] candidate_y_center = candidate["y_center"]
for face in deduped_faces: for idx, face in enumerate(deduped_faces):
face_center_x = face["x_center"] face_center_x = face["x_center"]
face_center_y = face["y_center"] face_center_y = face["y_center"]
face_radius_w = face["mesh_width"] / 2 face_radius_w = face["mesh_width"] / 2
@ -105,6 +149,7 @@ def prepare_faces_list(
) )
if p < 1: # Inside of the already-added face's radius if p < 1: # Inside of the already-added face's radius
deduped_faces[idx] = coalesce_faces(face, candidate)
should_add = False should_add = False
break break
@ -138,7 +183,6 @@ def generate_face_box_mask(
chunk_x_offset: int = 0, chunk_x_offset: int = 0,
chunk_y_offset: int = 0, chunk_y_offset: int = 0,
draw_mesh: bool = True, draw_mesh: bool = True,
check_bounds: bool = True,
) -> list[FaceResultData]: ) -> list[FaceResultData]:
result = [] result = []
mask_pil = None mask_pil = None
@ -211,33 +255,20 @@ def generate_face_box_mask(
mask_pil = create_white_image(w + chunk_x_offset, h + chunk_y_offset) mask_pil = create_white_image(w + chunk_x_offset, h + chunk_y_offset)
mask_pil.paste(init_mask_pil, (chunk_x_offset, chunk_y_offset)) mask_pil.paste(init_mask_pil, (chunk_x_offset, chunk_y_offset))
left_side = x_center - mesh_width x_center = float(x_center)
right_side = x_center + mesh_width y_center = float(y_center)
top_side = y_center - mesh_height face = FaceResultData(
bottom_side = y_center + mesh_height image=pil_image,
im_width, im_height = pil_image.size mask=mask_pil or create_white_image(*pil_image.size),
over_w = im_width * 0.1 x_center=x_center + chunk_x_offset,
over_h = im_height * 0.1 y_center=y_center + chunk_y_offset,
if not check_bounds or ( mesh_width=mesh_width,
(left_side >= -over_w) mesh_height=mesh_height,
and (right_side < im_width + over_w) chunk_x_offset=chunk_x_offset,
and (top_side >= -over_h) chunk_y_offset=chunk_y_offset,
and (bottom_side < im_height + over_h) )
):
x_center = float(x_center)
y_center = float(y_center)
face = FaceResultData(
image=pil_image,
mask=mask_pil or create_white_image(*pil_image.size),
x_center=x_center + chunk_x_offset,
y_center=y_center + chunk_y_offset,
mesh_width=mesh_width,
mesh_height=mesh_height,
)
result.append(face) result.append(face)
else:
context.services.logger.info("FaceTools --> Face out of bounds, ignoring.")
return result return result
@ -346,7 +377,6 @@ def get_faces_list(
chunk_x_offset=0, chunk_x_offset=0,
chunk_y_offset=0, chunk_y_offset=0,
draw_mesh=draw_mesh, draw_mesh=draw_mesh,
check_bounds=False,
) )
if should_chunk or len(result) == 0: if should_chunk or len(result) == 0:
context.services.logger.info("FaceTools --> Chunking image (chunk toggled on, or no face found in full image).") context.services.logger.info("FaceTools --> Chunking image (chunk toggled on, or no face found in full image).")
@ -360,24 +390,26 @@ def get_faces_list(
if width > height: if width > height:
# Landscape - slice the image horizontally # Landscape - slice the image horizontally
fx = 0.0 fx = 0.0
steps = int(width * 2 / height) steps = int(width * 2 / height) + 1
increment = (width - height) / (steps - 1)
while fx <= (width - height): while fx <= (width - height):
x = int(fx) x = int(fx)
image_chunks.append(image.crop((x, 0, x + height - 1, height - 1))) image_chunks.append(image.crop((x, 0, x + height, height)))
x_offsets.append(x) x_offsets.append(x)
y_offsets.append(0) y_offsets.append(0)
fx += (width - height) / steps fx += increment
context.services.logger.info(f"FaceTools --> Chunk starting at x = {x}") context.services.logger.info(f"FaceTools --> Chunk starting at x = {x}")
elif height > width: elif height > width:
# Portrait - slice the image vertically # Portrait - slice the image vertically
fy = 0.0 fy = 0.0
steps = int(height * 2 / width) steps = int(height * 2 / width) + 1
increment = (height - width) / (steps - 1)
while fy <= (height - width): while fy <= (height - width):
y = int(fy) y = int(fy)
image_chunks.append(image.crop((0, y, width - 1, y + width - 1))) image_chunks.append(image.crop((0, y, width, y + width)))
x_offsets.append(0) x_offsets.append(0)
y_offsets.append(y) y_offsets.append(y)
fy += (height - width) / steps fy += increment
context.services.logger.info(f"FaceTools --> Chunk starting at y = {y}") context.services.logger.info(f"FaceTools --> Chunk starting at y = {y}")
for idx in range(len(image_chunks)): for idx in range(len(image_chunks)):
@ -404,7 +436,7 @@ def get_faces_list(
return all_faces return all_faces
@invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.0.1") @invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.0.2")
class FaceOffInvocation(BaseInvocation): class FaceOffInvocation(BaseInvocation):
"""Bound, extract, and mask a face from an image using MediaPipe detection""" """Bound, extract, and mask a face from an image using MediaPipe detection"""
@ -498,7 +530,7 @@ class FaceOffInvocation(BaseInvocation):
return output return output
@invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.0.1") @invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.0.2")
class FaceMaskInvocation(BaseInvocation): class FaceMaskInvocation(BaseInvocation):
"""Face mask creation using mediapipe face detection""" """Face mask creation using mediapipe face detection"""
@ -616,7 +648,7 @@ class FaceMaskInvocation(BaseInvocation):
@invocation( @invocation(
"face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.0.1" "face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.0.2"
) )
class FaceIdentifierInvocation(BaseInvocation): class FaceIdentifierInvocation(BaseInvocation):
"""Outputs an image with detected face IDs printed on each face. For use with other FaceTools.""" """Outputs an image with detected face IDs printed on each face. For use with other FaceTools."""

View File

@ -236,9 +236,16 @@ class ModelInstall(object):
if not models_installed: if not models_installed:
models_installed = dict() models_installed = dict()
model_path_id_or_url = str(model_path_id_or_url).strip("\"' ")
# A little hack to allow nested routines to retrieve info on the requested ID # A little hack to allow nested routines to retrieve info on the requested ID
self.current_id = model_path_id_or_url self.current_id = model_path_id_or_url
path = Path(model_path_id_or_url) path = Path(model_path_id_or_url)
# fix relative paths
if path.exists() and not path.is_absolute():
path = path.absolute() # make relative to current WD
# checkpoint file, or similar # checkpoint file, or similar
if path.is_file(): if path.is_file():
models_installed.update({str(path): self._install_path(path)}) models_installed.update({str(path): self._install_path(path)})

View File

@ -986,6 +986,8 @@ class ModelManager(object):
for model_path in models_dir.iterdir(): for model_path in models_dir.iterdir():
if model_path not in loaded_files: # TODO: check if model_path not in loaded_files: # TODO: check
if model_path.name.startswith("."):
continue
model_name = model_path.name if model_path.is_dir() else model_path.stem model_name = model_path.name if model_path.is_dir() else model_path.stem
model_key = self.create_key(model_name, cur_base_model, cur_model_type) model_key = self.create_key(model_name, cur_base_model, cur_model_type)

View File

@ -54,42 +54,42 @@
] ]
}, },
"dependencies": { "dependencies": {
"@chakra-ui/anatomy": "^2.2.0", "@chakra-ui/anatomy": "^2.2.1",
"@chakra-ui/icons": "^2.1.0", "@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8.0", "@chakra-ui/react": "^2.8.1",
"@chakra-ui/styled-system": "^2.9.1", "@chakra-ui/styled-system": "^2.9.1",
"@chakra-ui/theme-tools": "^2.1.0", "@chakra-ui/theme-tools": "^2.1.1",
"@dagrejs/graphlib": "^2.1.13", "@dagrejs/graphlib": "^2.1.13",
"@dnd-kit/core": "^6.0.8", "@dnd-kit/core": "^6.0.8",
"@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/modifiers": "^6.0.1",
"@dnd-kit/utilities": "^3.2.1", "@dnd-kit/utilities": "^3.2.1",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@floating-ui/react-dom": "^2.0.1", "@floating-ui/react-dom": "^2.0.2",
"@fontsource-variable/inter": "^5.0.8", "@fontsource-variable/inter": "^5.0.13",
"@fontsource/inter": "^5.0.8", "@fontsource/inter": "^5.0.13",
"@mantine/core": "^6.0.19", "@mantine/core": "^6.0.19",
"@mantine/form": "^6.0.19", "@mantine/form": "^6.0.19",
"@mantine/hooks": "^6.0.19", "@mantine/hooks": "^6.0.19",
"@nanostores/react": "^0.7.1", "@nanostores/react": "^0.7.1",
"@reduxjs/toolkit": "^1.9.5", "@reduxjs/toolkit": "^1.9.7",
"@roarr/browser-log-writer": "^1.1.5", "@roarr/browser-log-writer": "^1.3.0",
"@stevebel/png": "^1.5.1", "@stevebel/png": "^1.5.1",
"compare-versions": "^6.1.0", "compare-versions": "^6.1.0",
"dateformat": "^5.0.3", "dateformat": "^5.0.3",
"formik": "^2.4.3", "formik": "^2.4.5",
"framer-motion": "^10.16.1", "framer-motion": "^10.16.4",
"fuse.js": "^6.6.2", "fuse.js": "^6.6.2",
"i18next": "^23.4.4", "i18next": "^23.5.1",
"i18next-browser-languagedetector": "^7.0.2", "i18next-browser-languagedetector": "^7.0.2",
"i18next-http-backend": "^2.2.1", "i18next-http-backend": "^2.2.2",
"konva": "^9.2.0", "konva": "^9.2.2",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"nanostores": "^0.9.2", "nanostores": "^0.9.2",
"new-github-issue-url": "^1.0.0", "new-github-issue-url": "^1.0.0",
"openapi-fetch": "^0.7.4", "openapi-fetch": "^0.7.10",
"overlayscrollbars": "^2.2.0", "overlayscrollbars": "^2.3.2",
"overlayscrollbars-react": "^0.5.0", "overlayscrollbars-react": "^0.5.2",
"patch-package": "^8.0.0", "patch-package": "^8.0.0",
"query-string": "^8.1.0", "query-string": "^8.1.0",
"react": "^18.2.0", "react": "^18.2.0",
@ -98,25 +98,25 @@
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-error-boundary": "^4.0.11", "react-error-boundary": "^4.0.11",
"react-hotkeys-hook": "4.4.1", "react-hotkeys-hook": "4.4.1",
"react-i18next": "^13.1.2", "react-i18next": "^13.3.0",
"react-icons": "^4.10.1", "react-icons": "^4.11.0",
"react-konva": "^18.2.10", "react-konva": "^18.2.10",
"react-redux": "^8.1.2", "react-redux": "^8.1.3",
"react-resizable-panels": "^0.0.55", "react-resizable-panels": "^0.0.55",
"react-use": "^17.4.0", "react-use": "^17.4.0",
"react-virtuoso": "^4.5.0", "react-virtuoso": "^4.6.1",
"react-zoom-pan-pinch": "^3.0.8", "react-zoom-pan-pinch": "^3.2.0",
"reactflow": "^11.8.3", "reactflow": "^11.9.3",
"redux-dynamic-middlewares": "^2.2.0", "redux-dynamic-middlewares": "^2.2.0",
"redux-remember": "^4.0.1", "redux-remember": "^4.0.4",
"roarr": "^7.15.1", "roarr": "^7.15.1",
"serialize-error": "^11.0.1", "serialize-error": "^11.0.2",
"socket.io-client": "^4.7.2", "socket.io-client": "^4.7.2",
"type-fest": "^4.2.0", "type-fest": "^4.4.0",
"use-debounce": "^9.0.4", "use-debounce": "^9.0.4",
"use-image": "^1.1.1", "use-image": "^1.1.1",
"uuid": "^9.0.0", "uuid": "^9.0.1",
"zod": "^3.22.2", "zod": "^3.22.4",
"zod-validation-error": "^1.5.0" "zod-validation-error": "^1.5.0"
}, },
"peerDependencies": { "peerDependencies": {
@ -129,40 +129,40 @@
"devDependencies": { "devDependencies": {
"@chakra-ui/cli": "^2.4.1", "@chakra-ui/cli": "^2.4.1",
"@types/dateformat": "^5.0.0", "@types/dateformat": "^5.0.0",
"@types/lodash-es": "^4.14.194", "@types/lodash-es": "^4.17.9",
"@types/node": "^20.5.1", "@types/node": "^20.8.6",
"@types/react": "^18.2.20", "@types/react": "^18.2.28",
"@types/react-dom": "^18.2.6", "@types/react-dom": "^18.2.13",
"@types/react-redux": "^7.1.25", "@types/react-redux": "^7.1.27",
"@types/react-transition-group": "^4.4.6", "@types/react-transition-group": "^4.4.7",
"@types/uuid": "^9.0.2", "@types/uuid": "^9.0.5",
"@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.4.1", "@typescript-eslint/parser": "^6.7.5",
"@vitejs/plugin-react-swc": "^3.3.2", "@vitejs/plugin-react-swc": "^3.4.0",
"axios": "^1.4.0", "axios": "^1.5.1",
"babel-plugin-transform-imports": "^2.0.0", "babel-plugin-transform-imports": "^2.0.0",
"concurrently": "^8.2.0", "concurrently": "^8.2.1",
"eslint": "^8.47.0", "eslint": "^8.51.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0", "eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^14.0.1", "lint-staged": "^15.0.1",
"madge": "^6.1.0", "madge": "^6.1.0",
"openapi-types": "^12.1.3", "openapi-types": "^12.1.3",
"openapi-typescript": "^6.5.2", "openapi-typescript": "^6.7.0",
"postinstall-postinstall": "^2.1.0", "postinstall-postinstall": "^2.1.0",
"prettier": "^3.0.2", "prettier": "^3.0.3",
"rollup-plugin-visualizer": "^5.9.2", "rollup-plugin-visualizer": "^5.9.2",
"ts-toolbelt": "^9.6.0", "ts-toolbelt": "^9.6.0",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vite": "^4.4.9", "vite": "^4.4.11",
"vite-plugin-css-injected-by-js": "^3.3.0", "vite-plugin-css-injected-by-js": "^3.3.0",
"vite-plugin-dts": "^3.5.2", "vite-plugin-dts": "^3.6.0",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.0", "vite-tsconfig-paths": "^4.2.1",
"yarn": "^1.22.19" "yarn": "^1.22.19"
} }
} }

View File

@ -44,7 +44,7 @@ export const addCanvasMergedListener = () => {
} }
const baseLayerRect = canvasBaseLayer.getClientRect({ const baseLayerRect = canvasBaseLayer.getClientRect({
relativeTo: canvasBaseLayer.getParent(), relativeTo: canvasBaseLayer.getParent() ?? undefined,
}); });
const imageDTO = await dispatch( const imageDTO = await dispatch(

View File

@ -30,6 +30,7 @@ import {
isCanvasMaskLine, isCanvasMaskLine,
} from './canvasTypes'; } from './canvasTypes';
import { appSocketQueueItemStatusChanged } from 'services/events/actions'; import { appSocketQueueItemStatusChanged } from 'services/events/actions';
import { queueApi } from 'services/api/endpoints/queue';
export const initialLayerState: CanvasLayerState = { export const initialLayerState: CanvasLayerState = {
objects: [], objects: [],
@ -812,6 +813,20 @@ export const canvasSlice = createSlice({
); );
} }
}); });
builder.addMatcher(
queueApi.endpoints.clearQueue.matchFulfilled,
(state) => {
state.batchIds = [];
}
);
builder.addMatcher(
queueApi.endpoints.cancelByBatchIds.matchFulfilled,
(state, action) => {
state.batchIds = state.batchIds.filter(
(id) => !action.meta.arg.originalArgs.batch_ids.includes(id)
);
}
);
}, },
}); });

File diff suppressed because it is too large Load Diff