|
|
|
|
|
import os |
|
|
import glob |
|
|
import gradio as gr |
|
|
from pathlib import Path |
|
|
from typing import List, Tuple, Optional |
|
|
|
|
|
from vincie_service import VincieService |
|
|
|
|
|
svc = VincieService() |
|
|
|
|
|
def setup() -> str: |
|
|
""" |
|
|
Prepara repositório e modelos (idempotente). |
|
|
""" |
|
|
try: |
|
|
svc.ensure_repo() |
|
|
svc.ensure_model() |
|
|
except Exception as e: |
|
|
return f"Setup falhou: {e}" |
|
|
return "Setup OK" |
|
|
|
|
|
def _list_media(out_dir: Path, max_images: int = 24) -> Tuple[List[str], Optional[str]]: |
|
|
""" |
|
|
Varre o diretório de saída por imagens e vídeo, retornando caminhos ordenados. |
|
|
""" |
|
|
exts_img = ("*.png", "*.jpg", "*.jpeg", "*.webp") |
|
|
imgs: List[Path] = [] |
|
|
for pat in exts_img: |
|
|
imgs += list(out_dir.rglob(pat)) |
|
|
imgs = sorted(imgs, key=lambda p: p.stat().st_mtime) |
|
|
imgs_paths = [str(p) for p in imgs[-max_images:]] if imgs else [] |
|
|
|
|
|
vids = sorted(out_dir.rglob("*.mp4"), key=lambda p: p.stat().st_mtime) |
|
|
vid_path = str(vids[-1]) if vids else None |
|
|
return imgs_paths, vid_path |
|
|
|
|
|
def ui_multi_turn(input_image, turns_text): |
|
|
""" |
|
|
Executa multi-turn editing e retorna mídia do diretório de saída. |
|
|
""" |
|
|
if not input_image or not str(input_image).strip(): |
|
|
return [], None, "Forneça uma imagem." |
|
|
if not turns_text or not turns_text.strip(): |
|
|
return [], None, "Forneça turns (um por linha)." |
|
|
|
|
|
turns = [ln.strip() for ln in turns_text.splitlines() if ln.strip()] |
|
|
try: |
|
|
out_dir = svc.multi_turn_edit(input_image, turns) |
|
|
except Exception as e: |
|
|
return [], None, f"Erro na geração: {e}" |
|
|
|
|
|
imgs, vid = _list_media(Path(out_dir)) |
|
|
status = f"Gerado em: {str(out_dir)}" |
|
|
return imgs, vid, status |
|
|
|
|
|
def ui_multi_concept(files, descs_text, final_prompt): |
|
|
""" |
|
|
Executa composição multi-conceito e retorna mídia do diretório de saída. |
|
|
""" |
|
|
if not files: |
|
|
return [], None, "Envie imagens de conceito." |
|
|
if not descs_text or not descs_text.strip(): |
|
|
return [], None, "Forneça descrições (uma por linha)." |
|
|
if not final_prompt or not final_prompt.strip(): |
|
|
return [], None, "Forneça o prompt final." |
|
|
|
|
|
descs = [ln.strip() for ln in descs_text.splitlines() if ln.strip()] |
|
|
if len(descs) != len(files): |
|
|
return [], None, f"Número de descrições ({len(descs)}) difere do número de imagens ({len(files)})." |
|
|
|
|
|
try: |
|
|
out_dir = svc.multi_concept_compose(files, descs, final_prompt) |
|
|
except Exception as e: |
|
|
return [], None, f"Erro na geração: {e}" |
|
|
|
|
|
imgs, vid = _list_media(Path(out_dir)) |
|
|
status = f"Gerado em: {str(out_dir)}" |
|
|
return imgs, vid, status |
|
|
|
|
|
with gr.Blocks(title="VINCIE Service") as demo: |
|
|
gr.Markdown("# 🎨 VINCIE Service — Multi-turn e Multi-concept") |
|
|
|
|
|
with gr.Row(): |
|
|
setup_btn = gr.Button("Preparar (repo + modelos)") |
|
|
setup_out = gr.Textbox(label="Status", interactive=False) |
|
|
setup_btn.click(fn=setup, outputs=setup_out) |
|
|
|
|
|
with gr.Tab("🔄 Multi-turn Editing"): |
|
|
with gr.Row(): |
|
|
img = gr.Image(type="filepath", label="Imagem inicial") |
|
|
turns = gr.Textbox(lines=8, label="Turns (um por linha)") |
|
|
run1 = gr.Button("Executar") |
|
|
out_gallery = gr.Gallery(label="Imagens", columns=4, height="auto") |
|
|
out_video = gr.Video(label="Vídeo (se houver)") |
|
|
out_status = gr.Textbox(label="Saída", interactive=False) |
|
|
run1.click(ui_multi_turn, inputs=[img, turns], outputs=[out_gallery, out_video, out_status]) |
|
|
|
|
|
with gr.Tab("🧩 Multi-concept Compose"): |
|
|
files = gr.File(file_count="multiple", type="filepath", label="Imagens de conceito") |
|
|
descs = gr.Textbox(lines=8, label="Descrições (uma por linha, na mesma ordem das imagens)") |
|
|
final_prompt = gr.Textbox(lines=2, label="Prompt final") |
|
|
run2 = gr.Button("Executar") |
|
|
out_gallery2 = gr.Gallery(label="Imagens", columns=4, height="auto") |
|
|
out_video2 = gr.Video(label="Vídeo (se houver)") |
|
|
out_status2 = gr.Textbox(label="Saída", interactive=False) |
|
|
run2.click(ui_multi_concept, inputs=[files, descs, final_prompt], outputs=[out_gallery2, out_video2, out_status2]) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=int(os.getenv("PORT", "7860")), |
|
|
allowed_paths=["/app/outputs", "/app/ckpt"] |
|
|
) |