-
Notifications
You must be signed in to change notification settings - Fork 2
/
serve.py
executable file
·154 lines (133 loc) · 4.39 KB
/
serve.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Serves the singing horse demo via bottle.py and bjoern.
Author: Jan Schlüter
"""
import sys
import os
import base64
import io
try:
from urllib import urlopen
except ImportError:
from urllib.request import urlopen
if sys.version_info[0] > 2:
from io import BytesIO as StringIO
else:
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
try:
import Image
except ImportError:
from PIL import Image
import bottle
import numpy as np
import spects
#import predict # for some reason, the app does not start up if we do this.
import plot
#bottle.TEMPLATE_PATH = ['.']
app = bottle.Bottle()
def load_config():
here = os.path.dirname(__file__)
config = dict()
with io.open(os.path.join(here, 'config.ini'), 'r') as f:
for l in f:
l = l.rstrip().split('=', 1)
if len(l) == 2:
config[l[0]] = l[1]
return config
CONFIG = load_config()
@app.route('/', method='GET')
def start():
"""Serves the index.html page.
Accepts(GET):
No parameters.
Returns:
The index page, in HTML.
"""
return bottle.static_file('index.html', root='.')
@app.route('/render', method='POST')
def render():
"""Computes and returns the audio and prediction curve for a given image.
Accepts(POST):
img: The drawing to add to the spectrogram, as a data URL in PNG format.
Returns:
the prediction curve image, as a data URL
a CR LF sequence
the resynthesized audio, as a data URL
"""
# Obtain and decode given image data
img = bottle.request.body.read().decode('ascii')
if not img:
bottle.response.status = 500
return 'Error: Missing img.'
if not img.startswith('data:image/png;base64,'):
bottle.response.status = 500
return 'Error: Not a PNG data URL.'
u = urlopen(img)
try:
img = u.read()
except Exception:
bottle.response.status = 500
return 'Error: Could not decode data URL.'
finally:
u.close()
try:
img = StringIO(img)
img = Image.open(img)
except Exception:
bottle.response.status = 500
return 'Error: Could not load given data as image.'
# Convert to numpy array, collapse channels if any
img = np.asarray(img)
if img.ndim == 3:
img = img[..., -1] # use last channel only (alpha, or blue, or gray)
img = img[::-1].T.astype(np.float32) / 255 # transpose and convert range
# Draw image with 70% opacity on top of spectrogram
img *= .7
spect = np.load(os.path.join(os.path.dirname(__file__), 'static', 'original.npy'))
spect = (spect - spects.VMIN) * (1 - img) + (spects.VMAX - spects.VMIN) * img
spect += spects.VMIN
# Resynthesize audio
samples = spects.undo_melspect(spect)
try:
audio = spects.write_ffmpeg(samples)
except OSError:
audio = spects.write_ffmpeg(samples, cmd='avconv')
# Compute network predictions
import predict
modeldir = os.path.join(os.path.dirname(__file__), CONFIG.get('modeldir'))
preds = predict.predict(
spect, os.path.join(modeldir, 'model.h5'),
os.path.join(modeldir, 'std_mean.h5'))
# Plot network predictions
curve = plot.pred_curve(preds)
return ("data:image/png;base64," + base64.b64encode(curve).decode('ascii') + "\r\n" +
"data:audio/mpeg;base64," + base64.b64encode(audio).decode('ascii'))
# Expose to mod_wsgi (we just need a global object called 'application'):
application = app
# Run as an internal server when this script is started directly:
def main():
if len(sys.argv) > 1:
print("Serves the demo. Needs bottle.py to run. Will serve via bjoern")
print("if installed, otherwise via wsgi_ref. Reads its configuration ")
print("from config.ini.")
return
# load configuration
port = int(CONFIG.get('port', 9090))
staticdir = os.path.join(os.path.dirname(__file__), 'static')
# start web server
print("Starting web server on localhost:%d..." % port)
app.route('/static/:path#.+#', callback=lambda path:
bottle.static_file(path, root=staticdir))
try:
import bjoern
except ImportError:
bjoern = None
bottle.run(app, host='localhost', port=port,
server='bjoern' if bjoern else 'wsgiref')
if __name__=="__main__":
main()