forked from TencentARC/MotionCtrl
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
623 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
#This is an example that uses the websockets api to know when a prompt execution is done | ||
#Once the prompt execution is done it downloads the images using the /history endpoint | ||
import os | ||
import websocket #NOTE: websocket-client (https://github.com/websocket-client/websocket-client) | ||
import uuid | ||
import json | ||
import urllib.request | ||
import urllib.parse | ||
from flask import Flask, request, jsonify, render_template, session, abort | ||
from flask_socketio import SocketIO, join_room, leave_room,send, emit | ||
import secrets | ||
|
||
from PIL import Image | ||
import io | ||
import base64 | ||
|
||
server_address = "127.0.0.1:8188" | ||
client_id = str(uuid.uuid4()) | ||
|
||
def queue_prompt(prompt): | ||
p = {"prompt": prompt, "client_id": client_id} | ||
data = json.dumps(p).encode('utf-8') | ||
req = urllib.request.Request("http://{}/prompt".format(server_address), data=data) | ||
return json.loads(urllib.request.urlopen(req).read()) | ||
|
||
def get_image(filename, subfolder, folder_type): | ||
data = {"filename": filename, "subfolder": subfolder, "type": folder_type} | ||
url_values = urllib.parse.urlencode(data) | ||
with urllib.request.urlopen("http://{}/view?{}".format(server_address, url_values)) as response: | ||
return response.read() | ||
|
||
def get_history(prompt_id): | ||
with urllib.request.urlopen("http://{}/history/{}".format(server_address, prompt_id)) as response: | ||
return json.loads(response.read()) | ||
|
||
def get_images(ws, prompt): | ||
prompt_id = queue_prompt(prompt)['prompt_id'] | ||
output_images = {} | ||
while True: | ||
out = ws.recv() | ||
if isinstance(out, str): | ||
message = json.loads(out) | ||
if message['type'] == 'executing': | ||
data = message['data'] | ||
if data['node'] is None and data['prompt_id'] == prompt_id: | ||
break #Execution is done | ||
else: | ||
continue #previews are binary data | ||
|
||
history = get_history(prompt_id)[prompt_id] | ||
for o in history['outputs']: | ||
for node_id in history['outputs']: | ||
node_output = history['outputs'][node_id] | ||
if 'images' in node_output: | ||
images_output = [] | ||
for image in node_output['images']: | ||
image_data = get_image(image['filename'], image['subfolder'], image['type']) | ||
images_output.append(image_data) | ||
output_images[node_id] = images_output | ||
|
||
return output_images | ||
|
||
prompt={} | ||
with open('./workflow_api_motionctrl_turbo.json') as fr: | ||
prompt = json.load(fr) | ||
|
||
ws = websocket.WebSocket() | ||
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id)) | ||
|
||
#Commented out code to display the output images: | ||
|
||
# for node_id in images: | ||
# for image_data in images[node_id]: | ||
# from PIL import Image | ||
# import io | ||
# image = Image.open(io.BytesIO(image_data)) | ||
# image.show() | ||
|
||
app = Flask(__name__, template_folder=os.path.abspath('.'), static_folder='assets') | ||
app.secret_key = secrets.token_hex(16) | ||
|
||
socketio = SocketIO(app, cors_allowed_origins='*') | ||
connected_sids = set() # 存放已连接的客户端 | ||
|
||
#后端程序 | ||
lockroom='None' | ||
@socketio.on('connect') | ||
def on_connect(): | ||
connected_sids.add(request.sid) | ||
print(f'{request.sid} 已连接') | ||
socketio.start_background_task(background_thread_heartbeat) | ||
|
||
@socketio.on('disconnect') | ||
def on_disconnect(): | ||
connected_sids.remove(request.sid) | ||
print(f'{request.sid} 已断开') | ||
|
||
@socketio.on('message') | ||
def handle_message(message): | ||
"""收消息""" | ||
print(f'message:{request.sid} {message}') | ||
json.loads(message) | ||
|
||
@socketio.on('camera_poses') | ||
def handle_message(camera_poses): | ||
print(f'camera_poses:{request.sid} {camera_poses}') | ||
prompt["60"]["inputs"]["camera"] = camera_poses["camera_poses"] | ||
images = get_images(ws, prompt) | ||
for node_id in images: | ||
for image_data in images[node_id]: | ||
b64img=base64.b64encode(image_data).decode('utf-8') | ||
socketio.emit('server_response',{'b64img':b64img}, to=camera_poses["roomid"]) | ||
|
||
@socketio.on('server_reconnect') | ||
def server_reconnect(message): | ||
print(f'server_reconnect:{request.sid} {message}') | ||
join_room(message['roomid']) | ||
|
||
def background_thread_heartbeat(): | ||
global lockroom | ||
while True: | ||
socketio.emit('server_response',{'lockroom':lockroom}) | ||
socketio.sleep(5) | ||
|
||
|
||
@app.route('/') | ||
def index(): | ||
session['user'] = None | ||
return render_template('index.html') | ||
|
||
if __name__ == '__main__': | ||
socketio.run(app, host='0.0.0.0', port=5017, debug=True) | ||
#app.run(host='0.0.0.0', port=5017) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | ||
<link type="text/css" rel="stylesheet" href="main.css"> | ||
<title>CAMERA MOTION DESIGNER</title> | ||
<style> | ||
body { margin: 0; } | ||
</style> | ||
</head> | ||
<body> | ||
<div id="info"><button id="btn_translate">Translate</button><button id="btn_rotate">Rotate</button> | ||
<button id="btn_addpoint" style="display:none;">Add Point</button> | ||
<!--"W" translate | "E" rotate--><br /> | ||
<!--textarea id="tb_result" style="width:256px; height:128px;">[]</textarea><br/--> | ||
<button id="btn_startrt">Start Real Time MotionCtrl</button><br/> | ||
<div style="width:256px;height:256px;" class="imageContainer"></div> | ||
</div> | ||
<script type="module" src="main.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
body { | ||
margin: 0; | ||
background-color: #000; | ||
color: #fff; | ||
font-family: Monospace; | ||
font-size: 13px; | ||
line-height: 24px; | ||
overscroll-behavior: none; | ||
} | ||
|
||
a { | ||
color: #ff0; | ||
text-decoration: none; | ||
} | ||
|
||
a:hover { | ||
text-decoration: underline; | ||
} | ||
|
||
button { | ||
cursor: pointer; | ||
text-transform: uppercase; | ||
} | ||
|
||
#info { | ||
position: absolute; | ||
top: 0px; | ||
left: 0px; | ||
padding: 10px; | ||
box-sizing: border-box; | ||
text-align: center; | ||
/*-moz-user-select: none; | ||
-webkit-user-select: none; | ||
-ms-user-select: none; | ||
user-select: none; | ||
pointer-events: none;*/ | ||
z-index: 1; /* TODO Solve this in HTML */ | ||
} | ||
|
||
a, button, input, select { | ||
pointer-events: auto; | ||
} | ||
|
||
.lil-gui { | ||
z-index: 2 !important; /* TODO Solve this in HTML */ | ||
} | ||
|
||
@media all and ( max-width: 640px ) { | ||
.lil-gui.root { | ||
right: auto; | ||
top: auto; | ||
max-height: 50%; | ||
max-width: 80%; | ||
bottom: 0; | ||
left: 0; | ||
} | ||
} | ||
|
||
#overlay { | ||
position: absolute; | ||
font-size: 16px; | ||
z-index: 2; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
flex-direction: column; | ||
background: rgba(0,0,0,0.7); | ||
} | ||
|
||
#overlay button { | ||
background: transparent; | ||
border: 0; | ||
border: 1px solid rgb(255, 255, 255); | ||
border-radius: 4px; | ||
color: #ffffff; | ||
padding: 12px 18px; | ||
text-transform: uppercase; | ||
cursor: pointer; | ||
} | ||
|
||
#notSupported { | ||
width: 50%; | ||
margin: auto; | ||
background-color: #f00; | ||
margin-top: 20px; | ||
padding: 10px; | ||
} |
Oops, something went wrong.