Surn commited on
Commit
4fc5901
·
1 Parent(s): ec28e0c

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

Files changed (5) hide show
  1. .gitignore +1 -0
  2. README.md +1 -1
  3. app.py +13 -11
  4. spec.mdx +258 -0
  5. 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: 5.44.1
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(css_paths="style_20250314.css", title=title, theme='Surn/beeuty',delete_cache=(21600,86400)) as hexaGrid:
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, show_download_button=True, show_fullscreen_button=True, show_share_button=True)
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, show_download_button=True, show_fullscreen_button=True, show_share_button=True, height=400)
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
- show_api=False
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
- show_api=False
1886
  )
1887
  accordian_3d.collapse(
1888
  fn=unload_3d_models,
1889
  trigger_mode="always_last",
1890
  outputs=[generate_3d_asset_button],
1891
- show_api=False
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 x: ([], "<div>Add Colors</div>"),
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
  )