SalexAI commited on
Commit
ea53bcc
·
verified ·
1 Parent(s): 88960b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -25
app.py CHANGED
@@ -1,5 +1,4 @@
1
- # Sir, this app.py implements /stream and /dashboard endpoints with telemetry streaming, offline buffering, and CSV download.
2
- # Sir, UI improved: dashboard uses responsive cards with shadows, two-column layout, scrollable feed; stream page styled simply.
3
 
4
  from fastapi import FastAPI, WebSocket
5
  from fastapi.responses import HTMLResponse, StreamingResponse
@@ -25,25 +24,29 @@ async def stream():
25
  body { margin:0; padding:0; display:flex; flex-direction:column; align-items:center; justify-content:center; height:100vh; background:#eef6fc; font-family:sans-serif; }
26
  h1 { margin-bottom:10px; color:#034f84; }
27
  #status { font-weight:bold; margin-bottom:20px; color:#fc3d03; }
28
- video { border:2px solid #034f84; border-radius:8px; }
29
  </style>
30
  </head>
31
  <body>
32
  <h1>Emerson Telemetry Stream</h1>
33
- <p id="status">Connecting...</p>
34
- <video id="video" width="320" height="240" autoplay muted></video>
35
  <script>
36
- const ws = new WebSocket(`wss://${location.host}/ws`);
37
- let buffer = [];
38
  const statusEl = document.getElementById('status');
39
- statusEl.textContent = navigator.onLine ? 'Connected' : 'Waiting for Emerson...';
40
- window.addEventListener('online', () => flushBuffer());
41
- window.addEventListener('offline', () => statusEl.textContent = 'Waiting for Emerson...');
42
- ws.onopen = () => { statusEl.textContent = 'Connected'; flushBuffer(); };
43
- ws.onclose = () => statusEl.textContent = 'Disconnected';
44
- ws.onerror = () => statusEl.textContent = 'Error';
 
 
 
 
45
 
 
46
  function sendTelemetry() {
 
47
  const video = document.getElementById('video');
48
  const canvas = document.createElement('canvas');
49
  canvas.width = video.videoWidth;
@@ -55,13 +58,30 @@ async def stream():
55
  if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(data)); else buffer.push(data);
56
  });
57
  }
58
- function flushBuffer() { while(buffer.length) ws.send(JSON.stringify(buffer.shift())); }
59
 
60
- navigator.mediaDevices.enumerateDevices().then(devices => {
61
- const cams = devices.filter(d => d.kind==='videoinput');
62
- if(cams.length) navigator.mediaDevices.getUserMedia({ video:{ deviceId:{ exact:cams[0].deviceId } } }).then(s=>video.srcObject=s);
63
- });
64
- setInterval(sendTelemetry,1000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  </script>
66
  </body>
67
  </html>
@@ -96,15 +116,15 @@ async def dashboard():
96
  const ws = new WebSocket(`wss://${location.host}/ws`);
97
  const statusEl = document.getElementById('status');
98
  const dataEl = document.getElementById('data');
99
- ws.onopen = () => statusEl.textContent='Connected';
100
- ws.onclose = () => statusEl.textContent='Disconnected';
101
  ws.onmessage = evt => {
102
  const d = JSON.parse(evt.data);
103
- statusEl.textContent='Streaming';
104
- const card = document.createElement('div'); card.className='entry';
105
  const text = document.createElement('p');
106
  text.textContent = `Time: ${new Date(d.timestamp).toLocaleTimeString()}\nGPS: ${d.gps.latitude.toFixed(5)}, ${d.gps.longitude.toFixed(5)}`;
107
- const img = document.createElement('img'); img.src=d.image;
108
  card.append(text, img);
109
  dataEl.prepend(card);
110
  };
@@ -135,7 +155,8 @@ async def websocket_endpoint(ws:WebSocket):
135
  for conn in dashboard_connections:
136
  try: await conn.send_text(json.dumps(obj))
137
  except: dashboard_connections.remove(conn)
138
- except: dashboard_connections.remove(ws)
 
139
 
140
  if __name__ == "__main__":
141
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ # Sir, this app.py implements /stream and /dashboard endpoints with telemetry streaming, offline buffering, CSV download, and proper camera permission prompt on mobile.
 
2
 
3
  from fastapi import FastAPI, WebSocket
4
  from fastapi.responses import HTMLResponse, StreamingResponse
 
24
  body { margin:0; padding:0; display:flex; flex-direction:column; align-items:center; justify-content:center; height:100vh; background:#eef6fc; font-family:sans-serif; }
25
  h1 { margin-bottom:10px; color:#034f84; }
26
  #status { font-weight:bold; margin-bottom:20px; color:#fc3d03; }
27
+ video { border:2px solid #034f84; border-radius:8px; width:100%; max-width:320px; }
28
  </style>
29
  </head>
30
  <body>
31
  <h1>Emerson Telemetry Stream</h1>
32
+ <p id="status">Initializing...</p>
33
+ <video id="video" autoplay muted playsinline></video>
34
  <script>
 
 
35
  const statusEl = document.getElementById('status');
36
+ let buffer = [];
37
+ let ws;
38
+
39
+ // Initialize WebSocket
40
+ function initWS() {
41
+ ws = new WebSocket(`wss://${location.host}/ws`);
42
+ ws.onopen = () => { statusEl.textContent = 'Connected'; flushBuffer(); };
43
+ ws.onclose = () => statusEl.textContent = 'Disconnected';
44
+ ws.onerror = () => statusEl.textContent = 'WebSocket error';
45
+ }
46
 
47
+ // Send telemetry data
48
  function sendTelemetry() {
49
+ if (!videoStream) return;
50
  const video = document.getElementById('video');
51
  const canvas = document.createElement('canvas');
52
  canvas.width = video.videoWidth;
 
58
  if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(data)); else buffer.push(data);
59
  });
60
  }
 
61
 
62
+ function flushBuffer() {
63
+ while (buffer.length && ws.readyState === WebSocket.OPEN) {
64
+ ws.send(JSON.stringify(buffer.shift()));
65
+ }
66
+ }
67
+
68
+ // Prompt for camera, mobile compatible
69
+ let videoStream;
70
+ navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
71
+ .then(stream => {
72
+ videoStream = stream;
73
+ const video = document.getElementById('video');
74
+ video.srcObject = stream;
75
+ statusEl.textContent = navigator.onLine ? 'Connected' : 'Waiting for Emerson...';
76
+ initWS();
77
+ window.addEventListener('online', () => flushBuffer());
78
+ window.addEventListener('offline', () => statusEl.textContent = 'Waiting for Emerson...');
79
+ setInterval(sendTelemetry, 1000);
80
+ })
81
+ .catch(err => {
82
+ console.error('Camera permission error:', err);
83
+ statusEl.textContent = 'Camera permission needed';
84
+ });
85
  </script>
86
  </body>
87
  </html>
 
116
  const ws = new WebSocket(`wss://${location.host}/ws`);
117
  const statusEl = document.getElementById('status');
118
  const dataEl = document.getElementById('data');
119
+ ws.onopen = () => statusEl.textContent = 'Connected';
120
+ ws.onclose = () => statusEl.textContent = 'Disconnected';
121
  ws.onmessage = evt => {
122
  const d = JSON.parse(evt.data);
123
+ statusEl.textContent = 'Streaming';
124
+ const card = document.createElement('div'); card.className = 'entry';
125
  const text = document.createElement('p');
126
  text.textContent = `Time: ${new Date(d.timestamp).toLocaleTimeString()}\nGPS: ${d.gps.latitude.toFixed(5)}, ${d.gps.longitude.toFixed(5)}`;
127
+ const img = document.createElement('img'); img.src = d.image;
128
  card.append(text, img);
129
  dataEl.prepend(card);
130
  };
 
155
  for conn in dashboard_connections:
156
  try: await conn.send_text(json.dumps(obj))
157
  except: dashboard_connections.remove(conn)
158
+ except:
159
+ dashboard_connections.remove(ws)
160
 
161
  if __name__ == "__main__":
162
  uvicorn.run(app, host="0.0.0.0", port=7860)