Spaces:
Sleeping
Sleeping
File size: 3,776 Bytes
a54a5ca 299ba9b a54a5ca 299ba9b a54a5ca 299ba9b a54a5ca 299ba9b a54a5ca 299ba9b a54a5ca | 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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | """
UI helpers β shared functions across Gradio tabs.
Keeps `app.py` focused on layout, not formatting logic.
"""
from __future__ import annotations
from . import quota, workspace
def get_status_bar() -> str:
"""Build the global status bar shown at the bottom of every tab.
Markdown-formatted single line with quota + workspace info.
"""
state = workspace.get_state()
parts = [
quota.format_status(),
f"π Workspace: {workspace.current_size_mb():.1f} MB",
f"π¦ Exports: {workspace.export_count()}",
]
if state.model_used:
parts.append(f"π§ Last: {state.model_used}")
return " Β· ".join(parts)
def get_asset_summary() -> str:
"""Multi-line summary of what's currently in `workspace/current/`.
Used in the viewer panel to show pipeline progress.
"""
state = workspace.get_state()
lines = [f"**Asset:** `{state.asset_name}`"]
if state.face_count:
lines.append(f"- Faces: {state.face_count:,}")
lines.append(f"- Vertices: {state.vertex_count:,}")
stages = []
if state.high_poly_glb:
stages.append("β Generated")
if state.cleaned_glb:
stages.append("β Cleaned")
if state.low_poly_glb:
stages.append("β Decimated")
if state.unwrapped_glb:
stages.append("β UV unwrapped")
if state.normal_dx_png or state.normal_gl_png:
stages.append("β Normal baked")
if state.albedo_png:
stages.append("β Albedo baked")
if state.orm_png or (state.roughness_png and state.metallic_png):
stages.append("β PBR maps")
if state.lod_glbs:
stages.append(f"β LODs ({len(state.lod_glbs)})")
if state.collision_glb:
stages.append("β Collision")
if state.rigged_glb or state.rigged_fbx:
stages.append("β Rigged")
if stages:
lines.append("")
lines.append("**Progress:**")
for s in stages:
lines.append(f"- {s}")
else:
lines.append("")
lines.append("*No asset loaded yet. Start at the Generate tab.*")
return "\n".join(lines)
def get_viewer_model_path() -> str | None:
"""Pick the best GLB to show in the 3D viewer.
Reads the filesystem directly so it works across the ZeroGPU subprocess
boundary (the in-memory state written inside @spaces.GPU is invisible to
the parent Gradio process).
"""
from .workspace import CURRENT
# Order: most processed β least processed
candidates = [
CURRENT / "rigged.glb",
CURRENT / "scaled.glb",
CURRENT / "pivoted.glb",
CURRENT / "lods" / "LOD0.glb",
CURRENT / "unwrapped.glb",
CURRENT / "low_poly.glb",
CURRENT / "cleaned.glb",
CURRENT / "repaired.glb",
CURRENT / "raw_gen.glb",
CURRENT / "high_poly.glb",
]
for path in candidates:
if path.exists():
return str(path)
return None
def quota_warning(operation: str) -> str:
"""Generate a warning if an operation would exceed the daily quota.
Returns an empty string if the operation fits comfortably.
"""
estimated = quota.estimate(operation)
state = quota.get_state()
remaining = state.remaining_seconds()
if estimated > remaining:
overage = estimated - remaining
cost = overage * quota.OVERAGE_RATE_PER_SECOND
return (
f"β οΈ **Quota warning:** This will use ~{estimated}s but you only "
f"have {remaining:.0f}s left today. "
f"Overage cost: ~${cost:.2f}"
)
elif estimated > remaining * 0.5:
return (
f"βΉοΈ Estimated GPU time: ~{estimated}s "
f"({remaining:.0f}s remaining today)"
)
return ""
|