q6 commited on
Commit
f2e0574
·
1 Parent(s): e22f338

Support URL CB asset uploads

Browse files
Files changed (1) hide show
  1. app.py +91 -44
app.py CHANGED
@@ -20,7 +20,7 @@ from datetime import datetime
20
  from functools import lru_cache
21
  from io import BytesIO
22
  from pathlib import Path
23
- from urllib.parse import quote
24
  from zoneinfo import ZoneInfo
25
 
26
  ASYNCIO_FD_ERROR = "Invalid file descriptor: -1"
@@ -197,6 +197,15 @@ MODEL_LOCATION_CHOICES = [
197
  (kind.replace("_", " ").title(), kind)
198
  for kind in MODEL_KINDS
199
  ]
 
 
 
 
 
 
 
 
 
200
  DEFAULT_NEGATIVE = (
201
  "(censored, mosaic censoring, bar censor:1.1), bad quality, worst quality, "
202
  "worst detail, bad anatomy, extra fingers, extra toes, extra legs, 4 toes, "
@@ -502,54 +511,90 @@ def bucket_numbers(kind, anima):
502
  return numbers
503
 
504
 
505
- def upload_bucket_assets(files, kind, anima, password):
 
 
 
 
 
 
 
 
 
506
  if not valid_pass(password):
507
  raise gr.Error("Invalid password")
508
  if kind not in MODEL_KINDS:
509
  raise gr.Error("Invalid CB location")
510
- if not files:
511
- raise gr.Error("Select at least one file")
 
 
512
 
513
- assets = []
514
- for file in files:
515
- source = Path(file)
516
- match = MODEL_NUMBER.match(source.name)
517
- number, name = (int(match.group(1)), match.group(2)) \
518
- if match else (None, source.name)
519
- if source.suffix.casefold() not in MODEL_SUFFIXES:
520
- raise gr.Error(f"Unsupported model file: {name}")
521
- if anima and not is_anima_asset(name):
522
- name = f"{ANIMA_PREFIX}_{name}"
523
- assets.append((source, number, name))
524
-
525
- with model_upload_lock:
526
- used = bucket_numbers(kind, anima)
527
- reserved = {
528
- number for _, number, _ in assets
529
- if number is not None and number not in used
530
- }
531
- next_number = max(used, default=0) + 1
532
- additions = []
533
- paths = []
534
- for source, number, name in assets:
535
- if number is not None and number in reserved:
536
- reserved.remove(number)
537
- else:
538
- while next_number in used or next_number in reserved:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  next_number += 1
540
- number = next_number
541
- next_number += 1
542
- used.add(number)
543
- path = f"{kind}/{number}_{name}"
544
- additions.append((source, path))
545
- paths.append(path)
546
- batch_bucket_files(
547
- BUCKET_ID,
548
- add=additions,
549
- token=IMAGE_TOKEN,
550
- )
551
- index_bucket_models()
552
- return "Added " + ", ".join(paths)
 
553
 
554
 
555
  def model_kind(name):
@@ -3612,6 +3657,7 @@ with gr.Blocks(title="Image generation") as demo:
3612
  file_types=list(MODEL_SUFFIXES),
3613
  type="filepath",
3614
  )
 
3615
  with gr.Row():
3616
  model_location_input = gr.Dropdown(
3617
  MODEL_LOCATION_CHOICES,
@@ -3622,7 +3668,7 @@ with gr.Blocks(title="Image generation") as demo:
3622
  False,
3623
  label="Anima model",
3624
  )
3625
- model_upload_button = gr.Button("Upload")
3626
  model_upload_status = gr.Textbox(
3627
  label="Status",
3628
  interactive=False,
@@ -3990,6 +4036,7 @@ with gr.Blocks(title="Image generation") as demo:
3990
  upload_bucket_assets,
3991
  [
3992
  model_files_input,
 
3993
  model_location_input,
3994
  anima_model_input,
3995
  pass_input,
 
20
  from functools import lru_cache
21
  from io import BytesIO
22
  from pathlib import Path
23
+ from urllib.parse import quote, unquote, urlparse
24
  from zoneinfo import ZoneInfo
25
 
26
  ASYNCIO_FD_ERROR = "Invalid file descriptor: -1"
 
197
  (kind.replace("_", " ").title(), kind)
198
  for kind in MODEL_KINDS
199
  ]
200
+ DOWNLOAD_HEADERS = {
201
+ "User-Agent": (
202
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) "
203
+ "Gecko/20100101 Firefox/140.0"
204
+ ),
205
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
206
+ "Accept-Language": "en-US,en;q=0.5",
207
+ "Referer": "https://civitai.com/",
208
+ }
209
  DEFAULT_NEGATIVE = (
210
  "(censored, mosaic censoring, bar censor:1.1), bad quality, worst quality, "
211
  "worst detail, bad anatomy, extra fingers, extra toes, extra legs, 4 toes, "
 
511
  return numbers
512
 
513
 
514
+ def bucket_url_filename(response):
515
+ name = response.headers.get_filename()
516
+ if not name:
517
+ name = Path(urlparse(response.geturl()).path).name
518
+ name = unquote(name).replace("\\", "/").rsplit("/", 1)[-1].strip()
519
+ match = MODEL_NUMBER.match(name)
520
+ return match.group(2) if match else name
521
+
522
+
523
+ def upload_bucket_assets(files, url, kind, anima, password):
524
  if not valid_pass(password):
525
  raise gr.Error("Invalid password")
526
  if kind not in MODEL_KINDS:
527
  raise gr.Error("Invalid CB location")
528
+ files = files or []
529
+ url = (url or "").strip()
530
+ if not files and not url:
531
+ raise gr.Error("Select a file or enter a URL")
532
 
533
+ temp = None
534
+ try:
535
+ assets = []
536
+ for file in files:
537
+ source = Path(file)
538
+ match = MODEL_NUMBER.match(source.name)
539
+ number, name = (int(match.group(1)), match.group(2)) \
540
+ if match else (None, source.name)
541
+ if source.suffix.casefold() not in MODEL_SUFFIXES:
542
+ raise gr.Error(f"Unsupported model file: {name}")
543
+ if anima and not is_anima_asset(name):
544
+ name = f"{ANIMA_PREFIX}_{name}"
545
+ assets.append((source, number, name))
546
+
547
+ if url:
548
+ parsed = urlparse(url)
549
+ if parsed.scheme not in ("http", "https") or not parsed.netloc:
550
+ raise gr.Error("Enter a valid URL")
551
+ request = urllib.request.Request(url, headers=DOWNLOAD_HEADERS)
552
+ with urllib.request.urlopen(request) as response:
553
+ name = bucket_url_filename(response)
554
+ suffix = Path(name).suffix.casefold()
555
+ if suffix not in MODEL_SUFFIXES:
556
+ raise gr.Error("URL did not return a model file")
557
+ if anima and not is_anima_asset(name):
558
+ name = f"{ANIMA_PREFIX}_{name}"
559
+ with tempfile.NamedTemporaryFile(
560
+ suffix=suffix,
561
+ delete=False,
562
+ ) as file:
563
+ temp = Path(file.name)
564
+ shutil.copyfileobj(response, file)
565
+ assets.append((temp, None, name))
566
+
567
+ with model_upload_lock:
568
+ used = bucket_numbers(kind, anima)
569
+ reserved = {
570
+ number for _, number, _ in assets
571
+ if number is not None and number not in used
572
+ }
573
+ next_number = max(used, default=0) + 1
574
+ additions = []
575
+ paths = []
576
+ for source, number, name in assets:
577
+ if number is not None and number in reserved:
578
+ reserved.remove(number)
579
+ else:
580
+ while next_number in used or next_number in reserved:
581
+ next_number += 1
582
+ number = next_number
583
  next_number += 1
584
+ used.add(number)
585
+ path = f"{kind}/{number}_{name}"
586
+ additions.append((source, path))
587
+ paths.append(path)
588
+ batch_bucket_files(
589
+ BUCKET_ID,
590
+ add=additions,
591
+ token=IMAGE_TOKEN,
592
+ )
593
+ index_bucket_models()
594
+ return "Added " + ", ".join(paths)
595
+ finally:
596
+ if temp:
597
+ temp.unlink(missing_ok=True)
598
 
599
 
600
  def model_kind(name):
 
3657
  file_types=list(MODEL_SUFFIXES),
3658
  type="filepath",
3659
  )
3660
+ model_url_input = gr.Textbox(label="URL")
3661
  with gr.Row():
3662
  model_location_input = gr.Dropdown(
3663
  MODEL_LOCATION_CHOICES,
 
3668
  False,
3669
  label="Anima model",
3670
  )
3671
+ model_upload_button = gr.Button("Add")
3672
  model_upload_status = gr.Textbox(
3673
  label="Status",
3674
  interactive=False,
 
4036
  upload_bucket_assets,
4037
  [
4038
  model_files_input,
4039
+ model_url_input,
4040
  model_location_input,
4041
  anima_model_input,
4042
  pass_input,