Compare commits

...
5 Commits
Author SHA1 Message Date
moosecrap 627ab3aec6 ZIT prompting guide and tweaks 2026-08-05 22:32:01 -07:00
moosecrap 74eaa2a3e2 requirements.txt 2026-08-05 22:31:53 -07:00
moosecrap 747bf5e02b Wikipedia redirect 2026-08-03 22:10:44 -07:00
moosecrap 8c18d0d40e Wikipedia text cleanup 2026-08-03 16:27:59 -07:00
moosecrap bad4a24426 Model preset tweaks, tag csv 2026-08-03 16:27:46 -07:00
7 changed files with 140842 additions and 22 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ This server requires Python 3.10+ and the following packages:
* `httpx`: For asynchronous API requests (e.g., Wikipedia).
```bash
pip install uvicorn starlette Pillow requests httpx
pip install -r requirements.txt
```
### Setup
+140782
View File
File diff suppressed because it is too large Load Diff
+8 -4
View File
@@ -10,9 +10,9 @@ This model is not aesthetic tuned, it must be given explicit tags for everything
Has very excellent understanding of characters and artists down to extremely niche. Unless prompting an original character, their name is enough to decribe their appearance completely except for clothing.
Accepts a list of comma-separated booru-style tags. Use spaces, not underscores, for tags. **Use the `search_tags` tool to verify your tags**.
Prompts MUST follow this format: <1girl/1boy/1other/solo/couple/(can use multiple)>, <character(s)>, <series>, <artist>, <tags>
Every prompt MUST include every one of the above sections.
Every prompt MUST include every one of the above sections (the angle brackets are not part of the prompt).
Quality tags such as "masterpiece", "best quality", "very awa", are a LAST RESORT, they override the artist tags. If absolutely required they should be prepended.
It understands 'implicit' artist tags such as "official art" or "game cg" for the 'artist' immediately following the series.
It understands every artist, so pick one appropriate for the image. If desired, it also knows 'implicit' artist tags such as "official art" or "game cg" for the 'artist' immediately following the series name.
Natural language understanding is very limited, but can do things like "dark blue skirt" or natural language order of tags such as "lying, on bed".
Do not use a negative prompt unless explicitly required to exclude something, your first prompt should have a blank negative prompt.
Has the SDXL problem with hands, works best if hand posture is explicitly prompted.
@@ -35,10 +35,14 @@ preset = "xl"
"Rescale CFG" = 0.3
["Z-Image-Turbo"]
description = "General image generation model. Aesthetic tuned, gets good results first try. Can only do softcore NSFW."
description = "General image generation model. Aesthetic tuned, gets good results first try. Can do softcore NSFW, e.g. underwear, breasts, asses. No full-frontal nudity."
guide = """
This model is aesthetic tuned, regenerating with the same prompt will yield essentially the same image. Change the prompt before resubmitting.
Understands natural language very well. Characters can be described by naming them and using this name later in the prompt. Longer, detailed prompts work better.
It's a CFG 1.0 turbo model, the negative prompt has no effect.
Understands natural language very well, uses Qwen 3 4B as the text encoder. The longer and more detailed prompt the better, take advantage of line breaks and formatting.
If any part of the image is left out of the prompt, it will default to generic AI slop which is most NOT what you want. Be very explicit about each character's details. Appearance, ethnicity, age, individual outfit components, facial expression, pose, action, where they are looking, position in the image, etc. should ALL be included in the prompt. Characters can be referenced by naming them and using this name later in the prompt. This also helps the model avoid mixing traits between them.
This also applies to the image itself. Composition, framing, lighting, image style, setting, background, etc. should all be explicitly specified in the prompt.
Has some idiosyncrasies so you may need to iterate the prompt a few times to get around some weird artifacts. Think things like "green eyes" making them glow green, or "blush" making the entire face glow. Also really wants to make shirts tucked in for some reason. Examine the generated image closely and edit the prompt if needed.
"""
preset = "zit"
filename = "z_image_turbo_bf16.safetensors"
+5
View File
@@ -0,0 +1,5 @@
uvicorn
starlette
requests
httpx
Pillow
+43 -14
View File
@@ -12,6 +12,20 @@ def strip_html(text: str) -> str:
"""Removes HTML tags from a string using regex to provide clean text to the LLM."""
return re.sub(r'<[^>]*>', '', text)
def clean_wikitext(text: str) -> str:
"""
Removes the most distracting elements of raw Wikitext:
1. HTML comments (<!-- ... -->)
2. Citations (<ref /> and <ref>...</ref>)
"""
# Remove HTML comments
text = re.sub(r'<!--.*?-->', '', text, flags=re.DOTALL)
# Remove self-closing citations FIRST to prevent them being seen as opening tags
text = re.sub(r'<ref[^>]*/>', '', text)
# Remove paired citations
text = re.sub(r'<ref[^>]*>.*?</ref>', '', text, flags=re.DOTALL)
return text
async def _make_request(params: Dict[str, Any]) -> Dict[str, Any]:
"""
Asynchronous helper to make the API request using httpx.
@@ -62,10 +76,11 @@ async def _search(title: str, limit: int = 5, fallback: bool = False) -> str:
return "\n".join(lines)
async def _fetch_content(title: str, section_index: int) -> Optional[str]:
async def _fetch_content(title: str, section_index: int) -> tuple[Optional[str], Optional[str]]:
"""
Retrieves raw Wikitext for a specific section.
section_index=0 returns the lead section.
Returns a tuple of (content, final_title).
"""
params = {
"action": "query",
@@ -80,23 +95,26 @@ async def _fetch_content(title: str, section_index: int) -> Optional[str]:
pages = data.get("query", {}).get("pages", {})
if not pages:
return None
return None, None
page_id = next(iter(pages))
page = pages[page_id]
final_title = page.get("title")
if "missing" in page:
return None
return None, None
revisions = page.get("revisions", [])
if not revisions:
return None
return None, final_title
return revisions[0].get("*")
content = revisions[0].get("*")
return (clean_wikitext(content) if content else None), final_title
async def _fetch_toc(title: str) -> Optional[str]:
async def _fetch_toc(title: str) -> tuple[Optional[str], Optional[str]]:
"""
Retrieves the Table of Contents data and formats it hierarchically.
Returns a tuple of (toc, final_title).
"""
params = {
"action": "parse",
@@ -109,14 +127,15 @@ async def _fetch_toc(title: str) -> Optional[str]:
parse_data = data.get("parse")
if not parse_data:
return None
return None, None
final_title = parse_data.get("title")
toc_data = parse_data.get("tocdata", {})
sections = toc_data.get("sections", [])
if not sections:
return "No table of contents found for this page."
return "No table of contents found for this page.", final_title
lines = [f"Table of Contents for \"{parse_data.get('title', title)}\":"]
lines = [f"Table of Contents for \"{final_title}\":"]
for s in sections:
level = s.get("tocLevel", 1)
index = s.get("index")
@@ -124,7 +143,7 @@ async def _fetch_toc(title: str) -> Optional[str]:
indent = " " * (level - 1)
lines.append(f"{indent}[{index}] {line}")
return "\n".join(lines)
return "\n".join(lines), final_title
async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
@@ -139,18 +158,24 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
section_index = args.get("section_index")
search_limit = args.get("search_limit", 5)
final_title = None
if mode == "search":
result = await _search(title, search_limit, fallback=False)
elif mode == "summary":
# Lead section + ToC is the default 'summary' to guide the AI's next steps
content = await _fetch_content(title, 0)
content, title_from_content = await _fetch_content(title, 0)
final_title = title_from_content
if content is None:
result = await _search(title, search_limit, fallback=True)
else:
toc = await _fetch_toc(title)
toc, title_from_toc = await _fetch_toc(title)
if title_from_toc:
final_title = title_from_toc
result = f"{content}\n\n---\n\n{toc}"
elif mode == "toc":
toc = await _fetch_toc(title)
toc, title_from_toc = await _fetch_toc(title)
final_title = title_from_toc
if toc is None:
result = await _search(title, search_limit, fallback=True)
else:
@@ -158,12 +183,16 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
elif mode == "section":
if section_index is None:
raise ToolError("Missing required parameter 'section_index' for mode='section'")
content = await _fetch_content(title, int(section_index))
content, title_from_content = await _fetch_content(title, int(section_index))
final_title = title_from_content
if content is None:
result = await _search(title, search_limit, fallback=True)
else:
result = content
else:
raise ToolError(f"Invalid mode '{mode}'. Supported modes: summary, toc, section, search")
if final_title and final_title != title:
result = f"Redirected to \"{final_title}\"\n\n{result}"
return [{"type": "text", "text": result}]
+1 -1
View File
@@ -174,7 +174,7 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
except (ValueError, AttributeError):
raise ToolError(f"Invalid resolution format for preset '{res_preset_name}': {res_val_str}. Expected 'WidthxHeight'.")
else:
raise ToolError(f"Resolution preset '{res_preset_name}' not found for this model. Available: {', '.join(res_set.keys())}")
raise ToolError(f"Resolution preset '{res_preset_name}' not found for this model. You MUST call get_model_info with this model_name to see the available resolution presets.")
else:
raise ToolError(f"No resolution set configured for model '{model_name}'.")
+2 -2
View File
@@ -24,7 +24,7 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
{
"type": "text",
"text": "Available models:\n\n" + "\n".join([f"- {m['name']}: {m['description']}" for m in catalog]) +
"\n\nTo get a detailed prompting guide and available resolutions for a specific model, call this tool again with the 'model_name' argument."
"\n\nBefore generating an image, you MUST call this tool again with your selected model as the 'model_name' argument."
}
]
@@ -41,7 +41,7 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
"type": "text",
"text": f"Model '{model_name}' not found.\n\nAvailable models:\n\n" +
"\n".join([f"- {m['name']}: {m['description']}" for m in catalog]) +
"\n\nTo get a detailed prompting guide and available resolutions for a specific model, call this tool again with the 'model_name' argument."
"\n\nBefore generating an image, you MUST call this tool again with selected model as the 'model_name' argument."
}
]