jeronimo9 commited on
Commit
781d332
·
verified ·
1 Parent(s): 18f8a16

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -26
app.py CHANGED
@@ -415,20 +415,31 @@ def recommend_preamble_solution(industry,
415
 
416
 
417
  def calculate_build_vs_buy_comparison(initial_dev_cost=1000000, num_ai_personnel=1, avg_annual_salary=200000, annual_maintenance=500000, security_compliance=250000):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
  first_year_cost = initial_dev_cost + (num_ai_personnel * avg_annual_salary) + security_compliance
420
  ongoing_annual_cost = (num_ai_personnel * avg_annual_salary) + annual_maintenance + security_compliance
421
 
422
-
423
  three_year_build_cost = first_year_cost + (ongoing_annual_cost * 2)
424
 
425
-
426
  preamble_annual_cost = 27000 * 12
427
  three_year_preamble_cost = preamble_annual_cost * 3
428
 
429
-
430
  three_year_savings = three_year_build_cost - three_year_preamble_cost
431
- savings_percentage = (three_year_savings / three_year_build_cost) * 100
432
 
433
  return {
434
  "first_year_build": first_year_cost,
@@ -752,34 +763,137 @@ CUSTOM_CSS = f"""
752
  color: {BRAND_COLORS['result_text']} !important;
753
  border-left: 5px solid {BRAND_COLORS['accent']} !important;
754
  }}
755
- /* Result Card Headings*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
756
  .result-card h3 {{
757
  font-size: 1.8rem !important;
758
- margin-bottom: 1.2rem !important;
759
  color: {BRAND_COLORS['result_text']} !important;
760
  font-weight: 600 !important;
761
- border-bottom: 2px solid {BRAND_COLORS['accent']} !important;
762
- padding-bottom: 0.5rem !important;
 
763
  }}
 
764
  .result-card h4 {{
765
  font-size: 1.5rem !important;
766
  margin: 1.2rem 0 0.8rem !important;
767
  color: {BRAND_COLORS['result_text']} !important;
768
  font-weight: 600 !important;
769
  }}
770
- /* Result card text */
771
- .result-card p, .result-card strong {{
 
 
 
 
 
 
 
 
772
  color: {BRAND_COLORS['result_text']} !important;
773
  font-size: 16px !important;
774
  line-height: 1.7 !important;
775
  margin-bottom: 1rem !important;
776
  }}
777
- .result-card ul {{
778
- padding-left: 1.5rem !important;
779
- margin-bottom: 1rem !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780
  }}
 
781
  .result-card li {{
782
- margin-bottom: 0.5rem !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
  }}
784
  /* Buttons styling */
785
  .calculate-button {{
@@ -1031,10 +1145,11 @@ def create_app():
1031
  with gr.Row(elem_classes="input-row"):
1032
  org_size = gr.Number(label="Number of Employees",
1033
  value=90,
 
1034
  elem_classes="number-input",
1035
  precision=0)
1036
  gr.Markdown(
1037
- """<div class="helper-text">This helps us scale recommendations appropriately for your organization size.</div>"""
1038
  )
1039
 
1040
  with gr.Row(elem_classes="input-row"):
@@ -1285,9 +1400,48 @@ def create_app():
1285
  if total_employees > 0:
1286
  current_total = updated_departments['Number of Employees'].sum()
1287
  if total_employees != current_total:
1288
- # Add difference to last row
1289
- diff = total_employees - current_total
1290
- updated_departments.at[updated_departments.index[-1], 'Number of Employees'] += diff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1291
 
1292
  # Update all subscription users at once
1293
  updated_subscriptions['Number of Users'] = total_employees
@@ -1341,14 +1495,45 @@ def create_app():
1341
  annual_maintenance, security_compliance, step):
1342
  try:
1343
  # Convert inputs to appropriate types with error handling
1344
- org_size_val = int(org_size) if org_size is not None else 90
1345
- monthly_budget_val = float(monthly_budget) if monthly_budget is not None else 30000
1346
- api_calls_val = int(api_calls) if api_calls is not None else 10000
1347
- initial_dev_cost_val = float(initial_dev_cost) if initial_dev_cost is not None else 1000000
1348
- num_ai_personnel_val = int(num_ai_personnel) if num_ai_personnel is not None else 1
1349
- avg_annual_salary_val = float(avg_annual_salary) if avg_annual_salary is not None else 200000
1350
- annual_maintenance_val = float(annual_maintenance) if annual_maintenance is not None else 500000
1351
- security_compliance_val = float(security_compliance) if security_compliance is not None else 250000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1352
 
1353
  # Validate dataframes and convert to default if invalid
1354
  if department_df is None or department_df.empty:
 
415
 
416
 
417
  def calculate_build_vs_buy_comparison(initial_dev_cost=1000000, num_ai_personnel=1, avg_annual_salary=200000, annual_maintenance=500000, security_compliance=250000):
418
+ # Convert inputs to numbers if they aren't already
419
+ try:
420
+ initial_dev_cost = float(initial_dev_cost)
421
+ num_ai_personnel = int(num_ai_personnel)
422
+ avg_annual_salary = float(avg_annual_salary)
423
+ annual_maintenance = float(annual_maintenance)
424
+ security_compliance = float(security_compliance)
425
+ except (ValueError, TypeError):
426
+ # Default values if conversion fails
427
+ initial_dev_cost = 1000000.0
428
+ num_ai_personnel = 1
429
+ avg_annual_salary = 200000.0
430
+ annual_maintenance = 500000.0
431
+ security_compliance = 250000.0
432
 
433
  first_year_cost = initial_dev_cost + (num_ai_personnel * avg_annual_salary) + security_compliance
434
  ongoing_annual_cost = (num_ai_personnel * avg_annual_salary) + annual_maintenance + security_compliance
435
 
 
436
  three_year_build_cost = first_year_cost + (ongoing_annual_cost * 2)
437
 
 
438
  preamble_annual_cost = 27000 * 12
439
  three_year_preamble_cost = preamble_annual_cost * 3
440
 
 
441
  three_year_savings = three_year_build_cost - three_year_preamble_cost
442
+ savings_percentage = (three_year_savings / three_year_build_cost) * 100 if three_year_build_cost > 0 else 0
443
 
444
  return {
445
  "first_year_build": first_year_cost,
 
763
  color: {BRAND_COLORS['result_text']} !important;
764
  border-left: 5px solid {BRAND_COLORS['accent']} !important;
765
  }}
766
+
767
+ /* Enhanced Markdown Rendering - All heading levels */
768
+ .result-card h1 {{
769
+ font-size: 2.2rem !important;
770
+ margin: 1.5rem 0 1.2rem !important;
771
+ color: {BRAND_COLORS['accent']} !important;
772
+ font-weight: 700 !important;
773
+ border-bottom: 2px solid {BRAND_COLORS['accent']} !important;
774
+ padding-bottom: 0.6rem !important;
775
+ }}
776
+
777
+ .result-card h2 {{
778
+ font-size: 2rem !important;
779
+ margin: 1.4rem 0 1rem !important;
780
+ color: {BRAND_COLORS['result_text']} !important;
781
+ font-weight: 700 !important;
782
+ border-bottom: 1px solid {BRAND_COLORS['accent']} !important;
783
+ padding-bottom: 0.5rem !important;
784
+ }}
785
+
786
  .result-card h3 {{
787
  font-size: 1.8rem !important;
788
+ margin: 1.3rem 0 1rem !important;
789
  color: {BRAND_COLORS['result_text']} !important;
790
  font-weight: 600 !important;
791
+ border-bottom: 1px solid rgba(255, 199, 0, 0.5) !important;
792
+ padding-bottom: 0.4rem !important;
793
+ display: inline-block !important;
794
  }}
795
+
796
  .result-card h4 {{
797
  font-size: 1.5rem !important;
798
  margin: 1.2rem 0 0.8rem !important;
799
  color: {BRAND_COLORS['result_text']} !important;
800
  font-weight: 600 !important;
801
  }}
802
+
803
+ .result-card h5 {{
804
+ font-size: 1.25rem !important;
805
+ margin: 1rem 0 0.6rem !important;
806
+ color: {BRAND_COLORS['result_text']} !important;
807
+ font-weight: 600 !important;
808
+ }}
809
+
810
+ /* Result card text elements */
811
+ .result-card p {{
812
  color: {BRAND_COLORS['result_text']} !important;
813
  font-size: 16px !important;
814
  line-height: 1.7 !important;
815
  margin-bottom: 1rem !important;
816
  }}
817
+
818
+ .result-card strong, .result-card b {{
819
+ color: {BRAND_COLORS['accent']} !important;
820
+ font-weight: 600 !important;
821
+ }}
822
+
823
+ .result-card em, .result-card i {{
824
+ font-style: italic !important;
825
+ }}
826
+
827
+ .result-card a {{
828
+ color: {BRAND_COLORS['accent']} !important;
829
+ text-decoration: underline !important;
830
+ transition: all 0.2s ease !important;
831
+ }}
832
+
833
+ .result-card a:hover {{
834
+ opacity: 0.8 !important;
835
+ }}
836
+
837
+ /* Lists styling */
838
+ .result-card ul, .result-card ol {{
839
+ padding-left: 1.8rem !important;
840
+ margin: 0.8rem 0 1.2rem 0.5rem !important;
841
  }}
842
+
843
  .result-card li {{
844
+ margin-bottom: 0.7rem !important;
845
+ color: {BRAND_COLORS['result_text']} !important;
846
+ }}
847
+
848
+ /* Code blocks */
849
+ .result-card code {{
850
+ background-color: rgba(0, 0, 0, 0.3) !important;
851
+ padding: 0.2rem 0.4rem !important;
852
+ border-radius: 4px !important;
853
+ font-family: monospace !important;
854
+ font-size: 0.9rem !important;
855
+ }}
856
+
857
+ .result-card pre {{
858
+ background-color: rgba(0, 0, 0, 0.3) !important;
859
+ padding: 1rem !important;
860
+ border-radius: 6px !important;
861
+ overflow-x: auto !important;
862
+ margin: 1rem 0 !important;
863
+ }}
864
+
865
+ /* Blockquotes */
866
+ .result-card blockquote {{
867
+ border-left: 4px solid {BRAND_COLORS['accent']} !important;
868
+ padding-left: 1rem !important;
869
+ margin-left: 0 !important;
870
+ margin-right: 0 !important;
871
+ font-style: italic !important;
872
+ color: rgba(255, 255, 255, 0.9) !important;
873
+ }}
874
+
875
+ /* Tables */
876
+ .result-card table {{
877
+ width: 100% !important;
878
+ border-collapse: collapse !important;
879
+ margin: 1.5rem 0 !important;
880
+ }}
881
+
882
+ .result-card th {{
883
+ background-color: {BRAND_COLORS['primary']} !important;
884
+ color: {BRAND_COLORS['light_text']} !important;
885
+ padding: 0.8rem !important;
886
+ text-align: left !important;
887
+ font-weight: 600 !important;
888
+ }}
889
+
890
+ .result-card td {{
891
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
892
+ padding: 0.8rem !important;
893
+ }}
894
+
895
+ .result-card tr:nth-child(even) {{
896
+ background-color: rgba(0, 0, 0, 0.2) !important;
897
  }}
898
  /* Buttons styling */
899
  .calculate-button {{
 
1145
  with gr.Row(elem_classes="input-row"):
1146
  org_size = gr.Number(label="Number of Employees",
1147
  value=90,
1148
+ minimum=10,
1149
  elem_classes="number-input",
1150
  precision=0)
1151
  gr.Markdown(
1152
+ """<div class="helper-text">This helps us scale recommendations appropriately for your organization size (minimum 10 employees).</div>"""
1153
  )
1154
 
1155
  with gr.Row(elem_classes="input-row"):
 
1400
  if total_employees > 0:
1401
  current_total = updated_departments['Number of Employees'].sum()
1402
  if total_employees != current_total:
1403
+ # Distribute employees proportionally across departments
1404
+ if current_total > 0:
1405
+ ratio = total_employees / current_total
1406
+ for idx in updated_departments.index:
1407
+ new_count = round(updated_departments.at[idx, 'Number of Employees'] * ratio)
1408
+ updated_departments.at[idx, 'Number of Employees'] = max(1, new_count) # Ensure at least 1 employee per department
1409
+ else:
1410
+ # If current total is 0, distribute evenly
1411
+ dept_count = len(updated_departments)
1412
+ base_count = total_employees // dept_count
1413
+ remainder = total_employees % dept_count
1414
+
1415
+ for idx in updated_departments.index:
1416
+ if idx < remainder:
1417
+ updated_departments.at[idx, 'Number of Employees'] = base_count + 1
1418
+ else:
1419
+ updated_departments.at[idx, 'Number of Employees'] = base_count
1420
+
1421
+ # Adjust to ensure exact total (due to rounding)
1422
+ current_sum = updated_departments['Number of Employees'].sum()
1423
+ if current_sum != total_employees:
1424
+ diff = total_employees - current_sum
1425
+ # Add or subtract the difference from the largest department to minimize impact
1426
+ largest_dept_idx = updated_departments['Number of Employees'].idxmax()
1427
+ updated_departments.at[largest_dept_idx, 'Number of Employees'] += diff
1428
+ # Ensure no negative values after adjustment
1429
+ if updated_departments.at[largest_dept_idx, 'Number of Employees'] < 1:
1430
+ # If the largest department would go negative, redistribute
1431
+ updated_departments.at[largest_dept_idx, 'Number of Employees'] = 1
1432
+ remaining_diff = diff + 1 - updated_departments.at[largest_dept_idx, 'Number of Employees']
1433
+
1434
+ # Distribute remaining difference across other departments
1435
+ for idx in updated_departments.index:
1436
+ if idx != largest_dept_idx and remaining_diff != 0:
1437
+ if remaining_diff < 0 and updated_departments.at[idx, 'Number of Employees'] > 1:
1438
+ updated_departments.at[idx, 'Number of Employees'] -= 1
1439
+ remaining_diff += 1
1440
+ elif remaining_diff > 0:
1441
+ updated_departments.at[idx, 'Number of Employees'] += 1
1442
+ remaining_diff -= 1
1443
+ if remaining_diff == 0:
1444
+ break
1445
 
1446
  # Update all subscription users at once
1447
  updated_subscriptions['Number of Users'] = total_employees
 
1495
  annual_maintenance, security_compliance, step):
1496
  try:
1497
  # Convert inputs to appropriate types with error handling
1498
+ try:
1499
+ org_size_val = int(org_size) if org_size is not None else 90
1500
+ except (ValueError, TypeError):
1501
+ org_size_val = 90
1502
+
1503
+ try:
1504
+ monthly_budget_val = float(monthly_budget) if monthly_budget is not None else 30000
1505
+ except (ValueError, TypeError):
1506
+ monthly_budget_val = 30000.0
1507
+
1508
+ try:
1509
+ api_calls_val = int(api_calls) if api_calls is not None else 10000
1510
+ except (ValueError, TypeError):
1511
+ api_calls_val = 10000
1512
+
1513
+ try:
1514
+ initial_dev_cost_val = float(initial_dev_cost) if initial_dev_cost is not None else 1000000
1515
+ except (ValueError, TypeError):
1516
+ initial_dev_cost_val = 1000000.0
1517
+
1518
+ try:
1519
+ num_ai_personnel_val = int(num_ai_personnel) if num_ai_personnel is not None else 1
1520
+ except (ValueError, TypeError):
1521
+ num_ai_personnel_val = 1
1522
+
1523
+ try:
1524
+ avg_annual_salary_val = float(avg_annual_salary) if avg_annual_salary is not None else 200000
1525
+ except (ValueError, TypeError):
1526
+ avg_annual_salary_val = 200000.0
1527
+
1528
+ try:
1529
+ annual_maintenance_val = float(annual_maintenance) if annual_maintenance is not None else 500000
1530
+ except (ValueError, TypeError):
1531
+ annual_maintenance_val = 500000.0
1532
+
1533
+ try:
1534
+ security_compliance_val = float(security_compliance) if security_compliance is not None else 250000
1535
+ except (ValueError, TypeError):
1536
+ security_compliance_val = 250000.0
1537
 
1538
  # Validate dataframes and convert to default if invalid
1539
  if department_df is None or department_df.empty: