nykadamec commited on
Commit
a95ab94
Β·
1 Parent(s): 668dc2e
Files changed (6) hide show
  1. Dockerfile +7 -1
  2. package-lock.json +861 -0
  3. package.json +7 -9
  4. server-simple.js +109 -0
  5. server.js +14 -4
  6. test-local.js +108 -0
Dockerfile CHANGED
@@ -4,11 +4,17 @@ FROM node:18-slim
4
  # Set working directory
5
  WORKDIR /app
6
 
7
- # Install system dependencies for TensorFlow.js
8
  RUN apt-get update && apt-get install -y \
9
  python3 \
10
  python3-pip \
11
  build-essential \
 
 
 
 
 
 
12
  && rm -rf /var/lib/apt/lists/*
13
 
14
  # Copy package files
 
4
  # Set working directory
5
  WORKDIR /app
6
 
7
+ # Install system dependencies for TensorFlow.js and Canvas
8
  RUN apt-get update && apt-get install -y \
9
  python3 \
10
  python3-pip \
11
  build-essential \
12
+ libcairo2-dev \
13
+ libpango1.0-dev \
14
+ libjpeg-dev \
15
+ libgif-dev \
16
+ librsvg2-dev \
17
+ pkg-config \
18
  && rm -rf /var/lib/apt/lists/*
19
 
20
  # Copy package files
package-lock.json ADDED
@@ -0,0 +1,861 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "upscaler-api",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "upscaler-api",
9
+ "version": "1.0.0",
10
+ "license": "MIT",
11
+ "dependencies": {
12
+ "cors": "^2.8.5",
13
+ "express": "^4.18.2",
14
+ "multer": "^1.4.5-lts.1"
15
+ },
16
+ "engines": {
17
+ "node": ">=18.0.0"
18
+ }
19
+ },
20
+ "node_modules/accepts": {
21
+ "version": "1.3.8",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "mime-types": "~2.1.34",
25
+ "negotiator": "0.6.3"
26
+ },
27
+ "engines": {
28
+ "node": ">= 0.6"
29
+ }
30
+ },
31
+ "node_modules/append-field": {
32
+ "version": "1.0.0",
33
+ "license": "MIT"
34
+ },
35
+ "node_modules/array-flatten": {
36
+ "version": "1.1.1",
37
+ "license": "MIT"
38
+ },
39
+ "node_modules/body-parser": {
40
+ "version": "1.20.3",
41
+ "license": "MIT",
42
+ "dependencies": {
43
+ "bytes": "3.1.2",
44
+ "content-type": "~1.0.5",
45
+ "debug": "2.6.9",
46
+ "depd": "2.0.0",
47
+ "destroy": "1.2.0",
48
+ "http-errors": "2.0.0",
49
+ "iconv-lite": "0.4.24",
50
+ "on-finished": "2.4.1",
51
+ "qs": "6.13.0",
52
+ "raw-body": "2.5.2",
53
+ "type-is": "~1.6.18",
54
+ "unpipe": "1.0.0"
55
+ },
56
+ "engines": {
57
+ "node": ">= 0.8",
58
+ "npm": "1.2.8000 || >= 1.4.16"
59
+ }
60
+ },
61
+ "node_modules/buffer-from": {
62
+ "version": "1.1.2",
63
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
64
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
65
+ "license": "MIT"
66
+ },
67
+ "node_modules/busboy": {
68
+ "version": "1.6.0",
69
+ "dependencies": {
70
+ "streamsearch": "^1.1.0"
71
+ },
72
+ "engines": {
73
+ "node": ">=10.16.0"
74
+ }
75
+ },
76
+ "node_modules/bytes": {
77
+ "version": "3.1.2",
78
+ "license": "MIT",
79
+ "engines": {
80
+ "node": ">= 0.8"
81
+ }
82
+ },
83
+ "node_modules/call-bind-apply-helpers": {
84
+ "version": "1.0.2",
85
+ "license": "MIT",
86
+ "dependencies": {
87
+ "es-errors": "^1.3.0",
88
+ "function-bind": "^1.1.2"
89
+ },
90
+ "engines": {
91
+ "node": ">= 0.4"
92
+ }
93
+ },
94
+ "node_modules/call-bound": {
95
+ "version": "1.0.4",
96
+ "license": "MIT",
97
+ "dependencies": {
98
+ "call-bind-apply-helpers": "^1.0.2",
99
+ "get-intrinsic": "^1.3.0"
100
+ },
101
+ "engines": {
102
+ "node": ">= 0.4"
103
+ },
104
+ "funding": {
105
+ "url": "https://github.com/sponsors/ljharb"
106
+ }
107
+ },
108
+ "node_modules/concat-stream": {
109
+ "version": "1.6.2",
110
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
111
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
112
+ "engines": [
113
+ "node >= 0.8"
114
+ ],
115
+ "license": "MIT",
116
+ "dependencies": {
117
+ "buffer-from": "^1.0.0",
118
+ "inherits": "^2.0.3",
119
+ "readable-stream": "^2.2.2",
120
+ "typedarray": "^0.0.6"
121
+ }
122
+ },
123
+ "node_modules/content-disposition": {
124
+ "version": "0.5.4",
125
+ "license": "MIT",
126
+ "dependencies": {
127
+ "safe-buffer": "5.2.1"
128
+ },
129
+ "engines": {
130
+ "node": ">= 0.6"
131
+ }
132
+ },
133
+ "node_modules/content-type": {
134
+ "version": "1.0.5",
135
+ "license": "MIT",
136
+ "engines": {
137
+ "node": ">= 0.6"
138
+ }
139
+ },
140
+ "node_modules/cookie": {
141
+ "version": "0.7.1",
142
+ "license": "MIT",
143
+ "engines": {
144
+ "node": ">= 0.6"
145
+ }
146
+ },
147
+ "node_modules/cookie-signature": {
148
+ "version": "1.0.6",
149
+ "license": "MIT"
150
+ },
151
+ "node_modules/core-util-is": {
152
+ "version": "1.0.3",
153
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
154
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
155
+ "license": "MIT"
156
+ },
157
+ "node_modules/cors": {
158
+ "version": "2.8.5",
159
+ "license": "MIT",
160
+ "dependencies": {
161
+ "object-assign": "^4",
162
+ "vary": "^1"
163
+ },
164
+ "engines": {
165
+ "node": ">= 0.10"
166
+ }
167
+ },
168
+ "node_modules/debug": {
169
+ "version": "2.6.9",
170
+ "license": "MIT",
171
+ "dependencies": {
172
+ "ms": "2.0.0"
173
+ }
174
+ },
175
+ "node_modules/depd": {
176
+ "version": "2.0.0",
177
+ "license": "MIT",
178
+ "engines": {
179
+ "node": ">= 0.8"
180
+ }
181
+ },
182
+ "node_modules/destroy": {
183
+ "version": "1.2.0",
184
+ "license": "MIT",
185
+ "engines": {
186
+ "node": ">= 0.8",
187
+ "npm": "1.2.8000 || >= 1.4.16"
188
+ }
189
+ },
190
+ "node_modules/dunder-proto": {
191
+ "version": "1.0.1",
192
+ "license": "MIT",
193
+ "dependencies": {
194
+ "call-bind-apply-helpers": "^1.0.1",
195
+ "es-errors": "^1.3.0",
196
+ "gopd": "^1.2.0"
197
+ },
198
+ "engines": {
199
+ "node": ">= 0.4"
200
+ }
201
+ },
202
+ "node_modules/ee-first": {
203
+ "version": "1.1.1",
204
+ "license": "MIT"
205
+ },
206
+ "node_modules/encodeurl": {
207
+ "version": "2.0.0",
208
+ "license": "MIT",
209
+ "engines": {
210
+ "node": ">= 0.8"
211
+ }
212
+ },
213
+ "node_modules/es-define-property": {
214
+ "version": "1.0.1",
215
+ "license": "MIT",
216
+ "engines": {
217
+ "node": ">= 0.4"
218
+ }
219
+ },
220
+ "node_modules/es-errors": {
221
+ "version": "1.3.0",
222
+ "license": "MIT",
223
+ "engines": {
224
+ "node": ">= 0.4"
225
+ }
226
+ },
227
+ "node_modules/es-object-atoms": {
228
+ "version": "1.1.1",
229
+ "license": "MIT",
230
+ "dependencies": {
231
+ "es-errors": "^1.3.0"
232
+ },
233
+ "engines": {
234
+ "node": ">= 0.4"
235
+ }
236
+ },
237
+ "node_modules/escape-html": {
238
+ "version": "1.0.3",
239
+ "license": "MIT"
240
+ },
241
+ "node_modules/etag": {
242
+ "version": "1.8.1",
243
+ "license": "MIT",
244
+ "engines": {
245
+ "node": ">= 0.6"
246
+ }
247
+ },
248
+ "node_modules/express": {
249
+ "version": "4.21.2",
250
+ "license": "MIT",
251
+ "dependencies": {
252
+ "accepts": "~1.3.8",
253
+ "array-flatten": "1.1.1",
254
+ "body-parser": "1.20.3",
255
+ "content-disposition": "0.5.4",
256
+ "content-type": "~1.0.4",
257
+ "cookie": "0.7.1",
258
+ "cookie-signature": "1.0.6",
259
+ "debug": "2.6.9",
260
+ "depd": "2.0.0",
261
+ "encodeurl": "~2.0.0",
262
+ "escape-html": "~1.0.3",
263
+ "etag": "~1.8.1",
264
+ "finalhandler": "1.3.1",
265
+ "fresh": "0.5.2",
266
+ "http-errors": "2.0.0",
267
+ "merge-descriptors": "1.0.3",
268
+ "methods": "~1.1.2",
269
+ "on-finished": "2.4.1",
270
+ "parseurl": "~1.3.3",
271
+ "path-to-regexp": "0.1.12",
272
+ "proxy-addr": "~2.0.7",
273
+ "qs": "6.13.0",
274
+ "range-parser": "~1.2.1",
275
+ "safe-buffer": "5.2.1",
276
+ "send": "0.19.0",
277
+ "serve-static": "1.16.2",
278
+ "setprototypeof": "1.2.0",
279
+ "statuses": "2.0.1",
280
+ "type-is": "~1.6.18",
281
+ "utils-merge": "1.0.1",
282
+ "vary": "~1.1.2"
283
+ },
284
+ "engines": {
285
+ "node": ">= 0.10.0"
286
+ },
287
+ "funding": {
288
+ "type": "opencollective",
289
+ "url": "https://opencollective.com/express"
290
+ }
291
+ },
292
+ "node_modules/finalhandler": {
293
+ "version": "1.3.1",
294
+ "license": "MIT",
295
+ "dependencies": {
296
+ "debug": "2.6.9",
297
+ "encodeurl": "~2.0.0",
298
+ "escape-html": "~1.0.3",
299
+ "on-finished": "2.4.1",
300
+ "parseurl": "~1.3.3",
301
+ "statuses": "2.0.1",
302
+ "unpipe": "~1.0.0"
303
+ },
304
+ "engines": {
305
+ "node": ">= 0.8"
306
+ }
307
+ },
308
+ "node_modules/forwarded": {
309
+ "version": "0.2.0",
310
+ "license": "MIT",
311
+ "engines": {
312
+ "node": ">= 0.6"
313
+ }
314
+ },
315
+ "node_modules/fresh": {
316
+ "version": "0.5.2",
317
+ "license": "MIT",
318
+ "engines": {
319
+ "node": ">= 0.6"
320
+ }
321
+ },
322
+ "node_modules/function-bind": {
323
+ "version": "1.1.2",
324
+ "license": "MIT",
325
+ "funding": {
326
+ "url": "https://github.com/sponsors/ljharb"
327
+ }
328
+ },
329
+ "node_modules/get-intrinsic": {
330
+ "version": "1.3.0",
331
+ "license": "MIT",
332
+ "dependencies": {
333
+ "call-bind-apply-helpers": "^1.0.2",
334
+ "es-define-property": "^1.0.1",
335
+ "es-errors": "^1.3.0",
336
+ "es-object-atoms": "^1.1.1",
337
+ "function-bind": "^1.1.2",
338
+ "get-proto": "^1.0.1",
339
+ "gopd": "^1.2.0",
340
+ "has-symbols": "^1.1.0",
341
+ "hasown": "^2.0.2",
342
+ "math-intrinsics": "^1.1.0"
343
+ },
344
+ "engines": {
345
+ "node": ">= 0.4"
346
+ },
347
+ "funding": {
348
+ "url": "https://github.com/sponsors/ljharb"
349
+ }
350
+ },
351
+ "node_modules/get-proto": {
352
+ "version": "1.0.1",
353
+ "license": "MIT",
354
+ "dependencies": {
355
+ "dunder-proto": "^1.0.1",
356
+ "es-object-atoms": "^1.0.0"
357
+ },
358
+ "engines": {
359
+ "node": ">= 0.4"
360
+ }
361
+ },
362
+ "node_modules/gopd": {
363
+ "version": "1.2.0",
364
+ "license": "MIT",
365
+ "engines": {
366
+ "node": ">= 0.4"
367
+ },
368
+ "funding": {
369
+ "url": "https://github.com/sponsors/ljharb"
370
+ }
371
+ },
372
+ "node_modules/has-symbols": {
373
+ "version": "1.1.0",
374
+ "license": "MIT",
375
+ "engines": {
376
+ "node": ">= 0.4"
377
+ },
378
+ "funding": {
379
+ "url": "https://github.com/sponsors/ljharb"
380
+ }
381
+ },
382
+ "node_modules/hasown": {
383
+ "version": "2.0.2",
384
+ "license": "MIT",
385
+ "dependencies": {
386
+ "function-bind": "^1.1.2"
387
+ },
388
+ "engines": {
389
+ "node": ">= 0.4"
390
+ }
391
+ },
392
+ "node_modules/http-errors": {
393
+ "version": "2.0.0",
394
+ "license": "MIT",
395
+ "dependencies": {
396
+ "depd": "2.0.0",
397
+ "inherits": "2.0.4",
398
+ "setprototypeof": "1.2.0",
399
+ "statuses": "2.0.1",
400
+ "toidentifier": "1.0.1"
401
+ },
402
+ "engines": {
403
+ "node": ">= 0.8"
404
+ }
405
+ },
406
+ "node_modules/iconv-lite": {
407
+ "version": "0.4.24",
408
+ "license": "MIT",
409
+ "dependencies": {
410
+ "safer-buffer": ">= 2.1.2 < 3"
411
+ },
412
+ "engines": {
413
+ "node": ">=0.10.0"
414
+ }
415
+ },
416
+ "node_modules/inherits": {
417
+ "version": "2.0.4",
418
+ "license": "ISC"
419
+ },
420
+ "node_modules/ipaddr.js": {
421
+ "version": "1.9.1",
422
+ "license": "MIT",
423
+ "engines": {
424
+ "node": ">= 0.10"
425
+ }
426
+ },
427
+ "node_modules/isarray": {
428
+ "version": "1.0.0",
429
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
430
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
431
+ "license": "MIT"
432
+ },
433
+ "node_modules/math-intrinsics": {
434
+ "version": "1.1.0",
435
+ "license": "MIT",
436
+ "engines": {
437
+ "node": ">= 0.4"
438
+ }
439
+ },
440
+ "node_modules/media-typer": {
441
+ "version": "0.3.0",
442
+ "license": "MIT",
443
+ "engines": {
444
+ "node": ">= 0.6"
445
+ }
446
+ },
447
+ "node_modules/merge-descriptors": {
448
+ "version": "1.0.3",
449
+ "license": "MIT",
450
+ "funding": {
451
+ "url": "https://github.com/sponsors/sindresorhus"
452
+ }
453
+ },
454
+ "node_modules/methods": {
455
+ "version": "1.1.2",
456
+ "license": "MIT",
457
+ "engines": {
458
+ "node": ">= 0.6"
459
+ }
460
+ },
461
+ "node_modules/mime": {
462
+ "version": "1.6.0",
463
+ "license": "MIT",
464
+ "bin": {
465
+ "mime": "cli.js"
466
+ },
467
+ "engines": {
468
+ "node": ">=4"
469
+ }
470
+ },
471
+ "node_modules/mime-db": {
472
+ "version": "1.52.0",
473
+ "license": "MIT",
474
+ "engines": {
475
+ "node": ">= 0.6"
476
+ }
477
+ },
478
+ "node_modules/mime-types": {
479
+ "version": "2.1.35",
480
+ "license": "MIT",
481
+ "dependencies": {
482
+ "mime-db": "1.52.0"
483
+ },
484
+ "engines": {
485
+ "node": ">= 0.6"
486
+ }
487
+ },
488
+ "node_modules/minimist": {
489
+ "version": "1.2.8",
490
+ "license": "MIT",
491
+ "funding": {
492
+ "url": "https://github.com/sponsors/ljharb"
493
+ }
494
+ },
495
+ "node_modules/mkdirp": {
496
+ "version": "0.5.6",
497
+ "license": "MIT",
498
+ "dependencies": {
499
+ "minimist": "^1.2.6"
500
+ },
501
+ "bin": {
502
+ "mkdirp": "bin/cmd.js"
503
+ }
504
+ },
505
+ "node_modules/ms": {
506
+ "version": "2.0.0",
507
+ "license": "MIT"
508
+ },
509
+ "node_modules/multer": {
510
+ "version": "1.4.5-lts.2",
511
+ "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz",
512
+ "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
513
+ "deprecated": "Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version.",
514
+ "license": "MIT",
515
+ "dependencies": {
516
+ "append-field": "^1.0.0",
517
+ "busboy": "^1.0.0",
518
+ "concat-stream": "^1.5.2",
519
+ "mkdirp": "^0.5.4",
520
+ "object-assign": "^4.1.1",
521
+ "type-is": "^1.6.4",
522
+ "xtend": "^4.0.0"
523
+ },
524
+ "engines": {
525
+ "node": ">= 6.0.0"
526
+ }
527
+ },
528
+ "node_modules/negotiator": {
529
+ "version": "0.6.3",
530
+ "license": "MIT",
531
+ "engines": {
532
+ "node": ">= 0.6"
533
+ }
534
+ },
535
+ "node_modules/object-assign": {
536
+ "version": "4.1.1",
537
+ "license": "MIT",
538
+ "engines": {
539
+ "node": ">=0.10.0"
540
+ }
541
+ },
542
+ "node_modules/object-inspect": {
543
+ "version": "1.13.4",
544
+ "license": "MIT",
545
+ "engines": {
546
+ "node": ">= 0.4"
547
+ },
548
+ "funding": {
549
+ "url": "https://github.com/sponsors/ljharb"
550
+ }
551
+ },
552
+ "node_modules/on-finished": {
553
+ "version": "2.4.1",
554
+ "license": "MIT",
555
+ "dependencies": {
556
+ "ee-first": "1.1.1"
557
+ },
558
+ "engines": {
559
+ "node": ">= 0.8"
560
+ }
561
+ },
562
+ "node_modules/parseurl": {
563
+ "version": "1.3.3",
564
+ "license": "MIT",
565
+ "engines": {
566
+ "node": ">= 0.8"
567
+ }
568
+ },
569
+ "node_modules/path-to-regexp": {
570
+ "version": "0.1.12",
571
+ "license": "MIT"
572
+ },
573
+ "node_modules/process-nextick-args": {
574
+ "version": "2.0.1",
575
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
576
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
577
+ "license": "MIT"
578
+ },
579
+ "node_modules/proxy-addr": {
580
+ "version": "2.0.7",
581
+ "license": "MIT",
582
+ "dependencies": {
583
+ "forwarded": "0.2.0",
584
+ "ipaddr.js": "1.9.1"
585
+ },
586
+ "engines": {
587
+ "node": ">= 0.10"
588
+ }
589
+ },
590
+ "node_modules/qs": {
591
+ "version": "6.13.0",
592
+ "license": "BSD-3-Clause",
593
+ "dependencies": {
594
+ "side-channel": "^1.0.6"
595
+ },
596
+ "engines": {
597
+ "node": ">=0.6"
598
+ },
599
+ "funding": {
600
+ "url": "https://github.com/sponsors/ljharb"
601
+ }
602
+ },
603
+ "node_modules/range-parser": {
604
+ "version": "1.2.1",
605
+ "license": "MIT",
606
+ "engines": {
607
+ "node": ">= 0.6"
608
+ }
609
+ },
610
+ "node_modules/raw-body": {
611
+ "version": "2.5.2",
612
+ "license": "MIT",
613
+ "dependencies": {
614
+ "bytes": "3.1.2",
615
+ "http-errors": "2.0.0",
616
+ "iconv-lite": "0.4.24",
617
+ "unpipe": "1.0.0"
618
+ },
619
+ "engines": {
620
+ "node": ">= 0.8"
621
+ }
622
+ },
623
+ "node_modules/readable-stream": {
624
+ "version": "2.3.8",
625
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
626
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
627
+ "license": "MIT",
628
+ "dependencies": {
629
+ "core-util-is": "~1.0.0",
630
+ "inherits": "~2.0.3",
631
+ "isarray": "~1.0.0",
632
+ "process-nextick-args": "~2.0.0",
633
+ "safe-buffer": "~5.1.1",
634
+ "string_decoder": "~1.1.1",
635
+ "util-deprecate": "~1.0.1"
636
+ }
637
+ },
638
+ "node_modules/readable-stream/node_modules/safe-buffer": {
639
+ "version": "5.1.2",
640
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
641
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
642
+ "license": "MIT"
643
+ },
644
+ "node_modules/readable-stream/node_modules/string_decoder": {
645
+ "version": "1.1.1",
646
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
647
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
648
+ "license": "MIT",
649
+ "dependencies": {
650
+ "safe-buffer": "~5.1.0"
651
+ }
652
+ },
653
+ "node_modules/safe-buffer": {
654
+ "version": "5.2.1",
655
+ "funding": [
656
+ {
657
+ "type": "github",
658
+ "url": "https://github.com/sponsors/feross"
659
+ },
660
+ {
661
+ "type": "patreon",
662
+ "url": "https://www.patreon.com/feross"
663
+ },
664
+ {
665
+ "type": "consulting",
666
+ "url": "https://feross.org/support"
667
+ }
668
+ ],
669
+ "license": "MIT"
670
+ },
671
+ "node_modules/safer-buffer": {
672
+ "version": "2.1.2",
673
+ "license": "MIT"
674
+ },
675
+ "node_modules/send": {
676
+ "version": "0.19.0",
677
+ "license": "MIT",
678
+ "dependencies": {
679
+ "debug": "2.6.9",
680
+ "depd": "2.0.0",
681
+ "destroy": "1.2.0",
682
+ "encodeurl": "~1.0.2",
683
+ "escape-html": "~1.0.3",
684
+ "etag": "~1.8.1",
685
+ "fresh": "0.5.2",
686
+ "http-errors": "2.0.0",
687
+ "mime": "1.6.0",
688
+ "ms": "2.1.3",
689
+ "on-finished": "2.4.1",
690
+ "range-parser": "~1.2.1",
691
+ "statuses": "2.0.1"
692
+ },
693
+ "engines": {
694
+ "node": ">= 0.8.0"
695
+ }
696
+ },
697
+ "node_modules/send/node_modules/encodeurl": {
698
+ "version": "1.0.2",
699
+ "license": "MIT",
700
+ "engines": {
701
+ "node": ">= 0.8"
702
+ }
703
+ },
704
+ "node_modules/send/node_modules/ms": {
705
+ "version": "2.1.3",
706
+ "license": "MIT"
707
+ },
708
+ "node_modules/serve-static": {
709
+ "version": "1.16.2",
710
+ "license": "MIT",
711
+ "dependencies": {
712
+ "encodeurl": "~2.0.0",
713
+ "escape-html": "~1.0.3",
714
+ "parseurl": "~1.3.3",
715
+ "send": "0.19.0"
716
+ },
717
+ "engines": {
718
+ "node": ">= 0.8.0"
719
+ }
720
+ },
721
+ "node_modules/setprototypeof": {
722
+ "version": "1.2.0",
723
+ "license": "ISC"
724
+ },
725
+ "node_modules/side-channel": {
726
+ "version": "1.1.0",
727
+ "license": "MIT",
728
+ "dependencies": {
729
+ "es-errors": "^1.3.0",
730
+ "object-inspect": "^1.13.3",
731
+ "side-channel-list": "^1.0.0",
732
+ "side-channel-map": "^1.0.1",
733
+ "side-channel-weakmap": "^1.0.2"
734
+ },
735
+ "engines": {
736
+ "node": ">= 0.4"
737
+ },
738
+ "funding": {
739
+ "url": "https://github.com/sponsors/ljharb"
740
+ }
741
+ },
742
+ "node_modules/side-channel-list": {
743
+ "version": "1.0.0",
744
+ "license": "MIT",
745
+ "dependencies": {
746
+ "es-errors": "^1.3.0",
747
+ "object-inspect": "^1.13.3"
748
+ },
749
+ "engines": {
750
+ "node": ">= 0.4"
751
+ },
752
+ "funding": {
753
+ "url": "https://github.com/sponsors/ljharb"
754
+ }
755
+ },
756
+ "node_modules/side-channel-map": {
757
+ "version": "1.0.1",
758
+ "license": "MIT",
759
+ "dependencies": {
760
+ "call-bound": "^1.0.2",
761
+ "es-errors": "^1.3.0",
762
+ "get-intrinsic": "^1.2.5",
763
+ "object-inspect": "^1.13.3"
764
+ },
765
+ "engines": {
766
+ "node": ">= 0.4"
767
+ },
768
+ "funding": {
769
+ "url": "https://github.com/sponsors/ljharb"
770
+ }
771
+ },
772
+ "node_modules/side-channel-weakmap": {
773
+ "version": "1.0.2",
774
+ "license": "MIT",
775
+ "dependencies": {
776
+ "call-bound": "^1.0.2",
777
+ "es-errors": "^1.3.0",
778
+ "get-intrinsic": "^1.2.5",
779
+ "object-inspect": "^1.13.3",
780
+ "side-channel-map": "^1.0.1"
781
+ },
782
+ "engines": {
783
+ "node": ">= 0.4"
784
+ },
785
+ "funding": {
786
+ "url": "https://github.com/sponsors/ljharb"
787
+ }
788
+ },
789
+ "node_modules/statuses": {
790
+ "version": "2.0.1",
791
+ "license": "MIT",
792
+ "engines": {
793
+ "node": ">= 0.8"
794
+ }
795
+ },
796
+ "node_modules/streamsearch": {
797
+ "version": "1.1.0",
798
+ "engines": {
799
+ "node": ">=10.0.0"
800
+ }
801
+ },
802
+ "node_modules/toidentifier": {
803
+ "version": "1.0.1",
804
+ "license": "MIT",
805
+ "engines": {
806
+ "node": ">=0.6"
807
+ }
808
+ },
809
+ "node_modules/type-is": {
810
+ "version": "1.6.18",
811
+ "license": "MIT",
812
+ "dependencies": {
813
+ "media-typer": "0.3.0",
814
+ "mime-types": "~2.1.24"
815
+ },
816
+ "engines": {
817
+ "node": ">= 0.6"
818
+ }
819
+ },
820
+ "node_modules/typedarray": {
821
+ "version": "0.0.6",
822
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
823
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
824
+ "license": "MIT"
825
+ },
826
+ "node_modules/unpipe": {
827
+ "version": "1.0.0",
828
+ "license": "MIT",
829
+ "engines": {
830
+ "node": ">= 0.8"
831
+ }
832
+ },
833
+ "node_modules/util-deprecate": {
834
+ "version": "1.0.2",
835
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
836
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
837
+ "license": "MIT"
838
+ },
839
+ "node_modules/utils-merge": {
840
+ "version": "1.0.1",
841
+ "license": "MIT",
842
+ "engines": {
843
+ "node": ">= 0.4.0"
844
+ }
845
+ },
846
+ "node_modules/vary": {
847
+ "version": "1.1.2",
848
+ "license": "MIT",
849
+ "engines": {
850
+ "node": ">= 0.8"
851
+ }
852
+ },
853
+ "node_modules/xtend": {
854
+ "version": "4.0.2",
855
+ "license": "MIT",
856
+ "engines": {
857
+ "node": ">=0.4"
858
+ }
859
+ }
860
+ }
861
+ }
package.json CHANGED
@@ -5,32 +5,30 @@
5
  "main": "server.js",
6
  "scripts": {
7
  "start": "node server.js",
8
- "dev": "node server.js"
 
 
9
  },
10
  "dependencies": {
11
  "express": "^4.18.2",
12
- "multer": "^2.0.0-rc.4",
13
  "cors": "^2.8.5",
14
  "@tensorflow/tfjs": "^4.11.0",
15
  "@tensorflow/tfjs-backend-wasm": "~4.11.0",
16
- "@tensorflow/tfjs-backend-webgl": "~4.11.0",
17
  "@tensorflow/tfjs-backend-cpu": "~4.11.0",
18
  "@upscalerjs/esrgan-slim": "1.0.0-beta.12",
19
  "@upscalerjs/esrgan-medium": "1.0.0-beta.13",
20
  "@upscalerjs/esrgan-thick": "1.0.0-beta.16",
21
  "upscaler": "1.0.0-beta.19",
22
- "canvas": "^2.11.2",
23
- "sharp": "^0.32.6"
24
  },
25
  "engines": {
26
  "node": ">=18.0.0"
27
  },
28
  "keywords": [
29
- "ai",
30
- "upscaler",
31
- "tensorflow",
32
  "image-processing",
33
- "api"
34
  ],
35
  "author": "Upscale2 Team",
36
  "license": "MIT"
 
5
  "main": "server.js",
6
  "scripts": {
7
  "start": "node server.js",
8
+ "dev": "node server.js",
9
+ "test": "node test-local.js",
10
+ "start-simple": "node server-simple.js"
11
  },
12
  "dependencies": {
13
  "express": "^4.18.2",
14
+ "multer": "^1.4.5-lts.1",
15
  "cors": "^2.8.5",
16
  "@tensorflow/tfjs": "^4.11.0",
17
  "@tensorflow/tfjs-backend-wasm": "~4.11.0",
 
18
  "@tensorflow/tfjs-backend-cpu": "~4.11.0",
19
  "@upscalerjs/esrgan-slim": "1.0.0-beta.12",
20
  "@upscalerjs/esrgan-medium": "1.0.0-beta.13",
21
  "@upscalerjs/esrgan-thick": "1.0.0-beta.16",
22
  "upscaler": "1.0.0-beta.19",
23
+ "canvas": "^2.11.2"
 
24
  },
25
  "engines": {
26
  "node": ">=18.0.0"
27
  },
28
  "keywords": [
29
+ "api",
 
 
30
  "image-processing",
31
+ "placeholder"
32
  ],
33
  "author": "Upscale2 Team",
34
  "license": "MIT"
server-simple.js ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const multer = require('multer');
3
+ const cors = require('cors');
4
+
5
+ const app = express();
6
+ const PORT = process.env.PORT || 7860;
7
+
8
+ // Middleware
9
+ app.use(cors());
10
+ app.use(express.json({ limit: '50mb' }));
11
+ app.use(express.urlencoded({ extended: true, limit: '50mb' }));
12
+
13
+ // Serve static files from public directory
14
+ app.use(express.static('public'));
15
+
16
+ // Configure multer for file uploads
17
+ const upload = multer({
18
+ storage: multer.memoryStorage(),
19
+ limits: {
20
+ fileSize: 10 * 1024 * 1024, // 10MB limit
21
+ },
22
+ fileFilter: (req, file, cb) => {
23
+ if (file.mimetype.startsWith('image/')) {
24
+ cb(null, true);
25
+ } else {
26
+ cb(new Error('Only image files are allowed'), false);
27
+ }
28
+ }
29
+ });
30
+
31
+ // Health check endpoint
32
+ app.get('/', (req, res) => {
33
+ res.json({
34
+ status: 'ok',
35
+ message: 'AI Image Upscaler API (Simple Mode)',
36
+ version: '1.0.0',
37
+ note: 'This is a simplified version. Full AI upscaling requires TensorFlow.js dependencies.',
38
+ endpoints: {
39
+ upscale: 'POST /upscale',
40
+ health: 'GET /'
41
+ }
42
+ });
43
+ });
44
+
45
+ // Simplified upscale endpoint (placeholder)
46
+ app.post('/upscale', upload.single('image'), async (req, res) => {
47
+ try {
48
+ if (!req.file) {
49
+ return res.status(400).json({ error: 'No image file provided' });
50
+ }
51
+
52
+ const { scale = 2, modelType = 'esrgan-slim', patchSize = 128, padding = 8 } = req.body;
53
+
54
+ console.log(`Received upscale request: ${req.file.originalname}, scale: ${scale}x, model: ${modelType}`);
55
+
56
+ // For now, return the original image as base64 (placeholder)
57
+ const originalImageBase64 = `data:${req.file.mimetype};base64,${req.file.buffer.toString('base64')}`;
58
+
59
+ // Simulate processing time
60
+ await new Promise(resolve => setTimeout(resolve, 1000));
61
+
62
+ res.json({
63
+ success: true,
64
+ result: originalImageBase64,
65
+ metadata: {
66
+ scale: parseInt(scale),
67
+ modelType: modelType,
68
+ patchSize: parseInt(patchSize),
69
+ padding: parseInt(padding),
70
+ processingTime: 1000,
71
+ backend: 'placeholder',
72
+ note: 'This is a placeholder response. Install TensorFlow.js dependencies for actual AI upscaling.'
73
+ }
74
+ });
75
+
76
+ } catch (error) {
77
+ console.error('Upscaling error:', error);
78
+ res.status(500).json({
79
+ error: 'Failed to process image',
80
+ message: error.message
81
+ });
82
+ }
83
+ });
84
+
85
+ // Error handling middleware
86
+ app.use((error, req, res, next) => {
87
+ if (error instanceof multer.MulterError) {
88
+ if (error.code === 'LIMIT_FILE_SIZE') {
89
+ return res.status(400).json({ error: 'File too large. Maximum size is 10MB' });
90
+ }
91
+ }
92
+
93
+ console.error('Unhandled error:', error);
94
+ res.status(500).json({ error: 'Internal server error' });
95
+ });
96
+
97
+ // Start server
98
+ app.listen(PORT, '0.0.0.0', () => {
99
+ console.log(`πŸš€ Simple Upscaler API server running on port ${PORT}`);
100
+ console.log(`πŸ“ Note: This is a simplified version without AI processing`);
101
+ console.log(`πŸ”— Health check: http://localhost:${PORT}/`);
102
+ console.log(`🌐 Web interface: http://localhost:${PORT}/index.html`);
103
+ });
104
+
105
+ // Handle graceful shutdown
106
+ process.on('SIGTERM', () => {
107
+ console.log('Received SIGTERM, shutting down gracefully...');
108
+ process.exit(0);
109
+ });
server.js CHANGED
@@ -1,11 +1,15 @@
1
  const express = require('express');
2
  const multer = require('multer');
3
  const cors = require('cors');
4
- const sharp = require('sharp');
5
  const tf = require('@tensorflow/tfjs');
6
  require('@tensorflow/tfjs-backend-wasm');
7
  require('@tensorflow/tfjs-backend-cpu');
8
- const Upscaler = require('upscaler').default;
 
 
 
 
 
9
 
10
  const app = express();
11
  const PORT = process.env.PORT || 7860;
@@ -95,10 +99,16 @@ async function getModelForScaleAndType(scale, modelType) {
95
  async function initializeUpscaler(scale = 2, modelType = 'esrgan-slim') {
96
  try {
97
  console.log(`Initializing upscaler with scale ${scale}x and model ${modelType}...`);
98
-
 
 
 
 
 
 
99
  const model = await getModelForScaleAndType(scale, modelType);
100
  upscalerInstance = new Upscaler({ model });
101
-
102
  console.log('Upscaler initialized successfully');
103
  return upscalerInstance;
104
  } catch (error) {
 
1
  const express = require('express');
2
  const multer = require('multer');
3
  const cors = require('cors');
 
4
  const tf = require('@tensorflow/tfjs');
5
  require('@tensorflow/tfjs-backend-wasm');
6
  require('@tensorflow/tfjs-backend-cpu');
7
+
8
+ // Setup Canvas for Node.js environment
9
+ const { createCanvas, loadImage } = require('canvas');
10
+
11
+ // Import Upscaler using dynamic import
12
+ let Upscaler;
13
 
14
  const app = express();
15
  const PORT = process.env.PORT || 7860;
 
99
  async function initializeUpscaler(scale = 2, modelType = 'esrgan-slim') {
100
  try {
101
  console.log(`Initializing upscaler with scale ${scale}x and model ${modelType}...`);
102
+
103
+ // Dynamic import of Upscaler
104
+ if (!Upscaler) {
105
+ const upscalerModule = await import('upscaler');
106
+ Upscaler = upscalerModule.default;
107
+ }
108
+
109
  const model = await getModelForScaleAndType(scale, modelType);
110
  upscalerInstance = new Upscaler({ model });
111
+
112
  console.log('Upscaler initialized successfully');
113
  return upscalerInstance;
114
  } catch (error) {
test-local.js ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Simple test script to verify basic functionality without full dependencies
2
+ const express = require('express');
3
+ const multer = require('multer');
4
+ const cors = require('cors');
5
+
6
+ const app = express();
7
+ const PORT = process.env.PORT || 7860;
8
+
9
+ // Middleware
10
+ app.use(cors());
11
+ app.use(express.json({ limit: '50mb' }));
12
+ app.use(express.urlencoded({ extended: true, limit: '50mb' }));
13
+ app.use(express.static('public'));
14
+
15
+ // Configure multer for file uploads
16
+ const upload = multer({
17
+ storage: multer.memoryStorage(),
18
+ limits: {
19
+ fileSize: 10 * 1024 * 1024, // 10MB limit
20
+ },
21
+ fileFilter: (req, file, cb) => {
22
+ if (file.mimetype.startsWith('image/')) {
23
+ cb(null, true);
24
+ } else {
25
+ cb(new Error('Only image files are allowed'), false);
26
+ }
27
+ }
28
+ });
29
+
30
+ // Health check endpoint
31
+ app.get('/', (req, res) => {
32
+ res.json({
33
+ status: 'ok',
34
+ message: 'AI Image Upscaler API (Test Mode)',
35
+ version: '1.0.0',
36
+ note: 'This is a test version. Canvas and TensorFlow.js dependencies are required for full functionality.',
37
+ endpoints: {
38
+ upscale: 'POST /upscale',
39
+ health: 'GET /'
40
+ }
41
+ });
42
+ });
43
+
44
+ // Test upscale endpoint
45
+ app.post('/upscale', upload.single('image'), async (req, res) => {
46
+ try {
47
+ if (!req.file) {
48
+ return res.status(400).json({ error: 'No image file provided' });
49
+ }
50
+
51
+ const { scale = 2, modelType = 'esrgan-slim', patchSize = 128, padding = 8 } = req.body;
52
+
53
+ console.log(`Test upscale request: ${req.file.originalname}, scale: ${scale}x, model: ${modelType}`);
54
+
55
+ // Return the original image as base64 (test mode)
56
+ const originalImageBase64 = `data:${req.file.mimetype};base64,${req.file.buffer.toString('base64')}`;
57
+
58
+ // Simulate processing time
59
+ await new Promise(resolve => setTimeout(resolve, 500));
60
+
61
+ res.json({
62
+ success: true,
63
+ result: originalImageBase64,
64
+ metadata: {
65
+ scale: parseInt(scale),
66
+ modelType: modelType,
67
+ patchSize: parseInt(patchSize),
68
+ padding: parseInt(padding),
69
+ processingTime: 500,
70
+ backend: 'test-mode',
71
+ note: 'This is a test response. Original image returned without upscaling.'
72
+ }
73
+ });
74
+
75
+ } catch (error) {
76
+ console.error('Test upscaling error:', error);
77
+ res.status(500).json({
78
+ error: 'Failed to process image',
79
+ message: error.message
80
+ });
81
+ }
82
+ });
83
+
84
+ // Error handling middleware
85
+ app.use((error, req, res, next) => {
86
+ if (error instanceof multer.MulterError) {
87
+ if (error.code === 'LIMIT_FILE_SIZE') {
88
+ return res.status(400).json({ error: 'File too large. Maximum size is 10MB' });
89
+ }
90
+ }
91
+
92
+ console.error('Unhandled error:', error);
93
+ res.status(500).json({ error: 'Internal server error' });
94
+ });
95
+
96
+ // Start server
97
+ app.listen(PORT, '0.0.0.0', () => {
98
+ console.log(`πŸ§ͺ Test Upscaler API server running on port ${PORT}`);
99
+ console.log(`πŸ“ Note: This is a test version without AI processing`);
100
+ console.log(`πŸ”— Health check: http://localhost:${PORT}/`);
101
+ console.log(`🌐 Web interface: http://localhost:${PORT}/index.html`);
102
+ });
103
+
104
+ // Handle graceful shutdown
105
+ process.on('SIGTERM', () => {
106
+ console.log('Received SIGTERM, shutting down gracefully...');
107
+ process.exit(0);
108
+ });