DivYonko commited on
Commit
4929dfe
Β·
1 Parent(s): 6909867

Add screenshot PDF export button to frontend/streamlit_app.py stats view

Browse files
Files changed (1) hide show
  1. frontend/streamlit_app.py +71 -0
frontend/streamlit_app.py CHANGED
@@ -2041,6 +2041,77 @@ elif len(st.session_state.streams) > 1:
2041
  st.divider()
2042
  st.info("Add video IDs to your extra stream slots and click β–Ά Start to enable multi-stream comparison.")
2043
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2044
  # ── AUTO REFRESH ──────────────────────────────────────────────
2045
  if auto_refresh:
2046
  time.sleep(refresh_rate)
 
2041
  st.divider()
2042
  st.info("Add video IDs to your extra stream slots and click β–Ά Start to enable multi-stream comparison.")
2043
 
2044
+ # ── SCREENSHOT / PDF EXPORT ───────────────────────────────────
2045
+ st.divider()
2046
+ st.markdown(
2047
+ '<div class="sec-hdr"><span class="sec-ttl">Export</span><span class="sec-pill">Stats Page</span></div>',
2048
+ unsafe_allow_html=True
2049
+ )
2050
+
2051
+ import streamlit.components.v1 as _components
2052
+ _components.html("""
2053
+ <div style="text-align:center; padding: 8px 0;">
2054
+ <button id="screenshotBtn" style="
2055
+ background: linear-gradient(135deg, #7c3aed, #4f46e5);
2056
+ color: #fff; border: none; border-radius: 10px;
2057
+ padding: 10px 28px; font-size: 14px; font-weight: 600;
2058
+ font-family: 'Space Grotesk', sans-serif; cursor: pointer;
2059
+ box-shadow: 0 4px 16px rgba(124,58,237,0.4); transition: transform 0.2s;"
2060
+ onmouseover="this.style.transform='translateY(-2px)'"
2061
+ onmouseout="this.style.transform='translateY(0)'"
2062
+ onclick="captureAndDownload()">
2063
+ &#128247; Download Stats as PDF
2064
+ </button>
2065
+ <div id="statusMsg" style="margin-top:8px; font-size:12px; color:#94a3b8;"></div>
2066
+ </div>
2067
+ <script>
2068
+ async function captureAndDownload() {
2069
+ const btn = document.getElementById('screenshotBtn');
2070
+ const msg = document.getElementById('statusMsg');
2071
+ btn.disabled = true; btn.textContent = 'Capturing...';
2072
+ msg.textContent = 'Please wait...';
2073
+ try {
2074
+ const target = window.parent.document.querySelector('[data-testid="stMain"]')
2075
+ || window.parent.document.querySelector('.main')
2076
+ || window.parent.document.body;
2077
+ const canvas = await window.parent.html2canvas(target, {
2078
+ scale: 1.5, useCORS: true, allowTaint: true,
2079
+ backgroundColor: '#07070f', logging: false,
2080
+ windowWidth: target.scrollWidth, windowHeight: target.scrollHeight,
2081
+ scrollX: 0, scrollY: 0,
2082
+ });
2083
+ const imgData = canvas.toDataURL('image/png', 0.95);
2084
+ const { jsPDF } = window.parent.jspdf;
2085
+ const pdf = new jsPDF({
2086
+ orientation: canvas.width > canvas.height ? 'l' : 'p',
2087
+ unit: 'px', format: [canvas.width, canvas.height], compress: true,
2088
+ });
2089
+ pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height);
2090
+ const ts = new Date().toISOString().slice(0,16).replace('T','_').replace(':','-');
2091
+ pdf.save('livepulse_stats_' + ts + '.pdf');
2092
+ btn.textContent = 'Download Stats as PDF'; btn.disabled = false;
2093
+ msg.textContent = 'Done! Check your downloads.';
2094
+ setTimeout(() => { msg.textContent = ''; }, 4000);
2095
+ } catch(e) {
2096
+ btn.textContent = 'Download Stats as PDF'; btn.disabled = false;
2097
+ msg.textContent = 'Error: ' + e.message;
2098
+ }
2099
+ }
2100
+ function loadScript(src, globalName) {
2101
+ return new Promise((resolve) => {
2102
+ if (window.parent[globalName]) { resolve(); return; }
2103
+ const s = window.parent.document.createElement('script');
2104
+ s.src = src; s.onload = resolve;
2105
+ window.parent.document.head.appendChild(s);
2106
+ });
2107
+ }
2108
+ (async () => {
2109
+ await loadScript('https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js', 'html2canvas');
2110
+ await loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js', 'jspdf');
2111
+ })();
2112
+ </script>
2113
+ """, height=90)
2114
+
2115
  # ── AUTO REFRESH ──────────────────────────────────────────────
2116
  if auto_refresh:
2117
  time.sleep(refresh_rate)