renderfy commited on
Commit
3654c3f
·
verified ·
1 Parent(s): 0a93515

Upload streamlit_app.py

Browse files
Files changed (1) hide show
  1. 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 (clean packshot) → Step 2 AI Composition (config) → Step 3 AI Generated Video
3
- # All tiles are uniform aspect (configurable). Images/videos fit inside (no overflow).
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("AI_LamboVision_API", "http://127.0.0.1:7860") or "http://127.0.0.1:7860").strip().strip("'\"").rstrip("/")
20
- HF_TOKEN = (os.getenv("AI_LamboVision_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,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 (clean packshot) · Step 2: AI Composition (config) · Step 3: AI Generated Video")
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("Generate Video", 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,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 (no padding; just native demos) =================
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 Composition",
406
  display_bytes=comp_bytes,
407
  download_bytes=comp_bytes,
408
- filename_stub="ai_composition", key_prefix="pre"
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 (clean packshot; 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
-
448
  gallery_native_url = (out_gallery["result"]["images_native"] or [{}])[0].get("url") if out_gallery else None
449
 
450
- # ---- Step 2: AI Composition (config prompt; native only) ----
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
- # ---- Step 3: Video (optional) ----
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, c_zip = st.columns([1.2, 1.2, 1.2, 0.6])
504
 
505
- # Gallery (clean packshot, native)
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 Composition (configured, native)
515
  show_tile_card_display_download(
516
- c_comp, "AI Composition",
517
  display_url=res.get("composition_native_url"),
518
  download_url=res.get("composition_native_url"),
519
- filename_stub="ai_composition_native",
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
- c_vid.caption("—")
545
-
546
- # ZIP bundle
547
- named = []
548
- gnat = fetch_bytes(res.get("gallery_native_url")) if res.get("gallery_native_url") else None
549
- cnat = fetch_bytes(res.get("composition_native_url")) if res.get("composition_native_url") else None
550
- if gnat: named.append((f"gallery_native{infer_ext(gnat)}", gnat))
551
- if cnat: named.append((f"ai_composition_native{infer_ext(cnat)}", cnat))
552
- if vbytes: named.append(("video.mp4", vbytes))
553
- with c_zip:
554
- st.markdown('<div class="lb-card-title">Export</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,