# -*- coding: utf-8 -*-
from typing import Optional, Dict, Any
import base64, mimetypes
from html import escape
from pathlib import Path
import streamlit as st
# ========= PATHS =========
BASE_DIR = Path(__file__).parent
ASSETS = BASE_DIR / "assets"
# ========= META =========
st.set_page_config(page_title="ST_LOG SUITE", layout="wide")
# ========= GLOBAL THEME (one place) =========
THEME: Dict[str, Any] = {
"strip": {
"gap": 10, "below_gap": 30, "pill_pad_v": 8, "pill_pad_h": 14,
"pill_font": 16, "tagline_font": 15,
"bg1": "#D4AF37", "bg2": "#B88917", "text": "#000052",
"tagline_color": "#000000",
},
"page": {
"top_padding": 50,
"container_width": 1120,
"bg_radial": True,
},
"hero": {
"width": 400,
"margin_bottom": 30,
"logo": ASSETS / "AI_Suite_Log_logo.png",
},
# ---------- GRID CONTROLS (you asked for this) ----------
"grid": {
"card_width": 340, # fixed card width to keep sizes consistent
"gap_x": 40, # horizontal gap between cards (px)
"gap_y": 40, # vertical gap between rows (px)
"cols_desktop": 4, # cards per row on desktop
"cols_tablet": 2, # cards per row for medium widths
"cols_mobile": 1, # cards per row on phones
# Optional: force left/center alignment of the whole grid row
"justify": "center", # 'start' | 'center' | 'end'
},
"card": {
"radius": 22, "border_width": 2, "pad_v": 24, "pad_h": 20,
"border": "#0B1220", "border_hover": "#243447",
"bg_top": "#FFFFFF", "bg_bot": "#FBFCFE",
"title_color": "#0B1220", "blurb_color": "#566275",
},
"icon": {
"diam": 118, "img": 106,
"circle_bg": "#F1F5F9",
"circle_border": "rgba(12,18,32,0.10)",
},
"button": {
"pad_v": 12, "pad_h": 20, "radius": 14,
"bg1": "#0B1220", "bg2": "#162338",
"text": "#FFFFFF", "border": "rgba(11,18,32,.55)",
},
}
# ========= CARDS =========
CARDS = [
{
"title": " ST_Log_GR",
"blurb": "Real-time gamma-ray log prediction.",
"url": "https://smart-thinking-gr.hf.space/",
"icon": ASSETS / "GR_logo.png",
"style": {"bg_top": "#EAF7F1", "bg_bot": "#F6FBF8", "border": "#0F3D3E"},
},
{
"title": " ST_Log_Sonic (Ts)",
"blurb": "Predict shear slowness (DtS) in real time.",
"url": "https://smart-thinking-sonic-ts.hf.space",
"icon": ASSETS / "Ts_logo.png",
"style": {"bg_top": "#EAF7FD", "bg_bot": "#F5FBFF", "border": "#0E4A6E"},
},
{
"title": " ST_Log_Sonic (Tc)",
"blurb": "Predict compressional slowness (DtC) in real time.",
"url": "https://smart-thinking-sonic-tc.hf.space",
"icon": ASSETS / "Tc_logo.png",
"style": {"bg_top": "#EEF0FF", "bg_bot": "#F7F8FF", "border": "#3E4EB8"},
},
{
"title": " ST_Log_RHOB",
"blurb": "Predict formation bulk density in real time.",
"url": "https://smart-thinking-rhob.hf.space",
"icon": ASSETS / "RHOB_logo.png",
"style": {"bg_top": "#EAF7FD", "bg_bot": "#F5FBFF", "border": "#0E4A6E"},
},
]
# ========= Helpers =========
def data_uri(path: Path) -> Optional[str]:
if not path or not path.exists():
return None
mime, _ = mimetypes.guess_type(path.name)
if not mime: mime = "image/png"
b64 = base64.b64encode(path.read_bytes()).decode("utf-8")
return f"data:{mime};base64,{b64}"
def img_tag(path: Path, alt: str, cls: str = "", style: str = "") -> str:
uri = data_uri(path)
if not uri: return ""
cls_attr = f' class="{cls}"' if cls else ""
style_attr = f' style="{style}"' if style else ""
return f''
# ========= CSS =========
strip = THEME["strip"]; page = THEME["page"]; hero = THEME["hero"]
grid = THEME["grid"]; card = THEME["card"]; icon = THEME["icon"]; button = THEME["button"]
bg_radial_css = """
background:
radial-gradient(980px 460px at 50% -140px,
rgba(2,12,30,0.06) 0%,
rgba(2,12,30,0.04) 28%,
rgba(255,255,255,0.98) 60%,
rgba(255,255,255,1) 100%);
""" if page["bg_radial"] else "background: #fff;"
st.markdown(f"""
""", unsafe_allow_html=True)
# ========= Strip (top-left) =========
st.markdown(
f"""
{escape(card_cfg['blurb'])}
" + f"Run App" + "