Spaces:
Sleeping
Sleeping
Upload streamlit_app.py
Browse files- streamlit_app.py +64 -32
streamlit_app.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
# streamlit_app.py — LamboVision · AI Car Studio (native-only UI, no padding)
|
| 2 |
-
# Flow: Step 1 Gallery (
|
| 3 |
-
#
|
| 4 |
|
| 5 |
import os, io, base64, zipfile, requests, streamlit as st
|
| 6 |
from PIL import Image
|
|
@@ -16,8 +16,8 @@ except Exception:
|
|
| 16 |
pass
|
| 17 |
|
| 18 |
# ================= Env & API =================
|
| 19 |
-
API_BASE = (os.getenv("
|
| 20 |
-
HF_TOKEN = (os.getenv("
|
| 21 |
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
|
| 22 |
|
| 23 |
VIDEO_MAX_PX_DEFAULT = int(os.getenv("VIDEO_MAX_PX", "720"))
|
|
@@ -298,7 +298,7 @@ st.set_page_config(page_title="LamboVision · AI Car Studio", layout="wide", pag
|
|
| 298 |
inject_base_css(card_fit_mode="contain")
|
| 299 |
|
| 300 |
st.title("🏎️ LamboVision · AI Car Studio")
|
| 301 |
-
st.caption("Step 1: Gallery (
|
| 302 |
|
| 303 |
ok = backend_ok()
|
| 304 |
|
|
@@ -311,7 +311,7 @@ with col2:
|
|
| 311 |
with col3:
|
| 312 |
preview_aspect = st.selectbox("Tile Aspect", ASPECT_OPTIONS, index=0, key="preview_aspect") # default 3:4
|
| 313 |
with col4:
|
| 314 |
-
to_video = st.checkbox("
|
| 315 |
with col5:
|
| 316 |
duration = st.selectbox("Video Duration", VIDEO_DUR_OPTIONS, index=0, key="duration_sel")
|
| 317 |
with col6:
|
|
@@ -372,7 +372,7 @@ with s1:
|
|
| 372 |
with s2:
|
| 373 |
scene_extra = st.text_input("Scene extra (optional)", value="", key="scene_extra")
|
| 374 |
|
| 375 |
-
# ================= SAMPLE PREVIEWS
|
| 376 |
st.subheader("Sample Previews")
|
| 377 |
col_in, col_gallery, col_comp, col_vid = st.columns(4)
|
| 378 |
|
|
@@ -394,7 +394,7 @@ show_tile_card_display_download(
|
|
| 394 |
|
| 395 |
gallery_bytes = demo_files.get("packshot.jpg") or input_bytes
|
| 396 |
show_tile_card_display_download(
|
| 397 |
-
col_gallery, "Gallery",
|
| 398 |
display_bytes=gallery_bytes,
|
| 399 |
download_bytes=gallery_bytes,
|
| 400 |
filename_stub="gallery", key_prefix="pre"
|
|
@@ -402,10 +402,10 @@ show_tile_card_display_download(
|
|
| 402 |
|
| 403 |
comp_bytes = gallery_bytes
|
| 404 |
show_tile_card_display_download(
|
| 405 |
-
col_comp, "AI
|
| 406 |
display_bytes=comp_bytes,
|
| 407 |
download_bytes=comp_bytes,
|
| 408 |
-
filename_stub="
|
| 409 |
)
|
| 410 |
|
| 411 |
vid_demo = demo_files.get("tryon.mp4")
|
|
@@ -439,15 +439,14 @@ if run:
|
|
| 439 |
for f in file_list:
|
| 440 |
files_payload.append(("files", (f.name, f.getvalue(), f.type or "image/jpeg")))
|
| 441 |
|
| 442 |
-
# ---- Step 1: Gallery (
|
| 443 |
gallery_payload = make_gallery_payload(preview_aspect)
|
| 444 |
if image_url:
|
| 445 |
gallery_payload["image_urls"] = image_url
|
| 446 |
out_gallery = post_image_edit(gallery_payload, files_payload if files_payload else None)
|
| 447 |
-
|
| 448 |
gallery_native_url = (out_gallery["result"]["images_native"] or [{}])[0].get("url") if out_gallery else None
|
| 449 |
|
| 450 |
-
# ---- Step 2: AI
|
| 451 |
edit_prompt = build_car_prompt(
|
| 452 |
model_name=(model_name or "Lamborghini"),
|
| 453 |
body_color=(body_color or "Verde Ithaca"),
|
|
@@ -459,10 +458,9 @@ if run:
|
|
| 459 |
comp_payload = make_composition_payload(edit_prompt, preview_aspect, upscale=False, upscale_factor="2")
|
| 460 |
comp_payload["image_urls"] = gallery_native_url or ""
|
| 461 |
out_comp = post_image_edit(comp_payload, files_payload=None)
|
| 462 |
-
|
| 463 |
comp_native_url = (out_comp["result"]["images_native"] or [{}])[0].get("url") if out_comp else None
|
| 464 |
|
| 465 |
-
# ----
|
| 466 |
vurl = None; ui_hints = {}
|
| 467 |
if st.session_state.get("to_video", False) and (comp_native_url or gallery_native_url):
|
| 468 |
video_prompt = build_video_prompt(scene_name, scene_extra)
|
|
@@ -500,23 +498,23 @@ res = st.session_state.get("results")
|
|
| 500 |
vbytes = None
|
| 501 |
if res:
|
| 502 |
st.subheader("Results")
|
| 503 |
-
c_gallery, c_comp, c_vid
|
| 504 |
|
| 505 |
-
# Gallery (
|
| 506 |
show_tile_card_display_download(
|
| 507 |
-
c_gallery, "Gallery",
|
| 508 |
display_url=res.get("gallery_native_url"),
|
| 509 |
download_url=res.get("gallery_native_url"),
|
| 510 |
filename_stub="gallery_native",
|
| 511 |
key_prefix=f"job{st.session_state['job_counter']}"
|
| 512 |
)
|
| 513 |
|
| 514 |
-
# AI
|
| 515 |
show_tile_card_display_download(
|
| 516 |
-
c_comp, "AI
|
| 517 |
display_url=res.get("composition_native_url"),
|
| 518 |
download_url=res.get("composition_native_url"),
|
| 519 |
-
filename_stub="
|
| 520 |
key_prefix=f"job{st.session_state['job_counter']}"
|
| 521 |
)
|
| 522 |
|
|
@@ -541,17 +539,51 @@ if res:
|
|
| 541 |
mime="video/mp4", key=f"job{st.session_state['job_counter']}_video_dl")
|
| 542 |
else:
|
| 543 |
c_vid.markdown('<div class="lb-frame"></div>', unsafe_allow_html=True)
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 555 |
if named:
|
| 556 |
zip_bytes = make_zip(named)
|
| 557 |
st.download_button("Download All (ZIP)", data=zip_bytes,
|
|
|
|
| 1 |
# streamlit_app.py — LamboVision · AI Car Studio (native-only UI, no padding)
|
| 2 |
+
# Flow: Step 1 Gallery (Background Cleaned) → Step 2 AI Configurated (config) → Step 3 AI Generated Video
|
| 3 |
+
# Tiles use a uniform aspect. Images/videos fit inside (no overflow). “Generate Video From These Results” button included.
|
| 4 |
|
| 5 |
import os, io, base64, zipfile, requests, streamlit as st
|
| 6 |
from PIL import Image
|
|
|
|
| 16 |
pass
|
| 17 |
|
| 18 |
# ================= Env & API =================
|
| 19 |
+
API_BASE = (os.getenv("AI_LIGHTBOX_API", "http://127.0.0.1:7860") or "http://127.0.0.1:7860").strip().strip("'\"").rstrip("/")
|
| 20 |
+
HF_TOKEN = (os.getenv("AI_LIGHTBOX_TOKEN", "") or "").strip().strip("'\"")
|
| 21 |
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
|
| 22 |
|
| 23 |
VIDEO_MAX_PX_DEFAULT = int(os.getenv("VIDEO_MAX_PX", "720"))
|
|
|
|
| 298 |
inject_base_css(card_fit_mode="contain")
|
| 299 |
|
| 300 |
st.title("🏎️ LamboVision · AI Car Studio")
|
| 301 |
+
st.caption("Step 1: Gallery (Background Cleaned) · Step 2: AI Configurated (config) · Step 3: AI Generated Video")
|
| 302 |
|
| 303 |
ok = backend_ok()
|
| 304 |
|
|
|
|
| 311 |
with col3:
|
| 312 |
preview_aspect = st.selectbox("Tile Aspect", ASPECT_OPTIONS, index=0, key="preview_aspect") # default 3:4
|
| 313 |
with col4:
|
| 314 |
+
to_video = st.checkbox("Auto-generate Video after Run", False, key="to_video")
|
| 315 |
with col5:
|
| 316 |
duration = st.selectbox("Video Duration", VIDEO_DUR_OPTIONS, index=0, key="duration_sel")
|
| 317 |
with col6:
|
|
|
|
| 372 |
with s2:
|
| 373 |
scene_extra = st.text_input("Scene extra (optional)", value="", key="scene_extra")
|
| 374 |
|
| 375 |
+
# ================= SAMPLE PREVIEWS =================
|
| 376 |
st.subheader("Sample Previews")
|
| 377 |
col_in, col_gallery, col_comp, col_vid = st.columns(4)
|
| 378 |
|
|
|
|
| 394 |
|
| 395 |
gallery_bytes = demo_files.get("packshot.jpg") or input_bytes
|
| 396 |
show_tile_card_display_download(
|
| 397 |
+
col_gallery, "Gallery (Background Cleaned)",
|
| 398 |
display_bytes=gallery_bytes,
|
| 399 |
download_bytes=gallery_bytes,
|
| 400 |
filename_stub="gallery", key_prefix="pre"
|
|
|
|
| 402 |
|
| 403 |
comp_bytes = gallery_bytes
|
| 404 |
show_tile_card_display_download(
|
| 405 |
+
col_comp, "AI Configurated",
|
| 406 |
display_bytes=comp_bytes,
|
| 407 |
download_bytes=comp_bytes,
|
| 408 |
+
filename_stub="ai_configurated", key_prefix="pre"
|
| 409 |
)
|
| 410 |
|
| 411 |
vid_demo = demo_files.get("tryon.mp4")
|
|
|
|
| 439 |
for f in file_list:
|
| 440 |
files_payload.append(("files", (f.name, f.getvalue(), f.type or "image/jpeg")))
|
| 441 |
|
| 442 |
+
# ---- Step 1: Gallery (Background Cleaned; native only) ----
|
| 443 |
gallery_payload = make_gallery_payload(preview_aspect)
|
| 444 |
if image_url:
|
| 445 |
gallery_payload["image_urls"] = image_url
|
| 446 |
out_gallery = post_image_edit(gallery_payload, files_payload if files_payload else None)
|
|
|
|
| 447 |
gallery_native_url = (out_gallery["result"]["images_native"] or [{}])[0].get("url") if out_gallery else None
|
| 448 |
|
| 449 |
+
# ---- Step 2: AI Configurated (config prompt; native only) ----
|
| 450 |
edit_prompt = build_car_prompt(
|
| 451 |
model_name=(model_name or "Lamborghini"),
|
| 452 |
body_color=(body_color or "Verde Ithaca"),
|
|
|
|
| 458 |
comp_payload = make_composition_payload(edit_prompt, preview_aspect, upscale=False, upscale_factor="2")
|
| 459 |
comp_payload["image_urls"] = gallery_native_url or ""
|
| 460 |
out_comp = post_image_edit(comp_payload, files_payload=None)
|
|
|
|
| 461 |
comp_native_url = (out_comp["result"]["images_native"] or [{}])[0].get("url") if out_comp else None
|
| 462 |
|
| 463 |
+
# ---- Optional auto video right after Run ----
|
| 464 |
vurl = None; ui_hints = {}
|
| 465 |
if st.session_state.get("to_video", False) and (comp_native_url or gallery_native_url):
|
| 466 |
video_prompt = build_video_prompt(scene_name, scene_extra)
|
|
|
|
| 498 |
vbytes = None
|
| 499 |
if res:
|
| 500 |
st.subheader("Results")
|
| 501 |
+
c_gallery, c_comp, c_vid = st.columns([1.2, 1.2, 1.2])
|
| 502 |
|
| 503 |
+
# Gallery (Background Cleaned, native)
|
| 504 |
show_tile_card_display_download(
|
| 505 |
+
c_gallery, "Gallery (Background Cleaned)",
|
| 506 |
display_url=res.get("gallery_native_url"),
|
| 507 |
download_url=res.get("gallery_native_url"),
|
| 508 |
filename_stub="gallery_native",
|
| 509 |
key_prefix=f"job{st.session_state['job_counter']}"
|
| 510 |
)
|
| 511 |
|
| 512 |
+
# AI Configurated (native)
|
| 513 |
show_tile_card_display_download(
|
| 514 |
+
c_comp, "AI Configurated",
|
| 515 |
display_url=res.get("composition_native_url"),
|
| 516 |
download_url=res.get("composition_native_url"),
|
| 517 |
+
filename_stub="ai_configurated_native",
|
| 518 |
key_prefix=f"job{st.session_state['job_counter']}"
|
| 519 |
)
|
| 520 |
|
|
|
|
| 539 |
mime="video/mp4", key=f"job{st.session_state['job_counter']}_video_dl")
|
| 540 |
else:
|
| 541 |
c_vid.markdown('<div class="lb-frame"></div>', unsafe_allow_html=True)
|
| 542 |
+
# ---- Explicit manual video trigger button ----
|
| 543 |
+
gen_now = c_vid.button("Generate Video From These Results", key=f"gen_video_job{st.session_state['job_counter']}")
|
| 544 |
+
if gen_now:
|
| 545 |
+
src_for_video = res.get("composition_native_url") or res.get("gallery_native_url")
|
| 546 |
+
if not src_for_video:
|
| 547 |
+
st.warning("No image available to generate video.")
|
| 548 |
+
else:
|
| 549 |
+
with st.spinner("Generating Video …"):
|
| 550 |
+
try:
|
| 551 |
+
video_prompt = build_video_prompt(st.session_state.get("scene_name", "Studio Cinematic"),
|
| 552 |
+
st.session_state.get("scene_extra",""))
|
| 553 |
+
v = post_video(
|
| 554 |
+
src_for_video,
|
| 555 |
+
duration=st.session_state.get("duration_sel", VIDEO_DUR_OPTIONS[0]),
|
| 556 |
+
resolution=st.session_state.get("resolution_sel", VIDEO_RES_OPTIONS[1]),
|
| 557 |
+
preview_aspect=st.session_state.get("preview_aspect","3:4"),
|
| 558 |
+
prompt_text=video_prompt,
|
| 559 |
+
prompt_optimizer=False,
|
| 560 |
+
)
|
| 561 |
+
vurl2 = (v.get("result") or {}).get("video", {}).get("url")
|
| 562 |
+
ui_hints = v.get("ui_hints") or {}
|
| 563 |
+
if vurl2:
|
| 564 |
+
st.session_state["results"]["video_url"] = vurl2
|
| 565 |
+
if isinstance(ui_hints, dict):
|
| 566 |
+
st.session_state["video_ui_max_px"] = int(ui_hints.get("suggested_video_max_px", VIDEO_MAX_PX_DEFAULT))
|
| 567 |
+
st.success("Video is ready. Showing preview…")
|
| 568 |
+
st.rerun()
|
| 569 |
+
else:
|
| 570 |
+
st.info("Video URL not returned.")
|
| 571 |
+
except requests.HTTPError as e:
|
| 572 |
+
st.error(f"HTTP {e.response.status_code}")
|
| 573 |
+
except Exception as e:
|
| 574 |
+
st.error(f"Error: {e}")
|
| 575 |
+
|
| 576 |
+
# ZIP bundle (bottom row)
|
| 577 |
+
st.markdown("---")
|
| 578 |
+
exp_col = st.container()
|
| 579 |
+
with exp_col:
|
| 580 |
+
st.markdown("#### Export")
|
| 581 |
+
named = []
|
| 582 |
+
gnat = fetch_bytes(res.get("gallery_native_url")) if res.get("gallery_native_url") else None
|
| 583 |
+
cnat = fetch_bytes(res.get("composition_native_url")) if res.get("composition_native_url") else None
|
| 584 |
+
if gnat: named.append((f"gallery_native{infer_ext(gnat)}", gnat))
|
| 585 |
+
if cnat: named.append((f"ai_configurated_native{infer_ext(cnat)}", cnat))
|
| 586 |
+
if vbytes: named.append(("video.mp4", vbytes))
|
| 587 |
if named:
|
| 588 |
zip_bytes = make_zip(named)
|
| 589 |
st.download_button("Download All (ZIP)", data=zip_bytes,
|