Download app.py from SolarWine/api: direct link, hf CLI and curl.
- Browser
- Download file 6.15 kB
-
https://huggingface.co/spaces/SolarWine/api/resolve/main/app.py
- Command line
-
hf download hf://spaces/SolarWine/api/app.py
-
curl -L -o app.py https://huggingface.co/spaces/SolarWine/api/resolve/main/app.py
6.15 kB
| """ | |
| Streamlit app: SolarWine — Smart Shading for Vineyard Solar Panels. | |
| 5 tabs: Overview, Photosynthesis & Data, Forecasting, Shading Simulator, Documentation. | |
| """ | |
| from __future__ import annotations | |
| import sys | |
| from pathlib import Path | |
| PROJECT_ROOT = Path(__file__).resolve().parent | |
| if str(PROJECT_ROOT) not in sys.path: | |
| sys.path.insert(0, str(PROJECT_ROOT)) | |
| try: | |
| from dotenv import load_dotenv | |
| load_dotenv(PROJECT_ROOT / ".env") | |
| except ImportError: | |
| pass | |
| import os | |
| import streamlit as st | |
| # Copy Streamlit secrets into os.environ so downstream clients (ThingsBoard, | |
| # IMS, etc.) can read them via os.environ without any code changes. | |
| for key, value in st.secrets.items(): | |
| if isinstance(value, str) and key not in os.environ: | |
| os.environ[key] = value | |
| from ui.bootstrap import img_to_base64, now_israel | |
| # --------------------------------------------------------------------------- | |
| # Page config | |
| # --------------------------------------------------------------------------- | |
| st.set_page_config(page_title="SolarWine - Smart Shading for Vineyards", layout="wide") | |
| # --------------------------------------------------------------------------- | |
| # Migration banner (shows only when new frontend URL is configured) | |
| # --------------------------------------------------------------------------- | |
| _NEW_FRONTEND_URL = os.environ.get("SOLARWINE_FRONTEND_URL", "") | |
| if _NEW_FRONTEND_URL: | |
| st.info( | |
| f"A new version of the SolarWine dashboard is available at " | |
| f"[{_NEW_FRONTEND_URL}]({_NEW_FRONTEND_URL}). " | |
| f"This Streamlit app will be retired soon.", | |
| icon="🔄", | |
| ) | |
| # --------------------------------------------------------------------------- | |
| # Brand CSS | |
| # --------------------------------------------------------------------------- | |
| _BRAND_GREEN = "#00BD3E" | |
| _BRAND_DARK = "#1A1A1A" | |
| st.markdown(f""" | |
| <style> | |
| /* SolarWine brand overrides — async font load (non-blocking) */ | |
| @font-face {{ | |
| font-family: 'Open Sans'; | |
| font-style: normal; | |
| font-weight: 300 400 600 700; | |
| font-display: swap; | |
| src: url('https://fonts.gstatic.com/s/opensans/v40/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-mu0SC55I.woff2') format('woff2'); | |
| }} | |
| html, body, [class*="css"] {{ | |
| font-family: 'Open Sans', sans-serif; | |
| }} | |
| /* Header bar */ | |
| header[data-testid="stHeader"] {{ | |
| background-color: {_BRAND_DARK}; | |
| }} | |
| /* Metric value color */ | |
| [data-testid="stMetricValue"] {{ | |
| color: {_BRAND_GREEN}; | |
| }} | |
| /* Tab labels */ | |
| button[data-baseweb="tab"] {{ | |
| font-weight: 600; | |
| }} | |
| /* Sidebar background */ | |
| section[data-testid="stSidebar"] {{ | |
| background-color: {_BRAND_DARK}; | |
| }} | |
| section[data-testid="stSidebar"] * {{ | |
| color: #FFFFFF !important; | |
| }} | |
| section[data-testid="stSidebar"] button {{ | |
| background-color: {_BRAND_GREEN} !important; | |
| color: #FFFFFF !important; | |
| border: none !important; | |
| border-radius: 6px !important; | |
| }} | |
| section[data-testid="stSidebar"] button:hover {{ | |
| background-color: #00a035 !important; | |
| }} | |
| /* Hero banner */ | |
| .hero-banner {{ | |
| background: linear-gradient(135deg, {_BRAND_DARK} 0%, #2d3a2d 100%); | |
| padding: 2rem 2.5rem; | |
| border-radius: 12px; | |
| margin-bottom: 1.5rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 2rem; | |
| }} | |
| .hero-banner img {{ | |
| max-height: 48px; | |
| }} | |
| .hero-text {{ | |
| color: #FFFFFF; | |
| }} | |
| .hero-text h1 {{ | |
| margin: 0 0 0.3rem 0; | |
| font-size: 1.8rem; | |
| font-weight: 700; | |
| color: #FFFFFF; | |
| }} | |
| .hero-text p {{ | |
| margin: 0; | |
| font-size: 1.05rem; | |
| color: #B8D4B8; | |
| }} | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --------------------------------------------------------------------------- | |
| # Hero banner with logo | |
| # --------------------------------------------------------------------------- | |
| _ASSETS = PROJECT_ROOT / "assets" | |
| _logo_path = _ASSETS / "logo.png" | |
| if _logo_path.exists(): | |
| _logo_b64 = img_to_base64(_logo_path) | |
| st.markdown(f""" | |
| <div class="hero-banner"> | |
| <img src="data:image/png;base64,{_logo_b64}" alt="SolarWine logo"> | |
| <div class="hero-text"> | |
| <h1>Smart Shading for Vineyard Solar Panels</h1> | |
| <p>Empowering growers · Harvesting sunshine</p> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| else: | |
| st.title("SolarWine — Smart Shading for Vineyard Solar Panels") | |
| # --------------------------------------------------------------------------- | |
| # Sidebar | |
| # --------------------------------------------------------------------------- | |
| sidebar = st.sidebar | |
| if _logo_path.exists(): | |
| sidebar.image(str(_logo_path), width=180) | |
| _now = now_israel() | |
| sidebar.caption("**Site:** Yeruham, Israel") | |
| sidebar.markdown(f"**Date:** {_now.strftime('%Y-%m-%d')}") | |
| sidebar.markdown(f"**Time (local):** {_now.strftime('%H:%M')}") | |
| st.session_state.current_time_israel = _now | |
| # --------------------------------------------------------------------------- | |
| # Navigation — only the selected page renders (avoids running all 6 tabs) | |
| # --------------------------------------------------------------------------- | |
| _PAGES = [ | |
| "System Status", | |
| "Overview", | |
| "Photosynthesis & Data", | |
| "Forecasting", | |
| "Shading Simulator", | |
| "Documentation", | |
| ] | |
| _selected = sidebar.radio("Navigate", _PAGES, label_visibility="collapsed") | |
| if _selected == "System Status": | |
| from ui.tab_system_status import render_tab_system_status | |
| render_tab_system_status() | |
| elif _selected == "Overview": | |
| from ui.tab_overview import render_tab_overview | |
| render_tab_overview() | |
| elif _selected == "Photosynthesis & Data": | |
| from ui.tab_data import render_tab_data | |
| render_tab_data() | |
| elif _selected == "Forecasting": | |
| from ui.tab_forecast import render_tab_forecast | |
| render_tab_forecast() | |
| elif _selected == "Shading Simulator": | |
| from ui.tab_shading import render_tab_shading | |
| render_tab_shading() | |
| elif _selected == "Documentation": | |
| from ui.tab_docs import render_tab_docs | |
| render_tab_docs() | |