|
import streamlit as st |
|
import pandas as pd |
|
from datetime import datetime |
|
import os |
|
import threading |
|
import time |
|
import base64 |
|
|
|
|
|
if 'file_history' not in st.session_state: |
|
st.session_state['file_history'] = [] |
|
if 'auto_capture_running' not in st.session_state: |
|
st.session_state['auto_capture_running'] = False |
|
if 'snapshot_data' not in st.session_state: |
|
st.session_state['snapshot_data'] = None |
|
|
|
|
|
def save_to_history(file_type, file_path): |
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
|
st.session_state['file_history'].append({ |
|
"Timestamp": timestamp, |
|
"Type": file_type, |
|
"Path": file_path |
|
}) |
|
|
|
|
|
def auto_capture(): |
|
if st.session_state['auto_capture_running'] and st.session_state['snapshot_data']: |
|
snapshot_data = st.session_state['snapshot_data'] |
|
filename = f"auto_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg" |
|
with open(filename, "wb") as f: |
|
f.write(base64.b64decode(snapshot_data.split(',')[1])) |
|
save_to_history("πΌοΈ Image", filename) |
|
threading.Timer(10, auto_capture).start() |
|
|
|
|
|
with st.sidebar: |
|
st.header("ποΈπΈ Snap Shack") |
|
if st.button("β° Start Auto-Snap"): |
|
st.session_state['auto_capture_running'] = True |
|
auto_capture() |
|
if st.button("βΉοΈ Stop Auto-Snap"): |
|
st.session_state['auto_capture_running'] = False |
|
|
|
|
|
st.subheader("π Snap Stash") |
|
if st.session_state['file_history']: |
|
images = [f for f in st.session_state['file_history'] if f['Type'] == "πΌοΈ Image"] |
|
if images: |
|
st.write("πΌοΈ Images") |
|
for img in images: |
|
st.write(f"- {img['Path']} @ {img['Timestamp']}") |
|
else: |
|
st.write("π³οΈ Empty Stash!") |
|
|
|
|
|
st.title("πΈ WebRTC Snap Craze") |
|
|
|
|
|
st.header("πΈπ₯ Snap Zone") |
|
webrtc_html = """ |
|
<div> |
|
<select id="cameraSelect"></select> |
|
<button onclick="startStream()">π· Start Stream</button> |
|
<button onclick="takeSnapshot()">πΈ Snap It!</button> |
|
<button onclick="stopStream()">βΉοΈ Stop Stream</button> |
|
<video id="video" autoplay playsinline></video> |
|
<canvas id="canvas" style="display:none;"></canvas> |
|
<img id="snapshot" style="display:none;"> |
|
</div> |
|
<script> |
|
let stream = null; |
|
let peerConnection = null; |
|
const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }; |
|
|
|
// πΉπ Enumerate cameras like a tech detective! |
|
async function enumerateCameras() { |
|
const devices = await navigator.mediaDevices.enumerateDevices(); |
|
const videoDevices = devices.filter(device => device.kind === 'videoinput'); |
|
const select = document.getElementById('cameraSelect'); |
|
select.innerHTML = ''; |
|
videoDevices.forEach((device, index) => { |
|
const option = document.createElement('option'); |
|
option.value = device.deviceId; |
|
option.text = device.label || `Camera ${index + 1}`; |
|
select.appendChild(option); |
|
}); |
|
} |
|
|
|
// πΈπ₯ Start streaming like a live broadcast pro! |
|
async function startStream() { |
|
if (stream) stopStream(); |
|
const cameraId = document.getElementById('cameraSelect').value; |
|
const constraints = { video: { deviceId: cameraId ? { exact: cameraId } : undefined } }; |
|
stream = await navigator.mediaDevices.getUserMedia(constraints); |
|
const video = document.getElementById('video'); |
|
video.srcObject = stream; |
|
|
|
peerConnection = new RTCPeerConnection(config); |
|
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); |
|
peerConnection.onicecandidate = event => { |
|
if (event.candidate) console.log('ICE Candidate:', event.candidate); |
|
}; |
|
const offer = await peerConnection.createOffer(); |
|
await peerConnection.setLocalDescription(offer); |
|
// Simulate remote answer (self-loop for demo) |
|
await peerConnection.setRemoteDescription(offer); |
|
} |
|
|
|
// πΈβοΈ Snap a pic like a stealthy paparazzi! |
|
function takeSnapshot() { |
|
const video = document.getElementById('video'); |
|
const canvas = document.getElementById('canvas'); |
|
const snapshot = document.getElementById('snapshot'); |
|
canvas.width = video.videoWidth; |
|
canvas.height = video.videoHeight; |
|
canvas.getContext('2d').drawImage(video, 0, 0); |
|
const dataUrl = canvas.toDataURL('image/jpeg'); |
|
snapshot.src = dataUrl; |
|
snapshot.style.display = 'block'; |
|
// Send snapshot to Python via session state |
|
window.parent.postMessage({ type: 'snapshot', data: dataUrl }, '*'); |
|
} |
|
|
|
// βΉοΈπ΄ Stop the stream like a broadcast kill switch! |
|
function stopStream() { |
|
if (stream) { |
|
stream.getTracks().forEach(track => track.stop()); |
|
stream = null; |
|
} |
|
if (peerConnection) { |
|
peerConnection.close(); |
|
peerConnection = null; |
|
} |
|
document.getElementById('video').srcObject = null; |
|
document.getElementById('snapshot').style.display = 'none'; |
|
} |
|
|
|
// π¬ Kick off the camera party! |
|
enumerateCameras(); |
|
</script> |
|
""" |
|
st.markdown(webrtc_html, unsafe_allow_html=True) |
|
|
|
|
|
def handle_snapshot(): |
|
if "snapshot" in st.session_state: |
|
st.session_state['snapshot_data'] = st.session_state["snapshot"] |
|
filename = f"snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg" |
|
with open(filename, "wb") as f: |
|
f.write(base64.b64decode(st.session_state['snapshot_data'].split(',')[1])) |
|
save_to_history("πΌοΈ Image", filename) |
|
st.image(filename, caption="Latest Snap", use_column_width=True) |
|
del st.session_state["snapshot"] |
|
|
|
|
|
st.components.v1.html( |
|
""" |
|
<script> |
|
window.addEventListener('message', function(event) { |
|
if (event.data.type === 'snapshot') { |
|
window.streamlitAPI.setComponentValue({snapshot: event.data.data}); |
|
} |
|
}); |
|
</script> |
|
""", |
|
height=0 |
|
) |
|
handle_snapshot() |
|
|
|
|
|
st.header("πͺ Snap Show") |
|
if st.session_state['file_history']: |
|
images = [f for f in st.session_state['file_history'] if f['Type'] == "πΌοΈ Image"] |
|
if images: |
|
st.subheader("πΌοΈ Pic Parade") |
|
cols = st.columns(3) |
|
for i, img in enumerate(images): |
|
with cols[i % 3]: |
|
st.image(img['Path'], caption=img['Path'], use_column_width=True) |
|
st.markdown(f'<a href="data:image/jpeg;base64,{base64.b64encode(open(img["Path"], "rb").read()).decode()}" download="{os.path.basename(img["Path"])}">π₯ Snag It!</a>', unsafe_allow_html=True) |
|
else: |
|
st.write("π« No snaps yet!") |
|
|
|
|
|
st.header("β³ Snap Saga") |
|
if st.session_state['file_history']: |
|
df = pd.DataFrame(st.session_state['file_history']) |
|
st.dataframe(df) |
|
else: |
|
st.write("π³οΈ Nothing snapped yet!") |