amisima commited on
Commit
bd40c76
·
verified ·
1 Parent(s): a85e416

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +103 -2
app.py CHANGED
@@ -1223,6 +1223,90 @@ def enhance_prompt(prompt, use_model, camera, framing, lighting, pace, add_quali
1223
  )
1224
 
1225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1226
  def _target_size(image):
1227
  """Same math as resize_image(), but returns only the final (w, h)."""
1228
  if image is None:
@@ -1378,7 +1462,7 @@ CSS = """
1378
  box-shadow: 0 8px 22px rgba(124, 58, 237, .28);
1379
  }
1380
  #estimate-btn, #enhance-btn { min-height: 42px !important; border-radius: 12px !important; }
1381
- #profile-load, #profile-save, #profile-delete, #profile-refresh {
1382
  min-height: 42px !important; border-radius: 12px !important; font-weight: 600 !important;
1383
  }
1384
  #stop-btn, #clear-btn { min-height: 46px !important; border-radius: 12px !important; }
@@ -1630,8 +1714,15 @@ with gr.Blocks(delete_cache=(3600, 86400)) as demo:
1630
  "two separate files, so paste the low-noise link straight into the Low box "
1631
  "(both boxes accept a pasted link). The Space downloads it itself, so being "
1632
  "signed in to CivitAI in your browser does not help a gated model: add "
1633
- "`CIVITAI_TOKEN` under Settings → Variables and secrets. Downloads are cached."
 
 
 
1634
  )
 
 
 
 
1635
  _my_rows = []
1636
  for _i in range(1, 6):
1637
  with gr.Accordion(f"Custom lora {_i}", open=(_i == 1)):
@@ -1871,6 +1962,16 @@ with gr.Blocks(delete_cache=(3600, 86400)) as demo:
1871
  outputs=[merged_video, merged_file, merge_queue, merge_status],
1872
  )
1873
 
 
 
 
 
 
 
 
 
 
 
1874
  _SETTINGS_FIELDS = [
1875
  prompt_input, negative_prompt_input, duration_seconds_input, steps_slider, quality_slider,
1876
  seed_input, randomize_seed_checkbox, scheduler_dropdown, flow_shift_slider, frame_multi,
 
1223
  )
1224
 
1225
 
1226
+ # ---------------------------------------------------------------------------
1227
+ # Naming CivitAI links
1228
+ # ---------------------------------------------------------------------------
1229
+ # A CivitAI download URL is a bare number, which is useless once three slots are
1230
+ # filled. The number is the *model version* id, and CivitAI's public API turns it
1231
+ # into the model's title, the version, the file behind `fileId`, and the words the
1232
+ # adapter was trained on. Public, cached, and never fatal.
1233
+
1234
+ from functools import lru_cache
1235
+
1236
+ CIVITAI_DOWNLOAD_RE = re.compile(r"/api/download/models/(\d+)")
1237
+
1238
+
1239
+ @lru_cache(maxsize=128)
1240
+ def civitai_details(version_id: str, file_id: str = ""):
1241
+ import requests
1242
+
1243
+ headers = {"User-Agent": "Mozilla/5.0"}
1244
+ token = os.environ.get("CIVITAI_TOKEN", "").strip()
1245
+ if token:
1246
+ headers["Authorization"] = f"Bearer {token}"
1247
+
1248
+ try:
1249
+ response = requests.get(
1250
+ f"https://civitai.com/api/v1/model-versions/{version_id}", headers=headers, timeout=20
1251
+ )
1252
+ response.raise_for_status()
1253
+ data = response.json()
1254
+ except Exception as error:
1255
+ return f"CivitAI {version_id} (name unavailable: {type(error).__name__})", []
1256
+
1257
+ model_name = (data.get("model") or {}).get("name") or f"model {data.get('modelId', '?')}"
1258
+ version_name = data.get("name") or ""
1259
+ label = f"{model_name} · {version_name}".strip(" ·")
1260
+
1261
+ if file_id:
1262
+ for entry in data.get("files") or []:
1263
+ if str(entry.get("id")) == str(file_id):
1264
+ label += f" · {entry.get('name', '')}"
1265
+ break
1266
+
1267
+ return label, [word for word in (data.get("trainedWords") or []) if word]
1268
+
1269
+
1270
+ def describe_lora(reference: str):
1271
+ """A readable line for whatever is in a box: a CivitAI link becomes its real title."""
1272
+ reference = (reference or "").strip()
1273
+ if not reference or reference == "(None)":
1274
+ return "", []
1275
+
1276
+ match = CIVITAI_DOWNLOAD_RE.search(reference)
1277
+ if match:
1278
+ file_id = ""
1279
+ if "fileId=" in reference:
1280
+ file_id = reference.split("fileId=", 1)[1].split("&")[0]
1281
+ return civitai_details(match.group(1), file_id)
1282
+
1283
+ if reference.startswith(("http://", "https://")):
1284
+ return os.path.basename(reference.split("?")[0]) or reference, []
1285
+ return reference, []
1286
+
1287
+
1288
+ def identify_loras(*fields):
1289
+ """Name every filled box across the five slots. `fields` arrives as
1290
+ `repo, high, low` per slot, so each slot is reported on one line."""
1291
+ lines = []
1292
+ for slot in range(len(fields) // 3):
1293
+ repo, high, low = fields[slot * 3: slot * 3 + 3]
1294
+ parts = []
1295
+ for role, value in (("repo", repo), ("high", high), ("low", low)):
1296
+ label, words = describe_lora(value)
1297
+ if not label:
1298
+ continue
1299
+ entry = f"{role}: {label}"
1300
+ if words:
1301
+ entry += f" — triggers: {', '.join(words[:6])}"
1302
+ parts.append(entry)
1303
+ if parts:
1304
+ lines.append(f"<b>Custom lora {slot + 1}</b> — " + " · ".join(parts))
1305
+ if not lines:
1306
+ return "<div class='status-idle'>Nothing in the slots yet.</div>"
1307
+ return "<div class='status-ok'>" + "<br>".join(lines) + "</div>"
1308
+
1309
+
1310
  def _target_size(image):
1311
  """Same math as resize_image(), but returns only the final (w, h)."""
1312
  if image is None:
 
1462
  box-shadow: 0 8px 22px rgba(124, 58, 237, .28);
1463
  }
1464
  #estimate-btn, #enhance-btn { min-height: 42px !important; border-radius: 12px !important; }
1465
+ #lora-identify, #profile-load, #profile-save, #profile-delete, #profile-refresh {
1466
  min-height: 42px !important; border-radius: 12px !important; font-weight: 600 !important;
1467
  }
1468
  #stop-btn, #clear-btn { min-height: 46px !important; border-radius: 12px !important; }
 
1714
  "two separate files, so paste the low-noise link straight into the Low box "
1715
  "(both boxes accept a pasted link). The Space downloads it itself, so being "
1716
  "signed in to CivitAI in your browser does not help a gated model: add "
1717
+ "`CIVITAI_TOKEN` under Settings → Variables and secrets. Downloads are cached.\n\n"
1718
+ "A CivitAI link is just a number, so press **🔎 name the CivitAI links** and "
1719
+ "each box is replaced by its real title, version, file name and trigger words, "
1720
+ "read from CivitAI's public API."
1721
  )
1722
+ with gr.Row():
1723
+ lora_identify_btn = gr.Button("🔎 name the CivitAI links",
1724
+ variant="secondary", elem_id="lora-identify")
1725
+ lora_names = gr.HTML("<div class='status-idle'>Nothing in the slots yet.</div>")
1726
  _my_rows = []
1727
  for _i in range(1, 6):
1728
  with gr.Accordion(f"Custom lora {_i}", open=(_i == 1)):
 
1962
  outputs=[merged_video, merged_file, merge_queue, merge_status],
1963
  )
1964
 
1965
+ # Naming the links. Registered here with the rest of the additions, and reading every box of every slot.
1966
+ _IDENTIFY_FIELDS = [
1967
+ my1_repo, my1_high, my1_low,
1968
+ my2_repo, my2_high, my2_low,
1969
+ my3_repo, my3_high, my3_low,
1970
+ my4_repo, my4_high, my4_low,
1971
+ my5_repo, my5_high, my5_low,
1972
+ ]
1973
+ lora_identify_btn.click(identify_loras, _IDENTIFY_FIELDS, lora_names)
1974
+
1975
  _SETTINGS_FIELDS = [
1976
  prompt_input, negative_prompt_input, duration_seconds_input, steps_slider, quality_slider,
1977
  seed_input, randomize_seed_checkbox, scheduler_dropdown, flow_shift_slider, frame_multi,