Read A1111/Forge generation parameters: fix the SELECT and parse multi-line prompts (#165)

* get_image_prompt_info: include gi.parameters in SELECT and return value

The function selects workflow_data, prompt_metadata and generation_time from
generated_images but omits the parameters column, so the A1111/Forge
generation-parameters string (steps, sampler, CFG, seed, LoRA list) never
reaches the API even when present in the database. Add it to the SELECT and
include it in the returned dict.

* parse A1111/Forge parameters: multi-line prompts, structured settings

_parse_comfyui_prompt took lines[0] of the parameters chunk as the whole
positive prompt, truncating every multi-line prompt to its first line, and
matched 'negative prompt:' only as a full line start. Split on the trailing
'Steps: ...' settings line instead, keep the full multi-line positive prompt,
and extract Steps / Sampler / Schedule type / CFG scale / Seed as structured
fields alongside the raw string.

Together with the get_image_prompt_info SELECT fix (previous commit), the
full A1111/Forge generation recipe now flows from the database to the API.

* style: apply black to the A1111 parameters parser

CI's black --check flagged py/api/__init__.py (slice spacing and two long
lines in the settings extraction). Formatting only; the AST is unchanged.

---------

Co-authored-by: kai <kai@hermes.local>
This commit is contained in:
ghosttigerllc-bit
2026-10-16 03:50:26 -07:00
committed by GitHub
co-authored by kai
parent 3bb21c621c
commit 2763e9f9fa
2 changed files with 37 additions and 10 deletions
+4 -2
View File
@@ -1971,12 +1971,13 @@ class PromptDatabase:
"""Look up prompt + image metadata for a given image path.
Returns a dict with prompt_id, text, category, tags, rating, notes,
workflow_data, prompt_metadata, generation_time — or None.
workflow_data, prompt_metadata, generation_time, parameters — or None.
"""
with self.model.get_connection() as conn:
cursor = conn.execute(
"""SELECT gi.prompt_id, p.text, p.category, p.rating, p.notes,
gi.workflow_data, gi.prompt_metadata, gi.generation_time
gi.workflow_data, gi.prompt_metadata, gi.generation_time,
gi.parameters
FROM generated_images gi
JOIN prompts p ON gi.prompt_id = p.id
WHERE gi.image_path = ? OR gi.file_path = ?
@@ -2009,6 +2010,7 @@ class PromptDatabase:
"workflow_data": workflow,
"prompt_metadata": prompt_meta,
"generation_time": row[7],
"parameters": row[8] if len(row) > 8 else None,
}
def get_prompt_id_for_image(self, image_path: str) -> Optional[int]:
+33 -8
View File
@@ -703,18 +703,43 @@ class PromptManagerAPI(
"negative_prompt": None,
}
# Check for A1111 style parameters first (like parse-metadata.py)
# Check for A1111/Forge style parameters first.
# The chunk is one block: a possibly multi-line positive prompt, then a
# "Negative prompt:" section, then a trailing "Steps: ..." settings line.
# Taking lines[0] as the positive prompt truncates any multi-line prompt
# to one line, so split on the settings line instead.
if "parameters" in metadata:
import re as _re
params = metadata["parameters"]
lines = params.splitlines()
if lines:
result["positive_prompt"] = lines[0].strip()
for line in lines:
if line.lower().startswith("negative prompt:"):
result["negative_prompt"] = line.split(":", 1)[1].strip()
break
body = params
settings = ""
_sm = _re.search(r"\nSteps:\s", body)
if _sm:
settings = body[_sm.start() + 1 :].strip()
body = body[: _sm.start()]
negative = None
_nm = _re.search(r"(?im)^\s*negative prompt:\s*", body)
if _nm:
negative = body[_nm.end() :].strip()
body = body[: _nm.start()]
elif body.lower().lstrip().startswith("negative prompt:"):
negative = body.lower().lstrip()[len("negative prompt:") :].strip()
body = ""
result["positive_prompt"] = body.strip() or None
if negative:
result["negative_prompt"] = negative
# Store raw parameters too
result["parameters"]["parameters"] = params
if settings:
for _f in ("Steps", "Sampler", "Schedule type", "CFG scale", "Seed"):
_fm = _re.search(
r"(?i)(?:^|,\s*)" + _re.escape(_f) + r":\s*([^,]+)", settings
)
if _fm:
result["parameters"][_f.lower().replace(" ", "_")] = _fm.group(
1
).strip()
# If no A1111 format found, proceed with ComfyUI parsing
if result["positive_prompt"] is None: