-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
163 lines (130 loc) · 5.05 KB
/
app.py
File metadata and controls
163 lines (130 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""
Shadow Payroll Calculator - Main Application Entry Point
This is the main entry point for the Streamlit application.
Run with: streamlit run app.py
"""
import logging
import sys
from pathlib import Path
import streamlit as st
# Add src to path for imports
src_path = Path(__file__).parent / "src"
sys.path.insert(0, str(src_path))
from shadow_payroll.ui import (
configure_page,
render_header,
get_api_key,
render_api_key_prompt,
render_fx_sidebar,
render_input_form,
render_results,
render_excel_download,
run_calculation,
run_estimation,
render_estimation_results,
render_sidebar_info,
render_scenario_controls,
render_saved_scenarios,
render_comparison_table,
render_scenario_summary,
render_export_buttons,
)
from shadow_payroll.scenarios import get_scenarios
from shadow_payroll.config import config
# Configure logging
logging.basicConfig(
level=getattr(logging, config.LOG_LEVEL),
format=config.LOG_FORMAT,
handlers=[logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
def main():
"""Main application entry point."""
logger.info("Starting Shadow Payroll Calculator")
# Configure page
configure_page()
# Render header
render_header()
# Check for API key
api_key = get_api_key()
if not api_key:
render_api_key_prompt()
render_sidebar_info()
return
# Initialize session state defaults
st.session_state.setdefault("fx_rate", config.FX_DEFAULT_RATE)
st.session_state.setdefault("fx_date", "Not yet fetched")
st.session_state.setdefault("fx_source", "Default")
st.session_state.setdefault("fx_stale", True)
st.session_state.setdefault("scenarios", [])
# Render sidebar
render_sidebar_info()
# Render input form (populates host_country in session state)
input_data = render_input_form()
if not input_data:
logger.warning("Invalid input data")
return
# Store host_country in session state so FX sidebar can react
st.session_state["host_country"] = input_data.host_country
st.session_state["home_country"] = input_data.home_country
# Render FX sidebar AFTER host_country is known
render_fx_sidebar()
# Calculate button -- run estimation and store in session state
if st.button("Calculate Shadow Payroll", type="primary", use_container_width=True):
logger.info("Estimation triggered")
result = run_estimation(input_data, api_key)
if result:
model_name = st.session_state.get("estimation_model_name", config.LLM_MODEL)
timestamp = st.session_state.get("estimation_timestamp", "Unknown")
# Persist result across Streamlit reruns
st.session_state["last_result"] = result.model_dump()
st.session_state["last_input"] = input_data.model_dump()
st.session_state["last_model_name"] = model_name
st.session_state["last_timestamp"] = timestamp
st.session_state["last_result_obj"] = result
else:
logger.error("Estimation failed")
# Re-render last result if it exists (persists across reruns)
if "last_result" in st.session_state:
result_obj = st.session_state.get("last_result_obj")
model_name = st.session_state.get("last_model_name", config.LLM_MODEL)
timestamp = st.session_state.get("last_timestamp", "Unknown")
if result_obj is not None:
render_estimation_results(result_obj, model_name, timestamp)
# Scenario controls below results
render_scenario_controls(
st.session_state["last_result"],
st.session_state["last_input"],
model_name,
timestamp,
)
# Saved scenarios section (always shown if scenarios exist)
render_saved_scenarios()
# Comparison section (2+ scenarios)
scenarios = get_scenarios()
if len(scenarios) >= 2:
st.markdown("---")
render_comparison_table(scenarios)
render_scenario_summary(scenarios)
# Export buttons (appear when scenarios exist OR a result is available)
model_name = st.session_state.get("last_model_name", config.LLM_MODEL)
timestamp = st.session_state.get("last_timestamp", "Unknown")
export_scenarios = scenarios if scenarios else []
# If no saved scenarios but a result exists, build a temporary scenario for export
if not export_scenarios and "last_result" in st.session_state:
from shadow_payroll.scenarios import auto_name
from shadow_payroll.ui import _prepare_result_for_scenario
tmp_result = _prepare_result_for_scenario(dict(st.session_state["last_result"]))
tmp_input = st.session_state.get("last_input", {})
export_scenarios = [{
"name": auto_name(tmp_input),
"input_data": tmp_input,
"result": tmp_result,
"model_name": model_name,
"timestamp": timestamp,
}]
if export_scenarios:
st.markdown("---")
render_export_buttons(export_scenarios, model_name, timestamp)
if __name__ == "__main__":
main()