Spaces:
Paused
Paused
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -13,6 +13,8 @@ Three tokens, three jobs:
|
|
| 13 |
|
| 14 |
from __future__ import annotations
|
| 15 |
|
|
|
|
|
|
|
| 16 |
import gradio as gr
|
| 17 |
|
| 18 |
import caption
|
|
@@ -20,6 +22,7 @@ import jobs
|
|
| 20 |
|
| 21 |
MAX_IMAGES = 40
|
| 22 |
MAX_LOG = 60_000
|
|
|
|
| 23 |
|
| 24 |
LR_SCHEDULERS = ["constant", "cosine", "linear", "constant_with_warmup", "polynomial"]
|
| 25 |
OPTIMIZERS = ["adamW", "prodigy"]
|
|
@@ -91,12 +94,34 @@ CAPTION_TIP = (
|
|
| 91 |
"trigger token.\n"
|
| 92 |
"- <b>✨ Auto-caption</b> fills these for you; edit anything you like. Blank captions fall "
|
| 93 |
"back to the trigger.\n"
|
|
|
|
|
|
|
| 94 |
"</details>"
|
| 95 |
)
|
| 96 |
|
| 97 |
|
| 98 |
-
def _paths(
|
| 99 |
-
return [p if isinstance(p, str) else getattr(p, "name", p) for p in (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
|
| 102 |
def _signin_state(profile: gr.OAuthProfile | None):
|
|
@@ -120,38 +145,46 @@ def on_concept_change(concept: str):
|
|
| 120 |
)
|
| 121 |
|
| 122 |
|
| 123 |
-
def load_captioning(
|
| 124 |
-
"""Reveal the captioning + training UI once images are uploaded; one row per image.
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
| 126 |
n = len(paths)
|
| 127 |
if n > MAX_IMAGES:
|
| 128 |
raise gr.Error(f"For now, up to {MAX_IMAGES} images are supported (got {n}).")
|
| 129 |
updates = [gr.update(visible=n > 0), gr.update(visible=n > 0)] # captioning_area, post_upload
|
| 130 |
for i in range(MAX_IMAGES):
|
| 131 |
visible = i < n
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
updates.append(gr.update(visible=visible)) # row
|
| 133 |
updates.append(gr.update(value=paths[i] if visible else None, visible=visible)) # image
|
| 134 |
-
updates.append(gr.update(value=
|
| 135 |
return updates
|
| 136 |
|
| 137 |
|
| 138 |
-
def ai_suggest_trigger(
|
| 139 |
-
paths =
|
| 140 |
if not paths:
|
| 141 |
raise gr.Error("Upload images first.")
|
| 142 |
return caption.suggest_trigger(paths, concept_type)
|
| 143 |
|
| 144 |
|
| 145 |
-
def ai_caption_all(
|
| 146 |
-
paths =
|
| 147 |
if not paths:
|
| 148 |
raise gr.Error("Upload images first.")
|
| 149 |
caps = [caption.caption_one(p, concept_type, trigger) for p in paths]
|
| 150 |
return [gr.update(value=caps[i]) if i < len(caps) else gr.update() for i in range(MAX_IMAGES)]
|
| 151 |
|
| 152 |
|
| 153 |
-
def gather_dataset(
|
| 154 |
-
paths =
|
| 155 |
return [[img, (captions[i] if i < len(captions) else "")] for i, img in enumerate(paths)]
|
| 156 |
|
| 157 |
|
|
@@ -240,7 +273,7 @@ with gr.Blocks(title="Krea 2 LoRA Trainer") as demo:
|
|
| 240 |
with gr.Row():
|
| 241 |
images = gr.File(
|
| 242 |
label="Upload your images (4–30 ideal)", file_count="multiple",
|
| 243 |
-
file_types=["image"], interactive=True, scale=1,
|
| 244 |
)
|
| 245 |
with gr.Column(scale=3, visible=False) as captioning_area:
|
| 246 |
gr.Markdown("## Trigger & captioning")
|
|
|
|
| 13 |
|
| 14 |
from __future__ import annotations
|
| 15 |
|
| 16 |
+
import os
|
| 17 |
+
|
| 18 |
import gradio as gr
|
| 19 |
|
| 20 |
import caption
|
|
|
|
| 22 |
|
| 23 |
MAX_IMAGES = 40
|
| 24 |
MAX_LOG = 60_000
|
| 25 |
+
IMAGE_EXTS = (".png", ".jpg", ".jpeg", ".webp", ".bmp", ".gif", ".tiff", ".tif")
|
| 26 |
|
| 27 |
LR_SCHEDULERS = ["constant", "cosine", "linear", "constant_with_warmup", "polynomial"]
|
| 28 |
OPTIMIZERS = ["adamW", "prodigy"]
|
|
|
|
| 94 |
"trigger token.\n"
|
| 95 |
"- <b>✨ Auto-caption</b> fills these for you; edit anything you like. Blank captions fall "
|
| 96 |
"back to the trigger.\n"
|
| 97 |
+
"- Already have captions? Upload a <code>.txt</code> next to each image with the same name "
|
| 98 |
+
"(e.g. <code>cat.jpg</code> + <code>cat.txt</code>) and they're filled in automatically.\n"
|
| 99 |
"</details>"
|
| 100 |
)
|
| 101 |
|
| 102 |
|
| 103 |
+
def _paths(files) -> list[str]:
|
| 104 |
+
return [p if isinstance(p, str) else getattr(p, "name", p) for p in (files or [])]
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def _split_uploads(files):
|
| 108 |
+
"""Split a mixed upload into image paths and a {basename: caption} map from .txt sidecars.
|
| 109 |
+
|
| 110 |
+
A .txt file whose name matches an image (e.g. cat.jpg + cat.txt) prefills that caption.
|
| 111 |
+
"""
|
| 112 |
+
images, captions = [], {}
|
| 113 |
+
for p in _paths(files):
|
| 114 |
+
ext = os.path.splitext(p)[1].lower()
|
| 115 |
+
base = os.path.splitext(os.path.basename(p))[0]
|
| 116 |
+
if ext == ".txt":
|
| 117 |
+
try:
|
| 118 |
+
with open(p, encoding="utf-8") as f:
|
| 119 |
+
captions[base] = f.read().strip()
|
| 120 |
+
except Exception: # noqa: BLE001
|
| 121 |
+
pass
|
| 122 |
+
elif ext in IMAGE_EXTS:
|
| 123 |
+
images.append(p)
|
| 124 |
+
return images, captions
|
| 125 |
|
| 126 |
|
| 127 |
def _signin_state(profile: gr.OAuthProfile | None):
|
|
|
|
| 145 |
)
|
| 146 |
|
| 147 |
|
| 148 |
+
def load_captioning(files, trigger):
|
| 149 |
+
"""Reveal the captioning + training UI once images are uploaded; one row per image.
|
| 150 |
+
|
| 151 |
+
If a matching `<name>.txt` sidecar was uploaded, its content prefills that image's caption.
|
| 152 |
+
"""
|
| 153 |
+
paths, txt_caps = _split_uploads(files)
|
| 154 |
n = len(paths)
|
| 155 |
if n > MAX_IMAGES:
|
| 156 |
raise gr.Error(f"For now, up to {MAX_IMAGES} images are supported (got {n}).")
|
| 157 |
updates = [gr.update(visible=n > 0), gr.update(visible=n > 0)] # captioning_area, post_upload
|
| 158 |
for i in range(MAX_IMAGES):
|
| 159 |
visible = i < n
|
| 160 |
+
if visible:
|
| 161 |
+
base = os.path.splitext(os.path.basename(paths[i]))[0]
|
| 162 |
+
cap_val = txt_caps.get(base) or (trigger or "")
|
| 163 |
+
else:
|
| 164 |
+
cap_val = None
|
| 165 |
updates.append(gr.update(visible=visible)) # row
|
| 166 |
updates.append(gr.update(value=paths[i] if visible else None, visible=visible)) # image
|
| 167 |
+
updates.append(gr.update(value=cap_val, visible=visible)) # caption
|
| 168 |
return updates
|
| 169 |
|
| 170 |
|
| 171 |
+
def ai_suggest_trigger(files, concept_type):
|
| 172 |
+
paths, _ = _split_uploads(files)
|
| 173 |
if not paths:
|
| 174 |
raise gr.Error("Upload images first.")
|
| 175 |
return caption.suggest_trigger(paths, concept_type)
|
| 176 |
|
| 177 |
|
| 178 |
+
def ai_caption_all(files, concept_type, trigger):
|
| 179 |
+
paths, _ = _split_uploads(files)
|
| 180 |
if not paths:
|
| 181 |
raise gr.Error("Upload images first.")
|
| 182 |
caps = [caption.caption_one(p, concept_type, trigger) for p in paths]
|
| 183 |
return [gr.update(value=caps[i]) if i < len(caps) else gr.update() for i in range(MAX_IMAGES)]
|
| 184 |
|
| 185 |
|
| 186 |
+
def gather_dataset(files, *captions):
|
| 187 |
+
paths, _ = _split_uploads(files)
|
| 188 |
return [[img, (captions[i] if i < len(captions) else "")] for i, img in enumerate(paths)]
|
| 189 |
|
| 190 |
|
|
|
|
| 273 |
with gr.Row():
|
| 274 |
images = gr.File(
|
| 275 |
label="Upload your images (4–30 ideal)", file_count="multiple",
|
| 276 |
+
file_types=["image", ".txt"], interactive=True, scale=1,
|
| 277 |
)
|
| 278 |
with gr.Column(scale=3, visible=False) as captioning_area:
|
| 279 |
gr.Markdown("## Trigger & captioning")
|