Skip to content

Commit 552d84f

Browse files
commited
0 parents  commit 552d84f

36 files changed

+38229
-0
lines changed

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM ubuntu:latest
2+
3+
WORKDIR /app
4+
5+
RUN apt-get update && \
6+
apt-get install -y python3-pip python3-dev libgssapi-krb5-2 && \
7+
pip3 install --upgrade pip
8+
9+
COPY requirements.txt requirements.txt
10+
RUN pip3 install -r requirements.txt
11+
12+
COPY . .
13+
14+
# CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0"]

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# meshroom-web
2+
Web client to interact with the meshroom cli
3+
4+
# Commands
5+
Start the flask webclient by running `python -m flask run` or `python -m flask run --host="0.0.0.0"` when running inside the container to make sure it is exposed to the host.
6+
Start the websocket server by running `python websocket.py`.
7+
Build the docker image by running `docker build -t <yourtag>`.
8+
Run the docker image by running `docker -p 5000:5000 -p 5678:5678 -it run <yourtag>`. This runs the image interactively in which you can call the commands mentioned above. Port 5000 is exposed for the flask application. Port 5678 is exposed for the websocket server. Thus, `localhost:5000` for the web client, and `ws://127.0.0.1:5678` for the websocket.

__pycache__/main.cpython-38.pyc

124 Bytes
Binary file not shown.

app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Include our application
2+
from app import app

app/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Dependencies
2+
from flask import Flask
3+
4+
# Define the application and port
5+
# Flask accepts a static folder parameter in which the static js and css is located
6+
# You can refer to it using the static_url_path parameter which is the href
7+
# used in templates, e.g. static_url_path = '/app' can be referred to as /app/main.js
8+
app = Flask(__name__, static_folder='static', static_url_path='/static')
9+
10+
# Import all views, these are all the pages or endpoints the application handles
11+
from app import views
289 Bytes
Binary file not shown.
284 Bytes
Binary file not shown.
285 Bytes
Binary file not shown.
332 Bytes
Binary file not shown.

app/__pycache__/views.cpython-36.pyc

397 Bytes
Binary file not shown.

app/__pycache__/views.cpython-37.pyc

1.52 KB
Binary file not shown.

app/__pycache__/views.cpython-38.pyc

339 Bytes
Binary file not shown.

app/lib/__init__.py

Whitespace-only changes.
143 Bytes
Binary file not shown.
144 Bytes
Binary file not shown.
1.45 KB
Binary file not shown.
1.69 KB
Binary file not shown.

app/lib/meshroom.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from os import path
2+
import subprocess
3+
import shutil
4+
5+
class Meshroom(object):
6+
7+
def __init__(self, inputdir, outputdir):
8+
"""
9+
Constructor.
10+
11+
---
12+
inputdir: Path to input folder where the images of the model should be.
13+
outputdir: Path where meshroom will place its output.
14+
"""
15+
if not path.isdir(inputdir):
16+
raise Exception(f"{inputdir} is not a directory")
17+
if not path.isdir(outputdir):
18+
raise Exception(f"{outputdir} is not a directory")
19+
20+
# Store the references to the input and output directories
21+
self._input = inputdir
22+
self._output = outputdir
23+
24+
async def run(self, config, pipe):
25+
"""
26+
Run a simulation with a given configuration file.
27+
28+
raises: Exception
29+
---
30+
config: Path to JSON file that holds the configuration of a meshroom simulation.
31+
pipe: Function that receives the output of the program.
32+
"""
33+
34+
# Check if the given config file exists
35+
if not path.isfile(config):
36+
raise Exception(f"Config file {config} does not exist")
37+
38+
# Check if it's a json file
39+
if not config.endswith('.json'):
40+
raise Exception(f"Config file {config} is not a JSON file")
41+
42+
# Check if meshroom exec is available
43+
if not path.isfile(path.join('.', 'meshroom', 'meshroom_batch')):
44+
raise Exception("Meshroom executable is not available")
45+
46+
# Run the meshroom cli
47+
process = subprocess.Popen([
48+
path.join(".", "meshroom", "meshroom_batch"),
49+
"--inputRecursive", self._input,
50+
"--output", self._output,
51+
"--overrides", config,
52+
"--save", path.join(self._output, "project")
53+
], stdout=subprocess.PIPE)
54+
55+
# Print the output
56+
while True:
57+
58+
# Read the current line of the process' output
59+
output = process.stdout.readline()
60+
if output == '' and process.poll() is not None:
61+
break
62+
63+
# Output the current line
64+
if output:
65+
await pipe(output)

app/static/app.css

Whitespace-only changes.

app/static/app.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Wait until the content of the DOM has loaded and parsed. This does
2+
// not wait on stylesheets, images, or subframes
3+
window.addEventListener('DOMContentLoaded', () => {
4+
5+
// Find the container and form
6+
const container = document.querySelector('.uk-container');
7+
const form = document.querySelector('form');
8+
const stdout = document.querySelector('code');
9+
10+
// Start a websocket connection. This websocket connection allows us to
11+
// ping the backend and start an actual meshroom process. This process
12+
// also streams the process' stdout over the connection
13+
const websocket = new WebSocket('ws://127.0.0.1:5678');
14+
15+
// Listen to incoming messages, which we want to stream the stdout element
16+
websocket.onmessage = (event) => {
17+
18+
// Get the text from the blob
19+
event.data.text().then((text) => {
20+
21+
// And update the stdout
22+
stdout.textContent = stdout.textContent + text;
23+
});
24+
};
25+
26+
// Fetch the default configuration of meshroom from the API
27+
fetch('/config').then((res) => {
28+
29+
// Fetch the text and load it into the form
30+
res.text().then((text) => {
31+
32+
// Set the text on the form field that holds the json configuration
33+
form.querySelector('textarea').textContent = text;
34+
});
35+
});
36+
37+
// Listen until the user submits the form
38+
form.addEventListener('submit', (event) => {
39+
40+
// Prevent the default behavior as we don't want the browser
41+
// redirect the user
42+
event.preventDefault();
43+
44+
// Create form data from the form
45+
const formdata = new FormData(form);
46+
form.classList.remove('uk-form-danger');
47+
48+
// Show a loading animation
49+
const overlay = container.appendChild(document.createElement('div'));
50+
overlay.classList.add('uk-overlay', 'uk-position-center');
51+
const loader = overlay.appendChild(document.createElement('div'));
52+
loader.setAttribute('uk-spinner', true);
53+
54+
// List of promises that are required to run meshroom
55+
const promises = [
56+
fetch('/upload', {
57+
method: 'POST',
58+
mode: 'cors',
59+
cache: 'no-cache',
60+
credentials: 'same-origin',
61+
body: formdata
62+
}),
63+
fetch('/config', {
64+
method: 'POST',
65+
mode: 'cors',
66+
credentials: 'same-origin',
67+
body: formdata
68+
})
69+
];
70+
71+
// Make a post request to upload the images
72+
Promise.all(promises).then(() => {
73+
74+
// Remove the loader
75+
overlay.remove();
76+
77+
// Inform the user
78+
UIkit.notification({
79+
message: 'Meshroom has started',
80+
status: 'success',
81+
pos: 'bottom-right',
82+
timeout: 3000
83+
});
84+
85+
// Refresh the view to show the progress of the meshroom progress
86+
websocket.send(JSON.stringify({ type: 'run' }));
87+
}).catch((err) => {
88+
89+
console.log(err);
90+
// Remove the loader
91+
overlay.remove();
92+
93+
// Something went wrong, so we need to inform the user
94+
form.classList.add('uk-form-danger');
95+
UIkit.notification({
96+
message: 'Files could not be uploaded',
97+
status: 'danger',
98+
pos: 'bottom-right',
99+
timeout: 3000
100+
});
101+
});
102+
});
103+
});

0 commit comments

Comments
 (0)