fabagent / app.py
hee_!J
feat: μ—μ΄μ „νŠΈ κ°€μ‹œν™” κ°•ν™” (페λ₯΄μ†Œλ‚˜Β·SPC 차트·LangGraph)
6fb4d4f
Raw
History Blame Contribute Delete
3.5 kB
"""FabAgent 운영자 λŒ€μ‹œλ³΄λ“œ μ—”νŠΈλ¦¬ν¬μΈνŠΈ
μ‹€ν–‰: streamlit run app.py --server.port 8501
"""
from pathlib import Path
import streamlit as st
from components.alarm_inbox import render_alarm_inbox
from components.header import render_header
from components.progress import render_progress_strip
from components.tiers import render_tier_cascade
from data.demo import DEFAULT_ALARMS
st.set_page_config(
page_title="FabAgent - 운영자 λŒ€μ‹œλ³΄λ“œ",
page_icon="assets/favicon.png",
layout="wide",
initial_sidebar_state="expanded",
)
def inject_css():
css_path = Path("styles/main.css")
if css_path.exists():
st.markdown(
f"<style>{css_path.read_text(encoding='utf-8')}</style>",
unsafe_allow_html=True,
)
st.markdown(
'<link rel="stylesheet" '
'href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable.min.css">',
unsafe_allow_html=True,
)
def handle_query_params():
# μ‚¬μ΄λ“œλ°” FabAgent 둜고 클릭 -> ?reset=1둜 μ§„μž… -> μ„Έμ…˜ μ΄ˆκΈ°ν™”
if "reset" in st.query_params:
for key in list(st.session_state.keys()):
del st.session_state[key]
del st.query_params["reset"]
return
# μ•ŒλžŒ μΉ΄λ“œ 클릭 -> ?alarm=X둜 μ§„μž… -> 선택 μ•ŒλžŒ λ³€κ²½
if "alarm" in st.query_params:
alarm_id = st.query_params["alarm"]
ss = st.session_state
if alarm_id != ss.get("selected_alarm_id"):
ss.selected_alarm_id = alarm_id
ss.stage = 0
ss.completed_tiers = set()
ss.approved = False
ss.animation_pending = True
ss.last_action = None
del st.query_params["alarm"]
def init_state():
ss = st.session_state
ss.setdefault("selected_alarm_id", "A1")
ss.setdefault("stage", 0) # 0=idle, 1..4=loading, 5=done
ss.setdefault("completed_tiers", set())
ss.setdefault("approved", False)
ss.setdefault("alarms", [a.copy() for a in DEFAULT_ALARMS])
ss.setdefault("animation_pending", False)
ss.setdefault("speed", "normal") # "fast" | "normal" | "real"
ss.setdefault("last_action", None) # 운영자 κ²°μ • κ²°κ³Ό (approved/held/rejected)
def _current_alarm():
ss = st.session_state
for a in ss.alarms:
if a["id"] == ss.selected_alarm_id:
return a
return None
def render_main():
render_header()
alarm = _current_alarm()
title_text = alarm["title"] if alarm else "μ•ŒλžŒμ„ μ„ νƒν•˜μ„Έμš”"
lot_id = alarm["lot_id"] if alarm else "-"
col_title, col_progress = st.columns([5, 4])
with col_title:
st.markdown(
f"""
<h1 class="fab-main-title">
{title_text} - <span style="font-family:var(--mono); font-weight:700;">{lot_id}</span>
</h1>
<div class="fab-main-sub">
<span>4-Tier 뢄석 μ›Œν¬ν”Œλ‘œμš°</span>
<span class="sep">Β·</span>
<span>이상 탐지 β†’ 원인 뢄석 β†’ 영ν–₯ 평가 β†’ λŒ€μ‘ ꢌ고</span>
</div>
""",
unsafe_allow_html=True,
)
with col_progress:
render_progress_strip()
st.markdown(
'<hr style="border-color: var(--border); margin: 16px 0 22px;"/>',
unsafe_allow_html=True,
)
render_tier_cascade()
inject_css()
handle_query_params()
init_state()
render_alarm_inbox()
render_main()