IDKHowToCodeFr commited on
Commit
4817546
·
verified ·
1 Parent(s): 55f07bf

Upload folder using huggingface_hub

Browse files
README.md CHANGED
@@ -31,7 +31,7 @@ pinned: false
31
 
32
  ---
33
 
34
- HeartFlow OS is an end-to-end telemetry and inference platform designed to stream cardiovascular vitals, predict anomalies using a soft-voting ensemble model, and export those models to highly-constrained edge devices (like ESP32/Arduino).
35
 
36
  ## System Architecture
37
 
 
31
 
32
  ---
33
 
34
+ HeartFlow OS streams cardiovascular vitals, predicts anomalies using a soft-voting ensemble, and exports models to highly-constrained edge devices (ESP32/Arduino).
35
 
36
  ## System Architecture
37
 
frontend/src/context/TelemetryContext.tsx CHANGED
@@ -1,14 +1,13 @@
1
  "use client";
2
 
3
- import { createContext, useContext, useEffect, useState, useRef } from "react";
 
4
 
5
  type StreamState = {
6
  hr: number[];
7
  temp: number[];
8
  };
9
 
10
- type ConnectionStatus = 'connected' | 'reconnecting' | 'disconnected';
11
-
12
  type TelemetryContextType = {
13
  data: any;
14
  stream: StreamState;
@@ -23,60 +22,20 @@ export function TelemetryProvider({ children }: { children: React.ReactNode }) {
23
  hr: Array(50).fill(75),
24
  temp: Array(50).fill(37.0)
25
  });
26
- const [status, setStatus] = useState<ConnectionStatus>('disconnected');
27
-
28
- const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
29
- const reconnectAttemptRef = useRef(0);
30
-
31
- useEffect(() => {
32
- let ws: WebSocket;
33
- let isComponentMounted = true;
34
-
35
- const connect = () => {
36
- ws = new WebSocket(process.env.NEXT_PUBLIC_WS_URL || "ws://localhost:8000/ws/feed");
37
-
38
- ws.onopen = () => {
39
- if (!isComponentMounted) return;
40
- setStatus('connected');
41
- reconnectAttemptRef.current = 0; // Reset attempts
42
- };
43
-
44
- ws.onmessage = (event) => {
45
- if (!isComponentMounted) return;
46
- const msg = JSON.parse(event.data);
47
- setData(msg);
48
- if (msg?.sensor_data) {
49
- setStream(prev => ({
50
- hr: [...prev.hr.slice(1), msg.sensor_data.Heart_Rate],
51
- temp: [...prev.temp.slice(1), msg.sensor_data.Body_Temp]
52
- }));
53
- }
54
- };
55
 
56
- ws.onclose = () => {
57
- if (!isComponentMounted) return;
58
- setStatus('reconnecting');
59
- const timeout = Math.min(1000 * (2 ** reconnectAttemptRef.current), 30000); // Max 30s
60
- reconnectAttemptRef.current += 1;
61
-
62
- reconnectTimeoutRef.current = setTimeout(connect, timeout);
63
- };
64
-
65
- ws.onerror = () => {
66
- if (!isComponentMounted) return;
67
- ws.close(); // Force trigger onclose
68
- };
69
- };
70
-
71
- connect();
72
-
73
- return () => {
74
- isComponentMounted = false;
75
- if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
76
- if (ws) ws.close();
77
- };
78
  }, []);
79
 
 
 
 
80
  return (
81
  <TelemetryContext.Provider value={{ data, stream, status }}>
82
  {children}
 
1
  "use client";
2
 
3
+ import { createContext, useContext, useState, useCallback } from "react";
4
+ import { useResilientSocket, ConnectionStatus } from "@/hooks/useResilientSocket";
5
 
6
  type StreamState = {
7
  hr: number[];
8
  temp: number[];
9
  };
10
 
 
 
11
  type TelemetryContextType = {
12
  data: any;
13
  stream: StreamState;
 
22
  hr: Array(50).fill(75),
23
  temp: Array(50).fill(37.0)
24
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ const handleMessage = useCallback((msg: any) => {
27
+ setData(msg);
28
+ if (msg?.sensor_data) {
29
+ setStream(prev => ({
30
+ hr: [...prev.hr.slice(1), msg.sensor_data.Heart_Rate],
31
+ temp: [...prev.temp.slice(1), msg.sensor_data.Body_Temp]
32
+ }));
33
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }, []);
35
 
36
+ const wsUrl = process.env.NEXT_PUBLIC_WS_URL || "ws://localhost:8000/ws/feed";
37
+ const status = useResilientSocket(wsUrl, handleMessage);
38
+
39
  return (
40
  <TelemetryContext.Provider value={{ data, stream, status }}>
41
  {children}
frontend/src/hooks/useResilientSocket.ts ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useRef, useState } from "react";
2
+
3
+ export type ConnectionStatus = 'connected' | 'reconnecting' | 'disconnected';
4
+
5
+ export function useResilientSocket(url: string, onMessage: (msg: any) => void) {
6
+ const [status, setStatus] = useState<ConnectionStatus>('disconnected');
7
+ const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
8
+ const reconnectAttemptRef = useRef(0);
9
+ const savedCallback = useRef(onMessage);
10
+
11
+ useEffect(() => {
12
+ savedCallback.current = onMessage;
13
+ }, [onMessage]);
14
+
15
+ useEffect(() => {
16
+ let ws: WebSocket;
17
+ let isComponentMounted = true;
18
+
19
+ const connect = () => {
20
+ ws = new WebSocket(url);
21
+
22
+ ws.onopen = () => {
23
+ if (!isComponentMounted) return;
24
+ setStatus('connected');
25
+ reconnectAttemptRef.current = 0; // Reset attempts
26
+ };
27
+
28
+ ws.onmessage = (event) => {
29
+ if (!isComponentMounted) return;
30
+ const msg = JSON.parse(event.data);
31
+ savedCallback.current(msg);
32
+ };
33
+
34
+ ws.onclose = () => {
35
+ if (!isComponentMounted) return;
36
+ setStatus('reconnecting');
37
+ const timeout = Math.min(1000 * (2 ** reconnectAttemptRef.current), 30000); // Max 30s
38
+ reconnectAttemptRef.current += 1;
39
+
40
+ reconnectTimeoutRef.current = setTimeout(connect, timeout);
41
+ };
42
+
43
+ ws.onerror = () => {
44
+ if (!isComponentMounted) return;
45
+ ws.close(); // Force trigger onclose
46
+ };
47
+ };
48
+
49
+ connect();
50
+
51
+ return () => {
52
+ isComponentMounted = false;
53
+ if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
54
+ if (ws) ws.close();
55
+ };
56
+ }, [url]);
57
+
58
+ return status;
59
+ }