Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +59 -51
src/streamlit_app.py
CHANGED
|
@@ -112,8 +112,8 @@ try:
|
|
| 112 |
except Exception as _e:
|
| 113 |
_pipeline_import_error = str(_e)
|
| 114 |
|
| 115 |
-
POD_URL = os.getenv("POD_URL", "")
|
| 116 |
-
VLLM_API_KEY = os.getenv("VLLM_API_KEY", "")
|
| 117 |
MODEL_NAME = "phase2-v1-merged"
|
| 118 |
|
| 119 |
MAX_PAGES_PER_REQUEST = 10
|
|
@@ -123,7 +123,7 @@ MAX_TOTAL_PAYLOAD_MB = 40.0
|
|
| 123 |
# -----------------------------
|
| 124 |
# Page config & CSS (must be the FIRST st.* call)
|
| 125 |
# -----------------------------
|
| 126 |
-
st.set_page_config(page_title="Invoice Extractor (Qwen3-VL) - Batch Mode", layout="wide"
|
| 127 |
|
| 128 |
if not POD_URL or not VLLM_API_KEY:
|
| 129 |
st.error("β οΈ API credentials not configured. Please set POD_URL and VLLM_API_KEY in Space settings.")
|
|
@@ -136,39 +136,35 @@ st.markdown(
|
|
| 136 |
.stApp { background-color: #ECECEC !important; }
|
| 137 |
div.block-container { padding-top: 3rem; padding-bottom: 1rem; }
|
| 138 |
|
| 139 |
-
/*
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
position: fixed !important;
|
| 147 |
top: 0 !important;
|
| 148 |
left: 0 !important;
|
|
|
|
| 149 |
height: 100vh !important;
|
|
|
|
| 150 |
z-index: 999999 !important;
|
| 151 |
box-shadow: 2px 0 12px rgba(0,0,0,0.25) !important;
|
|
|
|
|
|
|
| 152 |
}
|
| 153 |
-
|
| 154 |
-
width: 190px !important;
|
| 155 |
-
min-width: 190px !important;
|
| 156 |
-
}
|
| 157 |
-
/* Main content area ignores the sidebar's width entirely */
|
| 158 |
-
div[data-testid="stAppViewContainer"] > .main {
|
| 159 |
-
margin-left: 0 !important;
|
| 160 |
-
width: 100% !important;
|
| 161 |
-
}
|
| 162 |
-
div.block-container {
|
| 163 |
-
max-width: 100% !important;
|
| 164 |
-
}
|
| 165 |
-
/* Collapsed-state toggle arrow stays visible above the overlay */
|
| 166 |
-
[data-testid="collapsedControl"] {
|
| 167 |
-
z-index: 1000000 !important;
|
| 168 |
-
}
|
| 169 |
-
|
| 170 |
-
/* Sidebar nav buttons β flat, no border, centered */
|
| 171 |
-
[data-testid="stSidebar"] .stButton > button {
|
| 172 |
background: transparent !important;
|
| 173 |
border: none !important;
|
| 174 |
box-shadow: none !important;
|
|
@@ -180,7 +176,7 @@ st.markdown(
|
|
| 180 |
border-radius: 5px !important;
|
| 181 |
width: 100% !important;
|
| 182 |
}
|
| 183 |
-
|
| 184 |
background: #E0E0E0 !important;
|
| 185 |
color: #000 !important;
|
| 186 |
border: none !important;
|
|
@@ -3706,27 +3702,39 @@ for _mk in ["validation_master_hash", "po_master_hash", "gr_master_hash", "contr
|
|
| 3706 |
st.session_state[_mk] = None
|
| 3707 |
ensure_state("page", "Master Files")
|
| 3708 |
|
| 3709 |
-
# ββ
|
| 3710 |
-
|
| 3711 |
-
|
| 3712 |
-
|
| 3713 |
-
|
| 3714 |
-
|
| 3715 |
-
|
| 3716 |
-
|
| 3717 |
-
|
| 3718 |
-
|
| 3719 |
-
|
| 3720 |
-
st.
|
| 3721 |
-
|
| 3722 |
-
|
| 3723 |
-
|
| 3724 |
-
|
| 3725 |
-
|
| 3726 |
-
|
| 3727 |
-
st.
|
| 3728 |
-
|
| 3729 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3730 |
|
| 3731 |
_active_page = st.session_state.get("page", "Invoice Upload")
|
| 3732 |
|
|
|
|
| 112 |
except Exception as _e:
|
| 113 |
_pipeline_import_error = str(_e)
|
| 114 |
|
| 115 |
+
POD_URL = os.getenv("POD_URL", "https://0vpfyk7wnnc5vl-8000.proxy.runpod.net")
|
| 116 |
+
VLLM_API_KEY = os.getenv("VLLM_API_KEY", "9386aa7335c2072882ad367791f1dc863c63b4be88eda14c2dea0408f9d0105e")
|
| 117 |
MODEL_NAME = "phase2-v1-merged"
|
| 118 |
|
| 119 |
MAX_PAGES_PER_REQUEST = 10
|
|
|
|
| 123 |
# -----------------------------
|
| 124 |
# Page config & CSS (must be the FIRST st.* call)
|
| 125 |
# -----------------------------
|
| 126 |
+
st.set_page_config(page_title="Invoice Extractor (Qwen3-VL) - Batch Mode", layout="wide")
|
| 127 |
|
| 128 |
if not POD_URL or not VLLM_API_KEY:
|
| 129 |
st.error("β οΈ API credentials not configured. Please set POD_URL and VLLM_API_KEY in Space settings.")
|
|
|
|
| 136 |
.stApp { background-color: #ECECEC !important; }
|
| 137 |
div.block-container { padding-top: 3rem; padding-bottom: 1rem; }
|
| 138 |
|
| 139 |
+
/* Custom nav: a fixed toggle button + an overlay panel built from
|
| 140 |
+
st.container(key=...), driven entirely by session_state β no JS,
|
| 141 |
+
no fighting Streamlit's own sidebar collapse animation. */
|
| 142 |
+
.st-key-sidebar_toggle_btn button {
|
| 143 |
+
position: fixed !important;
|
| 144 |
+
top: 10px !important;
|
| 145 |
+
left: 10px !important;
|
| 146 |
+
z-index: 1000001 !important;
|
| 147 |
+
width: 38px !important;
|
| 148 |
+
height: 38px !important;
|
| 149 |
+
padding: 0 !important;
|
| 150 |
+
border-radius: 6px !important;
|
| 151 |
+
background: #F7F7F7 !important;
|
| 152 |
+
border: 1px solid #ccc !important;
|
| 153 |
+
font-size: 16px !important;
|
| 154 |
+
}
|
| 155 |
+
.st-key-nav_overlay_panel {
|
| 156 |
position: fixed !important;
|
| 157 |
top: 0 !important;
|
| 158 |
left: 0 !important;
|
| 159 |
+
width: 220px !important;
|
| 160 |
height: 100vh !important;
|
| 161 |
+
background-color: #F7F7F7 !important;
|
| 162 |
z-index: 999999 !important;
|
| 163 |
box-shadow: 2px 0 12px rgba(0,0,0,0.25) !important;
|
| 164 |
+
padding: 56px 14px 14px 14px !important;
|
| 165 |
+
overflow-y: auto !important;
|
| 166 |
}
|
| 167 |
+
.st-key-nav_overlay_panel .stButton > button {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
background: transparent !important;
|
| 169 |
border: none !important;
|
| 170 |
box-shadow: none !important;
|
|
|
|
| 176 |
border-radius: 5px !important;
|
| 177 |
width: 100% !important;
|
| 178 |
}
|
| 179 |
+
.st-key-nav_overlay_panel .stButton > button:hover {
|
| 180 |
background: #E0E0E0 !important;
|
| 181 |
color: #000 !important;
|
| 182 |
border: none !important;
|
|
|
|
| 3702 |
st.session_state[_mk] = None
|
| 3703 |
ensure_state("page", "Master Files")
|
| 3704 |
|
| 3705 |
+
# ββ Navigation β custom overlay panel, no native st.sidebar ββββββββββββββββββββ
|
| 3706 |
+
# Driven entirely by session_state: opening/closing the panel is just a normal
|
| 3707 |
+
# Streamlit rerun, so "click an item -> panel closes" can't get stuck in a loop.
|
| 3708 |
+
ensure_state("nav_open", False)
|
| 3709 |
+
|
| 3710 |
+
_toggle_label = "β" if st.session_state.nav_open else "β°"
|
| 3711 |
+
if st.button(_toggle_label, key="sidebar_toggle_btn"):
|
| 3712 |
+
st.session_state.nav_open = not st.session_state.nav_open
|
| 3713 |
+
st.rerun()
|
| 3714 |
+
|
| 3715 |
+
if st.session_state.nav_open:
|
| 3716 |
+
with st.container(key="nav_overlay_panel"):
|
| 3717 |
+
st.markdown("**Navigation**")
|
| 3718 |
+
_current_page = st.session_state.get("page", "Invoice Upload")
|
| 3719 |
+
# All 3 are always buttons β same element type, same wrapper height, zero layout shift.
|
| 3720 |
+
# Active page gets a βΈ prefix so the user knows where they are.
|
| 3721 |
+
for _pg in ["Master Files", "Config", "Invoice Upload"]:
|
| 3722 |
+
_label = f"βΈ {_pg}" if _pg == _current_page else _pg
|
| 3723 |
+
if st.button(_label, key=f"nav_{_pg.replace(' ','_')}", use_container_width=True):
|
| 3724 |
+
st.session_state.page = _pg
|
| 3725 |
+
st.session_state.nav_open = False
|
| 3726 |
+
st.rerun()
|
| 3727 |
+
st.divider()
|
| 3728 |
+
_n_inv = len(st.session_state.batch_results)
|
| 3729 |
+
st.caption(f"{_n_inv} invoice{'s' if _n_inv != 1 else ''} loaded")
|
| 3730 |
+
if _n_inv > 0:
|
| 3731 |
+
if st.button("Clear All", key="sidebar_clear_all"):
|
| 3732 |
+
st.session_state.batch_results.clear()
|
| 3733 |
+
st.session_state.current_file_hash = None
|
| 3734 |
+
st.session_state.is_processing_batch = False
|
| 3735 |
+
st.session_state.confirm_back = False
|
| 3736 |
+
st.session_state.nav_open = False
|
| 3737 |
+
st.rerun()
|
| 3738 |
|
| 3739 |
_active_page = st.session_state.get("page", "Invoice Upload")
|
| 3740 |
|