Spaces:
Build error
Build error
Download camera_utils.py from Hypecat/ChessCommanderFlet: direct link, hf CLI and curl.
- Browser
- Download file 6.52 kB
-
https://huggingface.co/spaces/Hypecat/ChessCommanderFlet/resolve/main/camera_utils.py
- Command line
-
hf download hf://spaces/Hypecat/ChessCommanderFlet/camera_utils.py
-
curl -L -o camera_utils.py https://huggingface.co/spaces/Hypecat/ChessCommanderFlet/resolve/main/camera_utils.py
6.52 kB
| import logging | |
| import flet as ft | |
| from js_execution import set_camera_frame_callback | |
| from flet_extensions import eval_js | |
| import asyncio | |
| from typing import List, Dict | |
| logger = logging.getLogger(__name__) | |
| class Frame: | |
| def __init__(self, data: str, timestamp: float): | |
| self.data = data | |
| self.timestamp = timestamp | |
| class CameraImage(ft.Container): | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| self.stream_active = False | |
| self.video_image1 = ft.Image( | |
| src="", | |
| width=self.width, | |
| height=self.height, | |
| fit=ft.ImageFit.CONTAIN, | |
| visible=False, | |
| ) | |
| self.video_image2 = ft.Image( | |
| src="", | |
| width=self.width, | |
| height=self.height, | |
| fit=ft.ImageFit.CONTAIN, | |
| visible=False, | |
| ) | |
| self.current_video_image = self.video_image1 | |
| self.video_stack = ft.Stack([self.video_image1, self.video_image2]) | |
| self.content = self.video_stack | |
| set_camera_frame_callback(self.handle_camera_frame) | |
| self.captured_frames: Dict[int, Frame] = {} | |
| self.stream_start_time = None | |
| async def start_camera_stream_async(self) -> str: | |
| try: | |
| result = await eval_js(self.page, """ | |
| window.cameraStreamActive = false; | |
| window.cameraWebSocket = null; | |
| async function setupCameraStream() { | |
| console.log("setupCameraStream called"); | |
| try { | |
| const stream = await navigator.mediaDevices.getUserMedia({ video: true }); | |
| console.log("Camera access granted"); | |
| const video = document.createElement('video'); | |
| video.srcObject = stream; | |
| await video.play(); | |
| const canvas = document.createElement('canvas'); | |
| canvas.width = video.videoWidth / 2; | |
| canvas.height = video.videoHeight / 2; | |
| const ctx = canvas.getContext('2d'); | |
| window.cameraWebSocket = new WebSocket(`ws://${window.location.host}/ws/camera`); | |
| function sendFrame() { | |
| if (window.cameraWebSocket && window.cameraWebSocket.readyState === WebSocket.OPEN) { | |
| ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height); | |
| window.cameraWebSocket.send(canvas.toDataURL('image/jpeg', 0.2)); // Added quality parameter | |
| window.cameraStreamActive && setTimeout(sendFrame, 1000 / 60); | |
| } | |
| } | |
| window.cameraWebSocket.onopen = () => { | |
| console.log("WebSocket connection opened"); | |
| window.cameraStreamActive = true; | |
| sendFrame(); | |
| }; | |
| window.cameraWebSocket.onclose = () => { | |
| console.log("WebSocket connection closed"); | |
| window.cameraStreamActive = false; | |
| stream.getTracks().forEach(track => track.stop()); | |
| }; | |
| return "Camera stream setup complete"; | |
| } catch (error) { | |
| console.error("Error accessing camera:", error); | |
| throw error; | |
| } | |
| } | |
| return await setupCameraStream(); | |
| """) | |
| logger.info(f"start_camera_stream_async result: {result}") | |
| self.stream_active = True | |
| self.stream_start_time = asyncio.get_event_loop().time() | |
| self.captured_frames.clear() | |
| return result | |
| except Exception as e: | |
| logger.error(f"Error in start_camera_stream_async: {str(e)}") | |
| return f"Error: {str(e)}" | |
| async def stop_camera_stream_async(self) -> str: | |
| try: | |
| result = await eval_js(self.page, """ | |
| if (window.cameraWebSocket) { | |
| window.cameraStreamActive = false; | |
| window.cameraWebSocket.close(); | |
| window.cameraWebSocket = null; | |
| } | |
| return 'Camera stream stopped'; | |
| """) | |
| logger.info(f"stop_camera_stream_async result: {result}") | |
| self.stream_active = False | |
| self.stream_start_time = None | |
| return result | |
| except Exception as e: | |
| logger.error(f"Error in stop_camera_stream_async: {str(e)}") | |
| return f"Error: {str(e)}" | |
| async def handle_camera_frame(self, frame_data: str): | |
| if self.stream_active: | |
| await self.update_webcam_image(frame_data) | |
| self.capture_timed_frames(frame_data) | |
| def capture_timed_frames(self, frame_data: str): | |
| current_time = asyncio.get_event_loop().time() | |
| if self.stream_start_time is None: | |
| self.stream_start_time = current_time | |
| elapsed_time = current_time - self.stream_start_time | |
| for seconds in [1, 2, 3]: | |
| if elapsed_time >= seconds and seconds not in self.captured_frames: | |
| self.captured_frames[seconds] = Frame(frame_data, current_time) | |
| def get_captured_frames(self) -> List[Frame]: | |
| return list(self.captured_frames.values()) | |
| async def update_webcam_image(self, frame_data: str) -> None: | |
| if not frame_data: | |
| print("Empty data!") | |
| return | |
| # Frame data is already in Data URI format | |
| new_src = frame_data | |
| self.video_image1.visible = True | |
| self.video_image2.visible = True | |
| # Determine which image to update | |
| if self.current_video_image == self.video_image1: | |
| image_to_update = self.video_image2 | |
| image_to_hide = self.video_image1 | |
| else: | |
| image_to_update = self.video_image1 | |
| image_to_hide = self.video_image2 | |
| # Update the hidden image | |
| image_to_update.src = new_src | |
| image_to_update.update() | |
| # Wait for the browser to load the new image | |
| await asyncio.sleep(0.02) # Adjust this delay if needed | |
| # Update opacity | |
| image_to_update.opacity = 1 | |
| image_to_hide.opacity = 0 | |
| self.current_video_image = image_to_update | |
| # Final update to apply opacity changes | |
| self.video_stack.update() | |