ICGenAIShare04 commited on
Commit
66d6b8c
Β·
1 Parent(s): d2d418c

make image style match and fix sizes

Browse files
Files changed (1) hide show
  1. app.py +40 -24
app.py CHANGED
@@ -1,16 +1,21 @@
1
  import gradio as gr
2
  import spaces
3
  import torch
4
- from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
 
 
 
 
5
  from gradio_client import Client, handle_file
6
 
7
  # ==========================================
8
  # 1. LAZY LOAD LOCAL CARTOON MODELS
9
  # ==========================================
10
  image_pipe = None
 
11
 
12
  def load_cartoon_models():
13
- global image_pipe
14
  if image_pipe is None:
15
  print("🟒 Loading Animagine XL 3.1 & Scribble ControlNet...")
16
  dtype = torch.float16
@@ -18,25 +23,32 @@ def load_cartoon_models():
18
  "xinsir/controlnet-scribble-sdxl-1.0",
19
  torch_dtype=dtype
20
  )
 
21
  image_pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
22
  "cagliostrolab/animagine-xl-3.1",
23
  controlnet=controlnet,
24
  torch_dtype=dtype
25
  )
 
 
 
 
 
26
  return True
27
 
28
  # ==========================================
29
  # 2. LOCAL ZEROGPU GENERATION (Sketch -> Cartoon)
30
  # ==========================================
31
  @spaces.GPU(duration=180)
32
- def generate_cartoons(sketch_1, sketch_2, user_prompt, ctrl_scale):
33
  load_cartoon_models()
34
  image_pipe.to("cuda")
 
35
 
36
  master_prompt = f"{user_prompt}, masterpiece, best quality, highly detailed, professional 2d animation, flat colors, anime style"
37
  neg_prompt = "nsfw, photorealistic, 3d render, ugly, messy lines, bad anatomy, bad hands, missing fingers, lowres, worst quality"
38
 
39
- print("🎨 Stylizing Start Sketch...")
40
  img_1 = image_pipe(
41
  prompt=master_prompt,
42
  negative_prompt=neg_prompt,
@@ -46,16 +58,23 @@ def generate_cartoons(sketch_1, sketch_2, user_prompt, ctrl_scale):
46
  controlnet_conditioning_scale=ctrl_scale
47
  ).images[0]
48
 
49
- print("🎨 Stylizing End Sketch...")
50
- img_2 = image_pipe(
51
  prompt=master_prompt,
52
  negative_prompt=neg_prompt,
53
- image=sketch_2,
 
 
54
  num_inference_steps=25,
55
  guidance_scale=7.0,
56
  controlnet_conditioning_scale=ctrl_scale
57
  ).images[0]
58
 
 
 
 
 
 
59
  img_1_path, img_2_path = "frame1.png", "frame2.png"
60
  img_1.save(img_1_path)
61
  img_2.save(img_2_path)
@@ -71,25 +90,21 @@ def run_tooncrafter(img_1_path, img_2_path, prompt):
71
 
72
  try:
73
  print("πŸ”„ Submitting to ToonCrafter API (/get_image)...")
74
- # We now use the EXACT keyword arguments and order required by the API
75
  result = client.predict(
76
  image=handle_file(img_1_path),
77
  prompt=prompt,
78
- steps=25, # Lowered from default 50 to 25 so you don't wait in queue forever
79
  cfg_scale=7.5,
80
  eta=1.0,
81
- fs=10, # FPS
82
  seed=123,
83
  image2=handle_file(img_2_path),
84
  api_name="/get_image"
85
  )
86
  print("βœ… ToonCrafter Generation Complete!")
87
 
88
- # The API documentation says it returns a Dict: {video: filepath, subtitles: None}
89
  if isinstance(result, dict) and 'video' in result:
90
  return result['video']
91
-
92
- # Fallback just in case they return the raw string
93
  return result
94
 
95
  except Exception as e:
@@ -98,21 +113,17 @@ def run_tooncrafter(img_1_path, img_2_path, prompt):
98
  # ==========================================
99
  # 4. MASTER PIPELINE CONTROLLER
100
  # ==========================================
101
- def process_full_animation(sketch_1, sketch_2, prompt, ctrl_scale):
102
- # Step 1: Run local ZeroGPU (Cartoons)
103
- img_1_path, img_2_path = generate_cartoons(sketch_1, sketch_2, prompt, ctrl_scale)
104
-
105
- # Step 2: Pass to remote API (Video)
106
  video_path = run_tooncrafter(img_1_path, img_2_path, prompt)
107
-
108
  return img_1_path, img_2_path, video_path
109
 
110
  # ==========================================
111
  # 5. GRADIO INTERFACE
112
  # ==========================================
113
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
114
- gr.Markdown("# ✏️ Sketch-to-ToonCrafter Studio")
115
- gr.Markdown("Upload two sketches. We use **Animagine XL 3.1** locally to turn them into professional cartoons, and pass them to **ToonCrafter** to animate the motion!")
116
 
117
  with gr.Row():
118
  with gr.Column():
@@ -122,18 +133,23 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
122
  label="Character & Motion Description",
123
  placeholder="e.g., A boy in a red shirt jumping"
124
  )
125
- ctrl_scale = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.05, label="Sketch Adherence Strength")
 
 
 
 
 
126
  generate_btn = gr.Button("Create Animation", variant="primary")
127
 
128
  with gr.Column():
129
  with gr.Row():
130
  out_img_1 = gr.Image(label="Animagine Start Frame")
131
- out_img_2 = gr.Image(label="Animagine End Frame")
132
  out_video = gr.Video(label="ToonCrafter Animated Video")
133
 
134
  generate_btn.click(
135
  fn=process_full_animation,
136
- inputs=[sketch_1, sketch_2, prompt, ctrl_scale],
137
  outputs=[out_img_1, out_img_2, out_video]
138
  )
139
 
 
1
  import gradio as gr
2
  import spaces
3
  import torch
4
+ from diffusers import (
5
+ StableDiffusionXLControlNetPipeline,
6
+ StableDiffusionXLControlNetImg2ImgPipeline,
7
+ ControlNetModel
8
+ )
9
  from gradio_client import Client, handle_file
10
 
11
  # ==========================================
12
  # 1. LAZY LOAD LOCAL CARTOON MODELS
13
  # ==========================================
14
  image_pipe = None
15
+ img2img_pipe = None
16
 
17
  def load_cartoon_models():
18
+ global image_pipe, img2img_pipe
19
  if image_pipe is None:
20
  print("🟒 Loading Animagine XL 3.1 & Scribble ControlNet...")
21
  dtype = torch.float16
 
23
  "xinsir/controlnet-scribble-sdxl-1.0",
24
  torch_dtype=dtype
25
  )
26
+ # Pipeline 1: Text + Sketch -> Cartoon
27
  image_pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
28
  "cagliostrolab/animagine-xl-3.1",
29
  controlnet=controlnet,
30
  torch_dtype=dtype
31
  )
32
+
33
+ # Pipeline 2: Previous Cartoon + New Sketch -> Consistent Cartoon
34
+ # We share the components so it uses 0 extra VRAM!
35
+ img2img_pipe = StableDiffusionXLControlNetImg2ImgPipeline(**image_pipe.components)
36
+
37
  return True
38
 
39
  # ==========================================
40
  # 2. LOCAL ZEROGPU GENERATION (Sketch -> Cartoon)
41
  # ==========================================
42
  @spaces.GPU(duration=180)
43
+ def generate_cartoons(sketch_1, sketch_2, user_prompt, ctrl_scale, consistency_strength):
44
  load_cartoon_models()
45
  image_pipe.to("cuda")
46
+ img2img_pipe.to("cuda") # Moving both to GPU
47
 
48
  master_prompt = f"{user_prompt}, masterpiece, best quality, highly detailed, professional 2d animation, flat colors, anime style"
49
  neg_prompt = "nsfw, photorealistic, 3d render, ugly, messy lines, bad anatomy, bad hands, missing fingers, lowres, worst quality"
50
 
51
+ print("🎨 Stylizing Start Sketch (From Scratch)...")
52
  img_1 = image_pipe(
53
  prompt=master_prompt,
54
  negative_prompt=neg_prompt,
 
58
  controlnet_conditioning_scale=ctrl_scale
59
  ).images[0]
60
 
61
+ print("🎨 Stylizing End Sketch (Inheriting colors from Start Sketch)...")
62
+ img_2 = img2img_pipe(
63
  prompt=master_prompt,
64
  negative_prompt=neg_prompt,
65
+ image=img_1,
66
+ control_image=sketch_2,
67
+ strength=consistency_strength,
68
  num_inference_steps=25,
69
  guidance_scale=7.0,
70
  controlnet_conditioning_scale=ctrl_scale
71
  ).images[0]
72
 
73
+ # 🚨 THE FIX: Resize to 512x320 so ToonCrafter doesn't crash!
74
+ print("πŸ“ Resizing images for ToonCrafter compatibility...")
75
+ img_1 = img_1.resize((512, 320))
76
+ img_2 = img_2.resize((512, 320))
77
+
78
  img_1_path, img_2_path = "frame1.png", "frame2.png"
79
  img_1.save(img_1_path)
80
  img_2.save(img_2_path)
 
90
 
91
  try:
92
  print("πŸ”„ Submitting to ToonCrafter API (/get_image)...")
 
93
  result = client.predict(
94
  image=handle_file(img_1_path),
95
  prompt=prompt,
96
+ steps=25,
97
  cfg_scale=7.5,
98
  eta=1.0,
99
+ fs=10,
100
  seed=123,
101
  image2=handle_file(img_2_path),
102
  api_name="/get_image"
103
  )
104
  print("βœ… ToonCrafter Generation Complete!")
105
 
 
106
  if isinstance(result, dict) and 'video' in result:
107
  return result['video']
 
 
108
  return result
109
 
110
  except Exception as e:
 
113
  # ==========================================
114
  # 4. MASTER PIPELINE CONTROLLER
115
  # ==========================================
116
+ def process_full_animation(sketch_1, sketch_2, prompt, ctrl_scale, consistency_strength):
117
+ img_1_path, img_2_path = generate_cartoons(sketch_1, sketch_2, prompt, ctrl_scale, consistency_strength)
 
 
 
118
  video_path = run_tooncrafter(img_1_path, img_2_path, prompt)
 
119
  return img_1_path, img_2_path, video_path
120
 
121
  # ==========================================
122
  # 5. GRADIO INTERFACE
123
  # ==========================================
124
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
125
+ gr.Markdown("# ✏️ Sketch-to-ToonCrafter Studio (Pro Workflow)")
126
+ gr.Markdown("Upload two sketches. We use **Img2Img ControlNet** to ensure the characters maintain their exact clothing and colors, then pass them to **ToonCrafter** to animate!")
127
 
128
  with gr.Row():
129
  with gr.Column():
 
133
  label="Character & Motion Description",
134
  placeholder="e.g., A boy in a red shirt jumping"
135
  )
136
+
137
+ with gr.Accordion("Advanced AI Settings", open=False):
138
+ ctrl_scale = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.05, label="Sketch Strictness (How closely to follow your lines)")
139
+ # New slider for Image-to-Image strength
140
+ consistency_strength = gr.Slider(minimum=0.5, maximum=1.0, value=0.85, step=0.05, label="Color & Style Consistency (Lower = More like Frame 1, Higher = More creative)")
141
+
142
  generate_btn = gr.Button("Create Animation", variant="primary")
143
 
144
  with gr.Column():
145
  with gr.Row():
146
  out_img_1 = gr.Image(label="Animagine Start Frame")
147
+ out_img_2 = gr.Image(label="Animagine End Frame (Color Matched)")
148
  out_video = gr.Video(label="ToonCrafter Animated Video")
149
 
150
  generate_btn.click(
151
  fn=process_full_animation,
152
+ inputs=[sketch_1, sketch_2, prompt, ctrl_scale, consistency_strength],
153
  outputs=[out_img_1, out_img_2, out_video]
154
  )
155