Update app.py
Browse files
app.py
CHANGED
@@ -4,15 +4,20 @@ from datetime import datetime
|
|
4 |
import os
|
5 |
import threading
|
6 |
import time
|
7 |
-
import
|
|
|
8 |
|
9 |
# ππ₯ Initialize session state like a galactic DJ spinning tracks!
|
10 |
if 'file_history' not in st.session_state:
|
11 |
st.session_state['file_history'] = []
|
12 |
if 'auto_capture_running' not in st.session_state:
|
13 |
st.session_state['auto_capture_running'] = False
|
14 |
-
if '
|
15 |
-
st.session_state['
|
|
|
|
|
|
|
|
|
16 |
|
17 |
# ππΎ Save to history like a time-traveling scribe! | π
β¨ save_to_history("πΌοΈ Image", "pic.jpg") - Stamps a pic in the history books like a boss!
|
18 |
def save_to_history(file_type, file_path):
|
@@ -25,17 +30,18 @@ def save_to_history(file_type, file_path):
|
|
25 |
|
26 |
# πΈβ° Auto-capture every 10 secs like a sneaky shutterbug!
|
27 |
def auto_capture():
|
28 |
-
if st.session_state['auto_capture_running'] and st.session_state['
|
29 |
-
|
30 |
filename = f"auto_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
31 |
with open(filename, "wb") as f:
|
32 |
-
f.write(
|
33 |
save_to_history("πΌοΈ Image", filename)
|
34 |
threading.Timer(10, auto_capture).start()
|
35 |
|
36 |
# ποΈ Sidebar config like a spaceship control panel!
|
37 |
with st.sidebar:
|
38 |
st.header("ποΈπΈ Snap Shack")
|
|
|
39 |
if st.button("β° Start Auto-Snap"):
|
40 |
st.session_state['auto_capture_running'] = True
|
41 |
auto_capture()
|
@@ -54,119 +60,45 @@ with st.sidebar:
|
|
54 |
st.write("π³οΈ Empty Stash!")
|
55 |
|
56 |
# ππ¨ Main UI kicks off like a cosmic art show!
|
57 |
-
st.title("πΈ
|
58 |
|
59 |
-
# πΈπ·
|
60 |
st.header("πΈπ₯ Snap Zone")
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
<canvas id="canvas" style="display:none;"></canvas>
|
69 |
-
<img id="snapshot" style="display:none;">
|
70 |
-
</div>
|
71 |
-
<script>
|
72 |
-
let stream = null;
|
73 |
-
let peerConnection = null;
|
74 |
-
const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
|
75 |
-
|
76 |
-
// πΉπ Enumerate cameras like a tech detective!
|
77 |
-
async function enumerateCameras() {
|
78 |
-
const devices = await navigator.mediaDevices.enumerateDevices();
|
79 |
-
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
80 |
-
const select = document.getElementById('cameraSelect');
|
81 |
-
select.innerHTML = '';
|
82 |
-
videoDevices.forEach((device, index) => {
|
83 |
-
const option = document.createElement('option');
|
84 |
-
option.value = device.deviceId;
|
85 |
-
option.text = device.label || `Camera ${index + 1}`;
|
86 |
-
select.appendChild(option);
|
87 |
-
});
|
88 |
-
}
|
89 |
-
|
90 |
-
// πΈπ₯ Start streaming like a live broadcast pro!
|
91 |
-
async function startStream() {
|
92 |
-
if (stream) stopStream();
|
93 |
-
const cameraId = document.getElementById('cameraSelect').value;
|
94 |
-
const constraints = { video: { deviceId: cameraId ? { exact: cameraId } : undefined } };
|
95 |
-
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
96 |
-
const video = document.getElementById('video');
|
97 |
-
video.srcObject = stream;
|
98 |
-
|
99 |
-
peerConnection = new RTCPeerConnection(config);
|
100 |
-
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
|
101 |
-
peerConnection.onicecandidate = event => {
|
102 |
-
if (event.candidate) console.log('ICE Candidate:', event.candidate);
|
103 |
-
};
|
104 |
-
const offer = await peerConnection.createOffer();
|
105 |
-
await peerConnection.setLocalDescription(offer);
|
106 |
-
// Simulate remote answer (self-loop for demo)
|
107 |
-
await peerConnection.setRemoteDescription(offer);
|
108 |
-
}
|
109 |
-
|
110 |
-
// πΈβοΈ Snap a pic like a stealthy paparazzi!
|
111 |
-
function takeSnapshot() {
|
112 |
-
const video = document.getElementById('video');
|
113 |
-
const canvas = document.getElementById('canvas');
|
114 |
-
const snapshot = document.getElementById('snapshot');
|
115 |
-
canvas.width = video.videoWidth;
|
116 |
-
canvas.height = video.videoHeight;
|
117 |
-
canvas.getContext('2d').drawImage(video, 0, 0);
|
118 |
-
const dataUrl = canvas.toDataURL('image/jpeg');
|
119 |
-
snapshot.src = dataUrl;
|
120 |
-
snapshot.style.display = 'block';
|
121 |
-
// Send snapshot to Python via session state
|
122 |
-
window.parent.postMessage({ type: 'snapshot', data: dataUrl }, '*');
|
123 |
-
}
|
124 |
-
|
125 |
-
// βΉοΈπ΄ Stop the stream like a broadcast kill switch!
|
126 |
-
function stopStream() {
|
127 |
-
if (stream) {
|
128 |
-
stream.getTracks().forEach(track => track.stop());
|
129 |
-
stream = null;
|
130 |
-
}
|
131 |
-
if (peerConnection) {
|
132 |
-
peerConnection.close();
|
133 |
-
peerConnection = null;
|
134 |
-
}
|
135 |
-
document.getElementById('video').srcObject = null;
|
136 |
-
document.getElementById('snapshot').style.display = 'none';
|
137 |
-
}
|
138 |
-
|
139 |
-
// π¬ Kick off the camera party!
|
140 |
-
enumerateCameras();
|
141 |
-
</script>
|
142 |
-
"""
|
143 |
-
st.markdown(webrtc_html, unsafe_allow_html=True)
|
144 |
-
|
145 |
-
# πΈπ₯ Handle snapshots from JS
|
146 |
-
def handle_snapshot():
|
147 |
-
if "snapshot" in st.session_state:
|
148 |
-
st.session_state['snapshot_data'] = st.session_state["snapshot"]
|
149 |
-
filename = f"snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
150 |
with open(filename, "wb") as f:
|
151 |
-
f.write(
|
|
|
|
|
152 |
save_to_history("πΌοΈ Image", filename)
|
153 |
-
st.image(filename, caption="
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
)
|
169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
|
171 |
# πΌοΈ Gallery like a media circus!
|
172 |
st.header("πͺ Snap Show")
|
@@ -178,7 +110,9 @@ if st.session_state['file_history']:
|
|
178 |
for i, img in enumerate(images):
|
179 |
with cols[i % 3]:
|
180 |
st.image(img['Path'], caption=img['Path'], use_column_width=True)
|
181 |
-
|
|
|
|
|
182 |
else:
|
183 |
st.write("π« No snaps yet!")
|
184 |
|
|
|
4 |
import os
|
5 |
import threading
|
6 |
import time
|
7 |
+
from PIL import Image
|
8 |
+
from io import BytesIO
|
9 |
|
10 |
# ππ₯ Initialize session state like a galactic DJ spinning tracks!
|
11 |
if 'file_history' not in st.session_state:
|
12 |
st.session_state['file_history'] = []
|
13 |
if 'auto_capture_running' not in st.session_state:
|
14 |
st.session_state['auto_capture_running'] = False
|
15 |
+
if 'cam0_file' not in st.session_state:
|
16 |
+
st.session_state['cam0_file'] = None
|
17 |
+
if 'cam1_file' not in st.session_state:
|
18 |
+
st.session_state['cam1_file'] = None
|
19 |
+
if 'selected_cam_img' not in st.session_state:
|
20 |
+
st.session_state['selected_cam_img'] = None
|
21 |
|
22 |
# ππΎ Save to history like a time-traveling scribe! | π
β¨ save_to_history("πΌοΈ Image", "pic.jpg") - Stamps a pic in the history books like a boss!
|
23 |
def save_to_history(file_type, file_path):
|
|
|
30 |
|
31 |
# πΈβ° Auto-capture every 10 secs like a sneaky shutterbug!
|
32 |
def auto_capture():
|
33 |
+
if st.session_state['auto_capture_running'] and st.session_state['selected_cam_img']:
|
34 |
+
cam_img = st.session_state['selected_cam_img']
|
35 |
filename = f"auto_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
36 |
with open(filename, "wb") as f:
|
37 |
+
f.write(cam_img.getvalue())
|
38 |
save_to_history("πΌοΈ Image", filename)
|
39 |
threading.Timer(10, auto_capture).start()
|
40 |
|
41 |
# ποΈ Sidebar config like a spaceship control panel!
|
42 |
with st.sidebar:
|
43 |
st.header("ποΈπΈ Snap Shack")
|
44 |
+
camera_choice = st.selectbox("π· Pick a Cam", ["Camera 0", "Camera 1"])
|
45 |
if st.button("β° Start Auto-Snap"):
|
46 |
st.session_state['auto_capture_running'] = True
|
47 |
auto_capture()
|
|
|
60 |
st.write("π³οΈ Empty Stash!")
|
61 |
|
62 |
# ππ¨ Main UI kicks off like a cosmic art show!
|
63 |
+
st.title("πΈ Streamlit Snap Craze")
|
64 |
|
65 |
+
# πΈπ· Camera snap zone!
|
66 |
st.header("πΈπ₯ Snap Zone")
|
67 |
+
cols = st.columns(2)
|
68 |
+
with cols[0]:
|
69 |
+
cam0_img = st.camera_input("π· Camera 0", key="cam0")
|
70 |
+
if cam0_img and camera_choice == "Camera 0":
|
71 |
+
filename = f"cam0_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
72 |
+
if st.session_state['cam0_file'] and os.path.exists(st.session_state['cam0_file']):
|
73 |
+
os.remove(st.session_state['cam0_file'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
with open(filename, "wb") as f:
|
75 |
+
f.write(cam0_img.getvalue())
|
76 |
+
st.session_state['cam0_file'] = filename
|
77 |
+
st.session_state['selected_cam_img'] = cam0_img
|
78 |
save_to_history("πΌοΈ Image", filename)
|
79 |
+
st.image(Image.open(filename), caption="Camera 0 Snap", use_column_width=True)
|
80 |
+
with cols[1]:
|
81 |
+
cam1_img = st.camera_input("π· Camera 1", key="cam1")
|
82 |
+
if cam1_img and camera_choice == "Camera 1":
|
83 |
+
filename = f"cam1_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
|
84 |
+
if st.session_state['cam1_file'] and os.path.exists(st.session_state['cam1_file']):
|
85 |
+
os.remove(st.session_state['cam1_file'])
|
86 |
+
with open(filename, "wb") as f:
|
87 |
+
f.write(cam1_img.getvalue())
|
88 |
+
st.session_state['cam1_file'] = filename
|
89 |
+
st.session_state['selected_cam_img'] = cam1_img
|
90 |
+
save_to_history("πΌοΈ Image", filename)
|
91 |
+
st.image(Image.open(filename), caption="Camera 1 Snap", use_column_width=True)
|
92 |
+
|
93 |
+
# π Upload zone like a media drop party!
|
94 |
+
st.header("π₯π Drop Zone")
|
95 |
+
uploaded_files = st.file_uploader("πΈ Toss Pics", accept_multiple_files=True, type=['jpg', 'png'])
|
96 |
+
if uploaded_files:
|
97 |
+
for uploaded_file in uploaded_files:
|
98 |
+
file_path = f"uploaded_{uploaded_file.name}"
|
99 |
+
with open(file_path, "wb") as f:
|
100 |
+
f.write(uploaded_file.read())
|
101 |
+
save_to_history("πΌοΈ Image", file_path)
|
102 |
|
103 |
# πΌοΈ Gallery like a media circus!
|
104 |
st.header("πͺ Snap Show")
|
|
|
110 |
for i, img in enumerate(images):
|
111 |
with cols[i % 3]:
|
112 |
st.image(img['Path'], caption=img['Path'], use_column_width=True)
|
113 |
+
with open(img['Path'], "rb") as f:
|
114 |
+
img_data = f.read()
|
115 |
+
st.markdown(f'<a href="data:image/jpeg;base64,{base64.b64encode(img_data).decode()}" download="{os.path.basename(img["Path"])}">π₯ Snag It!</a>', unsafe_allow_html=True)
|
116 |
else:
|
117 |
st.write("π« No snaps yet!")
|
118 |
|