cm107 commited on
Commit
ef75ac1
1 Parent(s): 84acff7

Initial commit

Browse files
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ venv
2
+ __pycache__
3
+ *.pyc
README.md CHANGED
@@ -5,6 +5,7 @@ colorFrom: red
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 3.13.0
 
8
  app_file: app.py
9
  pinned: false
10
  license: mit
 
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 3.13.0
8
+ python_version: 3.10.4
9
  app_file: app.py
10
  pinned: false
11
  license: mit
app.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import flask
2
+ import os
3
+
4
+ app = flask.Flask(__name__, template_folder="./templates/")
5
+
6
+ import numpy as np
7
+ import torch
8
+
9
+ from diffusers import LDMSuperResolutionPipeline
10
+ from diffusers.utils import PIL_INTERPOLATION, load_image, torch_device
11
+
12
+ from pkg.util import img_binary_data_to_pil, resizePilToMaxSide, pil_to_base64
13
+
14
+
15
+ torch.backends.cuda.matmul.allow_tf32 = False
16
+ ldm = LDMSuperResolutionPipeline.from_pretrained("duongna/ldm-super-resolution", device_map="auto")
17
+ ldm.to(torch_device)
18
+ ldm.set_progress_bar_config(disable=None)
19
+ generator = torch.Generator(device=torch_device).manual_seed(0)
20
+
21
+ @app.route('/')
22
+ def index():
23
+ print('Route: /')
24
+ return flask.render_template('index.html')
25
+
26
+ @app.route('/superres', methods=['POST'])
27
+ def superres():
28
+ print('Route: /superres')
29
+ if flask.request.method != 'POST':
30
+ return flask.jsonify(
31
+ isError=True,
32
+ message=f"This route doesn't support {flask.request.method} method."
33
+ )
34
+ imgBinary = flask.request.data
35
+ maxSideLength = flask.request.args.get('maxSideLength', default=100, type=int)
36
+ numIterations = flask.request.args.get('numIterations', default=20, type=int)
37
+
38
+
39
+ img = img_binary_data_to_pil(imgBinary)
40
+ # img.show()
41
+ # arr = np.asarray(img)
42
+
43
+ img = resizePilToMaxSide(img, maxSideLength=maxSideLength)
44
+ # img.show()
45
+
46
+ result = ldm(image=img, generator=generator, num_inference_steps=numIterations, output_type="pil").images[0]
47
+ # result.show()
48
+ resultBinary = pil_to_base64(result)
49
+
50
+ return flask.jsonify(
51
+ isError=False,
52
+ message='Success',
53
+ statusCode=200,
54
+ data=resultBinary
55
+ )
56
+
57
+ if __name__ == '__main__':
58
+ app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
pkg/__init__.py ADDED
File without changes
pkg/util.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import numpy as np
3
+ import numpy.typing as npt
4
+ from PIL import Image
5
+ from PIL.Image import Image as pilImage
6
+ import base64
7
+ import re
8
+ from diffusers.utils import PIL_INTERPOLATION
9
+
10
+ def img_binary_data_to_pil(imgBinary: bytes) -> pilImage:
11
+ image_data = re.sub('^data:image/.+;base64,', '', imgBinary.decode())
12
+ decoded = base64.b64decode(image_data)
13
+ img = Image.open(io.BytesIO(decoded))
14
+ return img
15
+
16
+ def resizePilToMaxSide(img: pilImage, maxSideLength: int) -> pilImage:
17
+ w, h = img.size
18
+ maxSide = max(w, h, maxSideLength)
19
+ scale = maxSideLength / maxSide
20
+ targetSize = (int(scale * w), int(scale * h))
21
+ img = img.resize(targetSize, resample=PIL_INTERPOLATION["lanczos"])
22
+ return img
23
+
24
+ def pil_to_base64(img: pilImage | npt.NDArray[np.uint8]) -> str:
25
+ if type(img) is pilImage:
26
+ pass
27
+ elif type(img) is np.ndarray:
28
+ img = pilImage.fromarray(img.astype('uint8'))
29
+ else:
30
+ raise TypeError
31
+
32
+ # https://stackoverflow.com/a/59583262/13797085
33
+ file_object = io.BytesIO()
34
+ img.save(file_object, 'PNG')
35
+ base64img = "data:image/png;base64," \
36
+ + base64.b64encode(file_object.getvalue()).decode('ascii')
37
+ return base64img
requirements.txt ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ accelerate==0.15.0
2
+ certifi==2022.12.7
3
+ charset-normalizer==2.1.1
4
+ click==8.1.3
5
+ diffusers @ git+https://github.com/huggingface/diffusers@69de9b2eaa3a9047e0074b49753eb7a71aec4a5d
6
+ filelock==3.8.2
7
+ Flask==2.2.2
8
+ huggingface-hub==0.11.1
9
+ idna==3.4
10
+ importlib-metadata==5.1.0
11
+ itsdangerous==2.1.2
12
+ Jinja2==3.1.2
13
+ MarkupSafe==2.1.1
14
+ numpy==1.23.5
15
+ packaging==22.0
16
+ Pillow==9.3.0
17
+ psutil==5.9.4
18
+ PyYAML==6.0
19
+ regex==2022.10.31
20
+ requests==2.28.1
21
+ torch==1.12.1+cu102
22
+ torchaudio==0.12.1+cu102
23
+ torchvision==0.13.1+cu102
24
+ tqdm==4.64.1
25
+ typing_extensions==4.4.0
26
+ urllib3==1.26.13
27
+ Werkzeug==2.2.2
28
+ zipp==3.11.0
static/css/main.css ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ padding: 2rem;
3
+ font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
+ overflow: auto;
5
+ }
6
+
7
+ .card {
8
+ max-width: 620px;
9
+ margin: 0 auto;
10
+ padding: 16px;
11
+ border: 1px solid lightgray;
12
+ border-radius: 16px;
13
+ }
14
+
15
+ .card p {
16
+ color: rgb(107, 114, 128);
17
+ font-size: 15px;
18
+ margin-bottom: 10px;
19
+ margin-top: 5px;
20
+ }
21
+
22
+ .card h1 {
23
+ font-size: 16px;
24
+ margin-top: 0;
25
+ }
26
+
27
+ .card p:last-child {
28
+ margin-bottom: 0;
29
+ }
30
+
31
+ #mainContainer {
32
+ display: flex;
33
+ /* width: fit-content; */
34
+ width: 800px;
35
+ /* height: fit-content; */
36
+ height: 600px;
37
+ background-color: gray;
38
+ }
39
+
40
+ #resultContainer {
41
+ width: 65%;
42
+ height: 50%;
43
+ margin-left: 5%;
44
+ background-color: red;
45
+ }
46
+
47
+ #resultContainer img {
48
+ display: flex;
49
+ max-width: 100%;
50
+ height: 100%;
51
+ justify-content: center;
52
+ align-items: center;
53
+ margin-left: auto;
54
+ margin-right: auto;
55
+ }
56
+
57
+ #sidebarContainer {
58
+ width: 35%;
59
+ height: 50%;
60
+ margin-right: 5%;
61
+ background-color: green;
62
+ }
63
+
64
+ #scDropZone {
65
+ display: flex;
66
+ border: 5px solid blue;
67
+ width: fit-content;
68
+ height: calc(20% - 5px * 2);
69
+ margin-left: auto;
70
+ margin-right: auto;
71
+ padding: 5px;
72
+ color: blue;
73
+ background-color: rgba(0.0, 255, 255, 0.2);
74
+ }
75
+
76
+ #scDropZone * {
77
+ text-align: middle;
78
+ margin-top: auto;
79
+ margin-bottom: auto;
80
+ }
81
+
82
+ #scDropImages {
83
+ display: flex;
84
+ max-width: 100%;
85
+ height: calc(20% - 5px * 2);
86
+ justify-content: center;
87
+ margin-left: auto;
88
+ margin-right: auto;
89
+ border: 5px solid rgba(0, 255, 255, 0);
90
+ }
91
+
92
+ #scDropImages .hoverDropImage {
93
+ border: 5px solid white;
94
+ }
95
+
96
+ #scDropImages .selectedDropImage {
97
+ border: 5px solid greenyellow;
98
+ }
99
+
100
+ .centeredBox {
101
+ border: 5px solid rgba(0, 0, 0, 0);
102
+ }
103
+
104
+ .centeredBox * {
105
+ text-align: middle;
106
+ margin-top: auto;
107
+ margin-bottom: auto;
108
+ }
109
+
110
+ .centeredBox p {
111
+ color: greenyellow;
112
+ margin-left: 10px;
113
+ }
114
+
115
+ .centeredBox input {
116
+ background-color: white;
117
+ width: 75%;
118
+ margin-right: 10px;
119
+ }
120
+
121
+ #scPromptsContainer {
122
+ /* width: fit-content; */
123
+ height: calc(60% - 5px * 2 * 2);
124
+ border: 5px solid rgba(128, 0, 128, 0);
125
+ }
126
+
127
+ #scMaxSidePrompt {
128
+ display: flex;
129
+ height: calc(33% - 5px * 2);
130
+ margin-top: auto;
131
+ margin-bottom: auto;
132
+ padding-left: 10px;
133
+ }
134
+
135
+ #scNumIters {
136
+ display: flex;
137
+ height: calc(33% - 5px * 2);
138
+ }
139
+
140
+ #scBtnBox {
141
+ display: flex;
142
+ height: calc(34% - 5px * 2);
143
+ }
144
+
145
+ #scBtnBox button {
146
+ margin-left: auto;
147
+ margin-right: auto;
148
+ width: 40%;
149
+ height: 75%;
150
+ font-size: 12px;
151
+ border: 2px solid greenyellow;
152
+ color: greenyellow;
153
+ background-color: blue;
154
+ border-radius: 3px;
155
+ }
156
+
157
+ #scBtnBox button.hoverScBtn {
158
+ border: 2px solid red;
159
+ }
static/img/loadingScreen.webp ADDED
static/js/main.js ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ImageHandler {
2
+ constructor(
3
+ maxImageSize = 10e6, //10MB
4
+ clearOnInit = true
5
+ ) {
6
+ this.resultImg = document.getElementById('resultImg');
7
+ this.maxImageSize = maxImageSize;
8
+ this.validTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
9
+
10
+ this.scDropZone = document.getElementById('scDropZone');
11
+ this.scDropImages = document.getElementById('scDropImages');
12
+
13
+ this.scRunBtn = document.getElementById('scRunBtn');
14
+ this.scDeleteBtn = document.getElementById('scDeleteBtn');
15
+
16
+ if (clearOnInit)
17
+ this.clearImages();
18
+ else {
19
+ for (var i = 0; i < this.scDropImages.children.length; i++) {
20
+ let child = this.scDropImages.children[i];
21
+ if (child.tagName == 'IMG') {
22
+ if (child.className == "hoverDropImage")
23
+ child.className = "";
24
+ this.processNewImage(child);
25
+ }
26
+ }
27
+ }
28
+
29
+ this.initButtons();
30
+
31
+ this.scDropZone.addEventListener('drop', e => this.processDrop(e));
32
+ this.scDropZone.addEventListener('dragover', e => this.processDragOver(e));
33
+ }
34
+
35
+ initButtons() {
36
+ var scBtnBox = document.getElementById('scBtnBox');
37
+ for (var i = 0; i < scBtnBox.children.length; i++) {
38
+ let child = scBtnBox.children[i];
39
+ if (child.tagName == "BUTTON") {
40
+ child.addEventListener(
41
+ 'mouseover',
42
+ function () {
43
+ child.className = 'hoverScBtn';
44
+ }
45
+ );
46
+ child.addEventListener(
47
+ 'mouseout',
48
+ function () {
49
+ child.className = '';
50
+ }
51
+ );
52
+ }
53
+ }
54
+
55
+ // TODO: scRunBtn
56
+ this.scRunBtn.addEventListener(
57
+ 'mouseup',
58
+ (e) => this.run()
59
+ );
60
+
61
+ // scDeleteBtn
62
+ this.scDeleteBtn.addEventListener(
63
+ 'mouseup',
64
+ (e) => this.deleteSelectedImage()
65
+ );
66
+
67
+ }
68
+
69
+ deleteSelectedImage() {
70
+ for (var i = this.scDropImages.children.length - 1; i >= 0; i--) {
71
+ let child = this.scDropImages.children[i];
72
+ if (child.tagName == 'IMG') {
73
+ if (child.className == "selectedDropImage") {
74
+ this.scDropImages.removeChild(child);
75
+ break;
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ clearImages() {
82
+ this.scDropImages.innerHTML = "";
83
+ }
84
+
85
+ validateDroppedImage(image) {
86
+ if (this.validTypes.indexOf(image.type) == -1) {
87
+ console.log('Invalid File Type: ' + image.type);
88
+ return false;
89
+ }
90
+
91
+ if (image.size > this.maxImageSize) {
92
+ console.log('File is too large: ' + image.size);
93
+ return false
94
+ }
95
+
96
+ return true;
97
+ }
98
+
99
+ processNewImage(img) {
100
+ img.addEventListener(
101
+ 'mouseover',
102
+ function () {
103
+ if (img.className != "selectedDropImage")
104
+ img.className = "hoverDropImage";
105
+ }
106
+ );
107
+ img.addEventListener(
108
+ 'mouseout',
109
+ function () {
110
+ if (img.className != "selectedDropImage")
111
+ img.className = "";
112
+ }
113
+ );
114
+ img.addEventListener(
115
+ 'mouseup',
116
+ function () {
117
+ if (img.className == "hoverDropImage") {
118
+ var existingSelectedImages = document.getElementsByClassName("selectedDropImage");
119
+ for (var i = 0; i < existingSelectedImages.length; i++)
120
+ existingSelectedImages[i].className = "";
121
+ img.className = "selectedDropImage";
122
+ }
123
+ }
124
+ )
125
+ }
126
+
127
+ /**
128
+ * Refer to https://soshace.com/the-ultimate-guide-to-drag-and-drop-image-uploading-with-pure-javascript/
129
+ * @param {object} event
130
+ */
131
+ processDrop(event) {
132
+ // Prevent default behavior (Prevent file from being opened)
133
+ event.preventDefault();
134
+
135
+ var dt = event.dataTransfer;
136
+ var files = dt.files;
137
+ if (files.length > 0) {
138
+ for (var i = 0; i < files.length; i++) {
139
+ if (this.validateDroppedImage(files[i])) {
140
+ var img = document.createElement('img');
141
+ var reader = new FileReader();
142
+ reader.onload = function (e) {
143
+ img.src = e.target.result;
144
+ // imageNav.sources.push(e.target.result);
145
+ }
146
+ this.processNewImage(img);
147
+ reader.readAsDataURL(files[i]);
148
+ this.scDropImages.appendChild(img);
149
+ }
150
+ }
151
+ }
152
+ else {
153
+ // console.log('Dropped ' + files.length + ' files.');
154
+ }
155
+ }
156
+
157
+ processDragOver(event) {
158
+ // console.log('File(s) in drop zone');
159
+
160
+ // Prevent default behavior (Prevent file from being opened)
161
+ event.preventDefault();
162
+ }
163
+
164
+ get maxSideLength() {
165
+ var result = document.getElementById('scMaxSidePromptInput').value;
166
+ return Number(result);
167
+ }
168
+
169
+ get numIterations() {
170
+ var result = document.getElementById('scNumItersInput').value;
171
+ return Number(result);
172
+ }
173
+
174
+ async infer(imgData) {
175
+ try {
176
+ let url = '../../superres?maxSideLength='
177
+ + this.maxSideLength
178
+ + '&&numIterations='
179
+ + this.numIterations;
180
+ let res = await fetch(
181
+ url,
182
+ {
183
+ method: 'POST',
184
+ body: imgData
185
+ }
186
+ );
187
+ return await res.json();
188
+ } catch (error) {
189
+ console.log(error);
190
+ }
191
+ }
192
+
193
+ async run() {
194
+ let imgData = null;
195
+ for (var i = this.scDropImages.children.length - 1; i >= 0; i--) {
196
+ let child = this.scDropImages.children[i];
197
+ if (child.tagName == 'IMG') {
198
+ if (child.className == "selectedDropImage") {
199
+ imgData = child.src;
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ if (imgData != null) {
205
+ this.resultImg.src = '../static/img/loadingScreen.webp';
206
+ let result = await this.infer(imgData);
207
+ // result['isError']
208
+ if (result == null) {
209
+ this.resultImg.src = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_0fzX1q44MiXQupdeYQTpGd_vAHs9zvTTVLxkfJu6g0RL9oawDeC5Edf-kRt27ygD4ZQ&usqp=CAU';
210
+ }
211
+ else
212
+ this.resultImg.src = result.data;
213
+ }
214
+ }
215
+ }
216
+
217
+ var imageHandler = new ImageHandler(
218
+ maxImageSize = 10e6,
219
+ clearOnInit = true
220
+ );
templates/index.html ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width" />
7
+ <title>Latent Defusion Super Resolution</title>
8
+ <link rel="stylesheet" href="../static/css/main.css" />
9
+ </head>
10
+
11
+ <body>
12
+ <h1>Latent Defusion Super Resolution</h1>
13
+ <div class="card">
14
+ <h1>Disclaimer</h1>
15
+ <p>
16
+ This page is still under testing. If you are reading this, don't expect the model to work as expected right
17
+ now.
18
+ </p>
19
+ <p>
20
+ I initially plan on using a model that was trained by someone else.
21
+ I can think about how to train a custom model afterwards.
22
+ </p>
23
+ </div>
24
+ <div id="mainContainer">
25
+ <div id="resultContainer">
26
+ <img id="resultImg" src="">
27
+ </div>
28
+ <div id="sidebarContainer">
29
+ <div id="scDropZone">
30
+ <p>Drop An Image In Here</p>
31
+ </div>
32
+ <div id="scDropImages">
33
+ <img class="selectedDropImage" src="../static/img/loadingScreen.webp">
34
+ <img class="hoverDropImage" src="../static/img/loadingScreen.webp">
35
+ <img src="../static/img/loadingScreen.webp">
36
+ </div>
37
+ <div id="scPromptsContainer">
38
+ <div id="scMaxSidePrompt" class="centeredBox">
39
+ <p>Max Side Length:</p>
40
+ <input id="scMaxSidePromptInput" type="text" class="textbox" value="100" />
41
+ </div>
42
+ <div id="scNumIters" class="centeredBox">
43
+ <p>Number of Iterations:</p>
44
+ <input id="scNumItersInput" type="text" class="textbox" value="20" />
45
+ </div>
46
+ <div id="scBtnBox" class="centeredBox">
47
+ <button id="scRunBtn">
48
+ <b>Run</b>
49
+ </button>
50
+ <button id="scDeleteBtn">
51
+ <b>Delete</b>
52
+ </button>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <script type="text/javascript" src="../static/js/main.js"></script>
59
+ <script
60
+ src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.2/iframeResizer.contentWindow.min.js"></script>
61
+ </body>
62
+
63
+ </html>