diff --git a/src/api/v1/api.py b/src/api/v1/api.py index ee45117..a216151 100644 --- a/src/api/v1/api.py +++ b/src/api/v1/api.py @@ -1,7 +1,9 @@ from typing import Union +import json from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect from websockets.exceptions import ConnectionClosed from fastapi.templating import Jinja2Templates +from fastapi.middleware.cors import CORSMiddleware import asyncio import cv2 @@ -9,16 +11,17 @@ camera = cv2.VideoCapture(1, cv2.CAP_DSHOW) templates = Jinja2Templates(directory="templates") +origins = [ + "http://localhost:3000", +] -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], # Allow all HTTP methods + allow_headers=["*"], # Allow all headers +) # https://stackoverflow.com/a/70626324 @app.websocket("/ws") @@ -32,6 +35,12 @@ async def get_stream(websocket: WebSocket): else: ret, buffer = cv2.imencode(".jpg", frame) await websocket.send_bytes(buffer.tobytes()) - await asyncio.sleep(0.01) + await asyncio.sleep(0.03) except (WebSocketDisconnect, ConnectionClosed): print("Client disconnected") + +@app.post("/command") +async def command(request: Request): + data = await request.json() + data_dict = json.loads(data) + return {"status": "success"} \ No newline at end of file diff --git a/src/ui/v1/src/app/page.tsx b/src/ui/v1/src/app/page.tsx index 94533e1..c7fcaf1 100644 --- a/src/ui/v1/src/app/page.tsx +++ b/src/ui/v1/src/app/page.tsx @@ -1,12 +1,16 @@ "use client" -import { useRef, useEffect, useInsertionEffect } from "react"; +import { useRef, useEffect, useInsertionEffect, useState } from "react"; export default function Home() { const ws = new WebSocket('ws://localhost:8000/ws'); const canvasRef = useRef(null); + const [left, setLeft] = useState(0); + const [up, setUp] = useState(0); + const [right, setRight] = useState(0); + const [down, setDown] = useState(0); + useInsertionEffect(() => { - ws.onmessage = (event) => { if (event.data instanceof Blob) { const reader = new FileReader(); @@ -27,7 +31,6 @@ export default function Home() { } }; - // Clean up WebSocket connection on component unmount return () => { ws.close(); }; @@ -37,11 +40,114 @@ export default function Home() { const canvas = canvasRef.current; const context = canvas?.getContext('2d'); }, []); - + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + switch (event.key) { + case "ArrowUp": + setUp(1); + break; + case "ArrowDown": + setDown(1); + break; + case "ArrowLeft": + setLeft(1); + break; + case "ArrowRight": + setRight(1); + break; + default: + break; + } + }; + + document.addEventListener("keydown", handleKeyDown); + + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); + + useEffect(() => { + const handleKeyUp = (event: KeyboardEvent) => { + switch (event.key) { + case "ArrowUp": + setUp(0); + break; + case "ArrowDown": + setDown(0); + break; + case "ArrowLeft": + setLeft(0); + break; + case "ArrowRight": + setRight(0); + break; + default: + break; + } + } + + document.addEventListener("keyup", handleKeyUp); + + return () => { + document.removeEventListener("keyup", handleKeyUp); + } + }, []) + + useEffect(() => { + if (left === 1 || up === 1 || right === 1 || down === 1) { + fetch('http://localhost:8000/command', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + left, + up, + right, + down + }), + }); + } + }, [down, left, right, up]) + return (
- +
+
+ +
+
+
+ + + + +
+
+
); diff --git a/src/ui/v1/tailwind.config.ts b/src/ui/v1/tailwind.config.ts index e9a0944..3964007 100644 --- a/src/ui/v1/tailwind.config.ts +++ b/src/ui/v1/tailwind.config.ts @@ -14,6 +14,16 @@ const config: Config = { "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", }, }, + colors: { + red: "#ee6352", + green: "#59cd90", + blue: "#3fa7d6", + yellow: "#fac05e", + purple: "#b678e0", + black: "#1e1e1e", + white: "#f9f9f9", + orange: "#f79d84" + } }, plugins: [], };