Spaces:
Sleeping
Sleeping
Muhammad Waqas commited on
Commit ·
0e95549
1
Parent(s): 78e3b99
Added: Generate image to video
Browse files- Dockerfile +2 -1
- app.py +39 -11
- workflows/cogvideox_image_to_video_workflow_api.json +1 -2
Dockerfile
CHANGED
|
@@ -39,4 +39,5 @@ USER flaskuser
|
|
| 39 |
EXPOSE 7860
|
| 40 |
|
| 41 |
# Run the Flask app using gunicorn with an infinite request timeout
|
| 42 |
-
CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--timeout", "0", "app:app"]
|
|
|
|
|
|
| 39 |
EXPOSE 7860
|
| 40 |
|
| 41 |
# Run the Flask app using gunicorn with an infinite request timeout
|
| 42 |
+
# CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--timeout", "0", "app:app"]
|
| 43 |
+
CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--timeout", "0", "--access-logfile", "-", "--error-logfile", "-", "app:app"]
|
app.py
CHANGED
|
@@ -261,8 +261,8 @@ def get_video_data(filename, subfolder, token):
|
|
| 261 |
##################################################
|
| 262 |
|
| 263 |
# Route: Image to Video
|
| 264 |
-
@app.route('/image_to_video', methods=['POST'])
|
| 265 |
-
def
|
| 266 |
data = request.json
|
| 267 |
|
| 268 |
# Extract and validate token
|
|
@@ -273,9 +273,21 @@ def image_to_video():
|
|
| 273 |
|
| 274 |
# Validate text prompt
|
| 275 |
text_prompt = data.get('text_prompt')
|
| 276 |
-
|
|
|
|
| 277 |
return jsonify({'error': 'Text prompt is required'}), 400
|
| 278 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
# Handle uploaded image or base64 image
|
| 280 |
image_file = request.files.get('image')
|
| 281 |
base64_image = data.get('base64_image')
|
|
@@ -322,8 +334,9 @@ def image_to_video():
|
|
| 322 |
|
| 323 |
# Modify workflow with inputs
|
| 324 |
workflow["30"]["inputs"]["prompt"] = text_prompt
|
|
|
|
| 325 |
workflow["73"]["inputs"]["url"] = image_url
|
| 326 |
-
workflow["31"]["inputs"]["prompt"] = "Low quality, watermark, strange motion"
|
| 327 |
|
| 328 |
# WebSocket connection to queue the prompt
|
| 329 |
ws = websocket.WebSocket()
|
|
@@ -345,9 +358,9 @@ def image_to_video():
|
|
| 345 |
# os.remove(image_path)
|
| 346 |
# print(f"Deleted temporary image: {image_path}", flush=True)
|
| 347 |
|
| 348 |
-
# Get
|
| 349 |
-
@app.route('/
|
| 350 |
-
def
|
| 351 |
token = request.headers.get('Authorization')
|
| 352 |
if not token or not token.startswith("Bearer "):
|
| 353 |
return jsonify({'error': 'Valid Bearer token required'}), 400
|
|
@@ -408,8 +421,8 @@ def get_video(prompt_id):
|
|
| 408 |
return jsonify({'error': str(e)}), 500
|
| 409 |
|
| 410 |
# Route: Image to Video old
|
| 411 |
-
@app.route('/
|
| 412 |
-
def
|
| 413 |
data = request.json
|
| 414 |
|
| 415 |
# Extract and validate token
|
|
@@ -420,9 +433,21 @@ def v1_image_to_video():
|
|
| 420 |
|
| 421 |
# Validate text prompt
|
| 422 |
text_prompt = data.get('text_prompt')
|
| 423 |
-
|
|
|
|
| 424 |
return jsonify({'error': 'Text prompt is required'}), 400
|
| 425 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
# Handle uploaded image or base64 image
|
| 427 |
image_file = request.files.get('image')
|
| 428 |
base64_image = data.get('base64_image')
|
|
@@ -469,6 +494,7 @@ def v1_image_to_video():
|
|
| 469 |
|
| 470 |
# Modify workflow with inputs
|
| 471 |
workflow["30"]["inputs"]["prompt"] = text_prompt
|
|
|
|
| 472 |
workflow["73"]["inputs"]["url"] = image_url
|
| 473 |
workflow["31"]["inputs"]["prompt"] = "Low quality, watermark, strange motion"
|
| 474 |
|
|
@@ -518,8 +544,10 @@ def v1_image_to_video():
|
|
| 518 |
local_video_path = f"static/generated_image_to_video_{prompt_id}.mp4"
|
| 519 |
with open(local_video_path, 'wb') as f:
|
| 520 |
f.write(video_data)
|
|
|
|
| 521 |
# Construct the public URL for the video
|
| 522 |
-
|
|
|
|
| 523 |
|
| 524 |
# Prepare the response with the video URL
|
| 525 |
# response_data = {
|
|
|
|
| 261 |
##################################################
|
| 262 |
|
| 263 |
# Route: Image to Video
|
| 264 |
+
@app.route('/v1/image_to_video', methods=['POST'])
|
| 265 |
+
def v1_image_to_video():
|
| 266 |
data = request.json
|
| 267 |
|
| 268 |
# Extract and validate token
|
|
|
|
| 273 |
|
| 274 |
# Validate text prompt
|
| 275 |
text_prompt = data.get('text_prompt')
|
| 276 |
+
frame_rate = data.get('frame_rate')
|
| 277 |
+
if not text_prompt or not text_prompt.strip():
|
| 278 |
return jsonify({'error': 'Text prompt is required'}), 400
|
| 279 |
|
| 280 |
+
# Check if frame_rate is missing or invalid
|
| 281 |
+
if not frame_rate: # If frame_rate is None, empty, or 0
|
| 282 |
+
frame_rate = 24 # Default to 24 fps
|
| 283 |
+
else:
|
| 284 |
+
try:
|
| 285 |
+
frame_rate = int(frame_rate)
|
| 286 |
+
if frame_rate not in [8, 12, 24]: # Ensure it's one of the allowed values
|
| 287 |
+
return jsonify({'error': 'Frame rate must be a valid number (8, 12, or 24).'}), 400
|
| 288 |
+
except ValueError:
|
| 289 |
+
return jsonify({'error': 'Frame rate must be a valid number (8, 12, or 24).'}), 400
|
| 290 |
+
|
| 291 |
# Handle uploaded image or base64 image
|
| 292 |
image_file = request.files.get('image')
|
| 293 |
base64_image = data.get('base64_image')
|
|
|
|
| 334 |
|
| 335 |
# Modify workflow with inputs
|
| 336 |
workflow["30"]["inputs"]["prompt"] = text_prompt
|
| 337 |
+
workflow["44"]["inputs"]["frame_rate"] = frame_rate
|
| 338 |
workflow["73"]["inputs"]["url"] = image_url
|
| 339 |
+
workflow["31"]["inputs"]["prompt"] = "Low quality, watermark, strange motion, blur"
|
| 340 |
|
| 341 |
# WebSocket connection to queue the prompt
|
| 342 |
ws = websocket.WebSocket()
|
|
|
|
| 358 |
# os.remove(image_path)
|
| 359 |
# print(f"Deleted temporary image: {image_path}", flush=True)
|
| 360 |
|
| 361 |
+
# Get video_tasks route
|
| 362 |
+
@app.route('/v1/video_tasks/<prompt_id>', methods=['GET'])
|
| 363 |
+
def video_tasks(prompt_id):
|
| 364 |
token = request.headers.get('Authorization')
|
| 365 |
if not token or not token.startswith("Bearer "):
|
| 366 |
return jsonify({'error': 'Valid Bearer token required'}), 400
|
|
|
|
| 421 |
return jsonify({'error': str(e)}), 500
|
| 422 |
|
| 423 |
# Route: Image to Video old
|
| 424 |
+
@app.route('/image_to_video', methods=['POST'])
|
| 425 |
+
def image_to_video():
|
| 426 |
data = request.json
|
| 427 |
|
| 428 |
# Extract and validate token
|
|
|
|
| 433 |
|
| 434 |
# Validate text prompt
|
| 435 |
text_prompt = data.get('text_prompt')
|
| 436 |
+
frame_rate = data.get('frame_rate')
|
| 437 |
+
if not text_prompt or not text_prompt.strip():
|
| 438 |
return jsonify({'error': 'Text prompt is required'}), 400
|
| 439 |
|
| 440 |
+
# Check if frame_rate is missing or invalid
|
| 441 |
+
if not frame_rate: # If frame_rate is None, empty, or 0
|
| 442 |
+
frame_rate = 24 # Default to 24 fps
|
| 443 |
+
else:
|
| 444 |
+
try:
|
| 445 |
+
frame_rate = int(frame_rate)
|
| 446 |
+
if frame_rate not in [8, 12, 24]:
|
| 447 |
+
return jsonify({'error': 'Frame rate must be a valid number (8, 12, or 24).'}), 400
|
| 448 |
+
except ValueError:
|
| 449 |
+
return jsonify({'error': 'Frame rate must be a valid number (8, 12, or 24).'}), 400
|
| 450 |
+
|
| 451 |
# Handle uploaded image or base64 image
|
| 452 |
image_file = request.files.get('image')
|
| 453 |
base64_image = data.get('base64_image')
|
|
|
|
| 494 |
|
| 495 |
# Modify workflow with inputs
|
| 496 |
workflow["30"]["inputs"]["prompt"] = text_prompt
|
| 497 |
+
workflow["44"]["inputs"]["frame_rate"] = frame_rate
|
| 498 |
workflow["73"]["inputs"]["url"] = image_url
|
| 499 |
workflow["31"]["inputs"]["prompt"] = "Low quality, watermark, strange motion"
|
| 500 |
|
|
|
|
| 544 |
local_video_path = f"static/generated_image_to_video_{prompt_id}.mp4"
|
| 545 |
with open(local_video_path, 'wb') as f:
|
| 546 |
f.write(video_data)
|
| 547 |
+
|
| 548 |
# Construct the public URL for the video
|
| 549 |
+
|
| 550 |
+
# video_url = f"https://gosign-de-comfyui-api.hf.space/{local_video_path}"
|
| 551 |
|
| 552 |
# Prepare the response with the video URL
|
| 553 |
# response_data = {
|
workflows/cogvideox_image_to_video_workflow_api.json
CHANGED
|
@@ -17,7 +17,6 @@
|
|
| 17 |
"clip_name": "t5\\google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
|
| 18 |
"type": "sd3"
|
| 19 |
},
|
| 20 |
-
"class_type": "CLIPLoader",
|
| 21 |
"_meta": {
|
| 22 |
"title": "Load CLIP"
|
| 23 |
}
|
|
@@ -72,7 +71,7 @@
|
|
| 72 |
},
|
| 73 |
"44": {
|
| 74 |
"inputs": {
|
| 75 |
-
"frame_rate":
|
| 76 |
"loop_count": 0,
|
| 77 |
"filename_prefix": "CogVideoX-I2V",
|
| 78 |
"format": "video/h264-mp4",
|
|
|
|
| 17 |
"clip_name": "t5\\google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
|
| 18 |
"type": "sd3"
|
| 19 |
},
|
|
|
|
| 20 |
"_meta": {
|
| 21 |
"title": "Load CLIP"
|
| 22 |
}
|
|
|
|
| 71 |
},
|
| 72 |
"44": {
|
| 73 |
"inputs": {
|
| 74 |
+
"frame_rate": 24,
|
| 75 |
"loop_count": 0,
|
| 76 |
"filename_prefix": "CogVideoX-I2V",
|
| 77 |
"format": "video/h264-mp4",
|