ICGenAIShare04 commited on
Commit
3175b6a
Β·
1 Parent(s): 52d5ae4

update to use tooncrafter

Browse files
Files changed (2) hide show
  1. app.py +110 -68
  2. requirements.txt +6 -1
app.py CHANGED
@@ -1,93 +1,135 @@
1
  import gradio as gr
2
- import replicate
 
 
 
3
  import os
4
 
5
- def process_animation(sketch_1_path, sketch_2_path, prompt):
6
- # 1. Check for API Token
7
- if not os.environ.get("REPLICATE_API_TOKEN"):
8
- raise gr.Error("REPLICATE_API_TOKEN is missing! Add it to your Space Secrets.")
9
-
10
- try:
11
- # ==========================================
12
- # STEP 1: Stylize the First Sketch
13
- # ==========================================
14
- print("🎨 Step 1: Stylizing Start Sketch...")
15
- img1_output = replicate.run(
16
- "jagilley/controlnet-scribble", # Replicate's standard Sketch-to-Image model
17
- input={
18
- "image": open(sketch_1_path, "rb"),
19
- "prompt": prompt,
20
- "a_prompt": "best quality, highly detailed cartoon, colorful, professional animation",
21
- "n_prompt": "photorealistic, ugly, bad anatomy, grayscale, messy lines"
22
- }
23
  )
24
- # ControlNet returns a list: [control_map, final_image]. We grab the final image.
25
- url_1 = img1_output[-1]
26
-
27
- # ==========================================
28
- # STEP 2: Stylize the Second Sketch
29
- # ==========================================
30
- print("🎨 Step 2: Stylizing End Sketch...")
31
- img2_output = replicate.run(
32
- "jagilley/controlnet-scribble",
33
- input={
34
- "image": open(sketch_2_path, "rb"),
35
- "prompt": prompt,
36
- "a_prompt": "best quality, highly detailed cartoon, colorful, professional animation",
37
- "n_prompt": "photorealistic, ugly, bad anatomy, grayscale, messy lines"
38
- }
39
  )
40
- url_2 = img2_output[-1]
41
-
42
- # ==========================================
43
- # STEP 3: Generate Video Interpolation
44
- # ==========================================
45
- print("🎬 Step 3: Generating Video with ToonCrafter...")
46
- video_output = replicate.run(
47
- "fofr/tooncrafter",
48
- input={
49
- # We pass the newly generated Image URLs directly to ToonCrafter!
50
- "image_1": url_1,
51
- "image_2": url_2,
52
- "prompt": prompt,
53
- "loop": False
54
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  )
56
- print("βœ… Generation Complete!")
57
-
58
- # Return all three outputs to the UI
59
- return url_1, url_2, video_output[0]
60
-
61
  except Exception as e:
62
- raise gr.Error(f"API Error: {str(e)}")
 
 
 
 
 
 
 
 
 
 
63
 
64
  # ==========================================
65
- # GRADIO INTERFACE
66
  # ==========================================
67
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
68
- gr.Markdown("# 🎨 Sketch-to-Motion Studio")
69
- gr.Markdown("1. Upload two rough sketches. 2. We turn them into cartoons. 3. We animate the transition!")
70
 
71
  with gr.Row():
72
  with gr.Column():
73
- sketch_1 = gr.Image(type="filepath", label="Start Sketch (Black & White lines)")
74
- sketch_2 = gr.Image(type="filepath", label="End Sketch (Black & White lines)")
75
  prompt = gr.Textbox(
76
- label="Cartoon Description",
77
- placeholder="e.g., A cute golden retriever dog running in a grassy field"
78
  )
 
79
  generate_btn = gr.Button("Create Animation", variant="primary")
80
 
81
  with gr.Column():
82
  with gr.Row():
83
- out_img_1 = gr.Image(label="AI Stylized Start")
84
- out_img_2 = gr.Image(label="AI Stylized End")
85
- out_video = gr.Video(label="Final Animated Video")
86
 
87
- # Link the UI to the function
88
  generate_btn.click(
89
- fn=process_animation,
90
- inputs=[sketch_1, sketch_2, prompt],
91
  outputs=[out_img_1, out_img_2, out_video]
92
  )
93
 
 
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
  import os
7
 
8
+ # ==========================================
9
+ # 1. LAZY LOAD LOCAL CARTOON MODELS
10
+ # ==========================================
11
+ image_pipe = None
12
+
13
+ def load_cartoon_models():
14
+ global image_pipe
15
+ if image_pipe is None:
16
+ print("🟒 Loading Animagine XL 3.1 & Scribble ControlNet...")
17
+ dtype = torch.float16
18
+ controlnet = ControlNetModel.from_pretrained(
19
+ "xinsir/controlnet-scribble-sdxl-1.0",
20
+ torch_dtype=dtype
 
 
 
 
 
21
  )
22
+ # Animagine XL 3.1 is the premier model for 2D animation/cartoon styles
23
+ image_pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
24
+ "cagliostrolab/animagine-xl-3.1",
25
+ controlnet=controlnet,
26
+ torch_dtype=dtype
 
 
 
 
 
 
 
 
 
 
27
  )
28
+ return True
29
+
30
+ # ==========================================
31
+ # 2. LOCAL ZEROGPU GENERATION (Sketch -> Cartoon)
32
+ # ==========================================
33
+ @spaces.GPU(duration=180)
34
+ def generate_cartoons(sketch_1, sketch_2, user_prompt, ctrl_scale):
35
+ load_cartoon_models()
36
+ image_pipe.to("cuda")
37
+
38
+ # Animagine responds best to these specific quality tags
39
+ master_prompt = f"{user_prompt}, masterpiece, best quality, highly detailed, professional 2d animation, flat colors, anime style"
40
+ neg_prompt = "nsfw, photorealistic, 3d render, ugly, messy lines, bad anatomy, bad hands, missing fingers, lowres, worst quality"
41
+
42
+ print("🎨 Stylizing Start Sketch...")
43
+ img_1 = image_pipe(
44
+ prompt=master_prompt,
45
+ negative_prompt=neg_prompt,
46
+ image=sketch_1,
47
+ num_inference_steps=25,
48
+ guidance_scale=7.0,
49
+ controlnet_conditioning_scale=ctrl_scale
50
+ ).images[0]
51
+
52
+ print("🎨 Stylizing End Sketch...")
53
+ img_2 = image_pipe(
54
+ prompt=master_prompt,
55
+ negative_prompt=neg_prompt,
56
+ image=sketch_2,
57
+ num_inference_steps=25,
58
+ guidance_scale=7.0,
59
+ controlnet_conditioning_scale=ctrl_scale
60
+ ).images[0]
61
+
62
+ image_pipe.to("cpu")
63
+
64
+ # Save temporarily to pass to the ToonCrafter API
65
+ img_1_path, img_2_path = "frame1.png", "frame2.png"
66
+ img_1.save(img_1_path)
67
+ img_2.save(img_2_path)
68
+
69
+ return img_1_path, img_2_path
70
+
71
+ # ==========================================
72
+ # 3. REMOTE API CALL (Cartoon -> Video)
73
+ # ==========================================
74
+ def run_tooncrafter(img_1_path, img_2_path, prompt):
75
+ print("🎬 Sending frames to official ToonCrafter Space...")
76
+ try:
77
+ # Connect silently to the free ToonCrafter HF Space
78
+ client = Client("Doubiiu/tooncrafter")
79
+ result = client.predict(
80
+ image0=handle_file(img_1_path),
81
+ image1=handle_file(img_2_path),
82
+ prompt=prompt,
83
+ seed=123,
84
+ eta=1.0,
85
+ cfg_scale=7.5,
86
+ steps=15,
87
+ frame_num=16,
88
+ api_name="/predict"
89
  )
90
+ print("βœ… Animation Complete!")
91
+ # The result returns a tuple, the video path is the second item [1]
92
+ return result[1]
 
 
93
  except Exception as e:
94
+ raise gr.Error(f"ToonCrafter API Error: {str(e)}")
95
+
96
+ # ==========================================
97
+ # 4. MASTER PIPELINE CONTROLLER
98
+ # ==========================================
99
+ def process_full_animation(sketch_1, sketch_2, prompt, ctrl_scale):
100
+ # Step 1: Run local ZeroGPU
101
+ img_1_path, img_2_path = generate_cartoons(sketch_1, sketch_2, prompt, ctrl_scale)
102
+ # Step 2: Pass to ToonCrafter
103
+ video_path = run_tooncrafter(img_1_path, img_2_path, prompt)
104
+ return img_1_path, img_2_path, video_path
105
 
106
  # ==========================================
107
+ # 5. GRADIO INTERFACE
108
  # ==========================================
109
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
110
+ gr.Markdown("# ✏️ Sketch-to-ToonCrafter Animation Studio")
111
+ 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!")
112
 
113
  with gr.Row():
114
  with gr.Column():
115
+ sketch_1 = gr.Image(type="pil", label="Start Sketch (Black & White lines)", image_mode="RGB")
116
+ sketch_2 = gr.Image(type="pil", label="End Sketch (Black & White lines)", image_mode="RGB")
117
  prompt = gr.Textbox(
118
+ label="Character & Motion Description",
119
+ placeholder="e.g., A boy in a red shirt and blue jeans jumping"
120
  )
121
+ ctrl_scale = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.05, label="Sketch Adherence Strength")
122
  generate_btn = gr.Button("Create Animation", variant="primary")
123
 
124
  with gr.Column():
125
  with gr.Row():
126
+ out_img_1 = gr.Image(label="Animagine Start Frame")
127
+ out_img_2 = gr.Image(label="Animagine End Frame")
128
+ out_video = gr.Video(label="ToonCrafter Animated Video")
129
 
 
130
  generate_btn.click(
131
+ fn=process_full_animation,
132
+ inputs=[sketch_1, sketch_2, prompt, ctrl_scale],
133
  outputs=[out_img_1, out_img_2, out_video]
134
  )
135
 
requirements.txt CHANGED
@@ -1,2 +1,7 @@
1
  gradio
2
- replicate
 
 
 
 
 
 
1
  gradio
2
+ spaces
3
+ torch
4
+ diffusers>=0.33.0
5
+ transformers
6
+ accelerate
7
+ gradio_client