Supra-Tex / hf_space /history_ui.py
UniLat3D's picture
Keep account rechecks quiet without resetting active sessions or tasks
6381524 verified
Raw History Blame Contribute Delete
10.7 kB
"""Native, account-scoped UI. Private images never enter Gradio's file cache."""
import base64
from pathlib import Path
import gradio as gr
from hf_space.gallery_preview import install_js as gallery_install_js
from hf_space.ui import THEME
DIRECTORY = Path(__file__).resolve().parent
CSS = (DIRECTORY / "ui.css").read_text(encoding="utf-8") + "\n" + (
DIRECTORY / "history_ui.css").read_text(encoding="utf-8")
HEADER = ('<header class="st-history-heading"><h1>Supra-Tex</h1>'
'<p>3D Generation with Super-Aligned Texture</p></header>')
# Official HF artwork and PRO badge treatment; FREE has no separate plan logo.
# Sources: https://huggingface.co/brand and https://huggingface.co/pricing
# Logo: https://huggingface.co/front/assets/huggingface_logo-noborder.svg
HF_LOGO = base64.b64encode((DIRECTORY / 'brand/huggingface-logo.svg').read_bytes()).decode('ascii')
RESOURCE_NOTICE = (
'<footer class="st-resource-notice" role="note">'
'This demo uses <strong>your personal ZeroGPU quota</strong>. '
'<a class="st-plan-link" href="https://huggingface.co/pricing" target="_blank" rel="noopener noreferrer" aria-label="Hugging Face FREE account">'
f'<img class="st-hf-logo" src="data:image/svg+xml;base64,{HF_LOGO}" alt="" aria-hidden="true"><span class="st-hf-free">FREE</span></a>'
' accounts have limited quota. We recommend a '
'<a class="st-plan-link" href="https://huggingface.co/pro" target="_blank" rel="noopener noreferrer" aria-label="Hugging Face PRO account">'
'<span class="st-hf-pro">PRO</span></a>'
' account for a better experience.</footer>'
)
# Keep Gradio's footer and settings controls in English on Chinese browsers.
# Flat translation keys take precedence over Gradio's nested locale resources.
ENGLISH_UI = {
"common.built_with": "built with",
"common.built_with_gradio": "Built with Gradio",
"common.clear": "Clear",
"common.download": "Download",
"common.edit": "Edit",
"common.empty": "Empty",
"common.error": "Error",
"common.hosted_on": "Hosted on",
"common.loading": "Loading",
"common.logo": "logo",
"common.or": "or",
"common.remove": "Remove",
"common.settings": "Settings",
"common.share": "Share",
"common.submit": "Submit",
"common.undo": "Undo",
"common.no_devices": "No devices found",
"common.language": "Language",
"common.display_theme": "Display Theme",
"common.pwa": "Progressive Web App",
"common.record": "Record",
"common.stop_recording": "Stop Recording",
"common.screen_studio": "Screen Studio",
"common.share_gradio_tab": "[Sharing] Gradio Tab",
"common.run": "Run",
"errors.build_error": "there is a build error",
"errors.config_error": "there is a config error",
"errors.contact_page_author": "Please contact the author of the page to let them know.",
"errors.no_app_file": "there is no app file",
"errors.runtime_error": "there is a runtime error",
"errors.space_not_working": '"Space isn\'t working because" {0}',
"errors.space_paused": "the space is paused",
"errors.use_via_api": "Use via API",
"errors.use_via_api_or_mcp": "Use via API or MCP",
}
I18N = gr.I18n(**{locale: dict(ENGLISH_UI) for locale in ("zh-CN", "zh-TW", "zh")})
MARKUP = """
<main id="st-app" class="st-history-app">
<div id="st-workspace" inert>
<section id="st-input-panel" class="st-native-panel">
<h2 class="st-panel-title">Reference image</h2>
<div id="st-upload" class="st-native-upload">
<button type="button" id="st-pick-image" aria-label="Upload reference image">
<img id="st-input-image" alt="Reference image" hidden>
<span id="st-upload-placeholder"><span aria-hidden="true">↑</span>Drop an image here or click to upload</span>
</button>
<input type="file" id="st-file-input" accept="image/*" hidden>
<div class="st-upload-actions"><button type="button" id="st-change-image">Upload image</button><button type="button" id="st-clear-image" hidden>Clear</button></div>
</div>
<div id="st-upload-status" hidden role="status" aria-live="polite"><span id="st-upload-label"></span><button id="st-upload-retry" type="button" hidden>Retry</button></div>
<details id="st-settings"><summary>Generation settings</summary><label for="st-seed">Seed<input id="st-seed" type="number" step="1" value="42"></label></details>
<div id="st-generate-control">
<button id="st-generate" type="button" disabled>Generate geometry</button>
<button id="st-generate-hit" type="button" aria-describedby="st-gate-note" hidden></button>
<p id="st-gate-note" role="status" aria-live="polite">Checking service…</p>
<p id="st-account-help" role="status" hidden></p>
<button id="st-cancel-signin" type="button" hidden>Cancel sign-in</button>
</div>
</section>
<section id="st-output-panel" class="st-native-panel">
<div class="st-viewer-heading"><h2 class="st-panel-title">3D preview</h2>
<div id="st-view-switch" role="group" aria-label="Result view" hidden>
<button type="button" data-result-view="render" aria-pressed="false">3D Preview</button>
<button type="button" data-result-view="glb" aria-pressed="false">GLB Viewer</button>
</div>
</div>
<div id="st-viewer">
<div id="st-native-empty" class="st-native-empty">Your 3D model will appear here.</div>
<div id="st-model" hidden></div>
<div id="st-ovoxel" hidden></div>
<div id="st-job-progress" hidden role="status" aria-live="polite"><h3 id="st-job-title"></h3><p id="st-job-detail"></p><p id="st-queue-note" hidden>Your request is queued due to Hugging Face GPU resource limits. Wait times may be longer during busy periods. You can check your task’s progress and results in <a id="st-queue-history-link" href="#st-history-panel">My History</a>.</p><progress aria-label="Generation in progress"></progress><small id="st-job-time"></small></div>
</div>
<div id="st-texture-actions" hidden>
<p id="st-texture-note" role="status">Geometry ready. Generate textures when you are ready.</p>
<div id="st-texture-progress" hidden role="status" aria-live="polite"><strong id="st-texture-title"></strong><p id="st-texture-detail"></p><progress max="100" aria-label="Texture generation progress"></progress><small id="st-texture-time" hidden></small></div>
<button id="st-texture" type="button">Generate textures</button>
</div>
<button id="st-extract" type="button" disabled>Extract GLB</button>
<a id="st-download" hidden download="asset.glb" tabindex="-1" aria-hidden="true"></a>
<div id="st-export-progress" hidden role="status" aria-live="polite"><strong id="st-export-label"></strong><progress id="st-export-meter" max="100" aria-label="GLB extraction stages"></progress><small id="st-export-detail"></small></div>
<p id="st-export-note" class="st-extraction-note">Extract and download GLB.</p>
</section>
<section id="st-history-panel" class="st-native-panel" aria-label="My History">
<div class="st-rail-heading"><button id="st-history-toggle" type="button" aria-label="Expand My History" aria-expanded="false" aria-controls="st-history-list">←</button><h2>My History</h2></div>
<p id="st-history-note">Your saved creations will appear here.</p>
<div id="st-history-account" hidden><span id="st-history-username"></span><button id="st-history-signout" type="button">Sign out</button></div>
<div id="st-history-list" aria-label="Saved generations"></div>
<button id="st-history-more" type="button" hidden>Load more</button>
</section>
<section id="st-examples-panel" class="st-native-panel">
<h2 class="st-panel-title">Try an example</h2>
<div id="st-examples" aria-label="Input examples"></div>
</section>
</div>
<div id="st-account-check-status" role="status" aria-live="polite" hidden>
<span id="st-account-check-message">Reconnecting…</span>
<button id="st-account-check-retry" type="button" hidden>Retry</button>
<button id="st-account-check-signin" type="button" hidden>Sign in</button>
</div>
<dialog id="st-auth-dialog" aria-labelledby="st-auth-title" aria-describedby="st-auth-message">
<h2 id="st-auth-title">Sign in to Supra-Tex</h2>
<p id="st-auth-message" role="status" aria-live="polite">Checking your Huggingface account…</p>
<button id="st-auth-signin" type="button" hidden>Sign in with Huggingface</button>
<button id="st-auth-cancel" type="button" hidden>Cancel sign-in</button>
<small>Your personal history is private to your account. Sign in to continue.</small>
</dialog>
<dialog id="st-delete-dialog" aria-labelledby="st-delete-title" aria-describedby="st-delete-message">
<h2 id="st-delete-title">Delete history record?</h2>
<p id="st-delete-message">This record will be removed from My History. You cannot undo this action.</p>
<p id="st-delete-error" role="alert" hidden></p>
<div class="st-delete-actions"><button id="st-delete-cancel" type="button" autofocus>Cancel</button><button id="st-delete-confirm" type="button">Delete</button></div>
</dialog>
<div id="st-history-backdrop" hidden></div>
<div id="st-native-notice" role="status" aria-live="polite" hidden></div>
</main>
"""
def build_ui(deployment_status=None):
"""Keep Gradio only for the page shell, OAuth, and viewer installation."""
with gr.Blocks(title="Supra-Tex — 3D Generation with Super-Aligned Texture", fill_width=True) as demo:
with gr.Column(elem_id="st-history-shell"):
with gr.Row(elem_id="st-history-header"):
gr.HTML(HEADER, apply_default_css=False)
# Register Gradio's signed OAuth session without a toolbar login.
gr.LoginButton(visible=False, elem_id="st-oauth-bootstrap")
gr.HTML(MARKUP, apply_default_css=False, elem_id="st-native-page")
gr.HTML(RESOURCE_NOTICE, apply_default_css=False, elem_id="st-resource-footer")
script = (DIRECTORY / "zerogpu_client.js").read_text(encoding="utf-8") + "\n" + (
DIRECTORY / "history_ui.js").read_text(encoding="utf-8")
demo.load(None, js="() => {\n" + script + "\n}", api_visibility="private", queue=False)
demo.load(None, js=gallery_install_js(), api_visibility="private", queue=False)
for filename in ("ovoxel_preview.js", "viewport.js"):
script = (DIRECTORY / filename).read_text(encoding="utf-8")
demo.load(None, js="() => {\n" + script + "\n}", api_visibility="private", queue=False)
return demo