Archive images to fallback bucket
Browse files
app.py
CHANGED
|
@@ -44,7 +44,11 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
| 44 |
from fastapi.responses import FileResponse, Response
|
| 45 |
from gradio_client import Client
|
| 46 |
from gradio.routes import App
|
| 47 |
-
from huggingface_hub import
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
from PIL import Image, ImageDraw, ImageFont
|
| 49 |
from PIL.PngImagePlugin import PngInfo
|
| 50 |
from pydantic import BaseModel, ConfigDict, Field
|
|
@@ -74,7 +78,7 @@ os.environ.setdefault("YOLO_CONFIG_DIR", "/tmp/Ultralytics")
|
|
| 74 |
|
| 75 |
DATA_MOUNT = Path("/data")
|
| 76 |
BUCKET_MOUNT = Path("/CB")
|
| 77 |
-
HAS_DATA_MOUNT = DATA_MOUNT.is_dir()
|
| 78 |
DEFAULT_DATA_DIR = DATA_MOUNT if HAS_DATA_MOUNT else Path.cwd() / "data"
|
| 79 |
DATA_DIR = Path(os.environ.get("DATA_DIR", DEFAULT_DATA_DIR))
|
| 80 |
LOCAL_MODEL_DIR = Path(os.environ.get("LOCAL_MODEL_DIR", "/tmp/models"))
|
|
@@ -139,6 +143,9 @@ if not PASSWORD:
|
|
| 139 |
raise RuntimeError("pass environment variable is required")
|
| 140 |
|
| 141 |
BUCKET_ID = "HyperHail/CB"
|
|
|
|
|
|
|
|
|
|
| 142 |
MODEL_KINDS = (
|
| 143 |
"checkpoints", "diffusion_models", "clip", "vae", "loras",
|
| 144 |
"upscale_models", "ultralytics",
|
|
@@ -263,6 +270,11 @@ def cleanup_mount():
|
|
| 263 |
if path.is_file() and path.suffix.casefold() == ".7z":
|
| 264 |
path.unlink()
|
| 265 |
log(f"Deleted img/{path.relative_to(IMAGE_DIR)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
|
| 268 |
def download(url, target):
|
|
@@ -1538,10 +1550,11 @@ def generate_image(request, from_api=True):
|
|
| 1538 |
|
| 1539 |
|
| 1540 |
def archive_image(image, from_api):
|
| 1541 |
-
if not HAS_DATA_MOUNT:
|
| 1542 |
-
return
|
| 1543 |
try:
|
| 1544 |
-
|
|
|
|
|
|
|
|
|
|
| 1545 |
except Exception as error:
|
| 1546 |
log(f"Archive failed: {error}")
|
| 1547 |
|
|
@@ -1566,29 +1579,46 @@ def image_key(salt):
|
|
| 1566 |
def save_image(image, from_api):
|
| 1567 |
path = IMAGE_DIR / datetime.now(TIMEZONE).date().isoformat()
|
| 1568 |
path.mkdir(parents=True, exist_ok=True)
|
| 1569 |
-
suffix = "ST.
|
| 1570 |
-
number = (
|
| 1571 |
-
|
| 1572 |
-
file.name.
|
| 1573 |
-
and file.name.removesuffix(suffix).isdigit()
|
| 1574 |
for file in path.iterdir()
|
| 1575 |
-
|
| 1576 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1577 |
)
|
| 1578 |
-
if from_api:
|
| 1579 |
-
name = f"{number}{suffix}"
|
| 1580 |
-
output = path / name
|
| 1581 |
-
temp = output.with_suffix(".png.part")
|
| 1582 |
-
temp.write_bytes(image_png_bytes(image))
|
| 1583 |
-
temp.replace(output)
|
| 1584 |
-
log(f"Saved img/{output.relative_to(IMAGE_DIR)}")
|
| 1585 |
-
else:
|
| 1586 |
-
save_named_image(image, path / f"{number}{suffix}")
|
| 1587 |
|
| 1588 |
|
| 1589 |
-
def
|
| 1590 |
-
output.parent.mkdir(parents=True, exist_ok=True)
|
| 1591 |
-
temp = output.with_suffix(".epng.part")
|
| 1592 |
salt = os.urandom(SALT_SIZE)
|
| 1593 |
nonce = os.urandom(NONCE_SIZE)
|
| 1594 |
encrypted = AESGCM(image_key(salt)).encrypt(
|
|
@@ -1596,7 +1626,13 @@ def save_named_image(image, output):
|
|
| 1596 |
image_png_bytes(image),
|
| 1597 |
FILE_MAGIC,
|
| 1598 |
)
|
| 1599 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1600 |
temp.replace(output)
|
| 1601 |
log(f"Saved img/{output.relative_to(IMAGE_DIR)}")
|
| 1602 |
|
|
@@ -2620,9 +2656,8 @@ def archive(
|
|
| 2620 |
body: bytes = Body(),
|
| 2621 |
from_api: bool = Query(True),
|
| 2622 |
):
|
| 2623 |
-
|
| 2624 |
-
|
| 2625 |
-
backup_pool.submit(save_image, image, from_api).result()
|
| 2626 |
return {"status": True}
|
| 2627 |
|
| 2628 |
|
|
|
|
| 44 |
from fastapi.responses import FileResponse, Response
|
| 45 |
from gradio_client import Client
|
| 46 |
from gradio.routes import App
|
| 47 |
+
from huggingface_hub import (
|
| 48 |
+
batch_bucket_files,
|
| 49 |
+
download_bucket_files,
|
| 50 |
+
list_bucket_tree,
|
| 51 |
+
)
|
| 52 |
from PIL import Image, ImageDraw, ImageFont
|
| 53 |
from PIL.PngImagePlugin import PngInfo
|
| 54 |
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
| 78 |
|
| 79 |
DATA_MOUNT = Path("/data")
|
| 80 |
BUCKET_MOUNT = Path("/CB")
|
| 81 |
+
HAS_DATA_MOUNT = (DATA_MOUNT / "img").is_dir()
|
| 82 |
DEFAULT_DATA_DIR = DATA_MOUNT if HAS_DATA_MOUNT else Path.cwd() / "data"
|
| 83 |
DATA_DIR = Path(os.environ.get("DATA_DIR", DEFAULT_DATA_DIR))
|
| 84 |
LOCAL_MODEL_DIR = Path(os.environ.get("LOCAL_MODEL_DIR", "/tmp/models"))
|
|
|
|
| 143 |
raise RuntimeError("pass environment variable is required")
|
| 144 |
|
| 145 |
BUCKET_ID = "HyperHail/CB"
|
| 146 |
+
IMAGE_BUCKET_ID = "HyperHail/C"
|
| 147 |
+
IMAGE_BUCKET_PREFIX = "img"
|
| 148 |
+
IMAGE_TOKEN = os.environ.get("hh") or False
|
| 149 |
MODEL_KINDS = (
|
| 150 |
"checkpoints", "diffusion_models", "clip", "vae", "loras",
|
| 151 |
"upscale_models", "ultralytics",
|
|
|
|
| 270 |
if path.is_file() and path.suffix.casefold() == ".7z":
|
| 271 |
path.unlink()
|
| 272 |
log(f"Deleted img/{path.relative_to(IMAGE_DIR)}")
|
| 273 |
+
if HAS_DATA_MOUNT:
|
| 274 |
+
for path in IMAGE_DIR.glob("????-??-??/*.png"):
|
| 275 |
+
with Image.open(path) as image:
|
| 276 |
+
save_named_image(image, path.with_suffix(".epng"))
|
| 277 |
+
path.unlink()
|
| 278 |
|
| 279 |
|
| 280 |
def download(url, target):
|
|
|
|
| 1550 |
|
| 1551 |
|
| 1552 |
def archive_image(image, from_api):
|
|
|
|
|
|
|
| 1553 |
try:
|
| 1554 |
+
if HAS_DATA_MOUNT:
|
| 1555 |
+
save_image(image, from_api)
|
| 1556 |
+
else:
|
| 1557 |
+
upload_image(image)
|
| 1558 |
except Exception as error:
|
| 1559 |
log(f"Archive failed: {error}")
|
| 1560 |
|
|
|
|
| 1579 |
def save_image(image, from_api):
|
| 1580 |
path = IMAGE_DIR / datetime.now(TIMEZONE).date().isoformat()
|
| 1581 |
path.mkdir(parents=True, exist_ok=True)
|
| 1582 |
+
suffix = "ST.epng" if from_api else "C.epng"
|
| 1583 |
+
number = max(
|
| 1584 |
+
(
|
| 1585 |
+
int(file.name.removesuffix(suffix))
|
|
|
|
| 1586 |
for file in path.iterdir()
|
| 1587 |
+
if file.name.endswith(suffix)
|
| 1588 |
+
and file.name.removesuffix(suffix).isdigit()
|
| 1589 |
+
),
|
| 1590 |
+
default=0,
|
| 1591 |
+
) + 1
|
| 1592 |
+
save_named_image(image, path / f"{number}{suffix}")
|
| 1593 |
+
|
| 1594 |
+
|
| 1595 |
+
def upload_image(image):
|
| 1596 |
+
date = datetime.now(TIMEZONE).date().isoformat()
|
| 1597 |
+
folder = f"{IMAGE_BUCKET_PREFIX}/{date}"
|
| 1598 |
+
suffix = "ST.epng"
|
| 1599 |
+
number = max(
|
| 1600 |
+
(
|
| 1601 |
+
int(Path(item.path).name.removesuffix(suffix))
|
| 1602 |
+
for item in list_bucket_tree(
|
| 1603 |
+
IMAGE_BUCKET_ID,
|
| 1604 |
+
prefix=f"{folder}/",
|
| 1605 |
+
recursive=True,
|
| 1606 |
+
token=IMAGE_TOKEN,
|
| 1607 |
+
)
|
| 1608 |
+
if item.type == "file"
|
| 1609 |
+
and Path(item.path).name.endswith(suffix)
|
| 1610 |
+
and Path(item.path).name.removesuffix(suffix).isdigit()
|
| 1611 |
+
),
|
| 1612 |
+
default=0,
|
| 1613 |
+
) + 1
|
| 1614 |
+
batch_bucket_files(
|
| 1615 |
+
IMAGE_BUCKET_ID,
|
| 1616 |
+
add=[(encrypted_image_bytes(image), f"{folder}/{number}{suffix}")],
|
| 1617 |
+
token=IMAGE_TOKEN,
|
| 1618 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1619 |
|
| 1620 |
|
| 1621 |
+
def encrypted_image_bytes(image):
|
|
|
|
|
|
|
| 1622 |
salt = os.urandom(SALT_SIZE)
|
| 1623 |
nonce = os.urandom(NONCE_SIZE)
|
| 1624 |
encrypted = AESGCM(image_key(salt)).encrypt(
|
|
|
|
| 1626 |
image_png_bytes(image),
|
| 1627 |
FILE_MAGIC,
|
| 1628 |
)
|
| 1629 |
+
return FILE_MAGIC + salt + nonce + encrypted
|
| 1630 |
+
|
| 1631 |
+
|
| 1632 |
+
def save_named_image(image, output):
|
| 1633 |
+
output.parent.mkdir(parents=True, exist_ok=True)
|
| 1634 |
+
temp = output.with_suffix(".epng.part")
|
| 1635 |
+
temp.write_bytes(encrypted_image_bytes(image))
|
| 1636 |
temp.replace(output)
|
| 1637 |
log(f"Saved img/{output.relative_to(IMAGE_DIR)}")
|
| 1638 |
|
|
|
|
| 2656 |
body: bytes = Body(),
|
| 2657 |
from_api: bool = Query(True),
|
| 2658 |
):
|
| 2659 |
+
image = Image.open(BytesIO(body)).copy()
|
| 2660 |
+
backup_pool.submit(archive_image, image, from_api).result()
|
|
|
|
| 2661 |
return {"status": True}
|
| 2662 |
|
| 2663 |
|