Spaces:
Runtime error
Runtime error
fix timeout/queue message
Browse files- app_init.py +13 -13
- frontend/src/lib/components/Warning.svelte +27 -0
- frontend/src/lib/lcmLive.ts +2 -3
- frontend/src/routes/+page.svelte +22 -12
app_init.py
CHANGED
|
@@ -41,7 +41,6 @@ def init_app(app: FastAPI, user_data: UserData, args: Args, pipeline):
|
|
| 41 |
try:
|
| 42 |
user_id = uuid.uuid4()
|
| 43 |
print(f"New user connected: {user_id}")
|
| 44 |
-
|
| 45 |
await user_data.create_user(user_id, websocket)
|
| 46 |
await websocket.send_json(
|
| 47 |
{"status": "connected", "message": "Connected", "userId": str(user_id)}
|
|
@@ -61,6 +60,16 @@ def init_app(app: FastAPI, user_data: UserData, args: Args, pipeline):
|
|
| 61 |
last_time = time.time()
|
| 62 |
try:
|
| 63 |
while True:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
data = await websocket.receive_json()
|
| 65 |
if data["status"] != "next_frame":
|
| 66 |
asyncio.sleep(THROTTLE)
|
|
@@ -74,21 +83,11 @@ def init_app(app: FastAPI, user_data: UserData, args: Args, pipeline):
|
|
| 74 |
image_data = await websocket.receive_bytes()
|
| 75 |
if len(image_data) == 0:
|
| 76 |
await websocket.send_json({"status": "send_frame"})
|
|
|
|
| 77 |
continue
|
| 78 |
params.image = bytes_to_pil(image_data)
|
| 79 |
await user_data.update_data(user_id, params)
|
| 80 |
await websocket.send_json({"status": "wait"})
|
| 81 |
-
if args.timeout > 0 and time.time() - last_time > args.timeout:
|
| 82 |
-
await websocket.send_json(
|
| 83 |
-
{
|
| 84 |
-
"status": "timeout",
|
| 85 |
-
"message": "Your session has ended",
|
| 86 |
-
"userId": user_id,
|
| 87 |
-
}
|
| 88 |
-
)
|
| 89 |
-
await websocket.close()
|
| 90 |
-
return
|
| 91 |
-
await asyncio.sleep(THROTTLE)
|
| 92 |
|
| 93 |
except Exception as e:
|
| 94 |
logging.error(f"Error: {e}")
|
|
@@ -102,7 +101,6 @@ def init_app(app: FastAPI, user_data: UserData, args: Args, pipeline):
|
|
| 102 |
@app.get("/api/stream/{user_id}")
|
| 103 |
async def stream(user_id: uuid.UUID, request: Request):
|
| 104 |
try:
|
| 105 |
-
print(f"New stream request: {user_id}")
|
| 106 |
|
| 107 |
async def generate():
|
| 108 |
websocket = user_data.get_websocket(user_id)
|
|
@@ -112,6 +110,7 @@ def init_app(app: FastAPI, user_data: UserData, args: Args, pipeline):
|
|
| 112 |
params = await user_data.get_latest_data(user_id)
|
| 113 |
if not vars(params) or params.__dict__ == last_params.__dict__:
|
| 114 |
await websocket.send_json({"status": "send_frame"})
|
|
|
|
| 115 |
continue
|
| 116 |
|
| 117 |
last_params = params
|
|
@@ -119,6 +118,7 @@ def init_app(app: FastAPI, user_data: UserData, args: Args, pipeline):
|
|
| 119 |
|
| 120 |
if image is None:
|
| 121 |
await websocket.send_json({"status": "send_frame"})
|
|
|
|
| 122 |
continue
|
| 123 |
frame = pil_to_frame(image)
|
| 124 |
yield frame
|
|
|
|
| 41 |
try:
|
| 42 |
user_id = uuid.uuid4()
|
| 43 |
print(f"New user connected: {user_id}")
|
|
|
|
| 44 |
await user_data.create_user(user_id, websocket)
|
| 45 |
await websocket.send_json(
|
| 46 |
{"status": "connected", "message": "Connected", "userId": str(user_id)}
|
|
|
|
| 60 |
last_time = time.time()
|
| 61 |
try:
|
| 62 |
while True:
|
| 63 |
+
if args.timeout > 0 and time.time() - last_time > args.timeout:
|
| 64 |
+
await websocket.send_json(
|
| 65 |
+
{
|
| 66 |
+
"status": "timeout",
|
| 67 |
+
"message": "Your session has ended",
|
| 68 |
+
"userId": str(user_id),
|
| 69 |
+
}
|
| 70 |
+
)
|
| 71 |
+
await websocket.close()
|
| 72 |
+
return
|
| 73 |
data = await websocket.receive_json()
|
| 74 |
if data["status"] != "next_frame":
|
| 75 |
asyncio.sleep(THROTTLE)
|
|
|
|
| 83 |
image_data = await websocket.receive_bytes()
|
| 84 |
if len(image_data) == 0:
|
| 85 |
await websocket.send_json({"status": "send_frame"})
|
| 86 |
+
await asyncio.sleep(THROTTLE)
|
| 87 |
continue
|
| 88 |
params.image = bytes_to_pil(image_data)
|
| 89 |
await user_data.update_data(user_id, params)
|
| 90 |
await websocket.send_json({"status": "wait"})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
except Exception as e:
|
| 93 |
logging.error(f"Error: {e}")
|
|
|
|
| 101 |
@app.get("/api/stream/{user_id}")
|
| 102 |
async def stream(user_id: uuid.UUID, request: Request):
|
| 103 |
try:
|
|
|
|
| 104 |
|
| 105 |
async def generate():
|
| 106 |
websocket = user_data.get_websocket(user_id)
|
|
|
|
| 110 |
params = await user_data.get_latest_data(user_id)
|
| 111 |
if not vars(params) or params.__dict__ == last_params.__dict__:
|
| 112 |
await websocket.send_json({"status": "send_frame"})
|
| 113 |
+
await asyncio.sleep(THROTTLE)
|
| 114 |
continue
|
| 115 |
|
| 116 |
last_params = params
|
|
|
|
| 118 |
|
| 119 |
if image is None:
|
| 120 |
await websocket.send_json({"status": "send_frame"})
|
| 121 |
+
await asyncio.sleep(THROTTLE)
|
| 122 |
continue
|
| 123 |
frame = pil_to_frame(image)
|
| 124 |
yield frame
|
frontend/src/lib/components/Warning.svelte
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
export let message: string = '';
|
| 3 |
+
|
| 4 |
+
let timeout = 0;
|
| 5 |
+
$: if (message !== '') {
|
| 6 |
+
console.log('message', message);
|
| 7 |
+
clearTimeout(timeout);
|
| 8 |
+
timeout = setTimeout(() => {
|
| 9 |
+
message = '';
|
| 10 |
+
}, 5000);
|
| 11 |
+
}
|
| 12 |
+
</script>
|
| 13 |
+
|
| 14 |
+
{#if message}
|
| 15 |
+
<div class="fixed right-0 top-0 m-4 cursor-pointer" on:click={() => (message = '')}>
|
| 16 |
+
<div class="rounded bg-red-800 p-4 text-white">
|
| 17 |
+
{message}
|
| 18 |
+
</div>
|
| 19 |
+
<div class="bar transition-all duration-500" style="width: 0;"></div>
|
| 20 |
+
</div>
|
| 21 |
+
{/if}
|
| 22 |
+
|
| 23 |
+
<style lang="postcss" scoped>
|
| 24 |
+
.button {
|
| 25 |
+
@apply rounded bg-gray-700 font-normal text-white hover:bg-gray-800 disabled:cursor-not-allowed disabled:bg-gray-300 dark:disabled:bg-gray-700 dark:disabled:text-black;
|
| 26 |
+
}
|
| 27 |
+
</style>
|
frontend/src/lib/lcmLive.ts
CHANGED
|
@@ -40,7 +40,6 @@ export const lcmLiveActions = {
|
|
| 40 |
const userId = data.userId;
|
| 41 |
lcmLiveStatus.set(LCMLiveStatus.CONNECTED);
|
| 42 |
streamId.set(userId);
|
| 43 |
-
resolve(userId);
|
| 44 |
break;
|
| 45 |
case "send_frame":
|
| 46 |
lcmLiveStatus.set(LCMLiveStatus.SEND_FRAME);
|
|
@@ -57,12 +56,12 @@ export const lcmLiveActions = {
|
|
| 57 |
console.log("timeout");
|
| 58 |
lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
|
| 59 |
streamId.set(null);
|
| 60 |
-
|
| 61 |
case "error":
|
| 62 |
console.log(data.message);
|
| 63 |
lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
|
| 64 |
streamId.set(null);
|
| 65 |
-
reject(data.message);
|
| 66 |
}
|
| 67 |
};
|
| 68 |
|
|
|
|
| 40 |
const userId = data.userId;
|
| 41 |
lcmLiveStatus.set(LCMLiveStatus.CONNECTED);
|
| 42 |
streamId.set(userId);
|
|
|
|
| 43 |
break;
|
| 44 |
case "send_frame":
|
| 45 |
lcmLiveStatus.set(LCMLiveStatus.SEND_FRAME);
|
|
|
|
| 56 |
console.log("timeout");
|
| 57 |
lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
|
| 58 |
streamId.set(null);
|
| 59 |
+
resolve({ status: "timeout" });
|
| 60 |
case "error":
|
| 61 |
console.log(data.message);
|
| 62 |
lcmLiveStatus.set(LCMLiveStatus.DISCONNECTED);
|
| 63 |
streamId.set(null);
|
| 64 |
+
reject(new Error(data.message));
|
| 65 |
}
|
| 66 |
};
|
| 67 |
|
frontend/src/routes/+page.svelte
CHANGED
|
@@ -7,6 +7,7 @@
|
|
| 7 |
import Button from '$lib/components/Button.svelte';
|
| 8 |
import PipelineOptions from '$lib/components/PipelineOptions.svelte';
|
| 9 |
import Spinner from '$lib/icons/spinner.svelte';
|
|
|
|
| 10 |
import { lcmLiveStatus, lcmLiveActions, LCMLiveStatus } from '$lib/lcmLive';
|
| 11 |
import { mediaStreamActions, onFrameChangeStore } from '$lib/mediaStream';
|
| 12 |
import { getPipelineValues, deboucedPipelineValues } from '$lib/store';
|
|
@@ -18,6 +19,7 @@
|
|
| 18 |
let maxQueueSize: number = 0;
|
| 19 |
let currentQueueSize: number = 0;
|
| 20 |
let queueCheckerRunning: boolean = false;
|
|
|
|
| 21 |
|
| 22 |
onMount(() => {
|
| 23 |
getSettings();
|
|
@@ -60,20 +62,27 @@
|
|
| 60 |
|
| 61 |
let disabled = false;
|
| 62 |
async function toggleLcmLive() {
|
| 63 |
-
|
| 64 |
-
if (
|
| 65 |
-
|
| 66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
}
|
| 68 |
-
|
| 69 |
-
|
| 70 |
disabled = false;
|
| 71 |
-
toggleQueueChecker(false);
|
| 72 |
-
} else {
|
| 73 |
-
if (isImageMode) {
|
| 74 |
-
mediaStreamActions.stop();
|
| 75 |
-
}
|
| 76 |
-
lcmLiveActions.stop();
|
| 77 |
toggleQueueChecker(true);
|
| 78 |
}
|
| 79 |
}
|
|
@@ -86,6 +95,7 @@
|
|
| 86 |
</svelte:head>
|
| 87 |
|
| 88 |
<main class="container mx-auto flex max-w-5xl flex-col gap-3 px-4 py-4">
|
|
|
|
| 89 |
<article class="text-center">
|
| 90 |
{#if pageContent}
|
| 91 |
{@html pageContent}
|
|
|
|
| 7 |
import Button from '$lib/components/Button.svelte';
|
| 8 |
import PipelineOptions from '$lib/components/PipelineOptions.svelte';
|
| 9 |
import Spinner from '$lib/icons/spinner.svelte';
|
| 10 |
+
import Warning from '$lib/components/Warning.svelte';
|
| 11 |
import { lcmLiveStatus, lcmLiveActions, LCMLiveStatus } from '$lib/lcmLive';
|
| 12 |
import { mediaStreamActions, onFrameChangeStore } from '$lib/mediaStream';
|
| 13 |
import { getPipelineValues, deboucedPipelineValues } from '$lib/store';
|
|
|
|
| 19 |
let maxQueueSize: number = 0;
|
| 20 |
let currentQueueSize: number = 0;
|
| 21 |
let queueCheckerRunning: boolean = false;
|
| 22 |
+
let warningMessage: string = '';
|
| 23 |
|
| 24 |
onMount(() => {
|
| 25 |
getSettings();
|
|
|
|
| 62 |
|
| 63 |
let disabled = false;
|
| 64 |
async function toggleLcmLive() {
|
| 65 |
+
try {
|
| 66 |
+
if (!isLCMRunning) {
|
| 67 |
+
if (isImageMode) {
|
| 68 |
+
await mediaStreamActions.enumerateDevices();
|
| 69 |
+
await mediaStreamActions.start();
|
| 70 |
+
}
|
| 71 |
+
disabled = true;
|
| 72 |
+
await lcmLiveActions.start(getSreamdata);
|
| 73 |
+
warningMessage = 'Timeout, please try again.';
|
| 74 |
+
disabled = false;
|
| 75 |
+
toggleQueueChecker(false);
|
| 76 |
+
} else {
|
| 77 |
+
if (isImageMode) {
|
| 78 |
+
mediaStreamActions.stop();
|
| 79 |
+
}
|
| 80 |
+
lcmLiveActions.stop();
|
| 81 |
+
toggleQueueChecker(true);
|
| 82 |
}
|
| 83 |
+
} catch (e) {
|
| 84 |
+
warningMessage = e instanceof Error ? e.message : '';
|
| 85 |
disabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
toggleQueueChecker(true);
|
| 87 |
}
|
| 88 |
}
|
|
|
|
| 95 |
</svelte:head>
|
| 96 |
|
| 97 |
<main class="container mx-auto flex max-w-5xl flex-col gap-3 px-4 py-4">
|
| 98 |
+
<Warning bind:message={warningMessage}></Warning>
|
| 99 |
<article class="text-center">
|
| 100 |
{#if pageContent}
|
| 101 |
{@html pageContent}
|