Upload folder using huggingface_hub
Browse files- gen_eiffel_base.py +33 -0
- gen_eiffel_hq.py +35 -0
- gen_eiffel_scene.py +36 -0
- gen_hq.py +38 -0
- gen_images.py +48 -0
- gen_splats.py +54 -0
- hf_call.py +65 -0
gen_eiffel_base.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Eiffel diorama candidates with a CLEAN solid base (circle / square) so the
|
| 3 |
+
splat doesn't reconstruct a ragged 'cut' edge."""
|
| 4 |
+
import pathlib
|
| 5 |
+
import hf_call
|
| 6 |
+
|
| 7 |
+
ROOT = "https://ideogram-ai-ideogram4.hf.space"
|
| 8 |
+
OUT = pathlib.Path(__file__).parent / "images"
|
| 9 |
+
|
| 10 |
+
BASE = ("An architectural scale-model diorama of the Eiffel Tower standing on the "
|
| 11 |
+
"Champ de Mars, with tree-lined garden promenades, rows of trees and green "
|
| 12 |
+
"lawns spreading around its base. The whole diorama sits on a solid thick "
|
| 13 |
+
"{shape} display pedestal with a clean smooth {edge} edge and visible side "
|
| 14 |
+
"thickness, the ENTIRE {shape} base fully visible and centered in the frame "
|
| 15 |
+
"with margin around it. Isolated on a pure solid black background, gentle "
|
| 16 |
+
"elevated three-quarter view, dramatic soft studio lighting, photorealistic, "
|
| 17 |
+
"crisp fine detail, sharp focus, no people, no text, no watermark.")
|
| 18 |
+
|
| 19 |
+
CANDIDATES = {
|
| 20 |
+
"eiffel-circle": BASE.format(shape="circular", edge="round"),
|
| 21 |
+
"eiffel-square": BASE.format(shape="square", edge="straight"),
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
for slug, prompt in CANDIDATES.items():
|
| 25 |
+
dest = OUT / f"{slug}.jpg"
|
| 26 |
+
print(f"[gen ] {slug} ...", flush=True)
|
| 27 |
+
data = hf_call.call(ROOT, "generate", [
|
| 28 |
+
prompt, "Quality · 48 steps", "Ideogram (remote)", 1024, 1024, 0, True,
|
| 29 |
+
])
|
| 30 |
+
hf_call.download(data[0], dest, space_root=ROOT)
|
| 31 |
+
print(f"[ok ] {slug} -> {dest} ({dest.stat().st_size//1024} kB)", flush=True)
|
| 32 |
+
|
| 33 |
+
print("DONE")
|
gen_eiffel_hq.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Re-generate the Eiffel Tower splat at higher quality: more gaussians and
|
| 3 |
+
more refinement steps. Tries decreasing gaussian counts if the space rejects
|
| 4 |
+
a high value, and writes to splats/tour-eiffel.ply."""
|
| 5 |
+
import pathlib, time
|
| 6 |
+
import hf_call
|
| 7 |
+
|
| 8 |
+
ROOT = "https://vast-ai-triposplat.hf.space"
|
| 9 |
+
SRC = pathlib.Path(__file__).parent / "images" / "tour-eiffel.jpg"
|
| 10 |
+
DEST = pathlib.Path(__file__).parent / "splats" / "tour-eiffel.ply"
|
| 11 |
+
|
| 12 |
+
GAUSSIAN_CANDIDATES = [524288, 393216, 327680, 262144]
|
| 13 |
+
STEPS = 32
|
| 14 |
+
|
| 15 |
+
ok = False
|
| 16 |
+
for ng in GAUSSIAN_CANDIDATES:
|
| 17 |
+
for attempt in range(1, 4):
|
| 18 |
+
try:
|
| 19 |
+
print(f"[up ] uploading image (ng={ng}, try {attempt}) ...", flush=True)
|
| 20 |
+
fd = hf_call.upload(ROOT, SRC)
|
| 21 |
+
print(f"[gen ] generating HQ splat: {ng} gaussians, {STEPS} steps ...", flush=True)
|
| 22 |
+
data = hf_call.call(ROOT, "generate", [
|
| 23 |
+
fd, 42, STEPS, 3.0, ng, "ply",
|
| 24 |
+
], timeout=2400)
|
| 25 |
+
hf_call.download(data[1], DEST, space_root=ROOT)
|
| 26 |
+
print(f"[ok ] tour-eiffel HQ -> {DEST} ({DEST.stat().st_size//1024} kB, {ng} gaussians)", flush=True)
|
| 27 |
+
ok = True
|
| 28 |
+
break
|
| 29 |
+
except Exception as e:
|
| 30 |
+
print(f"[err ] ng={ng} attempt {attempt}: {e}", flush=True)
|
| 31 |
+
time.sleep(12)
|
| 32 |
+
if ok:
|
| 33 |
+
break
|
| 34 |
+
|
| 35 |
+
print("DONE" if ok else "FAILED")
|
gen_eiffel_scene.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Generate richer Eiffel Tower 'scene diorama' candidate images (tower + its
|
| 3 |
+
setting) on black, for the user to pick from before splatting."""
|
| 4 |
+
import pathlib
|
| 5 |
+
import hf_call
|
| 6 |
+
|
| 7 |
+
ROOT = "https://ideogram-ai-ideogram4.hf.space"
|
| 8 |
+
OUT = pathlib.Path(__file__).parent / "images"
|
| 9 |
+
OUT.mkdir(exist_ok=True)
|
| 10 |
+
|
| 11 |
+
COMMON = ("scene presented as a floating circular diorama isolated on a pure solid "
|
| 12 |
+
"black background, dramatic soft three-quarter studio lighting, photorealistic, "
|
| 13 |
+
"crisp fine detail, sharp focus, no people, no text, no watermark, "
|
| 14 |
+
"elevated three-quarter aerial view")
|
| 15 |
+
|
| 16 |
+
CANDIDATES = {
|
| 17 |
+
"eiffel-gardens": (
|
| 18 |
+
"The Eiffel Tower rising from the Champ de Mars, with the long tree-lined "
|
| 19 |
+
"garden promenades, rows of trees and manicured green lawns spreading out "
|
| 20 |
+
"around its base, the complete iron tower fully visible, " + COMMON),
|
| 21 |
+
"eiffel-bridge": (
|
| 22 |
+
"The Eiffel Tower with the Pont d'Iéna stone bridge crossing the river Seine "
|
| 23 |
+
"directly in front of it, tree-lined riverbanks and quays, the complete iron "
|
| 24 |
+
"tower fully visible behind the bridge, " + COMMON),
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
for slug, prompt in CANDIDATES.items():
|
| 28 |
+
dest = OUT / f"{slug}.jpg"
|
| 29 |
+
print(f"[gen ] {slug} ...", flush=True)
|
| 30 |
+
data = hf_call.call(ROOT, "generate", [
|
| 31 |
+
prompt, "Quality · 48 steps", "Ideogram (remote)", 1024, 1024, 0, True,
|
| 32 |
+
])
|
| 33 |
+
hf_call.download(data[0], dest, space_root=ROOT)
|
| 34 |
+
print(f"[ok ] {slug} -> {dest} ({dest.stat().st_size//1024} kB)", flush=True)
|
| 35 |
+
|
| 36 |
+
print("DONE")
|
gen_hq.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Reusable high-quality splat generator: 524K gaussians (with fallbacks) + 32 steps.
|
| 3 |
+
Usage: python3 gen_hq.py <slug> [<slug> ...] (reads images/<slug>.jpg -> splats/<slug>.ply)"""
|
| 4 |
+
import sys, pathlib, time
|
| 5 |
+
import hf_call
|
| 6 |
+
|
| 7 |
+
ROOT = "https://vast-ai-triposplat.hf.space"
|
| 8 |
+
IMG = pathlib.Path(__file__).parent / "images"
|
| 9 |
+
OUT = pathlib.Path(__file__).parent / "splats"
|
| 10 |
+
OUT.mkdir(exist_ok=True)
|
| 11 |
+
|
| 12 |
+
GAUSSIANS = [524288, 393216, 327680, 262144]
|
| 13 |
+
STEPS = 32
|
| 14 |
+
|
| 15 |
+
for slug in sys.argv[1:]:
|
| 16 |
+
src = IMG / f"{slug}.jpg"
|
| 17 |
+
dest = OUT / f"{slug}.ply"
|
| 18 |
+
if not src.exists():
|
| 19 |
+
print(f"[miss] {slug}: no image", flush=True); continue
|
| 20 |
+
ok = False
|
| 21 |
+
for ng in GAUSSIANS:
|
| 22 |
+
for attempt in range(1, 4):
|
| 23 |
+
try:
|
| 24 |
+
print(f"[up ] {slug} (ng={ng}, try {attempt}) ...", flush=True)
|
| 25 |
+
fd = hf_call.upload(ROOT, src)
|
| 26 |
+
print(f"[gen ] {slug}: {ng} gaussians, {STEPS} steps ...", flush=True)
|
| 27 |
+
data = hf_call.call(ROOT, "generate", [fd, 42, STEPS, 3.0, ng, "ply"], timeout=2400)
|
| 28 |
+
hf_call.download(data[1], dest, space_root=ROOT)
|
| 29 |
+
print(f"[ok ] {slug} -> {dest} ({dest.stat().st_size//1024} kB, {ng} gaussians)", flush=True)
|
| 30 |
+
ok = True; break
|
| 31 |
+
except Exception as e:
|
| 32 |
+
print(f"[err ] {slug} ng={ng} attempt {attempt}: {e}", flush=True)
|
| 33 |
+
time.sleep(12)
|
| 34 |
+
if ok: break
|
| 35 |
+
if not ok:
|
| 36 |
+
print(f"[FAIL] {slug}", flush=True)
|
| 37 |
+
|
| 38 |
+
print("DONE")
|
gen_images.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Generate dark-background, isolated-specimen images of Paris monuments
|
| 3 |
+
via the ideogram-ai/ideogram4 Gradio space, then save them locally."""
|
| 4 |
+
import pathlib
|
| 5 |
+
import hf_call
|
| 6 |
+
|
| 7 |
+
ROOT = "https://ideogram-ai-ideogram4.hf.space"
|
| 8 |
+
OUT = pathlib.Path(__file__).parent / "images"
|
| 9 |
+
OUT.mkdir(exist_ok=True)
|
| 10 |
+
|
| 11 |
+
MONUMENTS = {
|
| 12 |
+
"tour-eiffel": "the Eiffel Tower, the complete iron lattice tower",
|
| 13 |
+
"opera-garnier": "the Palais Garnier opera house of Paris, the complete ornate Beaux-Arts opera building with its green dome, columned facade and gilded rooftop sculptures",
|
| 14 |
+
"arc-de-triomphe": "the Arc de Triomphe, the complete triumphal arch",
|
| 15 |
+
"sacre-coeur": "the Sacré-Cœur Basilica of Montmartre, the complete white-domed basilica",
|
| 16 |
+
"moulin-rouge": "the Moulin Rouge cabaret of Paris, the complete building with its iconic bright red windmill on the roof, red facade and awnings",
|
| 17 |
+
"pantheon": "the Panthéon of Paris, the complete neoclassical monument with its large dome and tall columned portico",
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
def prompt_for(subject):
|
| 21 |
+
return (
|
| 22 |
+
f"A photorealistic architectural studio photograph of {subject}, "
|
| 23 |
+
"the entire structure fully visible and centered in the frame, "
|
| 24 |
+
"isolated on a pure solid black background, dramatic soft three-quarter "
|
| 25 |
+
"studio lighting, crisp fine detail, sharp focus, no people, no text, "
|
| 26 |
+
"no watermark, museum specimen presentation, full object 3/4 view"
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
for slug, subject in MONUMENTS.items():
|
| 30 |
+
dest = OUT / f"{slug}.jpg"
|
| 31 |
+
if dest.exists():
|
| 32 |
+
print(f"[skip] {slug}", flush=True)
|
| 33 |
+
continue
|
| 34 |
+
print(f"[gen ] {slug} ...", flush=True)
|
| 35 |
+
data = hf_call.call(ROOT, "generate", [
|
| 36 |
+
prompt_for(subject), # prompt
|
| 37 |
+
"Quality · 48 steps", # mode
|
| 38 |
+
"Ideogram (remote)", # upsampler
|
| 39 |
+
1024, # width
|
| 40 |
+
1024, # height
|
| 41 |
+
0, # seed
|
| 42 |
+
True, # randomize_seed
|
| 43 |
+
])
|
| 44 |
+
img = data[0]
|
| 45 |
+
hf_call.download(img, dest, space_root=ROOT)
|
| 46 |
+
print(f"[ok ] {slug} -> {dest} ({dest.stat().st_size//1024} kB)", flush=True)
|
| 47 |
+
|
| 48 |
+
print("DONE")
|
gen_splats.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Turn each monument image into a 3D gaussian splat (.ply) via the
|
| 3 |
+
VAST-AI/TripoSplat Gradio space."""
|
| 4 |
+
import pathlib, sys, time
|
| 5 |
+
import hf_call
|
| 6 |
+
|
| 7 |
+
ROOT = "https://vast-ai-triposplat.hf.space"
|
| 8 |
+
IMG = pathlib.Path(__file__).parent / "images"
|
| 9 |
+
OUT = pathlib.Path(__file__).parent / "splats"
|
| 10 |
+
OUT.mkdir(exist_ok=True)
|
| 11 |
+
|
| 12 |
+
SLUGS = ["tour-eiffel", "louvre-pyramid", "arc-de-triomphe",
|
| 13 |
+
"sacre-coeur", "notre-dame", "obelisque"]
|
| 14 |
+
|
| 15 |
+
# allow running a subset: python3 gen_splats.py tour-eiffel obelisque
|
| 16 |
+
if len(sys.argv) > 1:
|
| 17 |
+
SLUGS = sys.argv[1:]
|
| 18 |
+
|
| 19 |
+
for slug in SLUGS:
|
| 20 |
+
src = IMG / f"{slug}.jpg"
|
| 21 |
+
dest = OUT / f"{slug}.ply"
|
| 22 |
+
if dest.exists():
|
| 23 |
+
print(f"[skip] {slug}", flush=True)
|
| 24 |
+
continue
|
| 25 |
+
if not src.exists():
|
| 26 |
+
print(f"[miss] {slug} image not found", flush=True)
|
| 27 |
+
continue
|
| 28 |
+
ok = False
|
| 29 |
+
for attempt in range(1, 5):
|
| 30 |
+
try:
|
| 31 |
+
print(f"[up ] {slug} uploading image (try {attempt}) ...", flush=True)
|
| 32 |
+
filedata = hf_call.upload(ROOT, src)
|
| 33 |
+
print(f"[gen ] {slug} generating splat (this can take a few min) ...", flush=True)
|
| 34 |
+
data = hf_call.call(ROOT, "generate", [
|
| 35 |
+
filedata, # image
|
| 36 |
+
42, # seed
|
| 37 |
+
20, # steps
|
| 38 |
+
3.0, # guidance_scale
|
| 39 |
+
262144, # num_gaussians
|
| 40 |
+
"ply", # output_format
|
| 41 |
+
], timeout=1800)
|
| 42 |
+
# returns (preprocessed_image, ply_file, download_file, info_string)
|
| 43 |
+
ply = data[1]
|
| 44 |
+
hf_call.download(ply, dest, space_root=ROOT)
|
| 45 |
+
print(f"[ok ] {slug} -> {dest} ({dest.stat().st_size//1024} kB)", flush=True)
|
| 46 |
+
ok = True
|
| 47 |
+
break
|
| 48 |
+
except Exception as e:
|
| 49 |
+
print(f"[err ] {slug} attempt {attempt}: {e}", flush=True)
|
| 50 |
+
time.sleep(15)
|
| 51 |
+
if not ok:
|
| 52 |
+
print(f"[FAIL] {slug} gave up after retries", flush=True)
|
| 53 |
+
|
| 54 |
+
print("DONE")
|
hf_call.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Minimal Gradio REST helper (no gradio_client dependency).
|
| 2 |
+
Implements: upload file, call endpoint, poll SSE result."""
|
| 3 |
+
import os, json, pathlib, requests
|
| 4 |
+
|
| 5 |
+
def token():
|
| 6 |
+
return (os.environ.get("HF_TOKEN")
|
| 7 |
+
or pathlib.Path("~/.cache/huggingface/token").expanduser().read_text().strip())
|
| 8 |
+
|
| 9 |
+
def _headers():
|
| 10 |
+
return {"Authorization": f"Bearer {token()}"}
|
| 11 |
+
|
| 12 |
+
def upload(space_root, filepath):
|
| 13 |
+
"""Upload a local file, return the gradio FileData dict to reference it."""
|
| 14 |
+
with open(filepath, "rb") as f:
|
| 15 |
+
r = requests.post(f"{space_root}/gradio_api/upload",
|
| 16 |
+
headers=_headers(),
|
| 17 |
+
files={"files": (pathlib.Path(filepath).name, f)},
|
| 18 |
+
timeout=300)
|
| 19 |
+
r.raise_for_status()
|
| 20 |
+
server_path = r.json()[0]
|
| 21 |
+
return {"path": server_path, "meta": {"_type": "gradio.FileData"},
|
| 22 |
+
"orig_name": pathlib.Path(filepath).name, "url": None,
|
| 23 |
+
"size": None, "mime_type": None, "is_stream": False}
|
| 24 |
+
|
| 25 |
+
def call(space_root, api_name, data, timeout=900):
|
| 26 |
+
"""Call /gradio_api/call/{api_name} with ordered `data` list; poll SSE; return data list."""
|
| 27 |
+
r = requests.post(f"{space_root}/gradio_api/call/{api_name}",
|
| 28 |
+
headers={**_headers(), "Content-Type": "application/json"},
|
| 29 |
+
data=json.dumps({"data": data}), timeout=60)
|
| 30 |
+
r.raise_for_status()
|
| 31 |
+
event_id = r.json()["event_id"]
|
| 32 |
+
# poll the SSE stream
|
| 33 |
+
with requests.get(f"{space_root}/gradio_api/call/{api_name}/{event_id}",
|
| 34 |
+
headers=_headers(), stream=True, timeout=timeout) as s:
|
| 35 |
+
s.raise_for_status()
|
| 36 |
+
event = None
|
| 37 |
+
for raw in s.iter_lines(decode_unicode=True):
|
| 38 |
+
if raw is None or raw == "":
|
| 39 |
+
continue
|
| 40 |
+
if raw.startswith("event:"):
|
| 41 |
+
event = raw.split(":", 1)[1].strip()
|
| 42 |
+
elif raw.startswith("data:"):
|
| 43 |
+
payload = raw.split(":", 1)[1].strip()
|
| 44 |
+
if event == "complete":
|
| 45 |
+
return json.loads(payload)
|
| 46 |
+
if event == "error":
|
| 47 |
+
raise RuntimeError(f"Gradio error: {payload}")
|
| 48 |
+
raise RuntimeError("SSE stream ended without a 'complete' event")
|
| 49 |
+
|
| 50 |
+
def download(url_or_data, dest, space_root=None):
|
| 51 |
+
"""Download a gradio result (url string or FileData dict) to dest."""
|
| 52 |
+
if isinstance(url_or_data, dict):
|
| 53 |
+
url = url_or_data.get("url")
|
| 54 |
+
if not url and url_or_data.get("path") and space_root:
|
| 55 |
+
url = f"{space_root}/gradio_api/file={url_or_data['path']}"
|
| 56 |
+
else:
|
| 57 |
+
url = url_or_data
|
| 58 |
+
if url and url.startswith("/") and space_root:
|
| 59 |
+
url = space_root + url
|
| 60 |
+
r = requests.get(url, headers=_headers(), stream=True, timeout=600)
|
| 61 |
+
r.raise_for_status()
|
| 62 |
+
with open(dest, "wb") as f:
|
| 63 |
+
for chunk in r.iter_content(chunk_size=1 << 16):
|
| 64 |
+
f.write(chunk)
|
| 65 |
+
return dest
|