UCS2014 commited on
Commit
a2a6274
·
verified ·
1 Parent(s): a29d564

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -208
app.py CHANGED
@@ -1,59 +1,53 @@
1
- # -*- coding: utf-8 -*-
2
  import base64, mimetypes
3
  from html import escape
4
  from pathlib import Path
5
  import streamlit as st
6
 
7
- # ========= PATHS =========
 
 
 
8
  BASE_DIR = Path(__file__).parent
9
  ASSETS = BASE_DIR / "assets"
 
10
 
11
- # ========= CONTROLS =========
12
- HERO_LOGO_SIZE = 168
13
- TOP_SPACER = 120
14
- GRID_GAP = 40
15
- BUTTON_TEXT = "Open App"
16
- OPEN_IN_NEW_TAB = False
17
-
18
- # BRAND (Logging suite)
19
  COMPANY_NAME = "Smart Thinking - Logging"
20
  TAGLINE = "We Deliver Smart AI-Based Solutions For O&G Industry"
21
  SUITE_NAME = "ST_LOG SUITE"
22
- ACCENT = "#0E7490" # teal start
23
- ACCENT_END = "#14B8A6" # teal end
24
-
25
- # ========= APPS =========
26
- APP1 = {
27
- "title": "ST_Log_GR",
28
- "url": "https://smart-thinking-gr.hf.space/",
29
- "blurb": "Real-time gamma-ray log prediction.",
30
- "icon": ASSETS / "app1_icon.png", # optional 24–32px glyph
31
- }
32
- APP2 = {
33
- "title": "ST_Log_Sonic (Ts)",
34
- "url": "https://smart-thinking-sonic-ts.hf.space",
35
- "blurb": "Predict shear slowness (ΔtS) in real time.",
36
- "icon": ASSETS / "app2_icon.png",
37
- }
38
- APP3 = {
39
- "title": "ST_Log_Sonic (Tc)",
40
- "url": "https://smart-thinking-sonic-tc.hf.space",
41
- "blurb": "Predict compressional slowness (ΔtC) in real time.",
42
- "icon": ASSETS / "app3_icon.png",
43
- }
44
 
45
- LOGO_PATH = ASSETS / "logo.png"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- # ========= PAGE META =========
48
- page_icon = str(LOGO_PATH) if LOGO_PATH.exists() else "🧭"
49
- st.set_page_config(page_title=f"{COMPANY_NAME} — Apps", page_icon=page_icon, layout="wide")
50
-
51
- # ========= HELPERS =========
52
  def data_uri(path: Path) -> str | None:
53
  if not path or not path.exists():
54
  return None
55
  mime, _ = mimetypes.guess_type(path.name)
56
- if not mime: mime = "image/png"
 
 
57
  b64 = base64.b64encode(path.read_bytes()).decode("utf-8")
58
  return f"data:{mime};base64,{b64}"
59
 
@@ -62,185 +56,161 @@ def img_tag(path: Path, alt: str, cls: str = "") -> str:
62
  if uri:
63
  cls_attr = f' class="{cls}"' if cls else ""
64
  return f'<img{cls_attr} src="{uri}" alt="{escape(alt)}" />'
65
- return f'<div class="{cls}" style="display:flex;align-items:center;justify-content:center;color:#6b7280;background:#eef2f7;border-radius:8px;">{escape(alt)}</div>'
66
 
67
  def tiny_icon_html(path: Path) -> str:
68
  uri = data_uri(path)
69
- return f"<img src='{uri}' alt='icon' style='width:22px;height:22px;display:block;'>" if uri else ""
70
 
71
- # ========= BACKGROUND (calm gradient) =========
72
  st.markdown(f"""
73
  <style>
74
- .stApp {{
75
- position: relative !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  background:
77
- radial-gradient(1200px 520px at 50% -80px,
78
  rgba(20,184,166,0.10) 0%,
79
  rgba(14,116,144,0.06) 28%,
80
- rgba(255,255,255,0.96) 64%,
81
- rgba(255,255,255,1) 100%) !important;
82
- }}
83
- [data-testid="stAppViewContainer"],
84
- [data-testid="stAppViewContainer"] > .main,
85
- html, body {{
86
- background: transparent !important;
87
  }}
88
- </style>
89
- """, unsafe_allow_html=True)
90
 
91
- # ========= CORE CSS =========
92
- st.markdown(
93
- f"""
94
- <style>
95
- :root {{
96
- --top-spacer: {TOP_SPACER}px;
97
- --grid-gap: {GRID_GAP}px;
98
- --brand: {ACCENT};
99
- --brand2: {ACCENT_END};
100
- }}
101
-
102
- html, body, [data-testid="stAppViewContainer"] {{ height: 100%; }}
103
- [data-testid="stAppViewContainer"] > .main {{
104
- padding-top: 0 !important; padding-bottom: 0 !important;
105
- }}
106
-
107
- .block-container {{
108
- max-width: 1080px;
109
- min-height: 100vh;
110
- display: flex; flex-direction: column;
111
- justify-content: flex-start;
112
- gap: 14px;
113
- padding: var(--top-spacer) 0 20px !important;
114
- }}
115
-
116
- /* HERO */
117
- .hero {{ text-align:center; margin: 0 0 0; }}
118
- .hero img {{
119
- width: {HERO_LOGO_SIZE}px; max-width: 95vw; height: auto;
120
- display:block; margin: 0 auto 8px;
121
- filter: drop-shadow(0 4px 14px rgba(0,0,0,.08));
122
- }}
123
- .hero h1 {{
124
- font-size: 2.4rem; line-height: 1.15; margin: .25rem 0 .15rem;
125
- letter-spacing: .2px; color: #0F172A;
126
- }}
127
- .hero p {{
128
- color: #445066; margin: 2px auto 10px; max-width: 720px; font-style: italic;
129
- }}
130
-
131
- /* SUITE BANNER (lighter) */
132
- .suite-banner {{
133
- display:flex; gap:12px; justify-content:center; align-items:center;
134
- margin: 4px 0 16px;
135
- }}
136
- .suite-pill {{
137
- background: linear-gradient(90deg, var(--brand) 0%, var(--brand2) 100%);
138
- color:#fff; padding:7px 12px; border-radius:999px;
139
- font-weight:700; letter-spacing:.2px;
140
- box-shadow: 0 6px 14px rgba(14,116,144,.22);
141
- }}
142
- .suite-sub {{
143
- color:#3b4656; font-weight:500; opacity:.92;
144
- }}
145
 
146
- /* GRID (3 → 2 → 1) */
147
- .grid {{
148
- display: grid;
149
- grid-template-columns: repeat(3, 280px);
150
- gap: var(--grid-gap);
151
- justify-content: center;
152
- align-items: stretch;
153
- margin-top: 8px;
154
- }}
155
- @media (max-width: 1040px) {{
156
- .grid {{ grid-template-columns: repeat(2, 280px); gap: 28px; }}
157
- }}
158
- @media (max-width: 640px) {{
159
- .grid {{ grid-template-columns: 1fr; }}
160
- }}
161
 
162
- /* CARD (clean + roomy) */
163
- .card {{
164
- width: 280px;
165
- background: #ffffff;
166
- border: 1px solid rgba(2,20,35,.06);
167
- border-radius:16px; padding:18px 16px 16px;
168
- box-shadow: 0 8px 28px rgba(2,20,35,.06);
169
- transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
170
- text-align:center; display:flex; flex-direction:column; gap:10px;
171
- align-items: center;
172
- }}
173
- .card:hover {{
174
- transform: translateY(-4px);
175
- box-shadow: 0 16px 44px rgba(2,20,35,.12);
176
- border-color: rgba(14,116,144,0.18);
177
- }}
178
 
179
- /* Top-left chip instead of big badge */
180
- .chip {{
181
- position: relative;
182
- align-self: stretch;
183
- display:flex; justify-content:flex-start; align-items:center; gap:8px;
184
- height: 34px;
185
- margin: 0 0 6px 0;
186
- }}
187
- .chip .pill {{
188
- display:flex; align-items:center; gap:8px;
189
- background: linear-gradient(90deg, var(--brand) 0%, var(--brand2) 100%);
190
- color:#fff; padding:6px 10px; border-radius:999px;
191
- font-weight:700; font-size:.85rem; letter-spacing:.2px;
192
- box-shadow: 0 6px 14px rgba(14,116,144,.22);
193
- }}
194
- .chip .dot {{
195
- width: 26px; height: 26px; border-radius: 8px;
196
- background: rgba(255,255,255,.18);
197
- display:grid; place-items:center; overflow:hidden;
198
- }}
199
- .chip .dot img {{ width:18px; height:18px; display:block; }}
200
 
201
- .card h3 {{
202
- margin: 8px 0 0; font-size: 1.05rem; font-weight: 800; color:#0b1220;
203
- }}
204
- .card p {{
205
- color:#536071; min-height: 32px; margin: 4px 8px 0; font-size: .96rem;
206
- }}
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
- /* BUTTON */
209
- .btn {{
210
- display:inline-block; padding:10px 16px; border-radius:12px;
211
- border:1px solid rgba(14,116,144,0.25); text-decoration:none;
212
- background: linear-gradient(90deg, var(--brand) 0%, var(--brand2) 100%);
213
- color: white; font-weight: 600; letter-spacing:.2px;
214
- margin: 10px auto 0;
215
- box-shadow: 0 6px 18px rgba(20,184,166,.26);
216
- }}
217
- .btn:hover {{
218
- filter: brightness(0.98) saturate(1.05);
219
- transform: translateY(-1px);
220
- box-shadow: 0 12px 28px rgba(20,184,166,.34);
221
- }}
222
 
223
- .footer {{ text-align:center; color:#3f4a5a; font-size:0.98em; margin-top: 24px; }}
224
- .footer hr {{ margin: 12px 0; border-color: rgba(0,0,0,.08); }}
225
- </style>
226
- """,
227
- unsafe_allow_html=True,
228
- )
 
 
 
 
 
 
 
 
229
 
230
- # ========= HERO =========
231
- def img_or_blank(path: Path) -> str:
232
- return img_tag(path, "logo", "") if path.exists() else ""
 
233
 
 
 
234
  st.markdown(
235
- '<div class="hero">'
236
- + img_or_blank(LOGO_PATH)
237
- + f"<h1>{escape(COMPANY_NAME)}</h1>"
238
- + f"<p>{escape(TAGLINE)}</p>"
239
- + "</div>",
 
 
240
  unsafe_allow_html=True,
241
  )
242
 
243
- # ========= SUITE BANNER =========
244
  st.markdown(
245
  f"""
246
  <div class="suite-banner">
@@ -251,9 +221,9 @@ st.markdown(
251
  unsafe_allow_html=True,
252
  )
253
 
254
- # ========= CARDS =========
255
  def card_chip(icon_path: Path | None) -> str:
256
- icon_html = f"{tiny_icon_html(icon_path)}" if icon_path else ""
257
  return f"""
258
  <div class="chip">
259
  <div class="pill">
@@ -264,26 +234,20 @@ def card_chip(icon_path: Path | None) -> str:
264
  """
265
 
266
  def app_card(app: dict) -> str:
267
- target = "_blank" if OPEN_IN_NEW_TAB else "_self"
268
  return (
269
  f"<div class='card'>"
270
  + card_chip(app.get("icon"))
271
  + f"<h3>{escape(app['title'])}</h3>"
272
  + f"<p>{escape(app['blurb'])}</p>"
273
- + f"<a class='btn' href='{escape(app['url'])}' target='{target}' rel='noopener'>{escape(BUTTON_TEXT)}</a>"
274
  + "</div>"
275
  )
276
 
277
- st.markdown(
278
- "<div class='grid'>"
279
- + app_card(APP1)
280
- + app_card(APP2)
281
- + app_card(APP3)
282
- + "</div>",
283
- unsafe_allow_html=True,
284
- )
285
 
286
- # ========= FOOTER =========
287
  st.markdown(
288
  """
289
  <hr>
 
1
+ # STEP 2 CLEAN BRANDED UI
2
  import base64, mimetypes
3
  from html import escape
4
  from pathlib import Path
5
  import streamlit as st
6
 
7
+ # --------- META FIRST ---------
8
+ st.set_page_config(page_title="Smart Thinking - Logging — Apps", page_icon="🧭", layout="wide")
9
+
10
+ # --------- PATHS ---------
11
  BASE_DIR = Path(__file__).parent
12
  ASSETS = BASE_DIR / "assets"
13
+ LOGO_PATH = ASSETS / "logo.png" # optional; renders if present
14
 
15
+ # --------- BRAND / DATA ---------
 
 
 
 
 
 
 
16
  COMPANY_NAME = "Smart Thinking - Logging"
17
  TAGLINE = "We Deliver Smart AI-Based Solutions For O&G Industry"
18
  SUITE_NAME = "ST_LOG SUITE"
19
+ ACCENT = "#0E7490" # start
20
+ ACCENT_END = "#14B8A6" # end
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ APPS = [
23
+ {
24
+ "title": "ST_Log_GR",
25
+ "url": "https://smart-thinking-gr.hf.space/",
26
+ "blurb": "Real-time gamma-ray log prediction.",
27
+ "icon": ASSETS / "app1_icon.png", # optional tiny glyph
28
+ },
29
+ {
30
+ "title": "ST_Log_Sonic (Ts)",
31
+ "url": "https://smart-thinking-sonic-ts.hf.space",
32
+ "blurb": "Predict shear slowness (DtS) in real time.", # ASCII only to avoid encoding issues
33
+ "icon": ASSETS / "app2_icon.png",
34
+ },
35
+ {
36
+ "title": "ST_Log_Sonic (Tc)",
37
+ "url": "https://smart-thinking-sonic-tc.hf.space",
38
+ "blurb": "Predict compressional slowness (DtC) in real time.",
39
+ "icon": ASSETS / "app3_icon.png",
40
+ },
41
+ ]
42
 
43
+ # --------- HELPERS ---------
 
 
 
 
44
  def data_uri(path: Path) -> str | None:
45
  if not path or not path.exists():
46
  return None
47
  mime, _ = mimetypes.guess_type(path.name)
48
+ if not mime:
49
+ mime = "image/png"
50
+ import base64
51
  b64 = base64.b64encode(path.read_bytes()).decode("utf-8")
52
  return f"data:{mime};base64,{b64}"
53
 
 
56
  if uri:
57
  cls_attr = f' class="{cls}"' if cls else ""
58
  return f'<img{cls_attr} src="{uri}" alt="{escape(alt)}" />'
59
+ return "" # silently skip if missing
60
 
61
  def tiny_icon_html(path: Path) -> str:
62
  uri = data_uri(path)
63
+ return f"<img src='{uri}' alt='icon' style='width:18px;height:18px;display:block;border-radius:4px;'>" if uri else ""
64
 
65
+ # --------- SAFE CSS (ONE BLOCK) ---------
66
  st.markdown(f"""
67
  <style>
68
+ :root {{
69
+ --brand: {ACCENT};
70
+ --brand2: {ACCENT_END};
71
+ }}
72
+
73
+ html, body, [data-testid="stAppViewContainer"] {{ height: 100%; }}
74
+ [data-testid="stAppViewContainer"] > .main {{
75
+ padding-top: 0 !important; padding-bottom: 0 !important;
76
+ }}
77
+
78
+ .block-container {{
79
+ max-width: 1080px;
80
+ min-height: 100vh;
81
+ display: flex; flex-direction: column;
82
+ gap: 8px;
83
+ padding: 100px 0 24px !important; /* generous top space */
84
  background:
85
+ radial-gradient(900px 420px at 50% -120px,
86
  rgba(20,184,166,0.10) 0%,
87
  rgba(14,116,144,0.06) 28%,
88
+ rgba(255,255,255,0.98) 64%,
89
+ rgba(255,255,255,1) 100%);
 
 
 
 
 
90
  }}
 
 
91
 
92
+ /* HERO */
93
+ .hero {{ text-align:center; margin: 0 0 6px; }}
94
+ .hero img {{
95
+ width: 160px; max-width: 95vw; height: auto;
96
+ display:block; margin: 0 auto 8px;
97
+ filter: drop-shadow(0 4px 12px rgba(0,0,0,.08));
98
+ }}
99
+ .hero h1 {{
100
+ font-size: 2.3rem; line-height: 1.15; margin: .25rem 0 .15rem;
101
+ letter-spacing: .2px; color: #0F172A;
102
+ }}
103
+ .hero p {{
104
+ color: #445066; margin: 2px auto 10px; max-width: 720px; font-style: italic;
105
+ }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ /* SUITE BANNER */
108
+ .suite-banner {{
109
+ display:flex; gap:12px; justify-content:center; align-items:center;
110
+ margin: 6px 0 18px;
111
+ }}
112
+ .suite-pill {{
113
+ background: linear-gradient(90deg, var(--brand) 0%, var(--brand2) 100%);
114
+ color:#fff; padding:7px 12px; border-radius:999px;
115
+ font-weight:700; letter-spacing:.2px;
116
+ box-shadow: 0 6px 14px rgba(14,116,144,.22);
117
+ }}
118
+ .suite-sub {{ color:#3b4656; font-weight:500; opacity:.92; }}
 
 
 
119
 
120
+ /* GRID */
121
+ .grid {{
122
+ display: grid;
123
+ grid-template-columns: repeat(3, 280px);
124
+ gap: 36px;
125
+ justify-content: center;
126
+ align-items: stretch;
127
+ margin-top: 4px;
128
+ }}
129
+ @media (max-width: 1040px) {{
130
+ .grid {{ grid-template-columns: repeat(2, 280px); gap: 28px; }}
131
+ }}
132
+ @media (max-width: 640px) {{
133
+ .grid {{ grid-template-columns: 1fr; }}
134
+ }}
 
135
 
136
+ /* CARD */
137
+ .card {{
138
+ width: 280px;
139
+ background: #ffffff;
140
+ border: 1px solid rgba(2,20,35,.06);
141
+ border-radius:16px; padding:16px 16px 16px;
142
+ box-shadow: 0 8px 28px rgba(2,20,35,.06);
143
+ transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
144
+ text-align:center; display:flex; flex-direction:column; gap:10px;
145
+ align-items: center;
146
+ }}
147
+ .card:hover {{
148
+ transform: translateY(-4px);
149
+ box-shadow: 0 16px 44px rgba(2,20,35,.12);
150
+ border-color: rgba(14,116,144,0.18);
151
+ }}
 
 
 
 
 
152
 
153
+ /* Small corner chip (keeps branding without crowding) */
154
+ .chip {{
155
+ align-self: stretch;
156
+ display:flex; justify-content:flex-start; align-items:center; gap:8px;
157
+ height: 30px; margin: 0 0 6px 0;
158
+ }}
159
+ .chip .pill {{
160
+ display:flex; align-items:center; gap:8px;
161
+ background: linear-gradient(90deg, var(--brand) 0%, var(--brand2) 100%);
162
+ color:#fff; padding:5px 10px; border-radius:999px;
163
+ font-weight:700; font-size:.82rem; letter-spacing:.2px;
164
+ box-shadow: 0 6px 14px rgba(14,116,144,.22);
165
+ }}
166
+ .chip .dot {{
167
+ width: 22px; height: 22px; border-radius: 7px;
168
+ background: rgba(255,255,255,.18);
169
+ display:grid; place-items:center; overflow:hidden;
170
+ }}
171
+ .chip .dot img {{ width:16px; height:16px; display:block; }}
172
 
173
+ .card h3 {{
174
+ margin: 6px 0 0; font-size: 1.05rem; font-weight: 800; color:#0b1220;
175
+ }}
176
+ .card p {{
177
+ color:#536071; min-height: 32px; margin: 4px 8px 0; font-size: .96rem;
178
+ }}
 
 
 
 
 
 
 
 
179
 
180
+ /* BUTTON */
181
+ .btn {{
182
+ display:inline-block; padding:10px 16px; border-radius:12px;
183
+ border:1px solid rgba(14,116,144,0.25); text-decoration:none;
184
+ background: linear-gradient(90deg, var(--brand) 0%, var(--brand2) 100%);
185
+ color: white; font-weight: 600; letter-spacing:.2px;
186
+ margin: 10px auto 0;
187
+ box-shadow: 0 6px 18px rgba(20,184,166,.26);
188
+ }}
189
+ .btn:hover {{
190
+ filter: brightness(0.98) saturate(1.05);
191
+ transform: translateY(-1px);
192
+ box-shadow: 0 12px 28px rgba(20,184,166,.34);
193
+ }}
194
 
195
+ .footer {{ text-align:center; color:#3f4a5a; font-size:0.98em; margin-top: 24px; }}
196
+ .footer hr {{ margin: 12px 0; border-color: rgba(0,0,0,.08); }}
197
+ </style>
198
+ """, unsafe_allow_html=True)
199
 
200
+ # --------- HERO ---------
201
+ hero_logo = img_tag(LOGO_PATH, "logo", "")
202
  st.markdown(
203
+ f"""
204
+ <div class="hero">
205
+ {hero_logo}
206
+ <h1>{escape(COMPANY_NAME)}</h1>
207
+ <p>{escape(TAGLINE)}</p>
208
+ </div>
209
+ """,
210
  unsafe_allow_html=True,
211
  )
212
 
213
+ # --------- SUITE BANNER ---------
214
  st.markdown(
215
  f"""
216
  <div class="suite-banner">
 
221
  unsafe_allow_html=True,
222
  )
223
 
224
+ # --------- CARDS ---------
225
  def card_chip(icon_path: Path | None) -> str:
226
+ icon_html = tiny_icon_html(icon_path) if icon_path else ""
227
  return f"""
228
  <div class="chip">
229
  <div class="pill">
 
234
  """
235
 
236
  def app_card(app: dict) -> str:
237
+ target = "_blank" if False else "_self"
238
  return (
239
  f"<div class='card'>"
240
  + card_chip(app.get("icon"))
241
  + f"<h3>{escape(app['title'])}</h3>"
242
  + f"<p>{escape(app['blurb'])}</p>"
243
+ + f"<a class='btn' href='{escape(app['url'])}' target='{target}' rel='noopener'>{escape('Open App')}</a>"
244
  + "</div>"
245
  )
246
 
247
+ cards_html = "".join(app_card(a) for a in APPS)
248
+ st.markdown(f"<div class='grid'>{cards_html}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
249
 
250
+ # --------- FOOTER ---------
251
  st.markdown(
252
  """
253
  <hr>