diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dbcb45d..091ed627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-or-later # Changelog +# 4.43.7 + +* Prevent anon gens being visible at their profile page +* fixes setting team for worker +* aborted jobs can't be restarted anymore + + # 4.43.6 * Fix returning `done` when a job was restarted. diff --git a/horde/apis/models/kobold_v2.py b/horde/apis/models/kobold_v2.py index 30a13062..4c7fa1dd 100644 --- a/horde/apis/models/kobold_v2.py +++ b/horde/apis/models/kobold_v2.py @@ -252,6 +252,7 @@ def __init__(self, api): example="00000000-0000-0000-0000-000000000000", ), ), + "ttl": fields.Integer(description="The amount of seconds before this job is considered stale and aborted."), "extra_source_images": fields.List(fields.Nested(self.model_extra_source_images)), "skipped": fields.Nested(self.response_model_generations_skipped, skip_none=True), "softprompt": fields.String(description="The soft prompt requested for this generation."), diff --git a/horde/apis/models/stable_v2.py b/horde/apis/models/stable_v2.py index f1ff0668..38fa4a98 100644 --- a/horde/apis/models/stable_v2.py +++ b/horde/apis/models/stable_v2.py @@ -494,6 +494,7 @@ def __init__(self, api): example="00000000-0000-0000-0000-000000000000", ), ), + "ttl": fields.Integer(description="The amount of seconds before this job is considered stale and aborted."), "skipped": fields.Nested(self.response_model_generations_skipped, skip_none=True), "model": fields.String(description="Which of the available models to use for this request."), "source_image": fields.String(description="The Base64-encoded webp to use for img2img."), diff --git a/horde/apis/models/v2.py b/horde/apis/models/v2.py index 863c03bb..57e5ff55 100644 --- a/horde/apis/models/v2.py +++ b/horde/apis/models/v2.py @@ -438,6 +438,7 @@ def __init__(self, api): { "payload": fields.Nested(self.response_model_generation_payload, skip_none=True), "id": fields.String(description="The UUID for this generation."), + "ttl": fields.Integer(description="The amount of seconds before this job is considered stale and aborted."), "skipped": fields.Nested(self.response_model_generations_skipped, skip_none=True), }, ) diff --git a/horde/apis/v2/base.py b/horde/apis/v2/base.py index 8caaa552..12e5eafd 100644 --- a/horde/apis/v2/base.py +++ b/horde/apis/v2/base.py @@ -23,7 +23,7 @@ from horde.classes.base import settings from horde.classes.base.detection import Filter from horde.classes.base.news import News -from horde.classes.base.team import Team, get_all_teams +from horde.classes.base.team import Team, find_team_by_id, get_all_teams from horde.classes.base.user import User, UserSharedKey from horde.classes.base.waiting_prompt import WaitingPrompt from horde.classes.base.worker import Worker @@ -1072,7 +1072,7 @@ def put(self, worker_id=""): worker.set_team(None) ret_dict["team"] = "None" else: - team = database.find_team_by_id(self.args.team) + team = find_team_by_id(self.args.team) if not team: raise e.TeamNotFound(self.args.team) ret = worker.set_team(team) @@ -2003,7 +2003,7 @@ class TeamSingle(Resource): @api.response(404, "Team Not Found", models.response_model_error) def get(self, team_id=""): """Details of a worker Team""" - team = database.find_team_by_id(team_id) + team = find_team_by_id(team_id) if not team: raise e.TeamNotFound(team_id) details_privilege = 0 @@ -2051,7 +2051,7 @@ def get(self, team_id=""): @api.response(404, "Team Not Found", models.response_model_error) def patch(self, team_id=""): """Update a Team's information""" - team = database.find_team_by_id(team_id) + team = find_team_by_id(team_id) if not team: raise e.TeamNotFound(team_id) self.args = self.patch_parser.parse_args() @@ -2107,7 +2107,7 @@ def delete(self, team_id=""): Only the team's creator or a horde moderator can use this endpoint. This action is unrecoverable! """ - team = database.find_team_by_id(team_id) + team = find_team_by_id(team_id) if not team: raise e.TeamNotFound(team_id) self.args = self.delete_parser.parse_args() diff --git a/horde/classes/base/waiting_prompt.py b/horde/classes/base/waiting_prompt.py index 506cd105..f096e40c 100644 --- a/horde/classes/base/waiting_prompt.py +++ b/horde/classes/base/waiting_prompt.py @@ -284,19 +284,16 @@ def get_pop_payload(self, procgen_list, payload): "id": procgen_list[0].id, "model": procgen_list[0].model, "ids": [g.id for g in procgen_list], + "ttl": procgen_list[0].job_ttl, } if self.extra_source_images and check_bridge_capability("extra_source_images", procgen_list[0].worker.bridge_agent): prompt_payload["extra_source_images"] = self.extra_source_images["esi"] return prompt_payload - def is_completed(self): - if self.faulted: - return True - if self.needs_gen(): - return False + def count_finished_jobs(self): procgen_class = procgen_classes[self.wp_type] - finished_procgens = ( + return ( db.session.query(procgen_class.wp_id) .filter( procgen_class.wp_id == self.id, @@ -308,7 +305,10 @@ def is_completed(self): ) .count() ) - processing_procgens = ( + + def count_processing_jobs(self): + procgen_class = procgen_classes[self.wp_type] + return ( db.session.query(procgen_class.wp_id) .filter( procgen_class.wp_id == self.id, @@ -318,7 +318,13 @@ def is_completed(self): ) .count() ) - if finished_procgens - processing_procgens < self.jobs: + + def is_completed(self): + if self.faulted: + return True + if self.needs_gen(): + return False + if self.count_finished_jobs() - self.count_processing_jobs() < self.jobs: return False return True @@ -346,6 +352,8 @@ def count_processing_gens(self): def get_generations(self): generations = [] + if self.user.is_anon(): + return generations for procgen in self.processing_gens: if procgen.fake: continue diff --git a/horde/classes/stable/processing_generation.py b/horde/classes/stable/processing_generation.py index 76f48d9f..9b94d6f8 100644 --- a/horde/classes/stable/processing_generation.py +++ b/horde/classes/stable/processing_generation.py @@ -100,7 +100,8 @@ def set_generation(self, generation, things_per_sec, **kwargs): # } # upload_prompt(prompt_dict) elif state == "faulted": - self.wp.n += 1 + if self.wp.count_finished_jobs() < self.wp.jobs: + self.wp.n += 1 self.abort() if self.is_completed(): return 0 @@ -167,6 +168,8 @@ def set_job_ttl(self): # Flux is way slower than Stable Diffusion if any(model_reference.get_model_baseline(mn) in ["flux_1"] for mn in self.wp.get_model_names()): self.job_ttl = self.job_ttl * 3 + if self.job_ttl < 150: + self.job_ttl = 150 if self.worker.extra_slow_worker is True: self.job_ttl = self.job_ttl * 3 db.session.commit() diff --git a/horde/classes/stable/waiting_prompt.py b/horde/classes/stable/waiting_prompt.py index 5c29771e..7f8ee610 100644 --- a/horde/classes/stable/waiting_prompt.py +++ b/horde/classes/stable/waiting_prompt.py @@ -197,6 +197,7 @@ def get_pop_payload(self, procgen_list, payload): "id": procgen.id, "model": procgen.model, "ids": [g.id for g in procgen_list], + "ttl": procgen_list[0].job_ttl, } if self.source_image and check_bridge_capability("img2img", procgen.worker.bridge_agent): if check_bridge_capability("r2_source", procgen.worker.bridge_agent): diff --git a/horde/consts.py b/horde/consts.py index 9fde65fd..0e630f24 100644 --- a/horde/consts.py +++ b/horde/consts.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: AGPL-3.0-or-later -HORDE_VERSION = "4.43.6" +HORDE_VERSION = "4.43.7" WHITELISTED_SERVICE_IPS = { "212.227.227.178", # Turing Bot