alidenewade commited on
Commit
abb7e3f
·
verified ·
1 Parent(s): 4a7f563

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -66
app.py CHANGED
@@ -4,119 +4,196 @@ import numpy as np
4
  from numpy.random import default_rng
5
  import io # For BytesIO to handle file in memory
6
 
7
- # 1. Data Generation Function (adapted from your script)
8
- def generate_cluster_model_points():
 
 
 
 
9
  """
10
- Generates seriatim model points based on the specifications
11
- from generate_model_points_for_cluster.py.
12
  """
13
- rng = default_rng(12345) # Fixed seed for reproducibility
14
- MPCount = 10000 # Number of Model Points
15
-
16
- # Issue Age (Integer): 20 - 59 year old
17
- age_at_entry = rng.integers(low=20, high=60, size=MPCount)
18
-
19
- # Sex (Char)
20
- sex_options = ["M", "F"]
21
- sex_col = np.fromiter(map(lambda i: sex_options[i], rng.integers(low=0, high=len(sex_options), size=MPCount)), np.dtype('<U1'))
22
-
23
- # Policy Term (Integer): 10, 15, 20
24
- policy_term_col = rng.integers(low=0, high=3, size=MPCount) * 5 + 10
25
-
26
- # Sum Assured (Float): 10,000 - 1,000,000
27
- sum_assured_col = np.round((1000000 - 10000) * rng.random(size=MPCount) + 10000, -3)
28
-
29
- # Duration in month (Int): 0 < Duration(mth) < Policy Term in month
30
- # Ensures duration_mth is at least 1 and less than policy_term_col in months.
31
- duration_mth_col = np.floor((policy_term_col * 12 - 1) * rng.random(size=MPCount)).astype(int) + 1
32
-
33
- # Policy Count (Integer): 1 for all model points
34
- policy_count_col = 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  # Create DataFrame
37
  data_dict = {
38
  "age_at_entry": age_at_entry,
39
  "sex": sex_col,
40
  "policy_term": policy_term_col,
41
- "policy_count": policy_count_col, # Pandas will broadcast this scalar to all rows
42
  "sum_assured": sum_assured_col,
43
  "duration_mth": duration_mth_col
44
  }
45
 
46
- # Create index named "policy_id" starting from 1
47
- model_point_df = pd.DataFrame(data_dict, index=pd.RangeIndex(start=1, stop=MPCount + 1, name="policy_id"))
48
 
49
  return model_point_df
50
 
51
  # 2. Gradio App Definition
52
- with gr.Blocks() as demo: # Default theme and font
53
- gr.Markdown("# Actuarial Model Points Generator (Cluster Version)")
54
  gr.Markdown(
55
- "This app generates 10,000 seriatim model points based on the logic from the "
56
- "`generate_model_points_for_cluster.py` script.\n"
57
- "Click 'Generate Model Points' to view the table, then 'Download Excel' to save the data."
58
  )
59
 
60
- # State to store the generated DataFrame
61
- df_state = gr.State()
62
 
63
- # UI Elements
64
  with gr.Row():
65
- generate_btn = gr.Button("Generate Model Points", variant="primary")
66
-
67
- model_points_display = gr.Dataframe(label="Generated Model Points")
68
-
69
- download_excel_btn = gr.DownloadButton(
70
- label="Download Excel",
71
- value="model_points.xlsx", # Sets the default filename for download
72
- variant="secondary"
73
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  # 3. Event Handlers
76
- def handle_generate_button_click():
77
- """
78
- Called when the 'Generate Model Points' button is clicked.
79
- Generates data and updates the UI.
80
- """
 
 
 
 
 
 
 
 
81
  gr.Info("Generating model points... Please wait.")
82
- df = generate_cluster_model_points()
 
 
83
  gr.Info(f"{len(df)} model points generated successfully!")
84
- return df, df # Update both the Dataframe display and the state
85
 
86
  def handle_download_button_click(current_df_to_download):
87
- """
88
- Called when the 'Download Excel' button is clicked.
89
- Prepares the DataFrame for download as an Excel file.
90
- """
91
  if current_df_to_download is None or current_df_to_download.empty:
92
- gr.Warning("No data available to download. Please generate model points first.")
93
- # Provide an empty Excel file to prevent download error if button is clicked prematurely
94
  empty_excel_output = io.BytesIO()
95
  pd.DataFrame().to_excel(empty_excel_output, index=False)
96
  empty_excel_output.seek(0)
97
  return empty_excel_output
98
 
99
  excel_output = io.BytesIO()
100
- # The DataFrame's index (policy_id) will be included by default
101
  current_df_to_download.to_excel(excel_output, sheet_name='ModelPoints', engine='xlsxwriter', index=True)
102
  excel_output.seek(0)
103
  return excel_output
104
 
105
- # Wire تعرض the button clicks to their handler functions
 
 
 
 
 
 
106
  generate_btn.click(
107
  fn=handle_generate_button_click,
108
- inputs=None, # No inputs from UI needed for generation
109
  outputs=[model_points_display, df_state]
110
  )
111
 
112
  download_excel_btn.click(
113
  fn=handle_download_button_click,
114
- inputs=[df_state], # Takes the DataFrame stored in the state
115
- outputs=[download_excel_btn] # The DownloadButton itself is the output for file streams
116
  )
117
 
118
- # Optionally, load data when the app starts (or leave it empty until generate is clicked)
119
- # demo.load(handle_generate_button_click, outputs=[model_points_display, df_state])
 
 
 
 
 
 
 
120
 
121
 
122
  if __name__ == "__main__":
 
4
  from numpy.random import default_rng
5
  import io # For BytesIO to handle file in memory
6
 
7
+ # 1. Data Generation Function (customizable via UI filters)
8
+ def generate_custom_model_points(
9
+ mp_count_val, seed_val, age_min_val, age_max_val,
10
+ sa_min_val, sa_max_val, policy_terms_selection_val,
11
+ include_sex_val, policy_count_fixed_val
12
+ ):
13
  """
14
+ Generates seriatim model points based on user-defined parameters.
 
15
  """
16
+ rng = default_rng(int(seed_val))
17
+ mp_count_val = int(mp_count_val)
18
+ age_min_val = int(age_min_val)
19
+ age_max_val = int(age_max_val)
20
+ sa_min_val = float(sa_min_val)
21
+ sa_max_val = float(sa_max_val)
22
+
23
+ # Issue Age
24
+ age_at_entry = rng.integers(low=age_min_val, high=age_max_val + 1, size=mp_count_val)
25
+
26
+ # Sex
27
+ if include_sex_val:
28
+ sex_options = ["M", "F"]
29
+ sex_col = np.fromiter(map(lambda i: sex_options[i], rng.integers(low=0, high=len(sex_options), size=mp_count_val)), np.dtype('<U1'))
30
+ else:
31
+ sex_col = np.full(mp_count_val, "U") # Unknown/Unspecified if not included
32
+
33
+ # Policy Term
34
+ if not policy_terms_selection_val: # Default if user deselects all
35
+ policy_terms_selection_val = [10, 15, 20]
36
+ policy_term_options = np.array(policy_terms_selection_val).astype(int)
37
+ policy_term_col = rng.choice(policy_term_options, size=mp_count_val)
38
+
39
+ # Sum Assured
40
+ sum_assured_col = np.round((sa_max_val - sa_min_val) * rng.random(size=mp_count_val) + sa_min_val, -3)
41
+
42
+ # Duration in month: 1 <= Duration(mth) < Policy Term in month
43
+ # (policy_term_col * 12) is term in months.
44
+ # Max duration is (term_in_months - 1). Min duration is 1.
45
+ max_duration_val = policy_term_col * 12 - 1
46
+ # Ensure max_duration_val is at least 1 to prevent issues with rng.random if term is very short
47
+ max_duration_val = np.maximum(1, max_duration_val)
48
+ duration_mth_col = (rng.random(size=mp_count_val) * max_duration_val).astype(int) + 1
49
+ # Ensure duration_mth does not exceed max_duration_val (especially if max_duration_val was 1)
50
+ duration_mth_col = np.minimum(duration_mth_col, max_duration_val)
51
+ # And ensure it's at least 1
52
+ duration_mth_col = np.maximum(1, duration_mth_col)
53
+
54
+
55
+ # Policy Count
56
+ if policy_count_fixed_val:
57
+ policy_count_col_val = np.ones(mp_count_val, dtype=int)
58
+ else:
59
+ policy_count_col_val = rng.integers(low=1, high=101, size=mp_count_val) # Variable 1-100
60
 
61
  # Create DataFrame
62
  data_dict = {
63
  "age_at_entry": age_at_entry,
64
  "sex": sex_col,
65
  "policy_term": policy_term_col,
66
+ "policy_count": policy_count_col_val,
67
  "sum_assured": sum_assured_col,
68
  "duration_mth": duration_mth_col
69
  }
70
 
71
+ model_point_df = pd.DataFrame(data_dict, index=pd.RangeIndex(start=1, stop=mp_count_val + 1, name="policy_id"))
 
72
 
73
  return model_point_df
74
 
75
  # 2. Gradio App Definition
76
+ with gr.Blocks() as demo:
77
+ gr.Markdown("# Actuarial Model Points Generator")
78
  gr.Markdown(
79
+ "Configure the parameters below to generate a custom set of seriatim model points. "
80
+ "The generated table can be viewed and downloaded as an Excel file."
 
81
  )
82
 
83
+ df_state = gr.State() # To hold the generated DataFrame
 
84
 
 
85
  with gr.Row():
86
+ with gr.Column(scale=1):
87
+ gr.Markdown("### Generation Parameters")
88
+
89
+ mp_count_input = gr.Slider(
90
+ minimum=100, maximum=50000, value=10000, step=100,
91
+ label="Number of Model Points"
92
+ )
93
+ seed_input = gr.Number(
94
+ value=12345, precision=0, label="Random Seed"
95
+ )
96
+
97
+ gr.Markdown("#### Age Parameters")
98
+ age_min_input = gr.Slider(
99
+ minimum=18, maximum=40, value=20, step=1, label="Minimum Age at Entry"
100
+ )
101
+ age_max_input = gr.Slider(
102
+ minimum=41, maximum=80, value=59, step=1, label="Maximum Age at Entry"
103
+ )
104
+
105
+ gr.Markdown("#### Sum Assured Parameters ($)")
106
+ sum_assured_min_input = gr.Number(
107
+ value=10000, label="Minimum Sum Assured"
108
+ )
109
+ sum_assured_max_input = gr.Number(
110
+ value=1000000, label="Maximum Sum Assured"
111
+ )
112
+
113
+ gr.Markdown("#### Policy Options")
114
+ policy_terms_input = gr.CheckboxGroup(
115
+ choices=[5, 10, 15, 20, 25, 30], value=[10, 15, 20],
116
+ label="Available Policy Terms (Years)"
117
+ )
118
+ include_sex_input = gr.Checkbox(
119
+ value=True, label="Include Sex (M/F)"
120
+ )
121
+ policy_count_fixed_input = gr.Checkbox(
122
+ value=True, label="Fixed Policy Count = 1 (Uncheck for variable count 1-100)"
123
+ )
124
+
125
+ generate_btn = gr.Button("Generate Model Points", variant="primary")
126
+
127
+ with gr.Column(scale=2):
128
+ model_points_display = gr.Dataframe(label="Generated Model Points")
129
+ download_excel_btn = gr.DownloadButton(
130
+ label="Download Excel",
131
+ value="model_points.xlsx", # Default filename
132
+ variant="secondary"
133
+ )
134
 
135
  # 3. Event Handlers
136
+ def handle_generate_button_click(
137
+ mp_c, s, age_m, age_mx, sa_m, sa_mx, p_terms, incl_sex, pc_fixed
138
+ ):
139
+ if int(age_m) >= int(age_mx):
140
+ gr.Warning("Minimum Age must be less than Maximum Age.")
141
+ return df_state.value, df_state.value # Keep current table and state
142
+ if float(sa_m) >= float(sa_mx):
143
+ gr.Warning("Minimum Sum Assured must be less than Maximum Sum Assured.")
144
+ return df_state.value, df_state.value
145
+ if not p_terms:
146
+ gr.Warning("No Policy Terms selected. Using defaults: [10, 15, 20].")
147
+ # Generation function will handle default if p_terms is empty list
148
+
149
  gr.Info("Generating model points... Please wait.")
150
+ df = generate_custom_model_points(
151
+ mp_c, s, age_m, age_mx, sa_m, sa_mx, p_terms, incl_sex, pc_fixed
152
+ )
153
  gr.Info(f"{len(df)} model points generated successfully!")
154
+ return df, df
155
 
156
  def handle_download_button_click(current_df_to_download):
 
 
 
 
157
  if current_df_to_download is None or current_df_to_download.empty:
158
+ gr.Warning("No data available to download. Generate model points first.")
 
159
  empty_excel_output = io.BytesIO()
160
  pd.DataFrame().to_excel(empty_excel_output, index=False)
161
  empty_excel_output.seek(0)
162
  return empty_excel_output
163
 
164
  excel_output = io.BytesIO()
 
165
  current_df_to_download.to_excel(excel_output, sheet_name='ModelPoints', engine='xlsxwriter', index=True)
166
  excel_output.seek(0)
167
  return excel_output
168
 
169
+ # Wire up UI components to functions
170
+ inputs_list = [
171
+ mp_count_input, seed_input, age_min_input, age_max_input,
172
+ sum_assured_min_input, sum_assured_max_input, policy_terms_input,
173
+ include_sex_input, policy_count_fixed_input
174
+ ]
175
+
176
  generate_btn.click(
177
  fn=handle_generate_button_click,
178
+ inputs=inputs_list,
179
  outputs=[model_points_display, df_state]
180
  )
181
 
182
  download_excel_btn.click(
183
  fn=handle_download_button_click,
184
+ inputs=[df_state],
185
+ outputs=[download_excel_btn]
186
  )
187
 
188
+ # Optional: Load with default values on app start
189
+ # def initial_load():
190
+ # # Use default values from the input components
191
+ # # This would require getting their default values
192
+ # # For simplicity, we can call generate with fixed defaults or trigger a click
193
+ # # Or, just start with an empty table.
194
+ # gr.Info("App loaded. Configure parameters and click 'Generate'.")
195
+ # return None, None # Empty table and state
196
+ # demo.load(initial_load, outputs=[model_points_display, df_state])
197
 
198
 
199
  if __name__ == "__main__":