Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -3,6 +3,8 @@ import pandas as pd
|
|
3 |
from datetime import datetime
|
4 |
import os
|
5 |
import base64
|
|
|
|
|
6 |
|
7 |
# ππ₯ Initialize session state like a galactic DJ spinning tracks!
|
8 |
if 'file_history' not in st.session_state:
|
@@ -33,79 +35,101 @@ with st.sidebar:
|
|
33 |
st.write("π³οΈ Empty Stash!")
|
34 |
|
35 |
# ππ¨ Main UI kicks off like a cosmic art show!
|
36 |
-
st.title("πΈ
|
37 |
|
38 |
-
# πΈπ· JS camera zone
|
39 |
-
st.header("πΈπ₯ Snap Zone")
|
40 |
-
|
41 |
-
<div
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
<script>
|
43 |
-
let
|
44 |
-
const
|
45 |
-
|
|
|
|
|
46 |
|
47 |
// πΉπ Enumerate cameras like a tech detective!
|
48 |
-
async function
|
49 |
const devices = await navigator.mediaDevices.enumerateDevices();
|
50 |
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
|
|
|
|
51 |
videoDevices.forEach((device, index) => {
|
52 |
-
const
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
<canvas id="canvas${index}" style="display:none;"></canvas>
|
57 |
-
<button onclick="takeSnapshot(${index})">πΈ Snap Cam ${index}</button>
|
58 |
-
`;
|
59 |
-
container.appendChild(div);
|
60 |
-
startStream(device.deviceId, index);
|
61 |
});
|
|
|
|
|
|
|
62 |
}
|
63 |
|
64 |
-
// πΈπ₯
|
65 |
-
async function
|
66 |
-
const
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
74 |
|
75 |
// πΈβοΈ Snap a pic like a stealthy paparazzi!
|
76 |
-
function takeSnapshot(
|
77 |
-
|
78 |
-
const canvas = document.getElementById(`canvas${index}`);
|
79 |
canvas.width = video.videoWidth;
|
80 |
canvas.height = video.videoHeight;
|
81 |
canvas.getContext('2d').drawImage(video, 0, 0);
|
82 |
const dataUrl = canvas.toDataURL('image/jpeg');
|
83 |
-
window.parent.postMessage({ type: 'snapshot', data: dataUrl
|
84 |
}
|
85 |
|
86 |
-
// βΉοΈπ΄ Stop
|
87 |
-
function
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
|
|
92 |
}
|
93 |
|
94 |
// π¬ Kick off the camera party!
|
95 |
-
|
96 |
-
window.onunload = stopStreams;
|
97 |
</script>
|
98 |
"""
|
99 |
-
st.markdown(
|
100 |
|
101 |
# πΈπ₯ Handle snapshots from JS
|
102 |
def handle_snapshot():
|
103 |
if "snapshot" in st.session_state:
|
104 |
snapshot_data = st.session_state["snapshot"]
|
105 |
-
|
106 |
-
filename = f"cam{cam_index}_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
107 |
save_to_history("πΌοΈ Image", filename, snapshot_data)
|
108 |
-
st.image(Image.open(BytesIO(base64.b64decode(snapshot_data.split(',')[1]))), caption=
|
109 |
del st.session_state["snapshot"]
|
110 |
|
111 |
st.components.v1.html(
|
@@ -113,7 +137,7 @@ st.components.v1.html(
|
|
113 |
<script>
|
114 |
window.addEventListener('message', function(event) {
|
115 |
if (event.data.type === 'snapshot') {
|
116 |
-
window.streamlitAPI.setComponentValue({snapshot: event.data.data
|
117 |
}
|
118 |
});
|
119 |
</script>
|
|
|
3 |
from datetime import datetime
|
4 |
import os
|
5 |
import base64
|
6 |
+
from io import BytesIO
|
7 |
+
from PIL import Image
|
8 |
|
9 |
# ππ₯ Initialize session state like a galactic DJ spinning tracks!
|
10 |
if 'file_history' not in st.session_state:
|
|
|
35 |
st.write("π³οΈ Empty Stash!")
|
36 |
|
37 |
# ππ¨ Main UI kicks off like a cosmic art show!
|
38 |
+
st.title("πΈ Live Camera Snap Craze")
|
39 |
|
40 |
+
# πΈπ· JS live camera zone!
|
41 |
+
st.header("πΈπ₯ Live Snap Zone")
|
42 |
+
live_camera_html = """
|
43 |
+
<div>
|
44 |
+
<select id="cameraSelect"></select>
|
45 |
+
<button id="startBtn" onclick="toggleStream()">π· Start Live</button>
|
46 |
+
<button onclick="takeSnapshot()">πΈ Snap Now</button>
|
47 |
+
<video id="video" autoplay playsinline style="width:100%;"></video>
|
48 |
+
<canvas id="canvas" style="display:none;"></canvas>
|
49 |
+
</div>
|
50 |
<script>
|
51 |
+
let stream = null;
|
52 |
+
const video = document.getElementById('video');
|
53 |
+
const canvas = document.getElementById('canvas');
|
54 |
+
let autoCaptureInterval = null;
|
55 |
+
let isStreaming = false;
|
56 |
|
57 |
// πΉπ Enumerate cameras like a tech detective!
|
58 |
+
async function enumerateCameras() {
|
59 |
const devices = await navigator.mediaDevices.enumerateDevices();
|
60 |
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
61 |
+
const select = document.getElementById('cameraSelect');
|
62 |
+
select.innerHTML = '';
|
63 |
videoDevices.forEach((device, index) => {
|
64 |
+
const option = document.createElement('option');
|
65 |
+
option.value = device.deviceId;
|
66 |
+
option.text = device.label || `Camera ${index}`;
|
67 |
+
select.appendChild(option);
|
|
|
|
|
|
|
|
|
|
|
68 |
});
|
69 |
+
if (videoDevices.length === 0) {
|
70 |
+
select.innerHTML = '<option>No cameras found</option>';
|
71 |
+
}
|
72 |
}
|
73 |
|
74 |
+
// πΈπ₯ Toggle live stream like a broadcast pro!
|
75 |
+
async function toggleStream() {
|
76 |
+
const startBtn = document.getElementById('startBtn');
|
77 |
+
if (isStreaming) {
|
78 |
+
stopStream();
|
79 |
+
startBtn.textContent = 'π· Start Live';
|
80 |
+
isStreaming = false;
|
81 |
+
} else {
|
82 |
+
const cameraId = document.getElementById('cameraSelect').value;
|
83 |
+
if (!cameraId) {
|
84 |
+
alert('No camera selected or available!');
|
85 |
+
return;
|
86 |
+
}
|
87 |
+
const constraints = { video: { deviceId: { exact: cameraId } } };
|
88 |
+
try {
|
89 |
+
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
90 |
+
video.srcObject = stream;
|
91 |
+
startBtn.textContent = 'βΉοΈ Stop Live';
|
92 |
+
isStreaming = true;
|
93 |
+
autoCaptureInterval = setInterval(takeSnapshot, 10000); // Auto-save every 10s
|
94 |
+
} catch (e) {
|
95 |
+
alert('Failed to start camera: ' + e.message);
|
96 |
+
}
|
97 |
+
}
|
98 |
}
|
99 |
|
100 |
// πΈβοΈ Snap a pic like a stealthy paparazzi!
|
101 |
+
function takeSnapshot() {
|
102 |
+
if (!stream) return;
|
|
|
103 |
canvas.width = video.videoWidth;
|
104 |
canvas.height = video.videoHeight;
|
105 |
canvas.getContext('2d').drawImage(video, 0, 0);
|
106 |
const dataUrl = canvas.toDataURL('image/jpeg');
|
107 |
+
window.parent.postMessage({ type: 'snapshot', data: dataUrl }, '*');
|
108 |
}
|
109 |
|
110 |
+
// βΉοΈπ΄ Stop the stream like a broadcast kill switch!
|
111 |
+
function stopStream() {
|
112 |
+
if (stream) {
|
113 |
+
stream.getTracks().forEach(track => track.stop());
|
114 |
+
stream = null;
|
115 |
+
video.srcObject = null;
|
116 |
+
clearInterval(autoCaptureInterval);
|
117 |
+
}
|
118 |
}
|
119 |
|
120 |
// π¬ Kick off the camera party!
|
121 |
+
enumerateCameras();
|
|
|
122 |
</script>
|
123 |
"""
|
124 |
+
st.markdown(live_camera_html, unsafe_allow_html=True)
|
125 |
|
126 |
# πΈπ₯ Handle snapshots from JS
|
127 |
def handle_snapshot():
|
128 |
if "snapshot" in st.session_state:
|
129 |
snapshot_data = st.session_state["snapshot"]
|
130 |
+
filename = f"snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
|
|
131 |
save_to_history("πΌοΈ Image", filename, snapshot_data)
|
132 |
+
st.image(Image.open(BytesIO(base64.b64decode(snapshot_data.split(',')[1]))), caption="Latest Snap", use_container_width=True)
|
133 |
del st.session_state["snapshot"]
|
134 |
|
135 |
st.components.v1.html(
|
|
|
137 |
<script>
|
138 |
window.addEventListener('message', function(event) {
|
139 |
if (event.data.type === 'snapshot') {
|
140 |
+
window.streamlitAPI.setComponentValue({snapshot: event.data.data});
|
141 |
}
|
142 |
});
|
143 |
</script>
|