snapio-mock-camera 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/_index.js ADDED
@@ -0,0 +1,110 @@
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const path = require('path');
4
+ const app = express();
5
+ const fs = require('fs');
6
+ const { Observable, Subject } = require('rxjs');
7
+ const { take } = require('rxjs/operators')
8
+ const { createCanvas, loadImage } = require('canvas');
9
+ const octopus = require('./octopus')
10
+ const printer = require('./printer')
11
+
12
+ app.use(cors());
13
+
14
+ let takeImage = {};
15
+
16
+ const IMAGE_SRC = 'public/960x640.jpg';
17
+
18
+ app.get('/liveViewImage', (req, res) => {
19
+ let s = fs.createReadStream(IMAGE_SRC);
20
+ s.on('open', function () {
21
+ res.set('Content-Type', 'image/jpeg');
22
+ s.pipe(res);
23
+ });
24
+ s.on('error', function () {
25
+ res.set('Content-Type', 'text/plain');
26
+ res.status(404).end('Not found');
27
+ });
28
+ });
29
+ app.get('/image', (req, res) => {
30
+ setTimeout(() => {
31
+ const latest = Math.max.apply(Math, Object.keys(takeImage));
32
+ if (!takeImage[latest]) return;
33
+ const { width, height, $ } = takeImage[latest];
34
+ const canvas = createCanvas(width, height)
35
+ const ctx = canvas.getContext('2d');
36
+ $.pipe(
37
+ take(1)
38
+ ).subscribe(value => {
39
+ console.log(new Date().toISOString(), 'image taken');
40
+ loadImage(IMAGE_SRC).then(img => {
41
+ const nRatio = img.naturalWidth / img.naturalHeight;
42
+ const sRatio = width / height;
43
+ if (nRatio < sRatio) {
44
+ const scale = width / img.naturalWidth;
45
+ ctx.drawImage(img,
46
+ 0, (img.naturalHeight - height / scale) / 2, img.naturalWidth, height / scale,
47
+ 0, 0, width, height);
48
+ } else {
49
+ const scale = height / img.naturalHeight;
50
+ ctx.drawImage(img,
51
+ (img.naturalWidth - width / scale) / 2, 0, width / scale, img.naturalHeight,
52
+ 0, 0, width, height);
53
+ }
54
+ res.set('Content-Type', 'image/jpeg');
55
+ canvas.createJPEGStream().pipe(res)
56
+ })
57
+ delete takeImage[latest];
58
+ })
59
+ }, 200)
60
+ });
61
+ app.post('/startLiveView', (req, res) => {
62
+ res.status(200).end();
63
+ })
64
+ app.post('/stopLiveView', (req, res) => {
65
+ res.status(200).end();
66
+ })
67
+ app.post('/shoot', (req, res) => {
68
+ const latest = Math.max.apply(Math, Object.keys(takeImage));
69
+ if (takeImage[latest])
70
+ takeImage[latest].$.next(true);
71
+ res.status(200).end();
72
+ })
73
+ app.post('/createTimer', (req, res) => {
74
+ const params = req.query;
75
+ const { width, height, seconds } = params;
76
+ const intSeconds = seconds ? parseInt(seconds) : 0;
77
+ console.log(new Date().toISOString(), `${intSeconds} secs`);
78
+ const now = new Date().getTime();
79
+ takeImage[now] = {
80
+ width: parseInt(width),
81
+ height: parseInt(height),
82
+ $: new Subject()
83
+ };
84
+ if (intSeconds > 0) {
85
+ const timeout = setTimeout(_ => {
86
+ console.log(new Date().toISOString(), 'timeout');
87
+ if (takeImage[now])
88
+ takeImage[now].$.next(true);
89
+ }, intSeconds * 1000);
90
+ }
91
+ res.status(200).end();
92
+ })
93
+ app.post('/setProperty', (req, res) => {
94
+ res.status(200).end();
95
+ })
96
+ app.get('/health', (req, res) => {
97
+ res.setHeader('content-type', 'application/json')
98
+ res.send({
99
+ status: 'pass',
100
+ details: {
101
+ isSDKLoaded: true,
102
+ isSessionOpen: true,
103
+ },
104
+ version: '999.9'
105
+ })
106
+ })
107
+
108
+ app.listen(40084, function () {
109
+ console.log('Camera listening on http://localhost:40084/');
110
+ });
package/camera.js ADDED
@@ -0,0 +1,364 @@
1
+ // Import necessary modules
2
+ const express = require('express');
3
+ const cors = require('cors');
4
+ const { spawn } = require('child_process'); // To run external commands like ffmpeg
5
+ const http = require('http'); // Required for HTTP server
6
+ const { Observable, Subject, BehaviorSubject } = require('rxjs');
7
+ const { take, takeUntil, filter, switchMap, first, throttleTime, takeWhile } = require('rxjs/operators')
8
+ const { createCanvas, loadImage } = require('canvas');
9
+
10
+ // Initialize Express application
11
+ const app = express();
12
+ app.use(cors())
13
+ const port = process.env['SNAPIO_CAMERA_MANAGER_PORT'] ? Number(process.env['SNAPIO_CAMERA_MANAGER_PORT']) : 40084;
14
+
15
+ // Create an HTTP server and attach Express app
16
+ const server = http.createServer(app);
17
+
18
+ let ffmpegProcess = null; // Variable to hold the ffmpeg process
19
+ let liveView = new BehaviorSubject(null);
20
+ let takeImage = {};
21
+ // --- MJPEG Stream Endpoint ---
22
+ app.get('/liveViewImage', (req, res) => {
23
+ console.log('Client connected to /liveViewImage endpoint (multipart/x-mixed-replace).');
24
+ const close$ = new Subject()
25
+ let isHeadersSent = false;
26
+ liveView.pipe(
27
+ throttleTime(1000/8),
28
+ filter(data => data != null),
29
+ takeUntil(close$)
30
+ ).subscribe({
31
+ next: (data) => {
32
+ if (!isHeadersSent) {
33
+ res.writeHead(200, {
34
+ 'Content-Type': 'multipart/x-mixed-replace; boundary=--myboundary',
35
+ 'Cache-Control': 'no-cache',
36
+ 'Connection': 'keep-alive',
37
+ });
38
+ isHeadersSent = true
39
+ }
40
+ res.write('--myboundary\r\n');
41
+ res.write('Content-Type: image/jpeg\r\n');
42
+ res.write('Content-Length: ' + data.length + '\r\n');
43
+ res.write('\r\n');
44
+ res.write(data); // Send raw MJPEG frame data
45
+ res.write('\r\n');
46
+ },
47
+ error: (err) => {
48
+ console.log(`Live view subscription error: ${ err }`)
49
+ res.status(500).send(`Error in ffmpeg process: ${ err }`)
50
+ res.end()
51
+ ffmpegProcess?.kill('SIGKILL')
52
+ ffmpegProcess = null;
53
+ },
54
+ complete: () => {
55
+ console.log('Live view subscription complete')
56
+ res.end('--myboundary--\r\n'); // End the multipart stream gracefully
57
+ }
58
+ })
59
+ // Handle client disconnection from the HTTP stream
60
+ req.on('close', () => {
61
+ console.log('Client disconnected from /liveViewImage. Killing ffmpeg process.');
62
+ close$.next()
63
+ });
64
+
65
+ req.on('error', (err) => {
66
+ console.error('Request error on /liveViewImage:', err);
67
+ close$.next()
68
+ });
69
+ });
70
+ app.get('/image', (req, res) => {
71
+ setTimeout(() => {
72
+ const latest = Math.max.apply(Math, Object.keys(takeImage));
73
+ if (!takeImage[latest]) return;
74
+ const { width, height, $ } = takeImage[latest];
75
+ const canvas = createCanvas(width, height)
76
+ const ctx = canvas.getContext('2d');
77
+ $.pipe(
78
+ take(1),
79
+ switchMap(() => liveView.pipe(
80
+ takeWhile(data => data != null)
81
+ )),
82
+ ).subscribe(async data => {
83
+ console.log(new Date().toISOString(), 'image taken');
84
+ const { w, h } = jpegProps(data);
85
+ const nRatio = w / h;
86
+ const sRatio = width / height;
87
+ const img = await loadImage(data)
88
+ if (nRatio < sRatio) {
89
+ const scale = width / w;
90
+ ctx.drawImage(img,
91
+ 0, (h - height / scale) / 2, w, height / scale,
92
+ 0, 0, width, height);
93
+ } else {
94
+ const scale = height / h;
95
+ ctx.drawImage(img,
96
+ (w - width / scale) / 2, 0, width / scale, h,
97
+ 0, 0, width, height);
98
+ }
99
+ res.set('Content-Type', 'image/jpeg');
100
+ canvas.createJPEGStream().pipe(res)
101
+ delete takeImage[latest];
102
+ })
103
+ }, 200)
104
+ })
105
+ app.post('/shoot', (req, res) => {
106
+ const latest = Math.max.apply(Math, Object.keys(takeImage));
107
+ if (takeImage[latest])
108
+ takeImage[latest].$.next(true);
109
+ res.status(200).end();
110
+ })
111
+ app.post('/createTimer', (req, res) => {
112
+ const params = req.query;
113
+ const { width, height, seconds } = params;
114
+ const intSeconds = seconds ? parseInt(seconds) : 0;
115
+ console.log(new Date().toISOString(), `${intSeconds} secs`);
116
+ const now = new Date().getTime();
117
+ takeImage[now] = {
118
+ width: parseInt(width),
119
+ height: parseInt(height),
120
+ $: new Subject()
121
+ };
122
+ if (intSeconds > 0) {
123
+ const timeout = setTimeout(_ => {
124
+ console.log(new Date().toISOString(), 'timeout');
125
+ if (takeImage[now])
126
+ takeImage[now].$.next(true);
127
+ }, intSeconds * 1000);
128
+ }
129
+ res.status(200).end();
130
+ })
131
+
132
+ app.post('/startLiveView', (req, res) => {
133
+ if (ffmpegProcess) {
134
+ console.log('ffmpeg is already running')
135
+ res.status(200).end();
136
+ return;
137
+ }
138
+ try {
139
+ liveView = new BehaviorSubject(null);
140
+ if (process.platform == 'darwin') {
141
+ // ffmpeg -y -f avfoundation -r 8 -i 0 -s 960x540 -f mjpeg -
142
+ // ffmpegProcess = spawn('ffmpeg', [
143
+ // '-y', '-f', 'avfoundation', '-r', '8', '-i', '0', '-s', '960x540', '-f', 'mjpeg', '-'
144
+ // ]);
145
+ // ffmpeg -y -f avfoundation -r 7.5 -i 0 -s 1280x720 -f mjpeg -
146
+ ffmpegProcess = spawn('ffmpeg', [
147
+ '-y', '-f', 'avfoundation', '-r', '15', '-i', '0', '-s', '960x720', '-f', 'mjpeg', '-'
148
+ ]);
149
+ } else if (process.platform == 'win32') {
150
+ ffmpegProcess = spawn('ffmpeg', [
151
+ '-y',
152
+ '-f', 'vfwcap',
153
+ '-i', '0',
154
+ // '-q:v', '3', // Video quality (lower is better, 1-31)
155
+ '-r', '8', // Frame rate (frames per second)
156
+ // '-s', '640x480', // Resolution
157
+ '-f', 'mjpeg',
158
+ '-' // Output to stdout
159
+ ]);
160
+ } else {
161
+ throw new Error('Unsupported platform: ' + process.platform);
162
+ }
163
+ ffmpegProcess.stdout.on('data', data => {
164
+ liveView.next(data);
165
+ });
166
+ // Handle ffmpeg process errors
167
+ ffmpegProcess.stderr.on('data', data => {
168
+ // the standard output always comes out from here, ignore
169
+ // console.error(`ffmpeg stderr: ${data}`);
170
+ // liveView.error(data)
171
+ // liveView.complete()
172
+ });
173
+ // Handle ffmpeg process close
174
+ ffmpegProcess.on('close', code => {
175
+ console.log(`ffmpeg process exited with code ${code}. Closing stream.`);
176
+ liveView.complete()
177
+ ffmpegProcess = null; // Clear the process reference
178
+ });
179
+ // Handle ffmpeg process errors (e.g., ffmpeg not found)
180
+ ffmpegProcess.on('error', err => {
181
+ console.error('Failed to start ffmpeg process:', err);
182
+ liveView.error(err)
183
+ liveView.complete()
184
+ ffmpegProcess = null;
185
+ });
186
+ res.status(200).end();
187
+ } catch (error) {
188
+ console.error('Error spawning ffmpeg:', error);
189
+ liveView.error(err)
190
+ liveView.complete()
191
+ ffmpegProcess = null
192
+ res.status(500).end()
193
+ }
194
+ })
195
+ app.post('/stopLiveView', (req, res) => {
196
+ if (ffmpegProcess) {
197
+ console.log('stopLiveView, killing ffmpeg')
198
+ ffmpegProcess.kill('SIGKILL');
199
+ ffmpegProcess = null;
200
+ liveView.complete();
201
+ res.status(200).end();
202
+ } else {
203
+ console.log('ffmpeg is not running')
204
+ res.status(200).end();
205
+ }
206
+ })
207
+ app.post('/setProperty', (req, res) => {
208
+ res.status(200).end();
209
+ })
210
+ app.get('/health', (req, res) => {
211
+ res.setHeader('content-type', 'application/json')
212
+ res.send({
213
+ status: 'pass',
214
+ details: {
215
+ isSDKLoaded: true,
216
+ isSessionOpen: true,
217
+ },
218
+ version: '999.9'
219
+ })
220
+ })
221
+
222
+ // --- Express Server Logic ---
223
+
224
+ // This doesn't work without calling startLiveView first
225
+ app.get('/', (req, res) => {
226
+ res.send(`
227
+ <!DOCTYPE html>
228
+ <html lang="en">
229
+ <head>
230
+ <meta charset="UTF-8">
231
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
232
+ <title>Live Webcam Stream (MJPEG)</title>
233
+ <script src="https://cdn.tailwindcss.com"></script>
234
+ <style>
235
+ body {
236
+ font-family: 'Inter', sans-serif;
237
+ background-color: #f0f2f5;
238
+ display: flex;
239
+ justify-content: center;
240
+ align-items: center;
241
+ min-height: 100vh;
242
+ margin: 0;
243
+ }
244
+ .container {
245
+ background-color: #ffffff;
246
+ border-radius: 10px;
247
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
248
+ padding: 2rem;
249
+ text-align: center;
250
+ width: 90%;
251
+ max-width: 800px;
252
+ }
253
+ #videoStream {
254
+ width: 100%;
255
+ max-width: 720px;
256
+ height: auto;
257
+ border-radius: 8px;
258
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
259
+ margin-top: 1rem;
260
+ background-color: #000;
261
+ display: block; /* Ensure it takes up full width */
262
+ margin-left: auto;
263
+ margin-right: auto;
264
+ }
265
+ .status-message {
266
+ margin-top: 1rem;
267
+ font-size: 1rem;
268
+ color: #555;
269
+ }
270
+ .error-message {
271
+ color: #e53e3e;
272
+ font-weight: bold;
273
+ }
274
+ </style>
275
+ </head>
276
+ <body>
277
+ <div class="container flex flex-col items-center">
278
+ <h1 class="text-3xl font-bold text-gray-800 mb-4">Live Webcam Stream (MJPEG)</h1>
279
+ <!-- The img tag's src points directly to the MJPEG stream endpoint -->
280
+ <img id="videoStream" class="rounded-lg" src="/liveViewImage" alt="Live Webcam Stream">
281
+ <p id="status" class="status-message">Loading video stream...</p>
282
+ <button id="refreshButton" class="mt-4 px-6 py-2 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75">
283
+ Refresh Stream
284
+ </button>
285
+ </div>
286
+
287
+ <script>
288
+ const videoStream = document.getElementById('videoStream');
289
+ const statusElement = document.getElementById('status');
290
+ const refreshButton = document.getElementById('refreshButton');
291
+
292
+ // Basic status update for initial load
293
+ videoStream.onload = () => {
294
+ statusElement.textContent = 'Live Streaming...';
295
+ };
296
+
297
+ videoStream.onerror = () => {
298
+ statusElement.className = 'status-message error-message';
299
+ statusElement.textContent = 'Failed to load stream. Ensure the server is running and FFmpeg is configured correctly.';
300
+ };
301
+
302
+ refreshButton.addEventListener('click', () => {
303
+ // Force reload the image source to re-establish the stream
304
+ const currentSrc = videoStream.src;
305
+ videoStream.src = ''; // Clear src to force reload
306
+ videoStream.src = currentSrc.split('?')[0] + '?' + new Date().getTime(); // Add cache busting
307
+ statusElement.className = 'status-message';
308
+ statusElement.textContent = 'Attempting to reconnect...';
309
+ });
310
+
311
+ // Initial check for stream status (optional, for faster feedback if stream fails immediately)
312
+ // This doesn't strictly monitor the stream, but can catch initial connection issues.
313
+ setTimeout(() => {
314
+ if (!videoStream.complete && videoStream.naturalWidth === 0) {
315
+ statusElement.className = 'status-message error-message';
316
+ statusElement.textContent = 'Stream not loading. Check server logs and FFmpeg setup.';
317
+ }
318
+ }, 5000); // Check after 5 seconds
319
+ </script>
320
+ </body>
321
+ </html>
322
+ `);
323
+ });
324
+
325
+ // Start the HTTP server
326
+ server.listen(port, () => {
327
+ console.log(`Webcam streaming server listening at http://localhost:${port}`);
328
+ });
329
+
330
+ process.on('unhandledRejection', (reason, promise) => {
331
+ console.error('Unhandled Rejection at:', promise, 'reason:', reason);
332
+ });
333
+
334
+ process.on('uncaughtException', (error) => {
335
+ console.error('Uncaught Exception:', error);
336
+ if (ffmpegProcess) {
337
+ ffmpegProcess.kill('SIGKILL');
338
+ console.log('Killed ffmpeg process due to uncaught exception.');
339
+ }
340
+ process.exit(1); // Exit process with failure
341
+ });
342
+
343
+ function jpegProps(data) {
344
+ var off = 0;
345
+ while(off<data.length) {
346
+ while(data[off]==0xff) off++;
347
+ var mrkr = data[off]; off++;
348
+
349
+ if(mrkr==0xd8) continue; // SOI
350
+ if(mrkr==0xd9) break; // EOI
351
+ if(0xd0<=mrkr && mrkr<=0xd7) continue;
352
+ if(mrkr==0x01) continue; // TEM
353
+
354
+ var len = (data[off]<<8) | data[off+1]; off+=2;
355
+
356
+ if(mrkr==0xc0) return {
357
+ bpc : data[off], // precission (bits per channel)
358
+ h : (data[off+1]<<8) | data[off+2],
359
+ w : (data[off+3]<<8) | data[off+4],
360
+ cps : data[off+5] // number of color components
361
+ }
362
+ off+=len-2;
363
+ }
364
+ }
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+
2
+ const octopus = require('./octopus')
3
+ const printer = require('./printer')
4
+ const camera = require('./camera')
package/octopus.js ADDED
@@ -0,0 +1,93 @@
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const app = express()
4
+
5
+ app.use(cors())
6
+
7
+ app.post('/init', (req, res) => {
8
+ res.setHeader('content-type', 'application/json')
9
+ res.send({
10
+ data: {
11
+ deviceId: 12345678,
12
+ isBlacklistOutdated: true,
13
+ }
14
+ })
15
+ })
16
+
17
+ let count = 0
18
+ app.post('/payments', (req, res) => {
19
+ setTimeout(() => {
20
+ res.setHeader('content-type', 'application/json')
21
+ res.send({
22
+ error: {
23
+ code: -100,
24
+ }
25
+ })
26
+ // if (count++ % 3 == 2) {
27
+ // res.send({
28
+ // data: {
29
+ // timestamp: Math.floor(Date.now() / 1000),
30
+ // deviceId: 12345678,
31
+ // receiptNo: 'qwertyasdf',
32
+ // cardId: 12345678,
33
+ // deductAmount: 60,
34
+ // remainingValue: 123,
35
+ // octopusType: 1,
36
+ // lastAddValueInfo: {
37
+ // date: '2024-11-12',
38
+ // type: 1,
39
+ // },
40
+ // }
41
+ // })
42
+ // } else {
43
+ // res.send({
44
+ // error: {
45
+ // extraData: {
46
+ // cardId: 123456789,
47
+ // receiptNo: 1234567890,
48
+ // },
49
+ // code: 100022,
50
+ // }
51
+ // })
52
+ // }
53
+ }, 3000)
54
+ })
55
+
56
+ app.post('/enquiry', (req, res) => {
57
+ setTimeout(() => {
58
+ res.send({
59
+ data: {
60
+ octopusType: 2,
61
+ remainingValue: 56.7,
62
+ cardId: 12345678,
63
+ cardLogs: [{
64
+ transactionAmount: -50,
65
+ transactionTimestamp: Math.floor(Date.now() / 1000),
66
+ deviceId: 1234,
67
+ isSameDevice: false,
68
+ }, {
69
+ transactionAmount: -12.3,
70
+ transactionTimestamp: Math.floor(Date.now() / 1000),
71
+ deviceId: 1234,
72
+ isSameDevice: false,
73
+ }, {
74
+ transactionAmount: 500,
75
+ transactionTimestamp: Math.floor(Date.now() / 1000),
76
+ deviceId: 1234,
77
+ isSameDevice: false,
78
+ }, {
79
+ transactionAmount: -0.1,
80
+ transactionTimestamp: Math.floor(Date.now() / 1000),
81
+ deviceId: 123456,
82
+ isSameDevice: true,
83
+ }],
84
+ }
85
+ })
86
+ }, 5_000)
87
+ })
88
+
89
+ const port = process.env['ALMAGEST_OCTOPUS_MANAGER_PORT'] ? Number(process.env['ALMAGEST_OCTOPUS_MANAGER_PORT']) : 40082;
90
+
91
+ app.listen(port, () => {
92
+ console.log(`Octopus listening on http://localhost:${port}`)
93
+ })
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "snapio-mock-camera",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "commonjs",
7
+ "scripts": {
8
+ "start": "nodemon index.js",
9
+ "test": "echo \"Error: no test specified\" && exit 1"
10
+ },
11
+ "author": "",
12
+ "license": "ISC",
13
+ "dependencies": {
14
+ "canvas": "^3.0.0-rc2",
15
+ "cors": "^2.8.5",
16
+ "express": "^4.17.1",
17
+ "node-webcam": "^0.8.2",
18
+ "rxjs": "^7.8.2"
19
+ },
20
+ "devDependencies": {
21
+ "nodemon": "^3.1.10"
22
+ }
23
+ }
package/printer.js ADDED
@@ -0,0 +1,38 @@
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+ const app = express()
6
+
7
+ app.use(cors())
8
+
9
+ let remaining = 100;
10
+
11
+ app.get('/health', (req, res) => {
12
+ res.setHeader('content-type', 'application/json')
13
+ res.send({
14
+ // status: Math.random() < 0.9 ? 'fail' : 'pass',
15
+ status: 'pass',
16
+ message: 'Hello world',
17
+ remainingMediaQuantity: remaining,
18
+ details: { printerModel: 'DS620' }
19
+ })
20
+ })
21
+ app.post('/printPhoto', (req, res) => {
22
+ const ws = fs.createWriteStream(path.join(__dirname, 'tmp', `${Date.now()}.jpg`))
23
+ req.pipe(ws)
24
+ ws.on('finish', () => {
25
+ res.setHeader('content-type', 'application/json')
26
+ res.send({
27
+ data: {
28
+ remainingMediaQuantity: --remaining,
29
+ }
30
+ })
31
+ })
32
+ })
33
+
34
+ const port = process.env['SNAPIO_PRINTER_MANAGER_PORT'] ? Number(process.env['SNAPIO_PRINTER_MANAGER_PORT']) : 40080;
35
+
36
+ app.listen(port, () => {
37
+ console.log(`Printer listening on http://localhost:${port}`)
38
+ })
Binary file
Binary file
Binary file
Binary file
package/test-ai.js ADDED
@@ -0,0 +1,21 @@
1
+ const fs = require('fs');
2
+
3
+ (async () => {
4
+ const IMAGE_SRC = 'public/960x640.jpg';
5
+ const blob = new File([await fs.openAsBlob(IMAGE_SRC)], 'asdf.jpg', { type: 'image/jpeg' })
6
+ const formData = new FormData()
7
+ formData.append('image_1', blob)
8
+ // formData.append('style', 'cr7')
9
+ const res = await fetch('https://pons-ai--generation-pipeline-fastapi-app.modal.run/ponsai-generation-pipeline?style=cr7', {
10
+ method: 'POST',
11
+ headers: {
12
+ // 'content-type': 'multipart/form-data',
13
+ 'accept': 'application/json',
14
+ 'Modal-Key': 'wk-rZQi1PiNn6esAt9Mh2GlUs',
15
+ 'Modal-Secret': 'ws-0U18fCTu1Zv6G1yTsvS8ZW'
16
+ },
17
+ body: formData
18
+ })
19
+ const json = await (res).json();
20
+ console.log(json)
21
+ })()