File size: 3,400 Bytes
a0e0dac
 
 
 
 
3c5d9dd
 
 
a0e0dac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c5d9dd
a0e0dac
3c5d9dd
a0e0dac
 
 
3c5d9dd
 
 
 
 
 
 
 
 
a0e0dac
3c5d9dd
 
 
a0e0dac
3c5d9dd
 
 
 
a0e0dac
 
 
 
 
 
 
 
 
 
 
 
3c5d9dd
 
a0e0dac
3c5d9dd
 
a0e0dac
3c5d9dd
 
 
a0e0dac
3c5d9dd
 
 
 
 
 
a0e0dac
 
3c5d9dd
 
 
a0e0dac
 
3c5d9dd
 
a0e0dac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import os
import time
import uuid
from typing import Optional

import gradio as gr
from PIL import Image

# ------------------------------------------------------------
# Pick a writable save directory automatically.
# Order:
# 1) SAVE_DIR env var (if supplied)
# 2) /data/uploads           (when Persistent Storage is enabled)
# 3) /home/user/app/uploads  (always writable in Spaces)
# 4) /tmp/uploads            (always writable, ephemeral)
# ------------------------------------------------------------
def pick_writable_dir() -> str:
    candidates = []
    env_dir = os.getenv("SAVE_DIR")
    if env_dir:
        candidates.append(env_dir)
    candidates += ["/data/uploads", "/home/user/app/uploads", "/tmp/uploads"]

    for path in candidates:
        try:
            os.makedirs(path, exist_ok=True)
            # double-check we can create files here
            testfile = os.path.join(path, f".write_test_{uuid.uuid4().hex}")
            with open(testfile, "w") as f:
                f.write("ok")
            os.remove(testfile)
            return path
        except Exception:
            continue
    # last resort: current directory
    fallback = "./uploads"
    os.makedirs(fallback, exist_ok=True)
    return fallback

SAVE_DIR = pick_writable_dir()

ALLOWED_FORMATS = {"JPEG", "PNG"}  # strict type enforcement

def handle_upload(file_path: Optional[str]):
    if not file_path:
        return "Please choose an image.", None

    try:
        with Image.open(file_path) as im:
            fmt = (im.format or "").upper()
            if fmt not in ALLOWED_FORMATS:
                return f"Only JPEG/PNG allowed. Detected: {fmt or 'unknown'}.", None

            # Normalize to RGB so we can always save safely
            if im.mode not in ("RGB", "RGBA"):
                im = im.convert("RGB")

            # Choose extension from the detected format
            ext = ".jpg" if fmt == "JPEG" else ".png"
            filename = f"{int(time.time())}_{uuid.uuid4().hex}{ext}"
            save_path = os.path.join(SAVE_DIR, filename)

            # Reasonable defaults for each format
            if fmt == "JPEG":
                im.save(save_path, quality=90, optimize=True)
            else:
                im.save(save_path, optimize=True)

            info = (
                f"βœ… Saved to **{save_path}**\n\n"
                f"- File: **{filename}**\n"
                f"- Size: **{im.width}Γ—{im.height}px**\n"
                f"- Format: **{fmt}**"
            )
            return info, im.copy()
    except Exception as e:
        return f"Failed to read/save image: {e}", None

with gr.Blocks(title="Image Upload (JPEG/PNG)") as demo:
    gr.Markdown("### Upload a JPEG or PNG. The file will be validated and saved.")
    with gr.Row():
        inp = gr.Image(
            label="Drop or click to upload",
            type="filepath",              # keep original temp filepath
            image_mode="RGB",
            sources=["upload", "clipboard"]
        )
        preview = gr.Image(label="Preview", interactive=False)

    msg = gr.Markdown()

    # Auto-save when the image changes; also allow manual click.
    inp.change(handle_upload, inputs=inp, outputs=[msg, preview])
    gr.Button("Save").click(handle_upload, inputs=inp, outputs=[msg, preview])

    gr.Markdown(f"**Save directory:** `{SAVE_DIR}`")

if __name__ == "__main__":
    demo.launch()