Update app.py
Browse files
app.py
CHANGED
|
@@ -2,7 +2,9 @@ import gradio as gr
|
|
| 2 |
import json
|
| 3 |
import requests
|
| 4 |
import os
|
| 5 |
-
|
|
|
|
|
|
|
| 6 |
|
| 7 |
# Fireworks AI configuration
|
| 8 |
FIREWORKS_API_KEY = os.getenv("FIREWORKS_API_KEY", "YOUR_API_KEY_HERE")
|
|
@@ -16,102 +18,254 @@ BODY_PARTS = {
|
|
| 16 |
"LEye": 15, "REar": 16, "LEar": 17
|
| 17 |
}
|
| 18 |
|
| 19 |
-
#
|
| 20 |
POSE_CONNECTIONS = [
|
| 21 |
-
("Neck", "
|
| 22 |
-
("
|
| 23 |
-
("Neck", "
|
| 24 |
-
("
|
| 25 |
-
("Neck", "RHip"), ("RHip", "RKnee"), ("RKnee", "RAnkle"),
|
| 26 |
-
("Neck", "LHip"), ("LHip", "LKnee"), ("LKnee", "LAnkle"),
|
| 27 |
-
("RHip", "LHip")
|
| 28 |
]
|
| 29 |
|
| 30 |
-
#
|
| 31 |
-
|
| 32 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
"Nose": [256, 80], "Neck": [256, 120],
|
| 34 |
-
"RShoulder": [220, 140], "RElbow": [
|
| 35 |
-
"LShoulder": [292, 140], "LElbow": [
|
| 36 |
"RHip": [240, 280], "RKnee": [235, 380], "RAnkle": [230, 480],
|
| 37 |
-
"LHip": [272, 280], "LKnee": [
|
| 38 |
"REye": [246, 70], "LEye": [266, 70], "REar": [236, 75], "LEar": [276, 75]
|
| 39 |
},
|
| 40 |
-
"
|
| 41 |
-
"Nose": [256,
|
| 42 |
-
"RShoulder": [
|
| 43 |
-
"LShoulder": [
|
| 44 |
-
"RHip": [240,
|
| 45 |
-
"LHip": [272,
|
| 46 |
-
"REye": [246,
|
| 47 |
},
|
| 48 |
-
"
|
| 49 |
-
"Nose": [256,
|
| 50 |
-
"RShoulder": [220,
|
| 51 |
-
"LShoulder": [292,
|
| 52 |
-
"RHip": [240,
|
| 53 |
-
"LHip": [272,
|
| 54 |
-
"REye": [246,
|
| 55 |
},
|
| 56 |
-
"Yoga": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
"Nose": [256, 100], "Neck": [256, 140],
|
| 58 |
-
"RShoulder": [
|
| 59 |
-
"LShoulder": [
|
| 60 |
-
"RHip": [
|
| 61 |
-
"LHip": [
|
| 62 |
"REye": [246, 90], "LEye": [266, 90], "REar": [236, 95], "LEar": [276, 95]
|
| 63 |
},
|
| 64 |
-
"
|
| 65 |
-
"Nose": [
|
| 66 |
-
"RShoulder": [
|
| 67 |
-
"LShoulder": [
|
| 68 |
-
"RHip": [
|
| 69 |
-
"LHip": [
|
| 70 |
-
"REye": [
|
| 71 |
},
|
| 72 |
-
"
|
| 73 |
"Nose": [256, 80], "Neck": [256, 120],
|
| 74 |
"RShoulder": [220, 140], "RElbow": [200, 100], "RWrist": [180, 60],
|
| 75 |
-
"LShoulder": [292, 140], "LElbow": [312,
|
| 76 |
"RHip": [240, 280], "RKnee": [235, 380], "RAnkle": [230, 480],
|
| 77 |
"LHip": [272, 280], "LKnee": [277, 380], "LAnkle": [282, 480],
|
| 78 |
"REye": [246, 70], "LEye": [266, 70], "REar": [236, 75], "LEar": [276, 75]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
}
|
| 80 |
}
|
| 81 |
|
| 82 |
-
def
|
| 83 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
img = Image.new('RGB', (width, height), color='white')
|
| 85 |
draw = ImageDraw.Draw(img)
|
| 86 |
|
| 87 |
-
#
|
| 88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
if start in keypoints and end in keypoints:
|
| 90 |
start_point = keypoints[start]
|
| 91 |
end_point = keypoints[end]
|
| 92 |
if start_point and end_point:
|
| 93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
-
# Draw keypoints
|
| 96 |
for part, point in keypoints.items():
|
| 97 |
if point:
|
| 98 |
x, y = point
|
| 99 |
-
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
return img
|
| 103 |
|
| 104 |
def generate_pose_from_llm(prompt):
|
| 105 |
-
"""Generate pose using LLM"""
|
| 106 |
-
|
| 107 |
-
|
|
|
|
| 108 |
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
Return ONLY a JSON object with keypoint names and [x, y] coordinates.
|
| 114 |
-
|
| 115 |
|
| 116 |
headers = {
|
| 117 |
"Accept": "application/json",
|
|
@@ -122,10 +276,10 @@ def generate_pose_from_llm(prompt):
|
|
| 122 |
payload = {
|
| 123 |
"model": "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507",
|
| 124 |
"max_tokens": 1024,
|
| 125 |
-
"temperature": 0.
|
| 126 |
"messages": [
|
| 127 |
-
{"role": "system", "content":
|
| 128 |
-
{"role": "user", "content": f"
|
| 129 |
]
|
| 130 |
}
|
| 131 |
|
|
@@ -143,60 +297,129 @@ def generate_pose_from_llm(prompt):
|
|
| 143 |
except Exception as e:
|
| 144 |
print(f"LLM Error: {e}")
|
| 145 |
|
| 146 |
-
return
|
| 147 |
|
| 148 |
-
def
|
| 149 |
-
"""Select template based on prompt"""
|
| 150 |
if not prompt:
|
| 151 |
-
return
|
| 152 |
|
| 153 |
prompt_lower = prompt.lower()
|
| 154 |
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
else:
|
| 166 |
-
|
|
|
|
|
|
|
| 167 |
|
| 168 |
-
def
|
| 169 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
if not current_keypoints or not instruction:
|
| 171 |
return current_keypoints
|
| 172 |
|
| 173 |
keypoints = current_keypoints.copy()
|
| 174 |
instruction_lower = instruction.lower()
|
| 175 |
|
| 176 |
-
#
|
| 177 |
-
if "
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
-
elif "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
if "arm" in instruction_lower:
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
|
| 196 |
return keypoints
|
| 197 |
|
| 198 |
def keypoints_to_openpose_format(keypoints):
|
| 199 |
-
"""Convert to OpenPose JSON format"""
|
| 200 |
if not keypoints:
|
| 201 |
return "{}"
|
| 202 |
|
|
@@ -220,107 +443,133 @@ def keypoints_to_openpose_format(keypoints):
|
|
| 220 |
return json.dumps({"candidate": candidate, "subset": subset}, indent=2)
|
| 221 |
|
| 222 |
# Main generation function
|
| 223 |
-
def generate_pose(prompt, use_llm, template):
|
| 224 |
-
"""
|
| 225 |
if template and template != "None":
|
| 226 |
-
keypoints =
|
| 227 |
elif use_llm and FIREWORKS_API_KEY != "YOUR_API_KEY_HERE" and prompt:
|
| 228 |
keypoints = generate_pose_from_llm(prompt)
|
| 229 |
elif prompt:
|
| 230 |
-
keypoints =
|
| 231 |
else:
|
| 232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
-
pose_img = draw_pose(keypoints)
|
| 235 |
json_str = keypoints_to_openpose_format(keypoints)
|
| 236 |
|
| 237 |
return pose_img, json_str, keypoints
|
| 238 |
|
| 239 |
def refine_existing_pose(instruction, keypoints_json):
|
| 240 |
-
"""Refine pose with
|
| 241 |
if not keypoints_json:
|
| 242 |
return None, "{}", {}
|
| 243 |
|
| 244 |
-
refined_keypoints =
|
| 245 |
-
pose_img = draw_pose(refined_keypoints)
|
| 246 |
json_str = keypoints_to_openpose_format(refined_keypoints)
|
| 247 |
|
| 248 |
return pose_img, json_str, refined_keypoints
|
| 249 |
|
| 250 |
def check_api_status():
|
| 251 |
-
"""Check
|
| 252 |
if FIREWORKS_API_KEY != "YOUR_API_KEY_HERE":
|
| 253 |
return "✅ API key configured - Advanced AI ready"
|
| 254 |
-
return "⚠️ API key not set -
|
| 255 |
|
| 256 |
-
# Create Gradio interface
|
| 257 |
-
app = gr.Blocks(title="AI Pose Generator")
|
| 258 |
|
| 259 |
with app:
|
| 260 |
keypoints_state = gr.State({})
|
| 261 |
|
| 262 |
gr.Markdown("""
|
| 263 |
-
#
|
| 264 |
-
### Generate
|
| 265 |
""")
|
| 266 |
|
| 267 |
with gr.Row():
|
| 268 |
with gr.Column(scale=1):
|
| 269 |
-
# Input controls
|
| 270 |
api_status = gr.Markdown(check_api_status())
|
| 271 |
|
| 272 |
use_llm = gr.Checkbox(
|
| 273 |
-
label="Use Advanced AI (Fireworks
|
| 274 |
value=False
|
| 275 |
)
|
| 276 |
|
| 277 |
prompt = gr.Textbox(
|
| 278 |
-
label="Describe
|
| 279 |
-
placeholder="e.g.,
|
| 280 |
lines=2
|
| 281 |
)
|
| 282 |
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
|
| 289 |
-
generate_btn = gr.Button("
|
| 290 |
|
| 291 |
-
|
| 292 |
-
gr.Markdown("### Refine Pose")
|
| 293 |
refinement = gr.Textbox(
|
| 294 |
-
label="Refinement
|
| 295 |
-
placeholder="e.g.,
|
| 296 |
lines=1
|
| 297 |
)
|
| 298 |
|
| 299 |
-
refine_btn = gr.Button("✨
|
| 300 |
|
| 301 |
-
# Examples
|
| 302 |
gr.Examples(
|
| 303 |
examples=[
|
| 304 |
-
"
|
| 305 |
-
"
|
| 306 |
-
"
|
| 307 |
-
"
|
| 308 |
-
"
|
|
|
|
|
|
|
|
|
|
| 309 |
],
|
| 310 |
inputs=prompt
|
| 311 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
|
| 313 |
with gr.Column(scale=1):
|
| 314 |
-
|
| 315 |
-
|
|
|
|
|
|
|
|
|
|
| 316 |
|
| 317 |
-
with gr.Accordion("OpenPose JSON", open=False):
|
| 318 |
-
json_output = gr.Code(
|
|
|
|
|
|
|
|
|
|
| 319 |
|
| 320 |
# Event handlers
|
| 321 |
generate_btn.click(
|
| 322 |
fn=generate_pose,
|
| 323 |
-
inputs=[prompt, use_llm, template],
|
| 324 |
outputs=[pose_image, json_output, keypoints_state]
|
| 325 |
)
|
| 326 |
|
|
@@ -330,6 +579,6 @@ with app:
|
|
| 330 |
outputs=[pose_image, json_output, keypoints_state]
|
| 331 |
)
|
| 332 |
|
| 333 |
-
#
|
| 334 |
app.queue()
|
| 335 |
app.launch()
|
|
|
|
| 2 |
import json
|
| 3 |
import requests
|
| 4 |
import os
|
| 5 |
+
import math
|
| 6 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 7 |
+
import numpy as np
|
| 8 |
|
| 9 |
# Fireworks AI configuration
|
| 10 |
FIREWORKS_API_KEY = os.getenv("FIREWORKS_API_KEY", "YOUR_API_KEY_HERE")
|
|
|
|
| 18 |
"LEye": 15, "REar": 16, "LEar": 17
|
| 19 |
}
|
| 20 |
|
| 21 |
+
# Enhanced skeleton connections with thickness
|
| 22 |
POSE_CONNECTIONS = [
|
| 23 |
+
("Neck", "Nose", 2), ("Nose", "REye", 1), ("REye", "REar", 1),
|
| 24 |
+
("Nose", "LEye", 1), ("LEye", "LEar", 1),
|
| 25 |
+
("Neck", "RShoulder", 3), ("RShoulder", "RElbow", 3), ("RElbow", "RWrist", 2),
|
| 26 |
+
("Neck", "LShoulder", 3), ("LShoulder", "LElbow", 3), ("LElbow", "LWrist", 2),
|
| 27 |
+
("Neck", "RHip", 4), ("RHip", "RKnee", 4), ("RKnee", "RAnkle", 3),
|
| 28 |
+
("Neck", "LHip", 4), ("LHip", "LKnee", 4), ("LKnee", "LAnkle", 3),
|
| 29 |
+
("RHip", "LHip", 4)
|
| 30 |
]
|
| 31 |
|
| 32 |
+
# Dynamic and precise pose templates
|
| 33 |
+
DYNAMIC_POSES = {
|
| 34 |
+
"🏃 Sprint": {
|
| 35 |
+
"Nose": [256, 60], "Neck": [256, 100],
|
| 36 |
+
"RShoulder": [230, 120], "RElbow": [260, 140], "RWrist": [290, 120],
|
| 37 |
+
"LShoulder": [282, 120], "LElbow": [252, 160], "LWrist": [222, 200],
|
| 38 |
+
"RHip": [245, 260], "RKnee": [220, 360], "RAnkle": [195, 460],
|
| 39 |
+
"LHip": [267, 260], "LKnee": [300, 340], "LAnkle": [330, 420],
|
| 40 |
+
"REye": [246, 50], "LEye": [266, 50], "REar": [236, 55], "LEar": [276, 55]
|
| 41 |
+
},
|
| 42 |
+
"🤸 Backflip": {
|
| 43 |
+
"Nose": [256, 250], "Neck": [256, 280],
|
| 44 |
+
"RShoulder": [220, 300], "RElbow": [180, 280], "RWrist": [140, 260],
|
| 45 |
+
"LShoulder": [292, 300], "LElbow": [332, 280], "LWrist": [372, 260],
|
| 46 |
+
"RHip": [240, 180], "RKnee": [220, 120], "RAnkle": [200, 60],
|
| 47 |
+
"LHip": [272, 180], "LKnee": [292, 120], "LAnkle": [312, 60],
|
| 48 |
+
"REye": [246, 260], "LEye": [266, 260], "REar": [236, 255], "LEar": [276, 255]
|
| 49 |
+
},
|
| 50 |
+
"🥋 Martial Arts Kick": {
|
| 51 |
"Nose": [256, 80], "Neck": [256, 120],
|
| 52 |
+
"RShoulder": [220, 140], "RElbow": [180, 120], "RWrist": [140, 100],
|
| 53 |
+
"LShoulder": [292, 140], "LElbow": [332, 160], "LWrist": [372, 180],
|
| 54 |
"RHip": [240, 280], "RKnee": [235, 380], "RAnkle": [230, 480],
|
| 55 |
+
"LHip": [272, 280], "LKnee": [350, 250], "LAnkle": [420, 220],
|
| 56 |
"REye": [246, 70], "LEye": [266, 70], "REar": [236, 75], "LEar": [276, 75]
|
| 57 |
},
|
| 58 |
+
"🩰 Ballet Leap": {
|
| 59 |
+
"Nose": [256, 100], "Neck": [256, 140],
|
| 60 |
+
"RShoulder": [200, 130], "RElbow": [150, 110], "RWrist": [100, 90],
|
| 61 |
+
"LShoulder": [312, 130], "LElbow": [362, 110], "LWrist": [412, 90],
|
| 62 |
+
"RHip": [240, 300], "RKnee": [180, 380], "RAnkle": [120, 460],
|
| 63 |
+
"LHip": [272, 300], "LKnee": [332, 380], "LAnkle": [392, 460],
|
| 64 |
+
"REye": [246, 90], "LEye": [266, 90], "REar": [236, 95], "LEar": [276, 95]
|
| 65 |
},
|
| 66 |
+
"🏀 Basketball Dunk": {
|
| 67 |
+
"Nose": [256, 60], "Neck": [256, 100],
|
| 68 |
+
"RShoulder": [220, 120], "RElbow": [200, 80], "RWrist": [180, 40],
|
| 69 |
+
"LShoulder": [292, 120], "LElbow": [312, 80], "LWrist": [332, 40],
|
| 70 |
+
"RHip": [240, 260], "RKnee": [230, 360], "RAnkle": [225, 460],
|
| 71 |
+
"LHip": [272, 260], "LKnee": [282, 340], "LAnkle": [287, 420],
|
| 72 |
+
"REye": [246, 50], "LEye": [266, 50], "REar": [236, 55], "LEar": [276, 55]
|
| 73 |
},
|
| 74 |
+
"🧘 Advanced Yoga": {
|
| 75 |
+
"Nose": [256, 380], "Neck": [256, 420],
|
| 76 |
+
"RShoulder": [220, 440], "RElbow": [200, 400], "RWrist": [180, 360],
|
| 77 |
+
"LShoulder": [292, 440], "LElbow": [312, 400], "LWrist": [332, 360],
|
| 78 |
+
"RHip": [240, 280], "RKnee": [220, 180], "RAnkle": [200, 80],
|
| 79 |
+
"LHip": [272, 280], "LKnee": [292, 180], "LAnkle": [312, 80],
|
| 80 |
+
"REye": [246, 390], "LEye": [266, 390], "REar": [236, 385], "LEar": [276, 385]
|
| 81 |
+
},
|
| 82 |
+
"🕺 Breakdance Freeze": {
|
| 83 |
+
"Nose": [150, 400], "Neck": [180, 420],
|
| 84 |
+
"RShoulder": [200, 400], "RElbow": [220, 350], "RWrist": [240, 300],
|
| 85 |
+
"LShoulder": [160, 440], "LElbow": [140, 480], "LWrist": [120, 500],
|
| 86 |
+
"RHip": [300, 350], "RKnee": [350, 300], "RAnkle": [400, 250],
|
| 87 |
+
"LHip": [280, 380], "LKnee": [330, 420], "LAnkle": [380, 460],
|
| 88 |
+
"REye": [140, 390], "LEye": [160, 390], "REar": [130, 395], "LEar": [170, 395]
|
| 89 |
+
},
|
| 90 |
+
"🏋️ Weightlifting": {
|
| 91 |
"Nose": [256, 100], "Neck": [256, 140],
|
| 92 |
+
"RShoulder": [210, 160], "RElbow": [180, 120], "RWrist": [150, 80],
|
| 93 |
+
"LShoulder": [302, 160], "LElbow": [332, 120], "LWrist": [362, 80],
|
| 94 |
+
"RHip": [235, 300], "RKnee": [220, 400], "RAnkle": [210, 480],
|
| 95 |
+
"LHip": [277, 300], "LKnee": [292, 400], "LAnkle": [302, 480],
|
| 96 |
"REye": [246, 90], "LEye": [266, 90], "REar": [236, 95], "LEar": [276, 95]
|
| 97 |
},
|
| 98 |
+
"🏊 Swimming Dive": {
|
| 99 |
+
"Nose": [380, 200], "Neck": [360, 220],
|
| 100 |
+
"RShoulder": [340, 240], "RElbow": [380, 230], "RWrist": [420, 220],
|
| 101 |
+
"LShoulder": [340, 200], "LElbow": [380, 190], "LWrist": [420, 180],
|
| 102 |
+
"RHip": [280, 260], "RKnee": [220, 280], "RAnkle": [160, 300],
|
| 103 |
+
"LHip": [280, 240], "LKnee": [220, 250], "LAnkle": [160, 260],
|
| 104 |
+
"REye": [390, 195], "LEye": [390, 205], "REar": [385, 190], "LEar": [385, 210]
|
| 105 |
},
|
| 106 |
+
"🎾 Tennis Serve": {
|
| 107 |
"Nose": [256, 80], "Neck": [256, 120],
|
| 108 |
"RShoulder": [220, 140], "RElbow": [200, 100], "RWrist": [180, 60],
|
| 109 |
+
"LShoulder": [292, 140], "LElbow": [312, 180], "LWrist": [332, 220],
|
| 110 |
"RHip": [240, 280], "RKnee": [235, 380], "RAnkle": [230, 480],
|
| 111 |
"LHip": [272, 280], "LKnee": [277, 380], "LAnkle": [282, 480],
|
| 112 |
"REye": [246, 70], "LEye": [266, 70], "REar": [236, 75], "LEar": [276, 75]
|
| 113 |
+
},
|
| 114 |
+
"🪂 Skydiving": {
|
| 115 |
+
"Nose": [256, 200], "Neck": [256, 240],
|
| 116 |
+
"RShoulder": [200, 260], "RElbow": [150, 240], "RWrist": [100, 220],
|
| 117 |
+
"LShoulder": [312, 260], "LElbow": [362, 240], "LWrist": [412, 220],
|
| 118 |
+
"RHip": [240, 340], "RKnee": [200, 400], "RAnkle": [160, 460],
|
| 119 |
+
"LHip": [272, 340], "LKnee": [312, 400], "LAnkle": [352, 460],
|
| 120 |
+
"REye": [246, 190], "LEye": [266, 190], "REar": [236, 195], "LEar": [276, 195]
|
| 121 |
+
},
|
| 122 |
+
"🤾 Handball Jump": {
|
| 123 |
+
"Nose": [256, 120], "Neck": [256, 160],
|
| 124 |
+
"RShoulder": [220, 180], "RElbow": [200, 140], "RWrist": [180, 100],
|
| 125 |
+
"LShoulder": [292, 180], "LElbow": [312, 220], "LWrist": [332, 260],
|
| 126 |
+
"RHip": [240, 320], "RKnee": [220, 400], "RAnkle": [200, 480],
|
| 127 |
+
"LHip": [272, 320], "LKnee": [292, 380], "LAnkle": [312, 440],
|
| 128 |
+
"REye": [246, 110], "LEye": [266, 110], "REar": [236, 115], "LEar": [276, 115]
|
| 129 |
}
|
| 130 |
}
|
| 131 |
|
| 132 |
+
def rotate_point(point, center, angle):
|
| 133 |
+
"""Rotate a point around a center by angle (in radians)"""
|
| 134 |
+
x, y = point
|
| 135 |
+
cx, cy = center
|
| 136 |
+
cos_a = math.cos(angle)
|
| 137 |
+
sin_a = math.sin(angle)
|
| 138 |
+
nx = cos_a * (x - cx) - sin_a * (y - cy) + cx
|
| 139 |
+
ny = sin_a * (x - cx) + cos_a * (y - cy) + cy
|
| 140 |
+
return [nx, ny]
|
| 141 |
+
|
| 142 |
+
def scale_pose(keypoints, scale_factor):
|
| 143 |
+
"""Scale pose around center"""
|
| 144 |
+
if not keypoints:
|
| 145 |
+
return keypoints
|
| 146 |
+
|
| 147 |
+
# Find center
|
| 148 |
+
valid_points = [p for p in keypoints.values() if p]
|
| 149 |
+
if not valid_points:
|
| 150 |
+
return keypoints
|
| 151 |
+
|
| 152 |
+
cx = sum(p[0] for p in valid_points) / len(valid_points)
|
| 153 |
+
cy = sum(p[1] for p in valid_points) / len(valid_points)
|
| 154 |
+
|
| 155 |
+
# Scale around center
|
| 156 |
+
scaled = {}
|
| 157 |
+
for part, point in keypoints.items():
|
| 158 |
+
if point:
|
| 159 |
+
x, y = point
|
| 160 |
+
nx = cx + (x - cx) * scale_factor
|
| 161 |
+
ny = cy + (y - cy) * scale_factor
|
| 162 |
+
scaled[part] = [nx, ny]
|
| 163 |
+
else:
|
| 164 |
+
scaled[part] = point
|
| 165 |
+
|
| 166 |
+
return scaled
|
| 167 |
+
|
| 168 |
+
def add_motion_blur(keypoints, direction="horizontal", intensity=0.3):
|
| 169 |
+
"""Add motion effect to pose"""
|
| 170 |
+
blurred = keypoints.copy()
|
| 171 |
+
|
| 172 |
+
for part in ["RWrist", "LWrist", "RAnkle", "LAnkle"]:
|
| 173 |
+
if part in blurred and blurred[part]:
|
| 174 |
+
x, y = blurred[part]
|
| 175 |
+
if direction == "horizontal":
|
| 176 |
+
blurred[part] = [x + intensity * 30, y]
|
| 177 |
+
elif direction == "vertical":
|
| 178 |
+
blurred[part] = [x, y + intensity * 30]
|
| 179 |
+
|
| 180 |
+
return blurred
|
| 181 |
+
|
| 182 |
+
def draw_pose(keypoints, width=512, height=512, style="dynamic"):
|
| 183 |
+
"""Draw pose with enhanced visualization"""
|
| 184 |
img = Image.new('RGB', (width, height), color='white')
|
| 185 |
draw = ImageDraw.Draw(img)
|
| 186 |
|
| 187 |
+
# Dynamic gradient background for action poses
|
| 188 |
+
if style == "dynamic":
|
| 189 |
+
for i in range(height):
|
| 190 |
+
color_val = 255 - int((i / height) * 50)
|
| 191 |
+
draw.rectangle([(0, i), (width, i+1)], fill=(color_val, color_val, 255))
|
| 192 |
+
|
| 193 |
+
# Draw shadow/trail effect for dynamic poses
|
| 194 |
+
if style == "dynamic":
|
| 195 |
+
for start, end, _ in POSE_CONNECTIONS:
|
| 196 |
+
if start in keypoints and end in keypoints:
|
| 197 |
+
start_point = keypoints[start]
|
| 198 |
+
end_point = keypoints[end]
|
| 199 |
+
if start_point and end_point:
|
| 200 |
+
# Shadow effect
|
| 201 |
+
shadow_start = [start_point[0] + 5, start_point[1] + 5]
|
| 202 |
+
shadow_end = [end_point[0] + 5, end_point[1] + 5]
|
| 203 |
+
draw.line([tuple(shadow_start), tuple(shadow_end)],
|
| 204 |
+
fill=(200, 200, 200), width=2)
|
| 205 |
+
|
| 206 |
+
# Draw skeleton connections with variable thickness
|
| 207 |
+
for connection in POSE_CONNECTIONS:
|
| 208 |
+
start, end = connection[0], connection[1]
|
| 209 |
+
thickness = connection[2] if len(connection) > 2 else 3
|
| 210 |
+
|
| 211 |
if start in keypoints and end in keypoints:
|
| 212 |
start_point = keypoints[start]
|
| 213 |
end_point = keypoints[end]
|
| 214 |
if start_point and end_point:
|
| 215 |
+
# Main line
|
| 216 |
+
draw.line([tuple(start_point), tuple(end_point)],
|
| 217 |
+
fill='darkblue', width=thickness)
|
| 218 |
+
# Highlight
|
| 219 |
+
draw.line([tuple(start_point), tuple(end_point)],
|
| 220 |
+
fill='blue', width=thickness-1)
|
| 221 |
|
| 222 |
+
# Draw keypoints with gradient effect
|
| 223 |
for part, point in keypoints.items():
|
| 224 |
if point:
|
| 225 |
x, y = point
|
| 226 |
+
# Determine size based on body part
|
| 227 |
+
if part in ["Neck", "RHip", "LHip"]:
|
| 228 |
+
radius = 7
|
| 229 |
+
elif part in ["RWrist", "LWrist", "RAnkle", "LAnkle"]:
|
| 230 |
+
radius = 4
|
| 231 |
+
else:
|
| 232 |
+
radius = 5
|
| 233 |
+
|
| 234 |
+
# Outer circle
|
| 235 |
+
draw.ellipse([x-radius-1, y-radius-1, x+radius+1, y+radius+1],
|
| 236 |
+
fill='darkred', outline='black')
|
| 237 |
+
# Inner circle
|
| 238 |
+
draw.ellipse([x-radius, y-radius, x+radius, y+radius],
|
| 239 |
+
fill='red', outline='darkred')
|
| 240 |
+
# Highlight
|
| 241 |
+
draw.ellipse([x-radius+2, y-radius+2, x+radius-2, y+radius-2],
|
| 242 |
+
fill='pink', outline=None)
|
| 243 |
|
| 244 |
return img
|
| 245 |
|
| 246 |
def generate_pose_from_llm(prompt):
|
| 247 |
+
"""Generate dynamic pose using LLM with enhanced prompt"""
|
| 248 |
+
enhanced_prompt = f"""You are an expert in generating DYNAMIC and PRECISE human pose keypoints.
|
| 249 |
+
|
| 250 |
+
Task: Generate highly dynamic, action-oriented pose for: {prompt}
|
| 251 |
|
| 252 |
+
Requirements:
|
| 253 |
+
1. Canvas: 512x512 pixels
|
| 254 |
+
2. Create EXTREME and DYNAMIC poses with:
|
| 255 |
+
- Large range of motion
|
| 256 |
+
- Athletic and acrobatic positions
|
| 257 |
+
- Dramatic angles and perspectives
|
| 258 |
+
- Action-oriented body positions
|
| 259 |
+
3. Use all 18 keypoints: Nose, Neck, RShoulder, RElbow, RWrist, LShoulder, LElbow, LWrist,
|
| 260 |
+
RHip, RKnee, RAnkle, LHip, LKnee, LAnkle, REye, LEye, REar, LEar
|
| 261 |
+
4. Make poses that show:
|
| 262 |
+
- Movement and energy
|
| 263 |
+
- Athletic performance
|
| 264 |
+
- Extreme flexibility
|
| 265 |
+
- Dramatic action
|
| 266 |
|
| 267 |
Return ONLY a JSON object with keypoint names and [x, y] coordinates.
|
| 268 |
+
Make it VERY dynamic and exciting!"""
|
| 269 |
|
| 270 |
headers = {
|
| 271 |
"Accept": "application/json",
|
|
|
|
| 276 |
payload = {
|
| 277 |
"model": "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507",
|
| 278 |
"max_tokens": 1024,
|
| 279 |
+
"temperature": 0.7, # Higher temperature for more creative poses
|
| 280 |
"messages": [
|
| 281 |
+
{"role": "system", "content": enhanced_prompt},
|
| 282 |
+
{"role": "user", "content": f"Create an extremely dynamic pose for: {prompt}"}
|
| 283 |
]
|
| 284 |
}
|
| 285 |
|
|
|
|
| 297 |
except Exception as e:
|
| 298 |
print(f"LLM Error: {e}")
|
| 299 |
|
| 300 |
+
return get_dynamic_template(prompt)
|
| 301 |
|
| 302 |
+
def get_dynamic_template(prompt):
|
| 303 |
+
"""Select dynamic template based on prompt"""
|
| 304 |
if not prompt:
|
| 305 |
+
return DYNAMIC_POSES["🏃 Sprint"]
|
| 306 |
|
| 307 |
prompt_lower = prompt.lower()
|
| 308 |
|
| 309 |
+
# Check for specific action keywords
|
| 310 |
+
if any(word in prompt_lower for word in ["run", "sprint", "dash"]):
|
| 311 |
+
return DYNAMIC_POSES["🏃 Sprint"]
|
| 312 |
+
elif any(word in prompt_lower for word in ["flip", "backflip", "acrobat"]):
|
| 313 |
+
return DYNAMIC_POSES["🤸 Backflip"]
|
| 314 |
+
elif any(word in prompt_lower for word in ["kick", "martial", "karate", "taekwondo"]):
|
| 315 |
+
return DYNAMIC_POSES["🥋 Martial Arts Kick"]
|
| 316 |
+
elif any(word in prompt_lower for word in ["ballet", "dance", "leap", "jump"]):
|
| 317 |
+
return DYNAMIC_POSES["🩰 Ballet Leap"]
|
| 318 |
+
elif any(word in prompt_lower for word in ["basketball", "dunk", "shoot"]):
|
| 319 |
+
return DYNAMIC_POSES["🏀 Basketball Dunk"]
|
| 320 |
+
elif any(word in prompt_lower for word in ["yoga", "stretch", "flexible"]):
|
| 321 |
+
return DYNAMIC_POSES["🧘 Advanced Yoga"]
|
| 322 |
+
elif any(word in prompt_lower for word in ["breakdance", "freeze", "bboy"]):
|
| 323 |
+
return DYNAMIC_POSES["🕺 Breakdance Freeze"]
|
| 324 |
+
elif any(word in prompt_lower for word in ["weight", "lift", "gym"]):
|
| 325 |
+
return DYNAMIC_POSES["🏋️ Weightlifting"]
|
| 326 |
+
elif any(word in prompt_lower for word in ["swim", "dive", "water"]):
|
| 327 |
+
return DYNAMIC_POSES["🏊 Swimming Dive"]
|
| 328 |
+
elif any(word in prompt_lower for word in ["tennis", "serve", "racket"]):
|
| 329 |
+
return DYNAMIC_POSES["🎾 Tennis Serve"]
|
| 330 |
+
elif any(word in prompt_lower for word in ["sky", "fall", "fly"]):
|
| 331 |
+
return DYNAMIC_POSES["🪂 Skydiving"]
|
| 332 |
+
elif any(word in prompt_lower for word in ["handball", "throw", "ball"]):
|
| 333 |
+
return DYNAMIC_POSES["🤾 Handball Jump"]
|
| 334 |
else:
|
| 335 |
+
# Return random dynamic pose
|
| 336 |
+
import random
|
| 337 |
+
return random.choice(list(DYNAMIC_POSES.values()))
|
| 338 |
|
| 339 |
+
def apply_physics(keypoints, effect="gravity"):
|
| 340 |
+
"""Apply physics effects to make poses more realistic"""
|
| 341 |
+
modified = keypoints.copy()
|
| 342 |
+
|
| 343 |
+
if effect == "gravity":
|
| 344 |
+
# Apply downward pull to limbs
|
| 345 |
+
for part in ["RWrist", "LWrist"]:
|
| 346 |
+
if part in modified and modified[part]:
|
| 347 |
+
modified[part][1] += 10
|
| 348 |
+
elif effect == "momentum":
|
| 349 |
+
# Add motion direction
|
| 350 |
+
if "RWrist" in modified and modified["RWrist"]:
|
| 351 |
+
modified["RWrist"][0] += 15
|
| 352 |
+
if "LAnkle" in modified and modified["LAnkle"]:
|
| 353 |
+
modified["LAnkle"][0] -= 10
|
| 354 |
+
|
| 355 |
+
return modified
|
| 356 |
+
|
| 357 |
+
def refine_pose_advanced(current_keypoints, instruction):
|
| 358 |
+
"""Advanced pose refinement with multiple options"""
|
| 359 |
if not current_keypoints or not instruction:
|
| 360 |
return current_keypoints
|
| 361 |
|
| 362 |
keypoints = current_keypoints.copy()
|
| 363 |
instruction_lower = instruction.lower()
|
| 364 |
|
| 365 |
+
# Complex refinements
|
| 366 |
+
if "rotate" in instruction_lower:
|
| 367 |
+
angle = math.pi / 6 # 30 degrees
|
| 368 |
+
center = [256, 256]
|
| 369 |
+
for part, point in keypoints.items():
|
| 370 |
+
if point:
|
| 371 |
+
keypoints[part] = rotate_point(point, center, angle)
|
| 372 |
+
|
| 373 |
+
elif "scale" in instruction_lower:
|
| 374 |
+
if "up" in instruction_lower or "large" in instruction_lower:
|
| 375 |
+
keypoints = scale_pose(keypoints, 1.2)
|
| 376 |
+
elif "down" in instruction_lower or "small" in instruction_lower:
|
| 377 |
+
keypoints = scale_pose(keypoints, 0.8)
|
| 378 |
+
|
| 379 |
+
elif "jump" in instruction_lower or "leap" in instruction_lower:
|
| 380 |
+
# Move everything up
|
| 381 |
+
for part, point in keypoints.items():
|
| 382 |
+
if point:
|
| 383 |
+
keypoints[part][1] -= 50
|
| 384 |
+
# Spread legs
|
| 385 |
+
if "RAnkle" in keypoints:
|
| 386 |
+
keypoints["RAnkle"][0] -= 30
|
| 387 |
+
if "LAnkle" in keypoints:
|
| 388 |
+
keypoints["LAnkle"][0] += 30
|
| 389 |
|
| 390 |
+
elif "crouch" in instruction_lower or "squat" in instruction_lower:
|
| 391 |
+
# Lower body parts
|
| 392 |
+
for part in ["RKnee", "LKnee", "RAnkle", "LAnkle"]:
|
| 393 |
+
if part in keypoints and keypoints[part]:
|
| 394 |
+
keypoints[part][1] += 40
|
| 395 |
+
|
| 396 |
+
elif "spread" in instruction_lower:
|
| 397 |
if "arm" in instruction_lower:
|
| 398 |
+
if "RWrist" in keypoints:
|
| 399 |
+
keypoints["RWrist"][0] -= 40
|
| 400 |
+
if "LWrist" in keypoints:
|
| 401 |
+
keypoints["LWrist"][0] += 40
|
| 402 |
+
elif "leg" in instruction_lower:
|
| 403 |
+
if "RAnkle" in keypoints:
|
| 404 |
+
keypoints["RAnkle"][0] -= 40
|
| 405 |
+
if "LAnkle" in keypoints:
|
| 406 |
+
keypoints["LAnkle"][0] += 40
|
| 407 |
+
|
| 408 |
+
elif "twist" in instruction_lower:
|
| 409 |
+
# Create twisting effect
|
| 410 |
+
if "RShoulder" in keypoints:
|
| 411 |
+
keypoints["RShoulder"][0] += 20
|
| 412 |
+
if "LShoulder" in keypoints:
|
| 413 |
+
keypoints["LShoulder"][0] -= 20
|
| 414 |
+
if "RHip" in keypoints:
|
| 415 |
+
keypoints["RHip"][0] -= 15
|
| 416 |
+
if "LHip" in keypoints:
|
| 417 |
+
keypoints["LHip"][0] += 15
|
| 418 |
|
| 419 |
return keypoints
|
| 420 |
|
| 421 |
def keypoints_to_openpose_format(keypoints):
|
| 422 |
+
"""Convert to OpenPose JSON format with confidence scores"""
|
| 423 |
if not keypoints:
|
| 424 |
return "{}"
|
| 425 |
|
|
|
|
| 443 |
return json.dumps({"candidate": candidate, "subset": subset}, indent=2)
|
| 444 |
|
| 445 |
# Main generation function
|
| 446 |
+
def generate_pose(prompt, use_llm, template, physics_effect):
|
| 447 |
+
"""Generate dynamic pose with physics"""
|
| 448 |
if template and template != "None":
|
| 449 |
+
keypoints = DYNAMIC_POSES[template]
|
| 450 |
elif use_llm and FIREWORKS_API_KEY != "YOUR_API_KEY_HERE" and prompt:
|
| 451 |
keypoints = generate_pose_from_llm(prompt)
|
| 452 |
elif prompt:
|
| 453 |
+
keypoints = get_dynamic_template(prompt)
|
| 454 |
else:
|
| 455 |
+
import random
|
| 456 |
+
keypoints = random.choice(list(DYNAMIC_POSES.values()))
|
| 457 |
+
|
| 458 |
+
# Apply physics effect
|
| 459 |
+
if physics_effect != "None":
|
| 460 |
+
keypoints = apply_physics(keypoints, physics_effect.lower())
|
| 461 |
|
| 462 |
+
pose_img = draw_pose(keypoints, style="dynamic")
|
| 463 |
json_str = keypoints_to_openpose_format(keypoints)
|
| 464 |
|
| 465 |
return pose_img, json_str, keypoints
|
| 466 |
|
| 467 |
def refine_existing_pose(instruction, keypoints_json):
|
| 468 |
+
"""Refine pose with advanced options"""
|
| 469 |
if not keypoints_json:
|
| 470 |
return None, "{}", {}
|
| 471 |
|
| 472 |
+
refined_keypoints = refine_pose_advanced(keypoints_json, instruction)
|
| 473 |
+
pose_img = draw_pose(refined_keypoints, style="dynamic")
|
| 474 |
json_str = keypoints_to_openpose_format(refined_keypoints)
|
| 475 |
|
| 476 |
return pose_img, json_str, refined_keypoints
|
| 477 |
|
| 478 |
def check_api_status():
|
| 479 |
+
"""Check API status"""
|
| 480 |
if FIREWORKS_API_KEY != "YOUR_API_KEY_HERE":
|
| 481 |
return "✅ API key configured - Advanced AI ready"
|
| 482 |
+
return "⚠️ API key not set - Using dynamic templates"
|
| 483 |
|
| 484 |
+
# Create Gradio interface
|
| 485 |
+
app = gr.Blocks(title="Dynamic AI Pose Generator", theme=gr.themes.Soft())
|
| 486 |
|
| 487 |
with app:
|
| 488 |
keypoints_state = gr.State({})
|
| 489 |
|
| 490 |
gr.Markdown("""
|
| 491 |
+
# 🎯 Dynamic AI Pose Generator
|
| 492 |
+
### Generate extremely dynamic and precise action poses!
|
| 493 |
""")
|
| 494 |
|
| 495 |
with gr.Row():
|
| 496 |
with gr.Column(scale=1):
|
|
|
|
| 497 |
api_status = gr.Markdown(check_api_status())
|
| 498 |
|
| 499 |
use_llm = gr.Checkbox(
|
| 500 |
+
label="🚀 Use Advanced AI (Fireworks)",
|
| 501 |
value=False
|
| 502 |
)
|
| 503 |
|
| 504 |
prompt = gr.Textbox(
|
| 505 |
+
label="Describe your action pose",
|
| 506 |
+
placeholder="e.g., Ninja doing a flying kick, Athlete jumping over hurdles",
|
| 507 |
lines=2
|
| 508 |
)
|
| 509 |
|
| 510 |
+
with gr.Row():
|
| 511 |
+
template = gr.Dropdown(
|
| 512 |
+
choices=["None"] + list(DYNAMIC_POSES.keys()),
|
| 513 |
+
label="🎬 Dynamic Templates",
|
| 514 |
+
value="None"
|
| 515 |
+
)
|
| 516 |
+
|
| 517 |
+
physics_effect = gr.Dropdown(
|
| 518 |
+
choices=["None", "Gravity", "Momentum"],
|
| 519 |
+
label="⚡ Physics Effect",
|
| 520 |
+
value="None"
|
| 521 |
+
)
|
| 522 |
|
| 523 |
+
generate_btn = gr.Button("💥 Generate Dynamic Pose", variant="primary", size="lg")
|
| 524 |
|
| 525 |
+
gr.Markdown("### 🔧 Advanced Refinement")
|
|
|
|
| 526 |
refinement = gr.Textbox(
|
| 527 |
+
label="Refinement command",
|
| 528 |
+
placeholder="e.g., rotate, scale up, jump higher, spread arms, twist body",
|
| 529 |
lines=1
|
| 530 |
)
|
| 531 |
|
| 532 |
+
refine_btn = gr.Button("✨ Apply Refinement", variant="secondary")
|
| 533 |
|
|
|
|
| 534 |
gr.Examples(
|
| 535 |
examples=[
|
| 536 |
+
"Ninja performing a flying kick",
|
| 537 |
+
"Basketball player doing a 360 dunk",
|
| 538 |
+
"Breakdancer doing a freeze",
|
| 539 |
+
"Gymnast doing a backflip",
|
| 540 |
+
"Martial artist in combat stance",
|
| 541 |
+
"Dancer leaping through the air",
|
| 542 |
+
"Rock climber reaching for a hold",
|
| 543 |
+
"Skateboarder doing a trick"
|
| 544 |
],
|
| 545 |
inputs=prompt
|
| 546 |
)
|
| 547 |
+
|
| 548 |
+
gr.Markdown("""
|
| 549 |
+
### 💡 Pro Tips:
|
| 550 |
+
- Use action verbs: jump, kick, flip, spin
|
| 551 |
+
- Add intensity: extreme, dynamic, explosive
|
| 552 |
+
- Specify sports/activities for better results
|
| 553 |
+
- Combine with physics effects for realism
|
| 554 |
+
""")
|
| 555 |
|
| 556 |
with gr.Column(scale=1):
|
| 557 |
+
pose_image = gr.Image(
|
| 558 |
+
label="🎨 Generated Dynamic Pose",
|
| 559 |
+
type="pil",
|
| 560 |
+
height=512
|
| 561 |
+
)
|
| 562 |
|
| 563 |
+
with gr.Accordion("📊 OpenPose JSON Data", open=False):
|
| 564 |
+
json_output = gr.Code(
|
| 565 |
+
language="json",
|
| 566 |
+
lines=15
|
| 567 |
+
)
|
| 568 |
|
| 569 |
# Event handlers
|
| 570 |
generate_btn.click(
|
| 571 |
fn=generate_pose,
|
| 572 |
+
inputs=[prompt, use_llm, template, physics_effect],
|
| 573 |
outputs=[pose_image, json_output, keypoints_state]
|
| 574 |
)
|
| 575 |
|
|
|
|
| 579 |
outputs=[pose_image, json_output, keypoints_state]
|
| 580 |
)
|
| 581 |
|
| 582 |
+
# Launch
|
| 583 |
app.queue()
|
| 584 |
app.launch()
|