radames commited on
Commit
fe66ec6
·
1 Parent(s): 5510eab
frontend/src/lib/lcmLive.ts CHANGED
@@ -1,12 +1,11 @@
1
  import { writable } from 'svelte/store';
2
 
3
-
4
  export enum LCMLiveStatus {
5
- CONNECTED = "connected",
6
- DISCONNECTED = "disconnected",
7
- WAIT = "wait",
8
- SEND_FRAME = "send_frame",
9
- TIMEOUT = "timeout",
10
  }
11
 
12
  const initStatus: LCMLiveStatus = LCMLiveStatus.DISCONNECTED;
@@ -16,84 +15,83 @@ export const streamId = writable<string | null>(null);
16
 
17
  let websocket: WebSocket | null = null;
18
  export const lcmLiveActions = {
19
- async start(getSreamdata: () => any[]) {
20
- return new Promise((resolve, reject) => {
21
-
22
- try {
23
- const userId = crypto.randomUUID();
24
- const websocketURL = `${window.location.protocol === "https:" ? "wss" : "ws"
25
- }:${window.location.host}/api/ws/${userId}`;
26
-
27
- websocket = new WebSocket(websocketURL);
28
- websocket.onopen = () => {
29
- console.log("Connected to websocket");
30
- };
31
- websocket.onclose = () => {
32
- lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
33
- console.log("Disconnected from websocket");
34
- };
35
- websocket.onerror = (err) => {
36
- console.error(err);
37
- };
38
- websocket.onmessage = (event) => {
39
- const data = JSON.parse(event.data);
40
- switch (data.status) {
41
- case "connected":
42
- lcmLiveStatus.set(LCMLiveStatus.CONNECTED);
43
- streamId.set(userId);
44
- resolve({ status: "connected", userId });
45
- break;
46
- case "send_frame":
47
- lcmLiveStatus.set(LCMLiveStatus.SEND_FRAME);
48
- const streamData = getSreamdata();
49
- websocket?.send(JSON.stringify({ status: "next_frame" }));
50
- for (const d of streamData) {
51
- this.send(d);
52
- }
53
- break;
54
- case "wait":
55
- lcmLiveStatus.set(LCMLiveStatus.WAIT);
56
- break;
57
- case "timeout":
58
- console.log("timeout");
59
- lcmLiveStatus.set(LCMLiveStatus.TIMEOUT);
60
- streamId.set(null);
61
- reject(new Error("timeout"));
62
- break;
63
- case "error":
64
- console.log(data.message);
65
- lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
66
- streamId.set(null);
67
- reject(new Error(data.message));
68
- break;
69
- }
70
- };
71
 
72
- } catch (err) {
73
- console.error(err);
74
- lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
75
- streamId.set(null);
76
- reject(err);
77
- }
78
- });
79
- },
80
- send(data: Blob | { [key: string]: any }) {
81
- if (websocket && websocket.readyState === WebSocket.OPEN) {
82
- if (data instanceof Blob) {
83
- websocket.send(data);
84
- } else {
85
- websocket.send(JSON.stringify(data));
86
- }
87
- } else {
88
- console.log("WebSocket not connected");
89
- }
90
- },
91
- async stop() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
93
- if (websocket) {
94
- websocket.close();
95
- }
96
- websocket = null;
97
  streamId.set(null);
98
- },
99
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import { writable } from 'svelte/store';
2
 
 
3
  export enum LCMLiveStatus {
4
+ CONNECTED = 'connected',
5
+ DISCONNECTED = 'disconnected',
6
+ WAIT = 'wait',
7
+ SEND_FRAME = 'send_frame',
8
+ TIMEOUT = 'timeout'
9
  }
10
 
11
  const initStatus: LCMLiveStatus = LCMLiveStatus.DISCONNECTED;
 
15
 
16
  let websocket: WebSocket | null = null;
17
  export const lcmLiveActions = {
18
+ async start(getSreamdata: () => any[]) {
19
+ return new Promise((resolve, reject) => {
20
+ try {
21
+ const userId = crypto.randomUUID();
22
+ const websocketURL = `${
23
+ window.location.protocol === 'https:' ? 'wss' : 'ws'
24
+ }:${window.location.host}/api/ws/${userId}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ websocket = new WebSocket(websocketURL);
27
+ websocket.onopen = () => {
28
+ console.log('Connected to websocket');
29
+ };
30
+ websocket.onclose = () => {
31
+ lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
32
+ console.log('Disconnected from websocket');
33
+ };
34
+ websocket.onerror = (err) => {
35
+ console.error(err);
36
+ };
37
+ websocket.onmessage = (event) => {
38
+ const data = JSON.parse(event.data);
39
+ switch (data.status) {
40
+ case 'connected':
41
+ lcmLiveStatus.set(LCMLiveStatus.CONNECTED);
42
+ streamId.set(userId);
43
+ resolve({ status: 'connected', userId });
44
+ break;
45
+ case 'send_frame':
46
+ lcmLiveStatus.set(LCMLiveStatus.SEND_FRAME);
47
+ const streamData = getSreamdata();
48
+ websocket?.send(JSON.stringify({ status: 'next_frame' }));
49
+ for (const d of streamData) {
50
+ this.send(d);
51
+ }
52
+ break;
53
+ case 'wait':
54
+ lcmLiveStatus.set(LCMLiveStatus.WAIT);
55
+ break;
56
+ case 'timeout':
57
+ console.log('timeout');
58
+ lcmLiveStatus.set(LCMLiveStatus.TIMEOUT);
59
+ streamId.set(null);
60
+ reject(new Error('timeout'));
61
+ break;
62
+ case 'error':
63
+ console.log(data.message);
64
+ lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
65
+ streamId.set(null);
66
+ reject(new Error(data.message));
67
+ break;
68
+ }
69
+ };
70
+ } catch (err) {
71
+ console.error(err);
72
  lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
 
 
 
 
73
  streamId.set(null);
74
+ reject(err);
75
+ }
76
+ });
77
+ },
78
+ send(data: Blob | { [key: string]: any }) {
79
+ if (websocket && websocket.readyState === WebSocket.OPEN) {
80
+ if (data instanceof Blob) {
81
+ websocket.send(data);
82
+ } else {
83
+ websocket.send(JSON.stringify(data));
84
+ }
85
+ } else {
86
+ console.log('WebSocket not connected');
87
+ }
88
+ },
89
+ async stop() {
90
+ lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
91
+ if (websocket) {
92
+ websocket.close();
93
+ }
94
+ websocket = null;
95
+ streamId.set(null);
96
+ }
97
+ };
frontend/src/lib/mediaStream.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { writable, type Writable, type Readable, get, derived } from 'svelte/store';
2
 
3
  const BASE_HEIGHT = 720;
4
  export enum MediaStreamStatusEnum {
5
- INIT = "init",
6
- CONNECTED = "connected",
7
- DISCONNECTED = "disconnected",
8
  }
9
  export const onFrameChangeStore: Writable<{ blob: Blob }> = writable({ blob: new Blob() });
10
 
@@ -13,108 +13,106 @@ export const mediaStreamStatus = writable(MediaStreamStatusEnum.INIT);
13
  export const mediaStream = writable<MediaStream | null>(null);
14
 
15
  export const mediaStreamActions = {
16
- async enumerateDevices() {
17
- // console.log("Enumerating devices");
18
- await navigator.mediaDevices.enumerateDevices()
19
- .then(devices => {
20
- const cameras = devices.filter(device => device.kind === 'videoinput');
21
- mediaDevices.set(cameras);
22
- })
23
- .catch(err => {
24
- console.error(err);
25
- });
26
- },
27
- async start(mediaDevicedID?: string, aspectRatio: number = 1) {
28
- const constraints = {
29
- audio: false,
30
- video: {
31
- width: {
32
- ideal: BASE_HEIGHT * aspectRatio,
33
- },
34
- height: {
35
- ideal: BASE_HEIGHT,
36
- },
37
- deviceId: mediaDevicedID
38
- }
39
- };
 
40
 
41
- await navigator.mediaDevices
42
- .getUserMedia(constraints)
43
- .then((stream) => {
44
- mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED);
45
- mediaStream.set(stream);
46
-
47
- })
48
- .catch((err) => {
49
- console.error(`${err.name}: ${err.message}`);
50
- mediaStreamStatus.set(MediaStreamStatusEnum.DISCONNECTED);
51
- mediaStream.set(null);
52
- });
53
- },
54
- async startScreenCapture() {
55
- const displayMediaOptions = {
56
- video: {
57
- displaySurface: "window",
58
- },
59
- audio: false,
60
- surfaceSwitching: "include"
61
- };
62
-
63
-
64
- let captureStream = null;
65
 
66
- try {
67
- captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
68
- const videoTrack = captureStream.getVideoTracks()[0];
69
 
70
- console.log("Track settings:");
71
- console.log(JSON.stringify(videoTrack.getSettings(), null, 2));
72
- console.log("Track constraints:");
73
- console.log(JSON.stringify(videoTrack.getConstraints(), null, 2));
74
- mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED);
75
- mediaStream.set(captureStream)
76
 
77
- const capabilities = videoTrack.getCapabilities();
78
- const aspectRatio = capabilities.aspectRatio;
79
- console.log('Aspect Ratio Constraints:', aspectRatio);
80
- } catch (err) {
81
- console.error(err);
82
- }
83
 
84
- },
85
- async switchCamera(mediaDevicedID: string, aspectRatio: number) {
86
- console.log("Switching camera");
87
- if (get(mediaStreamStatus) !== MediaStreamStatusEnum.CONNECTED) {
88
- return;
89
- }
90
- const constraints = {
91
- audio: false,
92
- video: {
93
- width: {
94
- ideal: BASE_HEIGHT * aspectRatio,
95
- },
96
- height: {
97
- ideal: BASE_HEIGHT,
98
- },
99
- deviceId: mediaDevicedID
100
- }
101
- };
102
- console.log("Switching camera", constraints);
103
- await navigator.mediaDevices
104
- .getUserMedia(constraints)
105
- .then((stream) => {
106
- mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED);
107
- mediaStream.set(stream)
108
- })
109
- .catch((err) => {
110
- console.error(`${err.name}: ${err.message}`);
111
- });
112
- },
113
- async stop() {
114
- navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
115
- stream.getTracks().forEach((track) => track.stop());
116
- });
117
- mediaStreamStatus.set(MediaStreamStatusEnum.DISCONNECTED);
118
- mediaStream.set(null);
119
- },
120
- };
 
 
 
 
 
 
 
1
+ import { get, writable, type Writable } from 'svelte/store';
2
 
3
  const BASE_HEIGHT = 720;
4
  export enum MediaStreamStatusEnum {
5
+ INIT = 'init',
6
+ CONNECTED = 'connected',
7
+ DISCONNECTED = 'disconnected'
8
  }
9
  export const onFrameChangeStore: Writable<{ blob: Blob }> = writable({ blob: new Blob() });
10
 
 
13
  export const mediaStream = writable<MediaStream | null>(null);
14
 
15
  export const mediaStreamActions = {
16
+ async enumerateDevices() {
17
+ // console.log("Enumerating devices");
18
+ await navigator.mediaDevices
19
+ .enumerateDevices()
20
+ .then((devices) => {
21
+ const cameras = devices.filter((device) => device.kind === 'videoinput');
22
+ mediaDevices.set(cameras);
23
+ })
24
+ .catch((err) => {
25
+ console.error(err);
26
+ });
27
+ },
28
+ async start(mediaDevicedID?: string, aspectRatio: number = 1) {
29
+ const constraints = {
30
+ audio: false,
31
+ video: {
32
+ width: {
33
+ ideal: BASE_HEIGHT * aspectRatio
34
+ },
35
+ height: {
36
+ ideal: BASE_HEIGHT
37
+ },
38
+ deviceId: mediaDevicedID
39
+ }
40
+ };
41
 
42
+ await navigator.mediaDevices
43
+ .getUserMedia(constraints)
44
+ .then((stream) => {
45
+ mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED);
46
+ mediaStream.set(stream);
47
+ })
48
+ .catch((err) => {
49
+ console.error(`${err.name}: ${err.message}`);
50
+ mediaStreamStatus.set(MediaStreamStatusEnum.DISCONNECTED);
51
+ mediaStream.set(null);
52
+ });
53
+ },
54
+ async startScreenCapture() {
55
+ const displayMediaOptions = {
56
+ video: {
57
+ displaySurface: 'window'
58
+ },
59
+ audio: false,
60
+ surfaceSwitching: 'include'
61
+ };
 
 
 
 
62
 
63
+ let captureStream = null;
 
 
64
 
65
+ try {
66
+ captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
67
+ const videoTrack = captureStream.getVideoTracks()[0];
 
 
 
68
 
69
+ console.log('Track settings:');
70
+ console.log(JSON.stringify(videoTrack.getSettings(), null, 2));
71
+ console.log('Track constraints:');
72
+ console.log(JSON.stringify(videoTrack.getConstraints(), null, 2));
73
+ mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED);
74
+ mediaStream.set(captureStream);
75
 
76
+ const capabilities = videoTrack.getCapabilities();
77
+ const aspectRatio = capabilities.aspectRatio;
78
+ console.log('Aspect Ratio Constraints:', aspectRatio);
79
+ } catch (err) {
80
+ console.error(err);
81
+ }
82
+ },
83
+ async switchCamera(mediaDevicedID: string, aspectRatio: number) {
84
+ console.log('Switching camera');
85
+ if (get(mediaStreamStatus) !== MediaStreamStatusEnum.CONNECTED) {
86
+ return;
87
+ }
88
+ const constraints = {
89
+ audio: false,
90
+ video: {
91
+ width: {
92
+ ideal: BASE_HEIGHT * aspectRatio
93
+ },
94
+ height: {
95
+ ideal: BASE_HEIGHT
96
+ },
97
+ deviceId: mediaDevicedID
98
+ }
99
+ };
100
+ console.log('Switching camera', constraints);
101
+ await navigator.mediaDevices
102
+ .getUserMedia(constraints)
103
+ .then((stream) => {
104
+ mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED);
105
+ mediaStream.set(stream);
106
+ })
107
+ .catch((err) => {
108
+ console.error(`${err.name}: ${err.message}`);
109
+ });
110
+ },
111
+ async stop() {
112
+ navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
113
+ stream.getTracks().forEach((track) => track.stop());
114
+ });
115
+ mediaStreamStatus.set(MediaStreamStatusEnum.DISCONNECTED);
116
+ mediaStream.set(null);
117
+ }
118
+ };
frontend/src/lib/store.ts CHANGED
@@ -1,15 +1,14 @@
1
-
2
- import { derived, writable, get, type Writable, type Readable } from 'svelte/store';
3
 
4
  export const pipelineValues: Writable<Record<string, any>> = writable({});
5
- export const deboucedPipelineValues: Readable<Record<string, any>>
6
- = derived(pipelineValues, ($pipelineValues, set) => {
7
- const debounced = setTimeout(() => {
8
- set($pipelineValues);
9
- }, 100);
10
- return () => clearTimeout(debounced);
11
- });
12
-
13
-
14
-
15
- export const getPipelineValues = () => get(pipelineValues);
 
1
+ import { derived, get, writable, type Readable, type Writable } from 'svelte/store';
 
2
 
3
  export const pipelineValues: Writable<Record<string, any>> = writable({});
4
+ export const deboucedPipelineValues: Readable<Record<string, any>> = derived(
5
+ pipelineValues,
6
+ ($pipelineValues, set) => {
7
+ const debounced = setTimeout(() => {
8
+ set($pipelineValues);
9
+ }, 100);
10
+ return () => clearTimeout(debounced);
11
+ }
12
+ );
13
+
14
+ export const getPipelineValues = () => get(pipelineValues);
frontend/src/lib/types.ts CHANGED
@@ -1,40 +1,39 @@
1
  export const enum FieldType {
2
- RANGE = "range",
3
- SEED = "seed",
4
- TEXTAREA = "textarea",
5
- CHECKBOX = "checkbox",
6
- SELECT = "select",
7
  }
8
  export const enum PipelineMode {
9
- IMAGE = "image",
10
- VIDEO = "video",
11
- TEXT = "text",
12
  }
13
 
14
-
15
  export interface Fields {
16
- [key: string]: FieldProps;
17
  }
18
 
19
  export interface FieldProps {
20
- default: number | string;
21
- max?: number;
22
- min?: number;
23
- title: string;
24
- field: FieldType;
25
- step?: number;
26
- disabled?: boolean;
27
- hide?: boolean;
28
- id: string;
29
- values?: string[];
30
  }
31
  export interface PipelineInfo {
32
- title: {
33
- default: string;
34
- }
35
- name: string;
36
- description: string;
37
- input_mode: {
38
- default: PipelineMode;
39
- }
40
- }
 
1
  export const enum FieldType {
2
+ RANGE = 'range',
3
+ SEED = 'seed',
4
+ TEXTAREA = 'textarea',
5
+ CHECKBOX = 'checkbox',
6
+ SELECT = 'select'
7
  }
8
  export const enum PipelineMode {
9
+ IMAGE = 'image',
10
+ VIDEO = 'video',
11
+ TEXT = 'text'
12
  }
13
 
 
14
  export interface Fields {
15
+ [key: string]: FieldProps;
16
  }
17
 
18
  export interface FieldProps {
19
+ default: number | string;
20
+ max?: number;
21
+ min?: number;
22
+ title: string;
23
+ field: FieldType;
24
+ step?: number;
25
+ disabled?: boolean;
26
+ hide?: boolean;
27
+ id: string;
28
+ values?: string[];
29
  }
30
  export interface PipelineInfo {
31
+ title: {
32
+ default: string;
33
+ };
34
+ name: string;
35
+ description: string;
36
+ input_mode: {
37
+ default: PipelineMode;
38
+ };
39
+ }
frontend/src/lib/utils.ts CHANGED
@@ -1,44 +1,46 @@
1
- import * as piexif from "piexifjs";
2
 
3
  interface IImageInfo {
4
- prompt?: string;
5
- negative_prompt?: string;
6
- seed?: number;
7
- guidance_scale?: number;
8
  }
9
 
10
  export function snapImage(imageEl: HTMLImageElement, info: IImageInfo) {
11
- try {
12
- const zeroth: { [key: string]: any } = {};
13
- const exif: { [key: string]: any } = {};
14
- const gps: { [key: string]: any } = {};
15
- zeroth[piexif.ImageIFD.Make] = "LCM Image-to-Image ControNet";
16
- zeroth[piexif.ImageIFD.ImageDescription] = `prompt: ${info?.prompt} | negative_prompt: ${info?.negative_prompt} | seed: ${info?.seed} | guidance_scale: ${info?.guidance_scale}`;
17
- zeroth[piexif.ImageIFD.Software] = "https://github.com/radames/Real-Time-Latent-Consistency-Model";
18
- exif[piexif.ExifIFD.DateTimeOriginal] = new Date().toISOString();
 
 
19
 
20
- const exifObj = { "0th": zeroth, "Exif": exif, "GPS": gps };
21
- const exifBytes = piexif.dump(exifObj);
22
 
23
- const canvas = document.createElement("canvas");
24
- canvas.width = imageEl.naturalWidth;
25
- canvas.height = imageEl.naturalHeight;
26
- const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
27
- ctx.drawImage(imageEl, 0, 0);
28
- const dataURL = canvas.toDataURL("image/jpeg");
29
- const withExif = piexif.insert(exifBytes, dataURL);
30
 
31
- const a = document.createElement("a");
32
- a.href = withExif;
33
- a.download = `lcm_txt_2_img${Date.now()}.png`;
34
- a.click();
35
- } catch (err) {
36
- console.log(err);
37
- }
38
  }
39
 
40
- export function expandWindow(steramURL: string): Window {
41
- const html = `
42
  <html>
43
  <head>
44
  <title>Real-Time Latent Consistency Model</title>
@@ -71,11 +73,15 @@ export function expandWindow(steramURL: string): Window {
71
  }
72
  </script>
73
 
74
- <img src="${steramURL}" style="width: 100%; height: 100%; object-fit: contain;" />
75
  </body>
76
  </html>
77
  `;
78
- const newWindow = window.open("", "_blank", "width=1024,height=1024,scrollbars=0,resizable=1,toolbar=0,menubar=0,location=0,directories=0,status=0") as Window;
79
- newWindow.document.write(html);
80
- return newWindow;
81
- }
 
 
 
 
 
1
+ import * as piexif from 'piexifjs';
2
 
3
  interface IImageInfo {
4
+ prompt?: string;
5
+ negative_prompt?: string;
6
+ seed?: number;
7
+ guidance_scale?: number;
8
  }
9
 
10
  export function snapImage(imageEl: HTMLImageElement, info: IImageInfo) {
11
+ try {
12
+ const zeroth: { [key: string]: any } = {};
13
+ const exif: { [key: string]: any } = {};
14
+ const gps: { [key: string]: any } = {};
15
+ zeroth[piexif.ImageIFD.Make] = 'LCM Image-to-Image ControNet';
16
+ zeroth[piexif.ImageIFD.ImageDescription] =
17
+ `prompt: ${info?.prompt} | negative_prompt: ${info?.negative_prompt} | seed: ${info?.seed} | guidance_scale: ${info?.guidance_scale}`;
18
+ zeroth[piexif.ImageIFD.Software] =
19
+ 'https://github.com/radames/Real-Time-Latent-Consistency-Model';
20
+ exif[piexif.ExifIFD.DateTimeOriginal] = new Date().toISOString();
21
 
22
+ const exifObj = { '0th': zeroth, Exif: exif, GPS: gps };
23
+ const exifBytes = piexif.dump(exifObj);
24
 
25
+ const canvas = document.createElement('canvas');
26
+ canvas.width = imageEl.naturalWidth;
27
+ canvas.height = imageEl.naturalHeight;
28
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
29
+ ctx.drawImage(imageEl, 0, 0);
30
+ const dataURL = canvas.toDataURL('image/jpeg');
31
+ const withExif = piexif.insert(exifBytes, dataURL);
32
 
33
+ const a = document.createElement('a');
34
+ a.href = withExif;
35
+ a.download = `lcm_txt_2_img${Date.now()}.png`;
36
+ a.click();
37
+ } catch (err) {
38
+ console.log(err);
39
+ }
40
  }
41
 
42
+ export function expandWindow(streamURL: string): Window {
43
+ const html = `
44
  <html>
45
  <head>
46
  <title>Real-Time Latent Consistency Model</title>
 
73
  }
74
  </script>
75
 
76
+ <img src="${streamURL}" style="width: 100%; height: 100%; object-fit: contain;" />
77
  </body>
78
  </html>
79
  `;
80
+ const newWindow = window.open(
81
+ '',
82
+ '_blank',
83
+ 'width=1024,height=1024,scrollbars=0,resizable=1,toolbar=0,menubar=0,location=0,directories=0,status=0'
84
+ ) as Window;
85
+ newWindow.document.write(html);
86
+ return newWindow;
87
+ }
frontend/src/routes/+page.ts CHANGED
@@ -1 +1 @@
1
- export const prerender = true
 
1
+ export const prerender = true;
frontend/vite.config.ts CHANGED
@@ -10,6 +10,6 @@ export default defineConfig({
10
  target: 'ws://localhost:7860',
11
  ws: true
12
  }
13
- },
14
  }
15
- });
 
10
  target: 'ws://localhost:7860',
11
  ws: true
12
  }
13
+ }
14
  }
15
+ });