carlex3321 commited on
Commit
3629c3e
·
verified ·
1 Parent(s): 6e9236e

Update app_vince.py

Browse files
Files changed (1) hide show
  1. app_vince.py +137 -157
app_vince.py CHANGED
@@ -1,201 +1,181 @@
1
  #!/usr/bin/env python3
 
 
 
 
 
 
 
 
 
2
  import os
3
  from pathlib import Path
4
  from typing import List, Tuple, Optional
 
5
  import gradio as gr
6
 
7
- from services.vincie import VincieService
 
 
 
 
 
 
8
 
 
9
  svc = VincieService()
10
- svc.repo_dir = Path(svc.repo_dir)
11
- svc.ckpt_dir = Path(svc.ckpt_dir)
12
-
13
- DEFAULT_NEGATIVE_PROMPT = (
14
- "Worst quality, Normal quality, Low quality, Low res, Blurry, Jpeg artifacts, Grainy, "
15
- "text, logo, watermark, banner, extra digits, signature, subtitling, Bad anatomy, "
16
- "Bad proportions, Deformed, Disconnected limbs, Disfigured, Extra arms, Extra limbs, "
17
- "Extra hands, Fused fingers, Gross proportions, Long neck, Malformed limbs, Mutated, "
18
- "Mutated hands, Mutated limbs, Missing arms, Missing fingers, Poorly drawn hands, "
19
- "Poorly drawn face, Nsfw, Uncensored, Cleavage, Nude, Nipples, Overexposed, "
20
- "Plain background, Grainy, Underexposed, Deformed structures"
21
- )
22
 
23
  def setup_auto() -> str:
 
 
 
 
 
 
24
  try:
25
  svc.ensure_repo()
26
  svc.ensure_model()
27
- return "Configuração concluída com sucesso: repositório e checkpoint estão prontos."
 
 
 
28
  except Exception as e:
29
- import traceback
30
- print(traceback.format_exc())
31
- return f"A configuração encontrou um erro: {e}"
32
 
33
  def _list_media(out_dir: Path, max_images: int = 24) -> Tuple[List[str], Optional[str]]:
 
 
 
 
 
 
 
 
 
 
 
 
34
  img_globs = ("*.png", "*.jpg", "*.jpeg", "*.webp")
35
- try:
36
- images = sorted(
37
- [p for pat in img_globs for p in out_dir.rglob(pat)],
38
- key=lambda p: p.stat().st_mtime
39
- )
40
- except FileNotFoundError:
41
- images = []
42
- image_paths = [str(p) for p in images[-max_images:]]
43
- try:
44
- videos = sorted(out_dir.rglob("*.mp4"), key=lambda p: p.stat().st_mtime)
45
- except FileNotFoundError:
46
- videos = []
47
  video_path = str(videos[-1]) if videos else None
48
  return image_paths, video_path
49
 
50
- def ui_multi_turn(input_image, turns_text, negative_prompt, seed, steps, cfg_scale, resolution, use_vae_slicing, num_gpus, batch_size):
51
- if not input_image:
52
- return [], None, "Por favor, forneça uma imagem de entrada."
 
 
 
 
 
 
 
 
 
 
 
53
  if not turns_text or not turns_text.strip():
54
- return [], None, "Por favor, forneça as instruções de edição (uma por linha)."
 
55
  turns = [ln.strip() for ln in turns_text.splitlines() if ln.strip()]
56
  try:
57
- out_dir = svc.multi_turn_edit(
58
- input_image,
59
- turns,
60
- negative_prompt=negative_prompt,
61
- seed=int(seed),
62
- steps=int(steps),
63
- cfg_scale=float(cfg_scale),
64
- resolution=int(resolution),
65
- use_vae_slicing=use_vae_slicing,
66
- num_gpus=int(num_gpus),
67
- batch_size=int(batch_size),
68
- )
69
- imgs, vid = _list_media(Path(out_dir))
70
- return imgs, vid, f"Saídas salvas em: {out_dir}"
71
- except Exception as e:
72
- import traceback
73
- print(traceback.format_exc())
74
- return [], None, f"Erro na geração: {e}"
75
-
76
- def ui_text_to_video(input_image, prompt, negative_prompt, seed, steps, cfg_scale, resolution, fps, use_vae_slicing, num_gpus, batch_size):
77
- if not input_image:
78
- return None, "Por favor, forneça uma imagem de entrada (frame inicial)."
79
- if not prompt or not prompt.strip():
80
- return None, "Por favor, forneça um prompt para o vídeo."
81
- try:
82
- out_dir = svc.text_to_video(
83
- input_image,
84
- prompt,
85
- negative_prompt=negative_prompt,
86
- seed=int(seed),
87
- steps=int(steps),
88
- cfg_scale=float(cfg_scale),
89
- resolution=int(resolution),
90
- fps=int(fps),
91
- use_vae_slicing=use_vae_slicing,
92
- num_gpus=int(num_gpus),
93
- batch_size=int(batch_size),
94
- )
95
- _, vid = _list_media(Path(out_dir))
96
- return vid, f"Vídeo salvo em: {out_dir}"
97
  except Exception as e:
98
- import traceback
99
- print(traceback.format_exc())
100
- return None, f"Erro na geração: {e}"
 
 
101
 
102
- def ui_multi_concept(files, descs_text, final_prompt):
 
 
 
 
 
 
 
 
 
 
 
 
103
  if not files:
104
- return [], None, "Por favor, faça o upload das imagens de conceito."
105
- if not descs_text:
106
- return [], None, "Por favor, forneça as descrições (uma por linha)."
107
- if not final_prompt:
108
- return [], None, "Por favor, forneça um prompt final."
 
109
  descs = [ln.strip() for ln in descs_text.splitlines() if ln.strip()]
110
  if len(descs) != len(files):
111
- return [], None, f"O número de descrições ({len(descs)}) deve ser igual ao de imagens ({len(files)})."
 
112
  try:
113
  out_dir = svc.multi_concept_compose(files, descs, final_prompt)
114
- imgs, vid = _list_media(Path(out_dir))
115
- return imgs, vid, f"Saídas salvas em: {out_dir}"
116
  except Exception as e:
117
- import traceback
118
- print(traceback.format_exc())
119
- return [], None, f"Erro na geração: {e}"
120
 
121
- with gr.Blocks(title="VINCIE Service", theme=gr.themes.Soft()) as demo:
122
- gr.Markdown("# VINCIE Service Geração Distribuída com Controles Avançados")
 
123
 
124
- with gr.Row():
125
- setup_out = gr.Textbox(label="Status da Configuração", interactive=False)
126
 
127
- with gr.Tab("Edição Multi-Turno"):
128
- with gr.Row():
129
- img_mt = gr.Image(type="filepath", label="Imagem de Entrada")
130
- with gr.Column():
131
- turns_mt = gr.Textbox(
132
- lines=5,
133
- label="Instruções de Edição (uma por linha)",
134
- placeholder="Ex: adicione um chapéu azul\nagora, mude o fundo para uma praia"
135
- )
136
- with gr.Accordion("Configurações Avançadas e de Desempenho", open=True):
137
- with gr.Row():
138
- num_gpus_mt = gr.Slider(label="Número de GPUs", minimum=1, maximum=8, step=1, value=8)
139
- batch_size_mt = gr.Number(label="Batch Size por GPU", value=1, precision=0)
140
- resolution_mt = gr.Slider(label="Resolução", minimum=256, maximum=1024, step=128, value=512)
141
- use_vae_slicing_mt = gr.Checkbox(label="Usar VAE Slicing (Economiza VRAM)", value=True)
142
- neg_prompt_mt = gr.Textbox(lines=3, label="Prompt Negativo", value=DEFAULT_NEGATIVE_PROMPT)
143
- seed_mt = gr.Number(label="Seed (Semente)", value=1, precision=0)
144
- steps_mt = gr.Slider(label="Passos de Inferência", minimum=10, maximum=100, step=1, value=50)
145
- cfg_mt = gr.Slider(label="Escala de Orientação (CFG)", minimum=1.0, maximum=20.0, step=0.5, value=7.5)
146
- run_mt = gr.Button("Executar Edição Multi-Turno", variant="primary")
147
- gallery_mt = gr.Gallery(label="Imagens Geradas", columns=4, height="auto")
148
- video_mt = gr.Video(label="Vídeo da Sequência (se disponível)")
149
- status_mt = gr.Textbox(label="Status da Saída", interactive=False)
150
- run_mt.click(
151
- ui_multi_turn,
152
- inputs=[img_mt, turns_mt, neg_prompt_mt, seed_mt, steps_mt, cfg_mt, resolution_mt, use_vae_slicing_mt, num_gpus_mt, batch_size_mt],
153
- outputs=[gallery_mt, video_mt, status_mt]
154
  )
 
155
 
156
- with gr.Tab("Texto-para-Vídeo"):
157
- with gr.Row():
158
- img_vid = gr.Image(type="filepath", label="Frame Inicial")
159
- with gr.Column():
160
- prompt_vid = gr.Textbox(lines=2, label="Prompt do Vídeo", placeholder="Ex: um gato andando pela sala")
161
- with gr.Accordion("Configurações Avançadas e de Desempenho", open=True):
162
- with gr.Row():
163
- num_gpus_vid = gr.Slider(label="Número de GPUs", minimum=1, maximum=8, step=1, value=8)
164
- batch_size_vid = gr.Number(label="Batch Size por GPU", value=1, precision=0)
165
- resolution_vid = gr.Slider(label="Resolução", minimum=256, maximum=1024, step=128, value=512)
166
- fps_vid = gr.Slider(label="Frames por Segundo (FPS)", minimum=1, maximum=24, step=1, value=2)
167
- use_vae_slicing_vid = gr.Checkbox(label="Usar VAE Slicing (Economiza VRAM)", value=True)
168
- neg_prompt_vid = gr.Textbox(lines=3, label="Prompt Negativo", value=DEFAULT_NEGATIVE_PROMPT)
169
- seed_vid = gr.Number(label="Seed (Semente)", value=1, precision=0)
170
- steps_vid = gr.Slider(label="Passos de Inferência", minimum=10, maximum=100, step=1, value=50)
171
- cfg_vid = gr.Slider(label="Escala de Orientação (CFG)", minimum=1.0, maximum=20.0, step=0.5, value=7.5)
172
- run_vid = gr.Button("Gerar Vídeo", variant="primary")
173
- video_vid = gr.Video(label="Vídeo Gerado")
174
- status_vid = gr.Textbox(label="Status da Saída", interactive=False)
175
- run_vid.click(
176
- ui_text_to_video,
177
- inputs=[img_vid, prompt_vid, neg_prompt_vid, seed_vid, steps_vid, cfg_vid, resolution_vid, fps_vid, use_vae_slicing_vid, num_gpus_vid, batch_size_vid],
178
- outputs=[video_vid, status_vid]
179
- )
180
 
181
- with gr.Tab("Composição Multi-Conceito"):
182
  with gr.Row():
183
- with gr.Column(scale=1):
184
- files_mc = gr.File(file_count="multiple", type="filepath", label="1. Imagens de Conceito")
185
- with gr.Column(scale=2):
186
- descs_mc = gr.Textbox(lines=5, label="2. Descrições (uma por linha, na mesma ordem)")
187
- final_prompt_mc = gr.Textbox(lines=3, label="3. Prompt Final de Composição")
188
- run_mc = gr.Button("Executar Composição", variant="primary")
189
- gallery_mc = gr.Gallery(label="Imagens Geradas", columns=4, height="auto")
190
- video_mc = gr.Video(label="Vídeo da Sequência (se disponível)")
191
- status_mc = gr.Textbox(label="Status da Saída", interactive=False)
192
- run_mc.click(
 
 
 
 
 
 
 
193
  ui_multi_concept,
194
- inputs=[files_mc, descs_mc, final_prompt_mc],
195
- outputs=[gallery_mc, video_mc, status_mc]
196
  )
197
 
 
198
  demo.load(fn=setup_auto, outputs=setup_out)
199
 
200
  if __name__ == "__main__":
201
- demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")))
 
 
 
 
 
1
  #!/usr/bin/env python3
2
+ """
3
+ VINCIE Service UI (Gradio)
4
+ - Automatic setup runs on app load (no manual setup button).
5
+ - Multi-turn editing and multi-concept composition front-end.
6
+ - Designed for NVIDIA L40S (SM 8.9) environments aligned with CUDA 12.x.
7
+ - Functional reference: ByteDance-Seed/VINCIE.
8
+ - Space and Docker developed by Carlex (contact below).
9
+ """
10
+
11
  import os
12
  from pathlib import Path
13
  from typing import List, Tuple, Optional
14
+
15
  import gradio as gr
16
 
17
+ # Adapt this import to the project layout.
18
+ # Provide a VincieService with:
19
+ # - ensure_repo(): clones/updates upstream repo if missing
20
+ # - ensure_model(): downloads/validates checkpoints to /app/ckpt/VINCIE-3B
21
+ # - multi_turn_edit(image_path: str, turns: List[str]) -> str (output dir)
22
+ # - multi_concept_compose(files: List[str], descs: List[str], final_prompt: str) -> str (output dir)
23
+ from services.vincie import VincieService # change path if needed
24
 
25
+ # Instantiate the service (defaults to /app/VINCIE and /app/ckpt/VINCIE-3B)
26
  svc = VincieService()
27
+
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  def setup_auto() -> str:
30
+ """
31
+ Run an idempotent setup on interface load:
32
+ - Ensure the upstream repository is present and ready.
33
+ - Ensure the model checkpoint is downloaded and ready.
34
+ Returns an English status string for the UI.
35
+ """
36
  try:
37
  svc.ensure_repo()
38
  svc.ensure_model()
39
+ return (
40
+ "Setup completed successfully: repository and checkpoint are ready "
41
+ "for inference on an NVIDIA L40S environment."
42
+ )
43
  except Exception as e:
44
+ return f"Setup encountered an error: {e}"
45
+
 
46
 
47
  def _list_media(out_dir: Path, max_images: int = 24) -> Tuple[List[str], Optional[str]]:
48
+ """
49
+ Enumerate resulting images and the most recent video from an output directory.
50
+
51
+ Args:
52
+ out_dir: Path to the directory where the service wrote its results.
53
+ max_images: Upper bound on how many images to surface in the gallery.
54
+
55
+ Returns:
56
+ A tuple (images, video) where:
57
+ - images is a list of file paths to images sorted by modified time,
58
+ - video is the path to the latest .mp4 if found, otherwise None.
59
+ """
60
  img_globs = ("*.png", "*.jpg", "*.jpeg", "*.webp")
61
+ images: List[Path] = []
62
+ for pat in img_globs:
63
+ images += list(out_dir.rglob(pat))
64
+ images = sorted(images, key=lambda p: p.stat().st_mtime)
65
+ image_paths = [str(p) for p in images[-max_images:]] if images else []
66
+ videos = sorted(out_dir.rglob("*.mp4"), key=lambda p: p.stat().st_mtime)
 
 
 
 
 
 
67
  video_path = str(videos[-1]) if videos else None
68
  return image_paths, video_path
69
 
70
+
71
+ def ui_multi_turn(input_image: Optional[str], turns_text: Optional[str]):
72
+ """
73
+ Multi-turn image editing entrypoint for the UI.
74
+
75
+ Args:
76
+ input_image: Path to a single input image on disk.
77
+ turns_text: User-provided editing turns, one instruction per line.
78
+
79
+ Returns:
80
+ (gallery, video, status) for Gradio components.
81
+ """
82
+ if not input_image or not str(input_image).strip():
83
+ return [], None, "Please provide an input image."
84
  if not turns_text or not turns_text.strip():
85
+ return [], None, "Please provide edit turns (one per line)."
86
+
87
  turns = [ln.strip() for ln in turns_text.splitlines() if ln.strip()]
88
  try:
89
+ out_dir = svc.multi_turn_edit(input_image, turns)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  except Exception as e:
91
+ return [], None, f"Generation error: {e}"
92
+
93
+ imgs, vid = _list_media(Path(out_dir))
94
+ status = f"Outputs saved to: {out_dir}"
95
+ return imgs, vid, status
96
 
97
+
98
+ def ui_multi_concept(files: Optional[List[str]], descs_text: Optional[str], final_prompt: Optional[str]):
99
+ """
100
+ Multi-concept composition entrypoint for the UI.
101
+
102
+ Args:
103
+ files: List of paths to concept images on disk.
104
+ descs_text: Per-image descriptions (one line per image, in the same order).
105
+ final_prompt: A final composition prompt that aggregates the concepts.
106
+
107
+ Returns:
108
+ (gallery, video, status) for Gradio components.
109
+ """
110
  if not files:
111
+ return [], None, "Please upload concept images."
112
+ if not descs_text or not descs_text.strip():
113
+ return [], None, "Please provide descriptions (one per line)."
114
+ if not final_prompt or not final_prompt.strip():
115
+ return [], None, "Please provide a final prompt."
116
+
117
  descs = [ln.strip() for ln in descs_text.splitlines() if ln.strip()]
118
  if len(descs) != len(files):
119
+ return [], None, f"Descriptions count ({len(descs)}) must match images count ({len(files)})."
120
+
121
  try:
122
  out_dir = svc.multi_concept_compose(files, descs, final_prompt)
 
 
123
  except Exception as e:
124
+ return [], None, f"Generation error: {e}"
 
 
125
 
126
+ imgs, vid = _list_media(Path(out_dir))
127
+ status = f"Outputs saved to: {out_dir}"
128
+ return imgs, vid, status
129
 
 
 
130
 
131
+ with gr.Blocks(title="VINCIE Service") as demo:
132
+ # Header and credits
133
+ gr.Markdown(
134
+ "\n".join(
135
+ [
136
+ "# VINCIE Service — Multi-turn Editing and Multi-concept Composition",
137
+ "- Automatic setup runs at startup; setup status appears below.",
138
+ "- Hardware requirement: NVIDIA L40S (SM 8.9) is recommended for this build.",
139
+ "- Functional upstream model: ByteDance-Seed/VINCIE (see project repository).",
140
+ "- Space and Docker were developed by Carlex.",
141
+ "- Contact: Email: Carlex22@gmail.com | GitHub: carlex22",
142
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  )
144
+ )
145
 
146
+ with gr.Row():
147
+ setup_out = gr.Textbox(label="Setup Status", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ with gr.Tab("Multi-turn Editing"):
150
  with gr.Row():
151
+ img = gr.Image(type="filepath", label="Input image")
152
+ turns = gr.Textbox(lines=8, label="Turns (one per line)")
153
+ run1 = gr.Button("Run")
154
+ out_gallery = gr.Gallery(label="Images", columns=4, height="auto")
155
+ out_video = gr.Video(label="Video (if available)")
156
+ out_status = gr.Textbox(label="Output", interactive=False)
157
+ run1.click(ui_multi_turn, inputs=[img, turns], outputs=[out_gallery, out_video, out_status])
158
+
159
+ with gr.Tab("Multi-concept Composition"):
160
+ files = gr.File(file_count="multiple", type="filepath", label="Concept images")
161
+ descs = gr.Textbox(lines=8, label="Descriptions (one per line, same order as images)")
162
+ final_prompt = gr.Textbox(lines=2, label="Final prompt")
163
+ run2 = gr.Button("Run")
164
+ out_gallery2 = gr.Gallery(label="Images", columns=4, height="auto")
165
+ out_video2 = gr.Video(label="Video (if available)")
166
+ out_status2 = gr.Textbox(label="Output", interactive=False)
167
+ run2.click(
168
  ui_multi_concept,
169
+ inputs=[files, descs, final_prompt],
170
+ outputs=[out_gallery2, out_video2, out_status2],
171
  )
172
 
173
+ # Auto-setup on load (no manual button)
174
  demo.load(fn=setup_auto, outputs=setup_out)
175
 
176
  if __name__ == "__main__":
177
+ demo.launch(
178
+ server_name="0.0.0.0",
179
+ server_port=int(os.getenv("PORT", "7860")),
180
+ allowed_paths=["/app/outputs", "/app/ckpt"],
181
+ )