feat: better error messaging
This commit is contained in:
parent
0215cb9ac6
commit
2eb90ba559
|
@ -65,7 +65,7 @@ class EditSafetyStage(BaseStage):
|
||||||
|
|
||||||
if is_csam:
|
if is_csam:
|
||||||
logger.warning("blocking csam result")
|
logger.warning("blocking csam result")
|
||||||
raise CancelledException("csam detected")
|
raise CancelledException(reason="csam")
|
||||||
else:
|
else:
|
||||||
return StageResult.from_images(results, metadata=sources.metadata)
|
return StageResult.from_images(results, metadata=sources.metadata)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -174,7 +174,7 @@ class ChainPipeline:
|
||||||
worker.set_tiles(0)
|
worker.set_tiles(0)
|
||||||
if must_tile:
|
if must_tile:
|
||||||
logger.info(
|
logger.info(
|
||||||
"image contains sources or is larger than tile size of %s, tiling stage",
|
"image has mask or is larger than tile size of %s, tiling stage",
|
||||||
tile,
|
tile,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,9 @@ def add_safety_stage(
|
||||||
if server.has_feature("horde-safety"):
|
if server.has_feature("horde-safety"):
|
||||||
from ..chain.edit_safety import EditSafetyStage
|
from ..chain.edit_safety import EditSafetyStage
|
||||||
|
|
||||||
pipeline.stage(EditSafetyStage(), StageParams())
|
pipeline.stage(
|
||||||
|
EditSafetyStage(), StageParams(tile_size=EditSafetyStage.max_tile)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_txt2img_pipeline(
|
def run_txt2img_pipeline(
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class RetryException(Exception):
|
class RetryException(Exception):
|
||||||
"""
|
"""
|
||||||
Used when a chain pipeline has run out of retries.
|
Used when a chain pipeline has run out of retries.
|
||||||
|
@ -11,7 +14,12 @@ class CancelledException(Exception):
|
||||||
Used when a job has been cancelled and needs to stop.
|
Used when a job has been cancelled and needs to stop.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
reason: Optional[str]
|
||||||
|
|
||||||
|
def __init__(self, *args: object, reason: Optional[str] = None) -> None:
|
||||||
|
super().__init__(*args)
|
||||||
|
|
||||||
|
self.reason = reason
|
||||||
|
|
||||||
|
|
||||||
class RequestException(Exception):
|
class RequestException(Exception):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from os import path
|
from os import path
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from flask import Flask, jsonify, make_response, request, url_for
|
from flask import Flask, jsonify, make_response, request, url_for
|
||||||
from jsonschema import validate
|
from jsonschema import validate
|
||||||
|
@ -117,8 +117,9 @@ def image_reply(
|
||||||
stages: Progress = None,
|
stages: Progress = None,
|
||||||
steps: Progress = None,
|
steps: Progress = None,
|
||||||
tiles: Progress = None,
|
tiles: Progress = None,
|
||||||
outputs: List[str] = None,
|
outputs: Optional[List[str]] = None,
|
||||||
metadata: List[ImageMetadata] = None,
|
metadata: Optional[List[ImageMetadata]] = None,
|
||||||
|
reason: Optional[str] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
if queue is None:
|
if queue is None:
|
||||||
queue = EMPTY_PROGRESS
|
queue = EMPTY_PROGRESS
|
||||||
|
@ -141,6 +142,9 @@ def image_reply(
|
||||||
"tiles": tiles.tojson(),
|
"tiles": tiles.tojson(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if reason is not None:
|
||||||
|
data["reason"] = reason
|
||||||
|
|
||||||
if outputs is not None:
|
if outputs is not None:
|
||||||
if metadata is None:
|
if metadata is None:
|
||||||
logger.error("metadata is required with outputs")
|
logger.error("metadata is required with outputs")
|
||||||
|
@ -705,6 +709,7 @@ def job_status(server: ServerContext, pool: DevicePoolExecutor):
|
||||||
tiles=progress.tiles,
|
tiles=progress.tiles,
|
||||||
outputs=outputs,
|
outputs=outputs,
|
||||||
metadata=metadata,
|
metadata=metadata,
|
||||||
|
reason=progress.reason,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, Callable, Dict
|
from typing import Any, Callable, Dict, Optional
|
||||||
|
|
||||||
|
|
||||||
class JobStatus(str, Enum):
|
class JobStatus(str, Enum):
|
||||||
|
@ -64,7 +64,8 @@ class ProgressCommand:
|
||||||
job: str
|
job: str
|
||||||
job_type: str
|
job_type: str
|
||||||
status: JobStatus
|
status: JobStatus
|
||||||
result: Any # really StageResult but that would be a very circular import
|
reason: Optional[str]
|
||||||
|
result: Optional[Any] # really StageResult but that would be a very circular import
|
||||||
steps: Progress
|
steps: Progress
|
||||||
stages: Progress
|
stages: Progress
|
||||||
tiles: Progress
|
tiles: Progress
|
||||||
|
@ -79,6 +80,7 @@ class ProgressCommand:
|
||||||
stages: Progress,
|
stages: Progress,
|
||||||
tiles: Progress,
|
tiles: Progress,
|
||||||
result: Any = None,
|
result: Any = None,
|
||||||
|
reason: Optional[str] = None,
|
||||||
):
|
):
|
||||||
self.job = job
|
self.job = job
|
||||||
self.job_type = job_type
|
self.job_type = job_type
|
||||||
|
@ -90,6 +92,7 @@ class ProgressCommand:
|
||||||
self.stages = stages
|
self.stages = stages
|
||||||
self.tiles = tiles
|
self.tiles = tiles
|
||||||
self.result = result
|
self.result = result
|
||||||
|
self.reason = reason
|
||||||
|
|
||||||
|
|
||||||
class JobCommand:
|
class JobCommand:
|
||||||
|
|
|
@ -218,7 +218,7 @@ class WorkerContext:
|
||||||
block=False,
|
block=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def fail(self) -> None:
|
def fail(self, reason: Optional[str] = None) -> None:
|
||||||
if self.job is None:
|
if self.job is None:
|
||||||
logger.warning("setting failure without an active job")
|
logger.warning("setting failure without an active job")
|
||||||
else:
|
else:
|
||||||
|
@ -232,6 +232,7 @@ class WorkerContext:
|
||||||
steps=self.steps,
|
steps=self.steps,
|
||||||
stages=self.stages,
|
stages=self.stages,
|
||||||
tiles=self.tiles,
|
tiles=self.tiles,
|
||||||
|
reason=reason,
|
||||||
# TODO: should this include partial results?
|
# TODO: should this include partial results?
|
||||||
)
|
)
|
||||||
self.progress.put(
|
self.progress.put(
|
||||||
|
|
|
@ -5,7 +5,7 @@ from sys import exit
|
||||||
|
|
||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
|
|
||||||
from ..errors import RetryException
|
from ..errors import CancelledException, RetryException
|
||||||
from ..server import ServerContext, apply_patches
|
from ..server import ServerContext, apply_patches
|
||||||
from ..torch_before_ort import get_available_providers
|
from ..torch_before_ort import get_available_providers
|
||||||
from .context import WorkerContext
|
from .context import WorkerContext
|
||||||
|
@ -82,13 +82,16 @@ def worker_main(
|
||||||
logger.exception("value error in worker, exiting")
|
logger.exception("value error in worker, exiting")
|
||||||
worker.fail()
|
worker.fail()
|
||||||
return exit(EXIT_ERROR)
|
return exit(EXIT_ERROR)
|
||||||
|
except CancelledException as e:
|
||||||
|
logger.warning("job was cancelled, continuing")
|
||||||
|
worker.fail(e.reason or "cancelled")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
e_str = str(e)
|
e_str = str(e)
|
||||||
# restart the worker on memory errors
|
# restart the worker on memory errors
|
||||||
for e_mem in MEMORY_ERRORS:
|
for e_mem in MEMORY_ERRORS:
|
||||||
if e_mem in e_str:
|
if e_mem in e_str:
|
||||||
logger.error("detected out-of-memory error, exiting: %s", e)
|
logger.error("detected out-of-memory error, exiting: %s", e)
|
||||||
worker.fail()
|
worker.fail("oom")
|
||||||
return exit(EXIT_MEMORY)
|
return exit(EXIT_MEMORY)
|
||||||
|
|
||||||
# carry on for other errors
|
# carry on for other errors
|
||||||
|
|
|
@ -89,7 +89,7 @@ export const UNKNOWN_ERROR = `${IMAGE_ERROR}unknown`;
|
||||||
|
|
||||||
export function getImageErrorReason(image: FailedJobResponse | UnknownJobResponse) {
|
export function getImageErrorReason(image: FailedJobResponse | UnknownJobResponse) {
|
||||||
if (image.status === JobStatus.FAILED) {
|
if (image.status === JobStatus.FAILED) {
|
||||||
const error = image.error;
|
const error = image.reason;
|
||||||
if (doesExist(error) && error.startsWith(ANY_ERROR)) {
|
if (doesExist(error) && error.startsWith(ANY_ERROR)) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ export const I18N_STRINGS_DE = {
|
||||||
convert: '',
|
convert: '',
|
||||||
error: {
|
error: {
|
||||||
image: {
|
image: {
|
||||||
|
csam: '',
|
||||||
memory: '',
|
memory: '',
|
||||||
|
oom: '',
|
||||||
unknown: '',
|
unknown: '',
|
||||||
},
|
},
|
||||||
inpaint: {
|
inpaint: {
|
||||||
|
|
|
@ -8,7 +8,9 @@ export const I18N_STRINGS_EN = {
|
||||||
convert: 'Save and Convert',
|
convert: 'Save and Convert',
|
||||||
error: {
|
error: {
|
||||||
image: {
|
image: {
|
||||||
|
csam: 'CSAM detected',
|
||||||
memory: 'Memory error generating image',
|
memory: 'Memory error generating image',
|
||||||
|
oom: 'Out of memory generating image',
|
||||||
unknown: 'Unknown error generating image',
|
unknown: 'Unknown error generating image',
|
||||||
},
|
},
|
||||||
inpaint: {
|
inpaint: {
|
||||||
|
|
|
@ -13,7 +13,9 @@ export const I18N_STRINGS_ES = {
|
||||||
convert: '',
|
convert: '',
|
||||||
error: {
|
error: {
|
||||||
image: {
|
image: {
|
||||||
|
csam: '',
|
||||||
memory: '',
|
memory: '',
|
||||||
|
oom: '',
|
||||||
unknown: '',
|
unknown: '',
|
||||||
},
|
},
|
||||||
inpaint: {
|
inpaint: {
|
||||||
|
|
|
@ -13,7 +13,9 @@ export const I18N_STRINGS_FR = {
|
||||||
convert: '',
|
convert: '',
|
||||||
error: {
|
error: {
|
||||||
image: {
|
image: {
|
||||||
|
csam: '',
|
||||||
memory: '',
|
memory: '',
|
||||||
|
oom: '',
|
||||||
unknown: '',
|
unknown: '',
|
||||||
},
|
},
|
||||||
inpaint: {
|
inpaint: {
|
||||||
|
|
|
@ -76,7 +76,7 @@ export interface CancelledJobResponse extends BaseJobResponse {
|
||||||
export interface FailedJobResponse extends BaseJobResponse {
|
export interface FailedJobResponse extends BaseJobResponse {
|
||||||
status: JobStatus.FAILED;
|
status: JobStatus.FAILED;
|
||||||
|
|
||||||
error?: string;
|
reason?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue