Spaces:
Running on Zero
Running on Zero
Add project spec, update README metadata, and .gitignore
Browse files- Add detailed project specification in `spec.mdx`
- Update `.gitignore` to include `/TODO`
- Revise `README.md` frontmatter: new title, emoji, colors, sdk_version, and metadata
- .gitignore +1 -0
- README.md +1 -1
- app.py +13 -11
- spec.mdx +258 -0
- utils/hex_hura.py +2 -2
.gitignore
CHANGED
|
@@ -169,3 +169,4 @@ cython_debug/
|
|
| 169 |
**/*.pyc
|
| 170 |
**/__pycache__/
|
| 171 |
/utils/tmp
|
|
|
|
|
|
| 169 |
**/*.pyc
|
| 170 |
**/__pycache__/
|
| 171 |
/utils/tmp
|
| 172 |
+
/TODO
|
README.md
CHANGED
|
@@ -5,7 +5,7 @@ colorFrom: yellow
|
|
| 5 |
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
python_version: 3.10.13
|
| 8 |
-
sdk_version:
|
| 9 |
app_file: app.py
|
| 10 |
pinned: true
|
| 11 |
short_description: Transform Your Images into Mesmerizing Hexagon Grids and 3D!
|
|
|
|
| 5 |
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
python_version: 3.10.13
|
| 8 |
+
sdk_version: 6.10.0
|
| 9 |
app_file: app.py
|
| 10 |
pinned: true
|
| 11 |
short_description: Transform Your Images into Mesmerizing Hexagon Grids and 3D!
|
app.py
CHANGED
|
@@ -154,7 +154,11 @@ def start_session(req: gr.Request):
|
|
| 154 |
os.makedirs(user_dir, exist_ok=True)
|
| 155 |
|
| 156 |
|
| 157 |
-
def end_session(req: gr.Request):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
print(f"Ending session with hash: {req.session_hash}")
|
| 159 |
user_dir = os.path.join(constants.TMPDIR, str(req.session_hash))
|
| 160 |
if os.path.exists(user_dir):
|
|
@@ -1239,7 +1243,7 @@ examples = [["assets//examples//hex_map_p1.png", 32, 1, 0, 0, 0, 0, 0, "#ede9ac4
|
|
| 1239 |
gr.set_static_paths(paths=["images/","images/images","images/prerendered","LUT/","fonts/","assets/"])
|
| 1240 |
|
| 1241 |
# Gradio Blocks Interface
|
| 1242 |
-
with gr.Blocks(
|
| 1243 |
with gr.Row():
|
| 1244 |
gr.Markdown("""
|
| 1245 |
# HexaGrid Creator
|
|
@@ -1507,7 +1511,6 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
| 1507 |
allow_preview=False, preview=False ,
|
| 1508 |
columns=2,
|
| 1509 |
elem_id="lora_gallery",
|
| 1510 |
-
show_share_button=False,
|
| 1511 |
elem_classes="solid", type="filepath",
|
| 1512 |
object_fit="contain", height="auto", format="png",
|
| 1513 |
)
|
|
@@ -1599,7 +1602,7 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
| 1599 |
with gr.Row():
|
| 1600 |
add_border_button = gr.Button("Add Margins", elem_classes="solid", variant="secondary")
|
| 1601 |
with gr.Row():
|
| 1602 |
-
bordered_image_output = gr.Image(label="Image with Margins", image_mode="RGBA", elem_classes="centered solid imgcontainer", format="PNG", type="filepath", key="ImgBordered",interactive=False,
|
| 1603 |
with gr.Tab("3D and Depth (fun)", id="3D") as depth_tab:
|
| 1604 |
accordian_3d = gr.Accordion("Clicking here to toggle between Image Generation and 3D models", open=False, elem_id="accordian_3d")
|
| 1605 |
with accordian_3d:
|
|
@@ -1624,7 +1627,7 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
| 1624 |
with gr.Row():
|
| 1625 |
generate_3d_asset_button = gr.Button("Generate 3D Asset", elem_classes="solid", variant="secondary", interactive=False)
|
| 1626 |
with gr.Row():
|
| 1627 |
-
depth_output = gr.Image(label="Depth Map", image_mode="L", elem_classes="centered solid imgcontainer", format="PNG", type="filepath", key="DepthOutput",interactive=False,
|
| 1628 |
with gr.Row():
|
| 1629 |
# For display: video output and 3D model preview (GLTF)
|
| 1630 |
video_output = gr.Video(label="3D Asset Video", autoplay=True, loop=True, height=400)
|
|
@@ -1660,8 +1663,7 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
| 1660 |
)
|
| 1661 |
with gr.Row(visible=False) as permalink_row:
|
| 1662 |
permalink = gr.Textbox(
|
| 1663 |
-
label="Viewer Permalink",
|
| 1664 |
-
show_copy_button=True,
|
| 1665 |
elem_classes="solid small centered",
|
| 1666 |
max_lines=3
|
| 1667 |
)
|
|
@@ -1822,7 +1824,7 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
| 1822 |
fn=on_prerendered_gallery_selection,
|
| 1823 |
inputs=None,
|
| 1824 |
outputs=[gr.State(current_prerendered_image)], # Update the state with the selected image
|
| 1825 |
-
|
| 1826 |
)
|
| 1827 |
# replace input image with selected gallery image
|
| 1828 |
replace_input_image_button.click(
|
|
@@ -1882,13 +1884,13 @@ with gr.Blocks(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',
|
|
| 1882 |
fn=load_3d_models,
|
| 1883 |
trigger_mode="always_last",
|
| 1884 |
outputs=[generate_3d_asset_button],
|
| 1885 |
-
|
| 1886 |
)
|
| 1887 |
accordian_3d.collapse(
|
| 1888 |
fn=unload_3d_models,
|
| 1889 |
trigger_mode="always_last",
|
| 1890 |
outputs=[generate_3d_asset_button],
|
| 1891 |
-
|
| 1892 |
)
|
| 1893 |
# Chain the buttons
|
| 1894 |
generate_3d_asset_button.click(
|
|
@@ -1992,4 +1994,4 @@ if __name__ == "__main__":
|
|
| 1992 |
except:
|
| 1993 |
pass
|
| 1994 |
hexaGrid.queue(default_concurrency_limit=1,max_size=12,api_open=False)
|
| 1995 |
-
hexaGrid.launch(allowed_paths=["assets","/","./assets","images","./images", "./images/prerendered", 'e:/TMP'], favicon_path="./assets/favicon.ico", max_file_size="10mb")
|
|
|
|
| 154 |
os.makedirs(user_dir, exist_ok=True)
|
| 155 |
|
| 156 |
|
| 157 |
+
def end_session(req: Optional[gr.Request] = None):
|
| 158 |
+
if req is None:
|
| 159 |
+
cleanup_temp_files()
|
| 160 |
+
return
|
| 161 |
+
|
| 162 |
print(f"Ending session with hash: {req.session_hash}")
|
| 163 |
user_dir = os.path.join(constants.TMPDIR, str(req.session_hash))
|
| 164 |
if os.path.exists(user_dir):
|
|
|
|
| 1243 |
gr.set_static_paths(paths=["images/","images/images","images/prerendered","LUT/","fonts/","assets/"])
|
| 1244 |
|
| 1245 |
# Gradio Blocks Interface
|
| 1246 |
+
with gr.Blocks(title=title, delete_cache=(21600,86400)) as hexaGrid:
|
| 1247 |
with gr.Row():
|
| 1248 |
gr.Markdown("""
|
| 1249 |
# HexaGrid Creator
|
|
|
|
| 1511 |
allow_preview=False, preview=False ,
|
| 1512 |
columns=2,
|
| 1513 |
elem_id="lora_gallery",
|
|
|
|
| 1514 |
elem_classes="solid", type="filepath",
|
| 1515 |
object_fit="contain", height="auto", format="png",
|
| 1516 |
)
|
|
|
|
| 1602 |
with gr.Row():
|
| 1603 |
add_border_button = gr.Button("Add Margins", elem_classes="solid", variant="secondary")
|
| 1604 |
with gr.Row():
|
| 1605 |
+
bordered_image_output = gr.Image(label="Image with Margins", image_mode="RGBA", elem_classes="centered solid imgcontainer", format="PNG", type="filepath", key="ImgBordered",interactive=False, buttons=["download", "fullscreen", "share"])
|
| 1606 |
with gr.Tab("3D and Depth (fun)", id="3D") as depth_tab:
|
| 1607 |
accordian_3d = gr.Accordion("Clicking here to toggle between Image Generation and 3D models", open=False, elem_id="accordian_3d")
|
| 1608 |
with accordian_3d:
|
|
|
|
| 1627 |
with gr.Row():
|
| 1628 |
generate_3d_asset_button = gr.Button("Generate 3D Asset", elem_classes="solid", variant="secondary", interactive=False)
|
| 1629 |
with gr.Row():
|
| 1630 |
+
depth_output = gr.Image(label="Depth Map", image_mode="L", elem_classes="centered solid imgcontainer", format="PNG", type="filepath", key="DepthOutput",interactive=False, buttons=["download", "fullscreen", "share"], height=400)
|
| 1631 |
with gr.Row():
|
| 1632 |
# For display: video output and 3D model preview (GLTF)
|
| 1633 |
video_output = gr.Video(label="3D Asset Video", autoplay=True, loop=True, height=400)
|
|
|
|
| 1663 |
)
|
| 1664 |
with gr.Row(visible=False) as permalink_row:
|
| 1665 |
permalink = gr.Textbox(
|
| 1666 |
+
label="Viewer Permalink",
|
|
|
|
| 1667 |
elem_classes="solid small centered",
|
| 1668 |
max_lines=3
|
| 1669 |
)
|
|
|
|
| 1824 |
fn=on_prerendered_gallery_selection,
|
| 1825 |
inputs=None,
|
| 1826 |
outputs=[gr.State(current_prerendered_image)], # Update the state with the selected image
|
| 1827 |
+
api_visibility="undocumented"
|
| 1828 |
)
|
| 1829 |
# replace input image with selected gallery image
|
| 1830 |
replace_input_image_button.click(
|
|
|
|
| 1884 |
fn=load_3d_models,
|
| 1885 |
trigger_mode="always_last",
|
| 1886 |
outputs=[generate_3d_asset_button],
|
| 1887 |
+
api_visibility="undocumented"
|
| 1888 |
)
|
| 1889 |
accordian_3d.collapse(
|
| 1890 |
fn=unload_3d_models,
|
| 1891 |
trigger_mode="always_last",
|
| 1892 |
outputs=[generate_3d_asset_button],
|
| 1893 |
+
api_visibility="undocumented"
|
| 1894 |
)
|
| 1895 |
# Chain the buttons
|
| 1896 |
generate_3d_asset_button.click(
|
|
|
|
| 1994 |
except:
|
| 1995 |
pass
|
| 1996 |
hexaGrid.queue(default_concurrency_limit=1,max_size=12,api_open=False)
|
| 1997 |
+
hexaGrid.launch(theme='Surn/beeuty', css_paths="style_20250314.css", allowed_paths=["assets","/","./assets","images","./images", "./images/prerendered", 'e:/TMP'], favicon_path="./assets/favicon.ico", max_file_size="10mb")
|
spec.mdx
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: HexaGrid Creator — Project Spec / Context
|
| 3 |
+
version: 0.1
|
| 4 |
+
source_repo:
|
| 5 |
+
github: https://github.com/Oncorporation/HexaGrid
|
| 6 |
+
huggingface_space: https://huggingface.co/spaces/Surn/HexaGrid
|
| 7 |
+
last_updated: 2026-02-12
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# HexaGrid Creator (Beeuty-MapMaker)
|
| 11 |
+
|
| 12 |
+
## 1) What this project is
|
| 13 |
+
HexaGrid Creator is a Gradio (Hugging Face Spaces) application that:
|
| 14 |
+
|
| 15 |
+
- Takes an **input image** and generates a **tiled grid overlay** (hexagon / square / triangle) suitable for tabletop maps.
|
| 16 |
+
- Optionally generates a new image via **FLUX** (Diffusers) with **LoRA** styles, and then applies the grid.
|
| 17 |
+
- Supports interactive **image filtering** via **LUT (.cube)** files, plus compositing/blur utilities.
|
| 18 |
+
- Can generate a **depth map** (DPT) and a **3D asset** (TRELLIS pipeline), then export **GLB** and **Gaussian PLY**.
|
| 19 |
+
- Can produce a shareable **permalink** to an external 3D viewer by uploading assets to a Hugging Face **dataset repo**.
|
| 20 |
+
|
| 21 |
+
Primary entrypoint: `app.py`.
|
| 22 |
+
|
| 23 |
+
## 2) Deployment target and runtime
|
| 24 |
+
### Hugging Face Spaces metadata (from `README.md` frontmatter)
|
| 25 |
+
- SDK: `gradio`
|
| 26 |
+
- `python_version`: **3.10.13**
|
| 27 |
+
- `sdk_version`: **5.44.1**
|
| 28 |
+
- `app_file`: `app.py`
|
| 29 |
+
- OAuth: `hf_oauth: true`
|
| 30 |
+
|
| 31 |
+
### GPUs and ZeroGPU note
|
| 32 |
+
The UI warns that **ZeroGPU** may be unavailable or crash intermittently. This is treated as an infrastructure limitation rather than a code defect.
|
| 33 |
+
|
| 34 |
+
## 3) Repository layout (high-level)
|
| 35 |
+
- `app.py`: Main Gradio Blocks UI + orchestration.
|
| 36 |
+
- `utils/`: Application modules used by `app.py`.
|
| 37 |
+
- `trellis/`: TRELLIS 3D pipeline package (imported as `trellis.*`).
|
| 38 |
+
- `assets/`, `images/`, `LUT/`, `fonts/`: Static resources used by the UI.
|
| 39 |
+
- `style_20250314.css`: UI CSS.
|
| 40 |
+
- `requirements.txt`, `pre-requirements.txt`: Python dependencies.
|
| 41 |
+
- `wheels/`: platform-specific wheel artifacts referenced by `requirements.txt`.
|
| 42 |
+
|
| 43 |
+
## 4) Key dependencies and version-sensitive components
|
| 44 |
+
### Python package stack (from `requirements.txt`)
|
| 45 |
+
This project relies on:
|
| 46 |
+
- Gradio UI + Spaces GPU decorator: `gradio`, `spaces`
|
| 47 |
+
- Diffusers & model tooling: `diffusers` (git), `transformers`, `accelerate`, `safetensors`, `peft`
|
| 48 |
+
- Torch stack (CUDA index used): `torch`, `torchvision`, `xformers==0.0.29.post3`
|
| 49 |
+
- Image processing: `Pillow`, `opencv-python`, `opencv-python-headless`, `imageio`, `imageio-ffmpeg`, `numpy==1.26.4`, `scipy`
|
| 50 |
+
- Palette extraction: `Haishoku`
|
| 51 |
+
- 3D processing: `open3d`, `trimesh`, `xatlas`, `pyvista`, `pymeshfix`, `igraph`, `utils3d` (git)
|
| 52 |
+
- Background removal: `rembg`, `onnxruntime`
|
| 53 |
+
- Cairo/Pango for text rendering: `pycairo`, `cairocffi`, `pangocffi`, `pangocairocffi`, `cairosvg`
|
| 54 |
+
- CUDA/3D special wheels referenced (Linux-specific links present):
|
| 55 |
+
- `flash_attn` wheel
|
| 56 |
+
- `diff_gaussian_rasterization` wheel
|
| 57 |
+
- `nvdiffrast` wheel
|
| 58 |
+
|
| 59 |
+
### Environment and tokens
|
| 60 |
+
- `utils/constants.py` requires `HF_TOKEN` to be present; it raises at import time if missing.
|
| 61 |
+
- Several Hugging Face operations implicitly depend on write permissions to a dataset used for uploads/shortlinks.
|
| 62 |
+
|
| 63 |
+
## 5) Session model and temp storage
|
| 64 |
+
### Session directories
|
| 65 |
+
- `start_session(req)` creates a per-session directory at `utils.constants.TMPDIR/<session_hash>`.
|
| 66 |
+
- `end_session(req)` deletes that directory on unload.
|
| 67 |
+
|
| 68 |
+
Notes:
|
| 69 |
+
- Many image outputs are written under `TMPDIR/<session_hash>`.
|
| 70 |
+
- Some functions still use the module-level `user_dir = constants.TMPDIR`; watch for places where session scoping is expected but not passed through.
|
| 71 |
+
|
| 72 |
+
## 6) Feature map & UI structure (Gradio)
|
| 73 |
+
The app is defined using `gr.Blocks(...) as hexaGrid` in `app.py` with major sections:
|
| 74 |
+
|
| 75 |
+
### Left panel
|
| 76 |
+
- `Input Image` (uploaded file path)
|
| 77 |
+
- `Sketch Pad` (`gr.Sketchpad`) for drawing/overlaying; can replace the input image.
|
| 78 |
+
- `Generate HURA Background` (procedural pattern generator from `utils/hex_hura.py`).
|
| 79 |
+
|
| 80 |
+
### Right panel
|
| 81 |
+
- `Image Filters (LUT)`: upload/select `.cube` file and apply to input/sketch/HURA.
|
| 82 |
+
- `Color Composite` and `Blur` tools.
|
| 83 |
+
|
| 84 |
+
### Tabs
|
| 85 |
+
1. `HexaGrid Generation`
|
| 86 |
+
- Core grid parameters (hex size, border, fill, rotation, background/border colors).
|
| 87 |
+
- Excluded color list management.
|
| 88 |
+
- Grid shape selection: triangle / square / hexagon.
|
| 89 |
+
- Optional text labeling inside tiles.
|
| 90 |
+
- Output images: grid render + overlay.
|
| 91 |
+
- Post transforms: tilt/rotate, alpha composite, multiply blend, interpolate (lerp).
|
| 92 |
+
|
| 93 |
+
2. `Image Generation (AI)`
|
| 94 |
+
- Generates an image using FLUX pipelines and LoRA “style gallery”.
|
| 95 |
+
- Supports img2img and “Fill” model flows.
|
| 96 |
+
- Template (pre-rendered) image gallery.
|
| 97 |
+
|
| 98 |
+
3. `Add Margins`
|
| 99 |
+
- Adds printable margins (DPI-aware) to input/overlay image.
|
| 100 |
+
|
| 101 |
+
4. `3D and Depth (fun)`
|
| 102 |
+
- Loads DPT depth estimation + TRELLIS 3D pipeline on accordion expand.
|
| 103 |
+
- Creates depth map, then generates 3D asset, video preview.
|
| 104 |
+
- Exports GLB and Gaussian PLY.
|
| 105 |
+
- Builds permalink for external viewer.
|
| 106 |
+
|
| 107 |
+
## 7) Core pipelines (end-to-end flows)
|
| 108 |
+
|
| 109 |
+
### 7.1 Grid generation pipeline
|
| 110 |
+
Entry: `hex_button.click(...)` → `hex_create(...)`
|
| 111 |
+
|
| 112 |
+
- Loads input image, coerces to RGBA; if conversion fails, it pads onto a minimum canvas.
|
| 113 |
+
- Builds an input palette via `Haishoku.loadHaishoku(...)`.
|
| 114 |
+
- Converts UI colors + opacity to RGBA tuples via `utils.color_utils.update_color_opacity`.
|
| 115 |
+
- Calls `utils.hex_grid.generate_hexagon_grid_interface(...)` (wrapper around grid generation + overlay creation).
|
| 116 |
+
- Writes output files with `utils.image_utils.save_image_to_temp_png(...)` under the session directory.
|
| 117 |
+
|
| 118 |
+
Outputs:
|
| 119 |
+
- `output_image`: rendered tiled grid result
|
| 120 |
+
- `overlay_image`: overlay-only layer
|
| 121 |
+
|
| 122 |
+
### 7.2 Excluded color workflow
|
| 123 |
+
Module: `utils/excluded_colors.py`
|
| 124 |
+
|
| 125 |
+
- Stores excluded colors as a `gr.State` list of RGBA tuples.
|
| 126 |
+
- UI allows adding via `add_color`, deleting rows via `delete_color`, and manual edits via `on_input`.
|
| 127 |
+
- Grid sampling can filter out excluded colors (`filter_color` checkbox).
|
| 128 |
+
|
| 129 |
+
### 7.3 LUT filter pipeline
|
| 130 |
+
Module: `utils.image_utils.py`
|
| 131 |
+
|
| 132 |
+
- UI selects a LUT filename (from `constants.lut_files`) and previews it (`show_lut`).
|
| 133 |
+
- Apply operations call `apply_lut_to_image_path(lut_filename, image_path, intensity)`.
|
| 134 |
+
|
| 135 |
+
Important behavior:
|
| 136 |
+
- Images are opened through `open_image(...)` which supports local paths, URLs, and DataURL strings.
|
| 137 |
+
- Some file types (SVG/ICO) are converted to PNG.
|
| 138 |
+
|
| 139 |
+
### 7.4 AI image generation (FLUX + LoRA)
|
| 140 |
+
Primary functions:
|
| 141 |
+
- `get_model_and_lora(model_textbox)`
|
| 142 |
+
- `set_pipeline(model_name, lora_weights, pipeline_name)`
|
| 143 |
+
- `generate_image_lowmem(...)` (decorated with `@spaces.GPU(duration=230)`)
|
| 144 |
+
- `generate_ai_image_local(...)`
|
| 145 |
+
- `generate_input_image_click(...)` (UI handler)
|
| 146 |
+
|
| 147 |
+
Key concepts:
|
| 148 |
+
- Pipeline classes are selected from `PIPELINE_CLASSES`:
|
| 149 |
+
- `FluxPipeline`
|
| 150 |
+
- `FluxImg2ImgPipeline`
|
| 151 |
+
- `FluxControlPipeline`
|
| 152 |
+
- `FluxFillPipeline`
|
| 153 |
+
- LoRA configuration is driven by `utils.constants.LORA_DETAILS` and helper methods in `utils/lora_details.py`.
|
| 154 |
+
- For long prompts, `split_prompt_precisely(...)` is used when token count exceeds a threshold.
|
| 155 |
+
|
| 156 |
+
Performance/memory approach:
|
| 157 |
+
- Pipeline is moved to `device` for execution then returned to CPU with CUDA cache cleared.
|
| 158 |
+
- `enable_model_cpu_offload()` is used in some paths.
|
| 159 |
+
|
| 160 |
+
### 7.5 Depth + 3D generation (DPT + TRELLIS)
|
| 161 |
+
Load/unload model flow:
|
| 162 |
+
- `load_3d_models(is_open=True)` loads:
|
| 163 |
+
- `DPTImageProcessor.from_pretrained("Intel/dpt-large")`
|
| 164 |
+
- `DPTForDepthEstimation.from_pretrained("Intel/dpt-large", ignore_mismatched_sizes=True)`
|
| 165 |
+
- TRELLIS pipeline via `load_trellis_model()` when not in shared space.
|
| 166 |
+
- `unload_3d_models(is_open=False)` deletes models and runs GC.
|
| 167 |
+
|
| 168 |
+
Depth map creation:
|
| 169 |
+
- `depth_process_image(image_path, resized_width, z_scale)` produces an 8-bit depth image.
|
| 170 |
+
|
| 171 |
+
3D asset creation:
|
| 172 |
+
- `generate_3d_asset_part1(...)` chooses source image, creates depth map file.
|
| 173 |
+
- `generate_3d_asset_part2(...)` runs TRELLIS:
|
| 174 |
+
- preprocesses images
|
| 175 |
+
- optionally uses multi-image algorithms (`singleimage`, `stochastic`, `multidiffusion`)
|
| 176 |
+
- renders a preview mp4 via `render_utils.render_video`
|
| 177 |
+
- packs results into a serializable “state” dict (`pack_state` / `unpack_state`).
|
| 178 |
+
|
| 179 |
+
Exports:
|
| 180 |
+
- `extract_glb(state, mesh_simplify, texture_size)` writes `<name>.glb`.
|
| 181 |
+
- `extract_gaussian(state)` writes `<name>.ply`.
|
| 182 |
+
|
| 183 |
+
### 7.6 Permalink creation + upload storage
|
| 184 |
+
The 3D tab can create a shareable viewer link.
|
| 185 |
+
|
| 186 |
+
Implementation components:
|
| 187 |
+
- `app.py:create_permalink(...)` calls `utils.storage.upload_files_to_repo(...)` with:
|
| 188 |
+
- smallest of (GLB, Gaussian)
|
| 189 |
+
- depth image
|
| 190 |
+
- source image used for depth
|
| 191 |
+
- `utils/storage.py` handles:
|
| 192 |
+
- extension filtering
|
| 193 |
+
- `upload_folder(...)` batching
|
| 194 |
+
- link building under `https://huggingface.co/datasets/<repo_id>/resolve/main/<folder_name>/...`
|
| 195 |
+
- optional permalink building and URL shortening via JSON mapping
|
| 196 |
+
|
| 197 |
+
`utils/storage.py` version:
|
| 198 |
+
- `__version__ = "0.1.1"`
|
| 199 |
+
|
| 200 |
+
Shortener behavior:
|
| 201 |
+
- `gen_full_url(full_url=...)` stores mapping in a JSON file in a dataset repo.
|
| 202 |
+
- `version_info.versions_html()` links to the shortener JSON file for debugging.
|
| 203 |
+
|
| 204 |
+
## 8) `utils/` modules (responsibilities)
|
| 205 |
+
This list focuses on modules imported directly by `app.py`.
|
| 206 |
+
|
| 207 |
+
- `utils/constants.py`
|
| 208 |
+
- Environment loading (`.env`) and required `HF_TOKEN` enforcement
|
| 209 |
+
- UI prompt presets and negative prompts (`PROMPTS`, `NEGATIVE_PROMPTS`)
|
| 210 |
+
- Pre-rendered template image registry (`PRE_RENDERED_MAPS_JSON_LEVELS`)
|
| 211 |
+
- Model registry (`MODELS`, `LORA_WEIGHTS`, `LORA_TO_MODEL`, `LORA_DETAILS`)
|
| 212 |
+
- Temp directory root (`TMPDIR`) used for session subfolders
|
| 213 |
+
|
| 214 |
+
- `utils/image_utils.py`
|
| 215 |
+
- `open_image(...)` + helpers (`get_image_from_dict`, SVG/ICO conversion)
|
| 216 |
+
- LUT preview/apply helpers
|
| 217 |
+
- Compositing/blending functions (`alpha_composite_with_control`, lerp, multiply)
|
| 218 |
+
- Temp PNG writer `save_image_to_temp_png(...)`
|
| 219 |
+
- Pre-rendered gallery builder `build_prerendered_images_by_quality(...)`
|
| 220 |
+
|
| 221 |
+
- `utils/hex_grid.py`
|
| 222 |
+
- Core grid rendering algorithms (hex/square/triangle tiling)
|
| 223 |
+
- Shape selection mapping via `map_sides(...)`
|
| 224 |
+
- Text-in-tile rendering utilities (Pango/Cairo + emoji font)
|
| 225 |
+
|
| 226 |
+
- `utils/excluded_colors.py`
|
| 227 |
+
- Gradio state + DataFrame helpers for excluded RGBA colors
|
| 228 |
+
|
| 229 |
+
- `utils/file_utils.py`
|
| 230 |
+
- File path parsing and safe extension normalization
|
| 231 |
+
- Temp file cleanup tracking via `constants.temp_files`
|
| 232 |
+
|
| 233 |
+
- `utils/storage.py`
|
| 234 |
+
- Upload assets to HF dataset repo and create permalink
|
| 235 |
+
- URL shortener JSON file management
|
| 236 |
+
|
| 237 |
+
- `utils/version_info.py`
|
| 238 |
+
- Visible runtime diagnostics in UI footer
|
| 239 |
+
|
| 240 |
+
## 9) Operational notes / gotchas
|
| 241 |
+
- `utils/constants.py` raises if `HF_TOKEN` is not set — this affects local dev and any import-time tooling.
|
| 242 |
+
- Some dependencies are platform-specific (Linux wheels referenced directly). Windows dev may require different wheels.
|
| 243 |
+
- Some paths in `hexaGrid.launch(allowed_paths=...)` include absolute drive paths (e.g., `e:/TMP`), which may not exist locally.
|
| 244 |
+
- `atexit.register(end_session)` registers `end_session(req)` without a `req`; this is likely a no-op or error path in some environments. Session cleanup is mostly handled by Gradio `load`/`unload` events.
|
| 245 |
+
|
| 246 |
+
## 10) How to extend safely (agent/human guidance)
|
| 247 |
+
- Prefer adding new UI actions as pure functions in `utils/` with minimal coupling to Gradio components.
|
| 248 |
+
- Keep session scoping by writing outputs to `TMPDIR/<session_hash>`.
|
| 249 |
+
- When adding new upload/permalink types, update `utils/constants.py` extension lists and ensure `utils/storage.py` filters accept them.
|
| 250 |
+
- When adding LoRAs, use `constants.LORA_DETAILS` and `utils/lora_details.py` conventions rather than hardcoding behavior in `app.py`.
|
| 251 |
+
|
| 252 |
+
## 11) Quick pointers for reading the code
|
| 253 |
+
- Start with `app.py` to understand UI event wiring and high-level orchestration.
|
| 254 |
+
- Then read:
|
| 255 |
+
- `utils/hex_grid.py` for the tiling algorithm
|
| 256 |
+
- `utils/image_utils.py` for I/O and image transforms
|
| 257 |
+
- `utils/storage.py` for permalink/upload semantics
|
| 258 |
+
- `utils/constants.py` for the “registry” of models, LoRAs, templates, and environment variables
|
utils/hex_hura.py
CHANGED
|
@@ -6,7 +6,7 @@ import math
|
|
| 6 |
import gradio as gr
|
| 7 |
from tempfile import NamedTemporaryFile
|
| 8 |
|
| 9 |
-
from transformers.models.deprecated.vit_hybrid import image_processing_vit_hybrid
|
| 10 |
import utils.constants as constants
|
| 11 |
import utils.color_utils as color_utils
|
| 12 |
|
|
@@ -399,7 +399,7 @@ def render() -> dict:
|
|
| 399 |
outputs=[state_colors, color_display]
|
| 400 |
)
|
| 401 |
delete_colors_button.click(
|
| 402 |
-
fn=lambda
|
| 403 |
inputs=[],
|
| 404 |
outputs=[state_colors, color_display]
|
| 405 |
)
|
|
|
|
| 6 |
import gradio as gr
|
| 7 |
from tempfile import NamedTemporaryFile
|
| 8 |
|
| 9 |
+
#from transformers.models.deprecated.vit_hybrid import image_processing_vit_hybrid
|
| 10 |
import utils.constants as constants
|
| 11 |
import utils.color_utils as color_utils
|
| 12 |
|
|
|
|
| 399 |
outputs=[state_colors, color_display]
|
| 400 |
)
|
| 401 |
delete_colors_button.click(
|
| 402 |
+
fn=lambda: ([], "<div>Add Colors</div>"),
|
| 403 |
inputs=[],
|
| 404 |
outputs=[state_colors, color_display]
|
| 405 |
)
|