q6 commited on
Commit
8734a4a
·
1 Parent(s): 5a03917

Add CB asset URL downloader

Browse files
Files changed (1) hide show
  1. app.py +114 -2
app.py CHANGED
@@ -20,6 +20,7 @@ from datetime import datetime
20
  from functools import lru_cache
21
  from io import BytesIO
22
  from pathlib import Path
 
23
  from zoneinfo import ZoneInfo
24
 
25
  ASYNCIO_FD_ERROR = "Invalid file descriptor: -1"
@@ -193,6 +194,10 @@ MODEL_SUFFIXES = (
193
  NUMBERED_MODEL_KINDS = ("checkpoints", "loras")
194
  MODEL_NUMBER = re.compile(r"^(\d+)_(.+)$")
195
  ANIMA_PREFIX = "anima"
 
 
 
 
196
  DEFAULT_NEGATIVE = (
197
  "(censored, mosaic censoring, bar censor:1.1), bad quality, worst quality, "
198
  "worst detail, bad anatomy, extra fingers, extra toes, extra legs, 4 toes, "
@@ -284,6 +289,7 @@ pool = ThreadPoolExecutor(max_workers=1)
284
  backup_pool = ThreadPoolExecutor(max_workers=1)
285
  matrix_pool = ThreadPoolExecutor(max_workers=1)
286
  model_pool = ThreadPoolExecutor(max_workers=1)
 
287
  matrix_grids = set()
288
  local_client = None
289
  local_client_lock = threading.Lock()
@@ -398,6 +404,11 @@ def download_assets(models):
398
  )
399
 
400
 
 
 
 
 
 
401
  def index_bucket_models():
402
  models = {kind: {} for kind in MODEL_KINDS}
403
  items = [
@@ -414,7 +425,7 @@ def index_bucket_models():
414
  kind, separator, name = item.path.partition("/")
415
  match = MODEL_NUMBER.match(name)
416
  if separator and kind in counters and match:
417
- anima = match.group(2).casefold().startswith(ANIMA_PREFIX)
418
  counters[kind][anima] = max(counters[kind][anima], int(match.group(1)))
419
 
420
  copies = []
@@ -424,7 +435,7 @@ def index_bucket_models():
424
  if not separator or kind not in models:
425
  continue
426
  if kind in counters and not MODEL_NUMBER.match(name):
427
- anima = name.casefold().startswith(ANIMA_PREFIX)
428
  counters[kind][anima] += 1
429
  name = f"{counters[kind][anima]}_{name}"
430
  path = f"{kind}/{name}"
@@ -451,6 +462,78 @@ def index_bucket_models():
451
  return added
452
 
453
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  def model_kind(name):
455
  return "diffusion_models" if is_anima_model(name) else "checkpoints"
456
 
@@ -3480,6 +3563,23 @@ with gr.Blocks(title="Image generation") as demo:
3480
  )
3481
  model_state = gr.State(DEFAULT_MODEL)
3482
  refresh_button = gr.Button("Refresh", scale=1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3483
  prompt_input = gr.Textbox(label="Prompt", lines=6)
3484
  negative_input = gr.Textbox(
3485
  DEFAULT_NEGATIVE,
@@ -3839,6 +3939,18 @@ with gr.Blocks(title="Image generation") as demo:
3839
  ],
3840
  queue=False,
3841
  )
 
 
 
 
 
 
 
 
 
 
 
 
3842
 
3843
  api_button.click(
3844
  api_generate,
 
20
  from functools import lru_cache
21
  from io import BytesIO
22
  from pathlib import Path
23
+ from urllib.parse import unquote, urlparse
24
  from zoneinfo import ZoneInfo
25
 
26
  ASYNCIO_FD_ERROR = "Invalid file descriptor: -1"
 
194
  NUMBERED_MODEL_KINDS = ("checkpoints", "loras")
195
  MODEL_NUMBER = re.compile(r"^(\d+)_(.+)$")
196
  ANIMA_PREFIX = "anima"
197
+ MODEL_LOCATION_CHOICES = [
198
+ (kind.replace("_", " ").title(), kind)
199
+ for kind in MODEL_KINDS
200
+ ]
201
  DEFAULT_NEGATIVE = (
202
  "(censored, mosaic censoring, bar censor:1.1), bad quality, worst quality, "
203
  "worst detail, bad anatomy, extra fingers, extra toes, extra legs, 4 toes, "
 
289
  backup_pool = ThreadPoolExecutor(max_workers=1)
290
  matrix_pool = ThreadPoolExecutor(max_workers=1)
291
  model_pool = ThreadPoolExecutor(max_workers=1)
292
+ model_download_lock = threading.Lock()
293
  matrix_grids = set()
294
  local_client = None
295
  local_client_lock = threading.Lock()
 
404
  )
405
 
406
 
407
+ def is_anima_asset(name):
408
+ name = name.casefold()
409
+ return name.startswith(ANIMA_PREFIX) and not name.startswith("animag")
410
+
411
+
412
  def index_bucket_models():
413
  models = {kind: {} for kind in MODEL_KINDS}
414
  items = [
 
425
  kind, separator, name = item.path.partition("/")
426
  match = MODEL_NUMBER.match(name)
427
  if separator and kind in counters and match:
428
+ anima = is_anima_asset(match.group(2))
429
  counters[kind][anima] = max(counters[kind][anima], int(match.group(1)))
430
 
431
  copies = []
 
435
  if not separator or kind not in models:
436
  continue
437
  if kind in counters and not MODEL_NUMBER.match(name):
438
+ anima = is_anima_asset(name)
439
  counters[kind][anima] += 1
440
  name = f"{counters[kind][anima]}_{name}"
441
  path = f"{kind}/{name}"
 
462
  return added
463
 
464
 
465
+ def bucket_url_filename(response):
466
+ name = response.headers.get_filename()
467
+ if not name:
468
+ name = Path(urlparse(response.geturl()).path).name
469
+ name = unquote(name).replace("\\", "/").rsplit("/", 1)[-1].strip()
470
+ match = MODEL_NUMBER.match(name)
471
+ return match.group(2) if match else name
472
+
473
+
474
+ def next_bucket_number(kind, anima):
475
+ numbers = []
476
+ for item in list_bucket_tree(
477
+ BUCKET_ID,
478
+ prefix=f"{kind}/",
479
+ recursive=True,
480
+ token=False,
481
+ ):
482
+ if item.type != "file" or "/" in item.path.removeprefix(f"{kind}/"):
483
+ continue
484
+ match = MODEL_NUMBER.match(Path(item.path).name)
485
+ if match and is_anima_asset(match.group(2)) == anima:
486
+ numbers.append(int(match.group(1)))
487
+ return max(numbers, default=0) + 1
488
+
489
+
490
+ def download_bucket_asset(url, kind, anima, password):
491
+ if not valid_pass(password):
492
+ raise gr.Error("Invalid password")
493
+ url = url.strip()
494
+ parsed = urlparse(url)
495
+ if parsed.scheme not in ("http", "https") or not parsed.netloc:
496
+ raise gr.Error("Enter a valid URL")
497
+ if kind not in MODEL_KINDS:
498
+ raise gr.Error("Invalid CB location")
499
+ if anima and kind == "checkpoints":
500
+ kind = "diffusion_models"
501
+
502
+ temp = None
503
+ try:
504
+ request = urllib.request.Request(
505
+ url,
506
+ headers={"User-Agent": "Mozilla/5.0"},
507
+ )
508
+ with urllib.request.urlopen(request) as response:
509
+ name = bucket_url_filename(response)
510
+ if Path(name).suffix.casefold() not in MODEL_SUFFIXES:
511
+ raise gr.Error("URL did not return a model file")
512
+ if anima and not is_anima_asset(name):
513
+ name = f"{ANIMA_PREFIX}_{name}"
514
+ with tempfile.NamedTemporaryFile(
515
+ suffix=Path(name).suffix,
516
+ delete=False,
517
+ ) as file:
518
+ temp = Path(file.name)
519
+ shutil.copyfileobj(response, file)
520
+
521
+ with model_download_lock:
522
+ number = next_bucket_number(kind, anima)
523
+ name = f"{number}_{name}"
524
+ path = f"{kind}/{name}"
525
+ batch_bucket_files(
526
+ BUCKET_ID,
527
+ add=[(temp, path)],
528
+ token=IMAGE_TOKEN,
529
+ )
530
+ index_bucket_models()
531
+ return f"Added {path}"
532
+ finally:
533
+ if temp:
534
+ temp.unlink(missing_ok=True)
535
+
536
+
537
  def model_kind(name):
538
  return "diffusion_models" if is_anima_model(name) else "checkpoints"
539
 
 
3563
  )
3564
  model_state = gr.State(DEFAULT_MODEL)
3565
  refresh_button = gr.Button("Refresh", scale=1)
3566
+ with gr.Accordion("Add CB asset", open=False):
3567
+ model_url_input = gr.Textbox(label="URL")
3568
+ with gr.Row():
3569
+ model_location_input = gr.Dropdown(
3570
+ MODEL_LOCATION_CHOICES,
3571
+ value="checkpoints",
3572
+ label="CB location",
3573
+ )
3574
+ anima_model_input = gr.Checkbox(
3575
+ False,
3576
+ label="Anima model",
3577
+ )
3578
+ model_download_button = gr.Button("Download")
3579
+ model_download_status = gr.Textbox(
3580
+ label="Status",
3581
+ interactive=False,
3582
+ )
3583
  prompt_input = gr.Textbox(label="Prompt", lines=6)
3584
  negative_input = gr.Textbox(
3585
  DEFAULT_NEGATIVE,
 
3939
  ],
3940
  queue=False,
3941
  )
3942
+ model_download_button.click(
3943
+ download_bucket_asset,
3944
+ [
3945
+ model_url_input,
3946
+ model_location_input,
3947
+ anima_model_input,
3948
+ pass_input,
3949
+ ],
3950
+ model_download_status,
3951
+ queue=False,
3952
+ api_visibility="private",
3953
+ )
3954
 
3955
  api_button.click(
3956
  api_generate,