File size: 8,083 Bytes
74f0b48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
"""
Evoneural MVP - Local 3D Mesh + Skybox Generation
Run: streamlit run app.py
Open: http://localhost:8501
"""

import os
import sys
from pathlib import Path

# Ensure project root is on path
ROOT = Path(__file__).resolve().parent
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

import streamlit as st

OUTPUTS = ROOT / "outputs"
OUTPUTS.mkdir(exist_ok=True)


def main() -> None:
    st.set_page_config(
        page_title="Evoneural MVP - Mesh & Skybox",
        page_icon="🎮",
        layout="wide",
    )
    st.title("Evoneural MVP – Local Mesh & Skybox")
    st.caption("Text → 3D mesh (TripoSR) and Text → 360° skybox (Stable Diffusion). Runs on localhost.")

    # Sidebar: model setup (token + download)
    with st.sidebar:
        st.subheader("Stable Diffusion model")
        from scripts.skybox_generator import _default_local_weights_dir
        local_model = _default_local_weights_dir()
        if local_model:
            st.success(f"Local model: found")
            st.caption(os.path.basename(local_model))
        else:
            st.warning("No local model. Download below or need internet on first generate.")
        hf_token = st.text_input(
            "Hugging Face token (optional, if behind firewall)",
            type="password",
            key="hf_token",
            placeholder="hf_...",
            help="Get a token at huggingface.co/settings/tokens",
        )
        if hf_token:
            os.environ["HF_TOKEN"] = hf_token
        if st.button("Download model (~4GB to ./weights/sd-v1-5)", key="btn_download"):
            with st.spinner("Downloading model... (may take several minutes)"):
                try:
                    from scripts.download_sd_model import download_sd_model
                    path = download_sd_model(token=hf_token or os.environ.get("HF_TOKEN"))
                    st.success(f"Model saved. Try generating a skybox.")
                    st.rerun()
                except Exception as e:
                    st.error(str(e))
                    st.caption("Set a Hugging Face token above if your network blocks Hugging Face.")

    tab_mesh, tab_skybox = st.tabs(["🟦 Text → 3D Mesh", "🌅 Text → Skybox"])

    with tab_mesh:
        st.subheader("Generate 3D mesh from text")
        st.markdown(
            "Uses **Stable Diffusion** for text→image, then **TripoSR** for image→mesh. "
            "TripoSR repo must be cloned into `./TripoSR` (see README)."
        )
        prompt_mesh = st.text_input(
            "Prompt (e.g. for mesh)",
            value="A highly detailed, sci-fi mechanical drone with glowing blue accents.",
            key="mesh_prompt",
        )
        col1, col2 = st.columns(2)
        with col1:
            mesh_format = st.selectbox("Mesh format", ["glb", "obj"], key="mesh_fmt")
            seed_mesh = st.number_input("Seed (optional)", value=42, min_value=0, key="mesh_seed")
        with col2:
            use_image = st.checkbox("Use uploaded image instead of text", value=False, key="use_img")
            uploaded = st.file_uploader("Upload image for mesh", type=["png", "jpg"], key="mesh_upload") if use_image else None

        if st.button("Generate mesh", key="btn_mesh"):
            if not prompt_mesh.strip() and not use_image:
                st.warning("Enter a prompt or upload an image.")
            else:
                with st.spinner("Running pipeline..."):
                    try:
                        from scripts.mesh_generator import (
                            generate_mesh_from_image,
                            generate_mesh_from_text,
                            find_triposr_root,
                        )
                        triposr_root = find_triposr_root(str(ROOT))
                        if not triposr_root:
                            st.error(
                                "TripoSR not found. Clone it: "
                                "`git clone https://github.com/VAST-AI-Research/TripoSR.git TripoSR`"
                            )
                        elif use_image and uploaded:
                            path = os.path.join(OUTPUTS, "uploaded_mesh_input.png")
                            with open(path, "wb") as f:
                                f.write(uploaded.getvalue())
                            mesh_path, elapsed, msg = generate_mesh_from_image(
                                path,
                                output_dir=str(OUTPUTS / "mesh_run"),
                                mesh_format=mesh_format,
                            )
                            if mesh_path:
                                st.success(f"Done in {elapsed:.1f}s. {msg}")
                                with open(mesh_path, "rb") as f:
                                    st.download_button("Download mesh", f, file_name=os.path.basename(mesh_path), key="dl_mesh_upload")
                            else:
                                st.error(msg)
                        else:
                            mesh_path, elapsed, msg = generate_mesh_from_text(
                                prompt_mesh,
                                output_dir=str(OUTPUTS),
                                mesh_format=mesh_format,
                                seed=seed_mesh,
                            )
                            if mesh_path:
                                st.success(f"Done in {elapsed:.1f}s. {msg}")
                                with open(mesh_path, "rb") as f:
                                    st.download_button("Download mesh", f, file_name=os.path.basename(mesh_path), key="dl_mesh")
                            else:
                                st.error(msg)
                    except Exception as e:
                        st.exception(e)

    with tab_skybox:
        st.subheader("Generate 2:1 equirectangular skybox")
        st.markdown(
            "Uses **Stable Diffusion 2.1** at 2:1 aspect (e.g. 1024×512). "
            "Optional seamless check compares left/right edges."
        )
        prompt_sky = st.text_input(
            "Prompt (e.g. for skybox)",
            value="Cyberpunk city skyline at dusk, neon reflections, cinematic lighting.",
            key="sky_prompt",
        )
        col1, col2 = st.columns(2)
        with col1:
            width = st.selectbox("Width", [1024, 2048], key="sky_w")
            height = width // 2
            seed_sky = st.number_input("Seed (optional)", value=42, min_value=0, key="sky_seed")
        with col2:
            check_seamless = st.checkbox("Run seamless edge check", value=True, key="seamless")

        if st.button("Generate skybox", key="btn_sky"):
            if not prompt_sky.strip():
                st.warning("Enter a prompt.")
            else:
                with st.spinner("Generating skybox..."):
                    try:
                        from scripts.skybox_generator import generate_skybox
                        from scripts.check_seamless import check_seamless as run_seamless

                        out_path, elapsed, vram_mb = generate_skybox(
                            prompt_sky,
                            output_dir=str(OUTPUTS),
                            width=width,
                            height=height,
                            seed=seed_sky,
                        )
                        st.success(f"Done in {elapsed:.1f}s. Peak VRAM: {vram_mb:.0f} MB")
                        st.image(out_path, use_container_width=True)
                        with open(out_path, "rb") as f:
                            st.download_button("Download skybox", f, file_name=os.path.basename(out_path), key="dl_sky")

                        if check_seamless:
                            result = run_seamless(out_path)
                            st.info(result["message"])
                    except Exception as e:
                        st.exception(e)

    st.divider()
    st.caption("Evoneural AI – Local ML Deployment MVP. Models run locally (no API).")


if __name__ == "__main__":
    main()