renderfy commited on
Commit
1c0f876
·
verified ·
1 Parent(s): e487326

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -26
app.py CHANGED
@@ -1,22 +1,21 @@
1
  # app.py — DiagStudio AI (Streamlit frontend)
2
- # Pairs with the FastAPI backend you built (composite image + JSON mode).
3
- # Configure the backend URL via one of:
4
- # CARDIAG_AI_API (preferred) | AI_LIGHTBOX_API | LUXFIT_API
5
- # Optional bearer auth passthrough:
6
  # CARDIAG_AI_TOKEN | AI_LIGHTBOX_TOKEN | LUXFIT_TOKEN
7
  #
8
- # Run (example):
9
  # CARDIAG_AI_API="https://<your-private-backend>" streamlit run app.py --server.port 7860
10
 
11
- import os, io, json, time, base64, requests, hashlib
 
12
 
13
- # Avoid /.streamlit permission errors on containers/HF
14
  os.environ.setdefault("HOME", "/tmp")
15
  os.environ.setdefault("STREAMLIT_BROWSER_GATHER_USAGE_STATS", "false")
16
  os.environ.setdefault("STREAMLIT_SERVER_HEADLESS", "true")
17
 
18
- import streamlit as st
19
-
20
  # ================= Theme (no extra files) =================
21
  try:
22
  st._config.set_option("theme.base", "dark")
@@ -38,12 +37,13 @@ API_BASE = (
38
  HF_TOKEN = _env("CARDIAG_AI_TOKEN") or _env("AI_LIGHTBOX_TOKEN") or _env("LUXFIT_TOKEN")
39
  HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
40
 
 
41
  st.set_page_config(page_title="DiagStudio AI", layout="wide")
42
  st.title("DiagStudio AI")
43
  st.caption("Upload a short engine recording and get a clear diagnosis with visuals and next steps.")
44
 
45
  # ================= Helpers =================
46
- @st.cache_data(show_spinner=False, ttl=30)
47
  def _health(url: str, headers: dict) -> bool:
48
  try:
49
  r = requests.get(f"{url}/health", headers=headers, timeout=10)
@@ -70,7 +70,7 @@ def _post_analyze(audio_file, rpm_file, sr_target, n_fft, hop, env_band, run_llm
70
  "env_band": env_band,
71
  "run_llm": "true" if run_llm else "false",
72
  "extra_text": notes or "",
73
- "nonce": str(time.time()) # cache-bypass hint; backend already sets no-store
74
  }
75
  r = requests.post(f"{API_BASE}/analyze", headers=HEADERS, files=files, data=data, timeout=240)
76
  r.raise_for_status()
@@ -111,14 +111,17 @@ with st.sidebar:
111
  hop = st.select_slider("Hop length", options=[128, 256, 512, 1024], value=512)
112
  env_band = st.text_input("Impact band (Hz low,high or 'auto')", value="auto")
113
 
 
114
  if not API_BASE:
115
- st.error("Backend URL is not set. Define CARDIAG_AI_API (or AI_LIGHTBOX_API / LUXFIT_API).")
116
  ok = _health(API_BASE, HEADERS) if API_BASE else False
117
- if not ok and API_BASE:
118
- st.warning("Could not reach the backend. Check your private Space URL.")
 
 
119
  analyze_btn = st.button("Analyze now", type="primary", disabled=(audio_up is None or not ok))
120
 
121
- # ================= Reset state on file change (prevents stale results) =================
122
  if "last_audio_id" not in st.session_state:
123
  st.session_state["last_audio_id"] = None
124
  if audio_up is not None:
@@ -150,11 +153,9 @@ if res:
150
 
151
  params = res.get("params", {})
152
  llm = res.get("llm_report") or {}
 
153
 
154
- model_name = params.get("vision_model", "gpt-4o")
155
- st.caption(f"AI model: **{model_name}**")
156
-
157
- # Input uniqueness proof + quick features
158
  if params.get("audio_id"):
159
  st.caption(f"Audio ID: **{params['audio_id']}**")
160
  if params.get("features"):
@@ -168,7 +169,6 @@ if res:
168
  except Exception:
169
  st.caption(f"Features — {feat}")
170
 
171
- # Show meta proving Vision read the image
172
  if isinstance(llm, dict) and llm.get("meta"):
173
  meta = llm["meta"]
174
  st.caption(f"Vision meta — seen_images: {meta.get('seen_images')}, views: {meta.get('views')}")
@@ -208,13 +208,10 @@ if res:
208
  "Signal envelope",
209
  "Order view",
210
  ])
211
- imgs = res.get("images", {}) if isinstance(res.get("images", {}), dict) else {}
212
 
213
  with tabs[0]:
214
- if imgs.get("composite"):
215
- st.image(imgs["composite"], caption="Composite diagnostic figure")
216
- else:
217
- st.caption("Composite image is not available.")
218
 
219
  with tabs[1]:
220
  if imgs.get("stft"): st.image(imgs["stft"], caption="Energy distribution across time.")
@@ -251,4 +248,4 @@ if res:
251
  except Exception as e:
252
  st.error(f"ZIP build failed: {e}")
253
  else:
254
- st.info("Upload an engine recording, optionally add an RPM CSV, then click Analyze.")
 
1
  # app.py — DiagStudio AI (Streamlit frontend)
2
+ # Pairs with the FastAPI backend (composite image + JSON mode).
3
+ # Backend URL via one of:
4
+ # CARDIAG_AI_API | AI_LIGHTBOX_API | LUXFIT_API
5
+ # Optional bearer token passthrough:
6
  # CARDIAG_AI_TOKEN | AI_LIGHTBOX_TOKEN | LUXFIT_TOKEN
7
  #
8
+ # Run:
9
  # CARDIAG_AI_API="https://<your-private-backend>" streamlit run app.py --server.port 7860
10
 
11
+ import os, json, time, hashlib, requests, io, base64
12
+ import streamlit as st
13
 
14
+ # ---- container-safe defaults to avoid '/.streamlit' permission errors
15
  os.environ.setdefault("HOME", "/tmp")
16
  os.environ.setdefault("STREAMLIT_BROWSER_GATHER_USAGE_STATS", "false")
17
  os.environ.setdefault("STREAMLIT_SERVER_HEADLESS", "true")
18
 
 
 
19
  # ================= Theme (no extra files) =================
20
  try:
21
  st._config.set_option("theme.base", "dark")
 
37
  HF_TOKEN = _env("CARDIAG_AI_TOKEN") or _env("AI_LIGHTBOX_TOKEN") or _env("LUXFIT_TOKEN")
38
  HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
39
 
40
+ # ================= Page =================
41
  st.set_page_config(page_title="DiagStudio AI", layout="wide")
42
  st.title("DiagStudio AI")
43
  st.caption("Upload a short engine recording and get a clear diagnosis with visuals and next steps.")
44
 
45
  # ================= Helpers =================
46
+ @st.cache_data(show_spinner=False, ttl=20)
47
  def _health(url: str, headers: dict) -> bool:
48
  try:
49
  r = requests.get(f"{url}/health", headers=headers, timeout=10)
 
70
  "env_band": env_band,
71
  "run_llm": "true" if run_llm else "false",
72
  "extra_text": notes or "",
73
+ "nonce": str(time.time()) # cache-bypass hint (backend already sets no-store)
74
  }
75
  r = requests.post(f"{API_BASE}/analyze", headers=HEADERS, files=files, data=data, timeout=240)
76
  r.raise_for_status()
 
111
  hop = st.select_slider("Hop length", options=[128, 256, 512, 1024], value=512)
112
  env_band = st.text_input("Impact band (Hz low,high or 'auto')", value="auto")
113
 
114
+ # Allow manual URL override if env not set
115
  if not API_BASE:
116
+ API_BASE = st.text_input("Backend URL", value="", placeholder="https://<your-private-backend>").strip().rstrip("/")
117
  ok = _health(API_BASE, HEADERS) if API_BASE else False
118
+ if not API_BASE:
119
+ st.error("Backend URL missing. Set CARDIAG_AI_API env or enter it above.")
120
+ elif not ok:
121
+ st.warning("Backend not reachable. Check URL or token.")
122
  analyze_btn = st.button("Analyze now", type="primary", disabled=(audio_up is None or not ok))
123
 
124
+ # ================= Reset state on file change =================
125
  if "last_audio_id" not in st.session_state:
126
  st.session_state["last_audio_id"] = None
127
  if audio_up is not None:
 
153
 
154
  params = res.get("params", {})
155
  llm = res.get("llm_report") or {}
156
+ imgs = res.get("images", {}) if isinstance(res.get("images", {}), dict) else {}
157
 
158
+ st.caption(f"AI model: **{params.get('vision_model','gpt-4o')}**")
 
 
 
159
  if params.get("audio_id"):
160
  st.caption(f"Audio ID: **{params['audio_id']}**")
161
  if params.get("features"):
 
169
  except Exception:
170
  st.caption(f"Features — {feat}")
171
 
 
172
  if isinstance(llm, dict) and llm.get("meta"):
173
  meta = llm["meta"]
174
  st.caption(f"Vision meta — seen_images: {meta.get('seen_images')}, views: {meta.get('views')}")
 
208
  "Signal envelope",
209
  "Order view",
210
  ])
 
211
 
212
  with tabs[0]:
213
+ if imgs.get("composite"): st.image(imgs["composite"], caption="Composite diagnostic figure")
214
+ else: st.caption("Composite image is not available.")
 
 
215
 
216
  with tabs[1]:
217
  if imgs.get("stft"): st.image(imgs["stft"], caption="Energy distribution across time.")
 
248
  except Exception as e:
249
  st.error(f"ZIP build failed: {e}")
250
  else:
251
+ st.info("Upload an engine recording, optionally add an RPM CSV, then click Analyze.")