Spaces:
Runtime error
Runtime error
File size: 6,987 Bytes
182af0c b747f96 182af0c 0bf8fdb 182af0c 0bf8fdb 182af0c 3997342 182af0c 3997342 182af0c 3997342 182af0c b747f96 182af0c 0bf8fdb 182af0c 0bf8fdb 182af0c 3997342 0bf8fdb 182af0c b747f96 1342931 b747f96 1342931 b747f96 182af0c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
"use client"
import { getWebsocketUrl } from '@/server/generate'
import { useCallback, useEffect, useRef, useState } from 'react'
import useSWR from 'swr'
import useWebSocket, { ReadyState } from 'react-use-websocket';
import { useDebounce } from "use-debounce";
import { Input } from './ui/input';
import { Badge } from './ui/badge';
import { Skeleton } from './ui/skeleton';
import { cn } from '@/lib/utils';
export function WebsocketDemo() {
const { data } = useSWR("ws", getWebsocketUrl, {
revalidateOnFocus: false,
})
const [ws, setWs] = useState<WebSocket>()
const [status, setStatus] = useState("not-connected")
const [prompt, setPrompt] = useState('A anime cat');
const [debouncedPrompt] = useDebounce(prompt, 200);
const [currentLog, setCurrentLog] = useState<string>();
const [reconnectCounter, setReconnectCounter] = useState(0)
const canvasRef = useRef<HTMLCanvasElement>(null); // Reference to the canvas element
const sendInput = useCallback(() => {
if (status == "reconnecting" || status == "connecting")
return
if (ws?.readyState == ws?.CLOSED) {
setStatus('reconnecting')
setReconnectCounter(x => x + 1)
return
}
if (status != "ready")
return
ws?.send(JSON.stringify(
{
"event": "input",
"inputs": {
"input_text": debouncedPrompt
}
}
))
}, [ws, debouncedPrompt, status])
const preStatus = useRef(status)
useEffect(() => {
if (preStatus.current != status && status == "ready")
sendInput();
preStatus.current = status
}, [status, sendInput])
useEffect(() => {
sendInput();
}, [debouncedPrompt])
const connectWS = useCallback((data: NonNullable<Awaited<ReturnType<typeof getWebsocketUrl>>>) => {
setStatus("connecting");
const websocket = new WebSocket(data.ws_connection_url);
websocket.binaryType = "arraybuffer";
websocket.onopen = () => {
setStatus("connected");
};
websocket.onmessage = (event) => {
if (typeof event.data === "string") {
const message = JSON.parse(event.data);
if (message?.event == "status" && message?.data?.sid) {
setStatus("ready");
}
if (message?.event) {
if (message?.event == "executing" && message?.data?.node == null)
setCurrentLog("done")
else if (message?.event == "live_status")
setCurrentLog(`running - ${message.data?.current_node} ${(message.data.progress * 100).toFixed(2)}%`)
else if (message?.event == "elapsed_time")
setCurrentLog(`elapsed time: ${Math.ceil(message.data?.elapsed_time * 100) / 100}s`)
}
console.log("Received message:", message);
}
if (event.data instanceof ArrayBuffer) {
console.log("Received binary message:");
drawImage(event.data);
}
};
websocket.onclose = () => setStatus("closed");
websocket.onerror = () => setStatus("error");
setWs(websocket);
return () => {
websocket.close();
};
}, [data])
const drawImage = useCallback((arrayBuffer: ArrayBuffer) => {
const view = new DataView(arrayBuffer);
const eventType = view.getUint32(0);
const buffer = arrayBuffer.slice(4);
switch (eventType) {
case 1:
const view2 = new DataView(arrayBuffer);
const imageType = view2.getUint32(0)
let imageMime
switch (imageType) {
case 1:
default:
imageMime = "image/jpeg";
break;
case 2:
imageMime = "image/png"
break;
case 3:
imageMime = "image/webp"
}
const blob = new Blob([buffer.slice(4)], { type: imageMime });
const fileSize = blob.size;
console.log(`Received image size: ${(fileSize / 1024).toFixed(2)} KB`);
// const blob = new Blob([arrayBuffer], { type: 'image/png' }); // Assuming the image is a JPEG
const url = URL.createObjectURL(blob);
const canvas = canvasRef.current;
const ctx = canvas?.getContext('2d');
if (ctx) {
console.log("drawing");
const img = new Image();
img.onload = () => {
if (canvas) {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
}
URL.revokeObjectURL(url); // Clean up
};
img.src = url;
}
// this.dispatchEvent(new CustomEvent("b_preview", { detail: imageBlob }));
break;
default:
throw new Error(`Unknown binary websocket message of type ${eventType}`);
}
}, []);
useEffect(() => {
if (!data) {
setStatus("not-connected");
return;
}
return connectWS(data)
}, [connectWS, reconnectCounter])
const pending = (status == "not-connected" || status == "connecting" || status == "reconnecting" || currentLog?.startsWith("running") || (!currentLog && status == "connected"))
return (
<div className='flex md:flex-col gap-2 px-2 flex-col-reverse'>
<div className='flex gap-2'>
<Badge variant={'outline'} className='w-fit'>Status: {status}</Badge>
{(currentLog || status == "connected" || status == "ready") && <Badge variant={'outline'} className='w-fit'>
{currentLog}
{status == "connected" && !currentLog && "stating comfy ui"}
{status == "ready" && !currentLog && " running"}
</Badge>}
</div>
<div className='relative w-full'>
<canvas ref={canvasRef} className='rounded-lg ring-1 ring-black/10 w-full aspect-square' width={1024} height={1024}></canvas>
{/* {
<><Skeleton className={
cn("absolute top-0 left-0 w-full h-full aspect-square opacity-20 transition-opacity", pending ? "visible" : "invisible opacity-0")
} /></>
} */}
</div>
<Input
type="text"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
/>
</div>
)
} |