jeronimo9's picture
Update app.py
febb144 verified
import gradio as gr
import pandas as pd
import numpy as np
import plotly.graph_objects as go
BRAND_COLORS = {
'primary': '#1F2C6D', # Navy
'secondary': '#081423', # Dark Navy
'accent': '#FFC700', # Yellow
'dark_bg': '#081423', # Dark Navy
'light_bg': '#ECF0F6', # Light Gray
'button_bg': '#FFC700', # Yellow
'light_text': '#FFFFFF', # White
'dark_text': '#081423', # Dark Navy
'table_header': '#4556E4', # Light Blue
'table_row_odd': '#FFFFFF', # Pure white
'table_row_even': '#ECF0F6', # Light Gray
'label_text': '#000000', # Black for Labels
'button_text': '#081423', # Dark Navy for Button Text
'input_text': '#081423', # Dark Navy for Input Text
'result_header': '#081423', # Dark Navy for Result Headings
'result_text': '#FFFFFF', # White
'result_bg': '#081423' # Dark Navy
}
default_departments = pd.DataFrame({
"Department": ["IT", "Finance", "HR", "Marketing", "Sales", "Operations"],
"Number of Employees": [10, 15, 8, 12, 20, 25],
"Average Salary": [95000, 85000, 70000, 75000, 85000, 65000],
"Hours Per Week on Manual Tasks": [20, 20, 15, 10, 12, 18]
})
default_subscriptions = pd.DataFrame({
"Tool Category": [
"CRM", "ERP", "Project Management", "Cloud Storage",
"SaaS Subscriptions"
],
"Current Monthly Cost per User": [80, 150, 30, 25, 45],
"Number of Users": [90, 90, 90, 90, 90],
"Estimated Reduction %": [30, 20, 50, 10, 15]
})
industry_compliance_data = {
"Financial Services":
pd.DataFrame({
"Regulation": ["GDPR", "CCPA", "SOX", "PCI DSS", "GLBA"],
"Potential Violations": [2, 1, 1, 3, 2],
"Penalty": [250000, 150000, 100000, 200000, 175000],
"Attorney Cost": [50000, 40000, 30000, 45000, 40000]
}),
"Healthcare":
pd.DataFrame({
"Regulation":
["HIPAA", "HITECH Act", "GDPR", "CCPA", "Data Protection Act 2018"],
"Potential Violations": [3, 2, 1, 1, 2],
"Penalty": [175000, 125000, 100000, 90000, 80000],
"Attorney Cost": [45000, 35000, 30000, 25000, 20000]
}),
"Manufacturing":
pd.DataFrame({
"Regulation": [
"OSHA Regulations", "EPA Regulations", "ISO Standards",
"NIST Cybersecurity Framework", "GDPR"
],
"Potential Violations": [2, 3, 1, 2, 1],
"Penalty": [75000, 100000, 50000, 150000, 200000],
"Attorney Cost": [20000, 30000, 15000, 45000, 50000]
}),
"Retail":
pd.DataFrame({
"Regulation": [
"PCI DSS", "CCPA", "GDPR", "Consumer Rights Act",
"Sales Tax Regulations"
],
"Potential Violations": [3, 2, 2, 1, 3],
"Penalty": [100000, 125000, 150000, 50000, 75000],
"Attorney Cost": [30000, 40000, 50000, 15000, 25000]
}),
"Technology":
pd.DataFrame({
"Regulation": [
"GDPR", "CCPA", "COPPA", "Software Licensing Compliance",
"Export Controls"
],
"Potential Violations": [2, 2, 1, 3, 2],
"Penalty": [200000, 150000, 100000, 175000, 125000],
"Attorney Cost": [50000, 45000, 30000, 40000, 35000]
}),
"Government/Defense":
pd.DataFrame({
"Regulation": ["FedRAMP", "CMMC", "NIST SP 800-171", "FISMA", "ITAR"],
"Potential Violations": [1, 2, 3, 2, 1],
"Penalty": [250000, 300000, 200000, 150000, 275000],
"Attorney Cost": [60000, 75000, 50000, 40000, 65000]
}),
"Professional Services":
pd.DataFrame({
"Regulation": [
"Client Confidentiality Agreements", "Professional Standards",
"GDPR", "CCPA", "Ethics Rules"
],
"Potential Violations": [2, 1, 1, 1, 3],
"Penalty": [50000, 100000, 150000, 125000, 75000],
"Attorney Cost": [20000, 30000, 40000, 35000, 25000]
}),
"Energy":
pd.DataFrame({
"Regulation": [
"NERC CIP", "FERC Regulations", "EPA Regulations",
"State Public Utility Commissions", "Cybersecurity Regulations"
],
"Potential Violations": [3, 2, 2, 1, 3],
"Penalty": [200000, 150000, 175000, 100000, 125000],
"Attorney Cost": [50000, 40000, 45000, 30000, 35000]
}),
"Other":
pd.DataFrame({
"Regulation": [
"Data Privacy", "Financial Reporting",
"Industry-Specific Requirements", "Records Retention",
"Security Controls"
],
"Potential Violations": [2, 1, 1, 3, 2],
"Penalty": [250000, 100000, 75000, 50000, 125000],
"Attorney Cost": [50000, 30000, 25000, 15000, 40000]
})
}
industry_ai_risks = {
"Financial Services": [
"Data privacy breaches with sensitive financial information",
"Sharing Material nonpublic information (MNPI) to unauthorized 3rd parties",
"Compliance violations with regulatory frameworks (e.g., GDPR, CCPA, SOX, PCI DSS, GLBA)"
],
"Healthcare": [
"Patient data confidentiality breaches", "HIPAA compliance violations",
"Data corruption","Sensitive healthcare information sharing to unauthorized 3rd parties",
"Compliance with HITECH Act, GDPR, CCPA, Data Protection Act 2018"
],
"Manufacturing": [
"Quality control failures from AI systems",
"Supply chain vulnerability from automated decisions",
"Safety risks from AI-controlled equipment",
"Compliance with OSHA, EPA, ISO standards, NIST, GDPR."
],
"Retail": [
"Customer data privacy breaches", "Payment processing vulnerabilities",
"Biased pricing algorithms",
"Compliance with PCI DSS, CCPA, GDPR, Consumer Rights Act, Sales Tax regulations."
],
"Technology": [
"Code vulnerabilities in AI-generated software",
"Intellectual property theft via AI systems",
"Data leakage through AI pipelines",
"Compliance with GDPR, CCPA, COPPA, Software Licensing, Export Controls."
],
"Government/Defense": [
"Classified information exposure through AI systems",
"Supply chain risks in AI components","Insider threats accessing data through AI systems",
"Compliance violations with FedRAMP, CMMC, NIST, FISMA, ITAR."
],
"Professional Services": [
"Client confidentiality breaches",
"Legal privilege violations through AI tools",
"Inaccurate professional advice from AI systems",
"Compliance with Client Agreements, GDPR, CCPA, and Ethics Rules"
],
"Energy": [
"Critical infrastructure vulnerability",
"Physical safety risks from automated control systems",
"Energy supply disruption from AI forecasting errors",
"Compliance with NERC CIP, FERC and EPA Regulations."
],
"Other": [
"Data privacy and security risks", "Regulatory compliance issues",
"Intellectual property protection"
]
}
department_use_cases = {
"IT": [
"Automated ticket resolution", "Infrastructure optimization",
"Code generation"
],
"Finance":
["Automated reporting", "Fraud detection", "Invoice processing"],
"HR": ["Resume screening", "Employee onboarding", "HR analytics"],
"Marketing":
["Content generation", "Campaign optimization", "Customer segmentation"],
"Sales":
["Lead prioritization", "Sales forecasting", "Automated follow-ups"],
"Operations":
["Process automation", "Supply chain optimization", "Quality control"],
"Legal/Compliance":
["Contract review", "Regulatory tracking", "Compliance monitoring"],
"Customer Service":
["Response generation", "Ticket categorization", "Sentiment analysis"],
"Research": ["Literature review", "Patent analysis", "Experiment design"],
"Other": ["Document processing", "Data analysis", "Process automation"]
}
# --- Calculation and Recommendation Functions ---
def create_subscription_savings_chart(subscription_data):
# Use pandas vectorized operations instead of loop
df = subscription_data.copy()
# Calculate costs and savings in one go
df['monthly_cost'] = df["Current Monthly Cost per User"] * df["Number of Users"]
df['savings'] = df['monthly_cost'] * (df["Estimated Reduction %"] / 100)
# Convert to lists for plotly
categories = df["Tool Category"].tolist()
current_costs = df['monthly_cost'].tolist()
savings = df['savings'].tolist()
# Create the figure with all styling applied at once
fig = go.Figure()
# Add both traces at once
fig.add_trace(
go.Bar(x=categories,
y=current_costs,
name="Current Monthly Cost",
marker_color=BRAND_COLORS['primary'],
opacity=0.9))
fig.add_trace(
go.Bar(x=categories,
y=savings,
name="Potential Monthly Savings",
marker_color=BRAND_COLORS['accent'],
opacity=0.9))
# Set layout all at once
fig.update_layout(
title="Potential Monthly Subscription Savings with AI",
barmode='group',
xaxis_title="Subscription Categories",
yaxis_title="Cost ($)",
legend=dict(orientation="h",
yanchor="bottom",
y=1.02,
xanchor="center",
x=0.5,
font=dict(color=BRAND_COLORS['light_text'])),
template="plotly_white",
font=dict(family="Inter, sans-serif",
size=12,
color=BRAND_COLORS['light_text']),
paper_bgcolor=BRAND_COLORS['dark_bg'],
plot_bgcolor=BRAND_COLORS['dark_bg'],
margin=dict(l=40, r=40, t=80, b=40)
)
return fig
def calculate_department_roi(dept_data, hourly_wage_multiplier=1.5):
results = []
for _, row in dept_data.iterrows():
department = row["Department"]
employees = row["Number of Employees"]
avg_salary = row["Average Salary"]
manual_hours = row["Hours Per Week on Manual Tasks"]
hourly_wage = avg_salary / (52 * 40) * hourly_wage_multiplier
efficiency_gain = np.random.uniform(0.3, 0.4)
annual_hours_saved = manual_hours * efficiency_gain * 52 * employees
annual_savings = annual_hours_saved * hourly_wage
implementation_cost = avg_salary * 0.2 * employees
roi = ((annual_savings - implementation_cost) /
implementation_cost) * 100 if implementation_cost > 0 else 0
use_cases = department_use_cases.get(
department,
department_use_cases.get(
next((k for k in department_use_cases
if k.lower() in department.lower()), "Other")))
results.append({
"Department": department,
"Employees": employees,
"Annual Hours Saved": annual_hours_saved,
"Annual Cost Savings": annual_savings,
"Implementation Cost": implementation_cost,
"ROI": roi,
"Use Cases": use_cases[:3]
})
return sorted(results, key=lambda x: x["ROI"], reverse=True)
def calculate_subscription_savings(subscription_data):
total_current_cost = subscription_data.apply(lambda row: row[
"Current Monthly Cost per User"] * row["Number of Users"] * 12,
axis=1).sum()
total_savings = subscription_data.apply(
lambda row: row["Current Monthly Cost per User"] * row[
"Number of Users"] * 12 * row["Estimated Reduction %"] / 100,
axis=1).sum()
savings_percentage = (total_savings / total_current_cost
) * 100 if total_current_cost > 0 else 0
return {
"total_current_cost": total_current_cost,
"total_savings": total_savings,
"savings_percentage": savings_percentage
}
def calculate_compliance_savings(compliance_data):
if compliance_data.empty:
return {"total_savings": 0, "key_regulations": []}
compliance_data["Potential Violations"] = pd.to_numeric(
compliance_data["Potential Violations"], errors='coerce').fillna(0)
compliance_data["Penalty"] = pd.to_numeric(compliance_data["Penalty"],
errors='coerce').fillna(0)
compliance_data["Attorney Cost"] = pd.to_numeric(
compliance_data["Attorney Cost"], errors='coerce').fillna(0)
total_savings = (
compliance_data["Potential Violations"] *
(compliance_data["Penalty"] + compliance_data["Attorney Cost"])).sum()
compliance_data['TotalCost'] = compliance_data["Potential Violations"] * (
compliance_data["Penalty"] + compliance_data["Attorney Cost"])
sorted_compliance = compliance_data.sort_values(by='TotalCost',
ascending=False)
key_regulations = [{
"name": row["Regulation"],
"cost": row["TotalCost"]
} for _, row in sorted_compliance.head(3).iterrows()]
return {"total_savings": total_savings, "key_regulations": key_regulations}
def recommend_preamble_solution(industry,
org_size,
monthly_budget,
has_ai_app,
api_calls=10000):
"""Recommends Preamble solution with budget and AI app considerations."""
high_risk_industries = [
"Financial Services", "Healthcare", "Government/Defense"
]
org_size = int(org_size) if org_size is not None else 0
monthly_budget = float(
monthly_budget) if monthly_budget is not None else 0.0
api_calls = int(api_calls) if api_calls is not None else 10000
shadow_ai_blocker = "[Shadow AI Blocker Chrome Extension](https://chromewebstore.google.com/detail/shadow-ai-blocker/jkcnihggbeejafmbgohlahlighagphon)"
if monthly_budget < 27000:
if has_ai_app:
solution = "Guardrails Only"
monthly_cost = api_calls * 0.005
description = f"""
#### ⚡ [Guardrails Only - Compliance](https://preamble.com/pricing)
Perfect for integrating with your existing AI application:
- Quick API integration.
- Pre-built security and privacy guardrails.
- Basic compliance templates.
- Agentless operation.
- Free Trial available.
- Free Shadow AI Tool {shadow_ai_blocker}
$0.005 per API call (Est. monthly cost: ${monthly_cost:,.2f} at {api_calls:,} calls/month)
[Learn more about Preamble pricing options](https://preamble.com/pricing)"""
image = "🛡️"
else:
solution = "SMB"
description = f"""
#### 🚀 [SMB](https://preamble.com/pricing)
Perfect for teams getting started with AI:
- Full platform features.
- Standard compliance templates.
- Protection for up to 25 AI applications.
- Secure Knowledge Base.
- SaaS Hosting.
- Free Shadow AI Tool {shadow_ai_blocker}
$50 per user/month
[Learn more about Preamble pricing options](https://preamble.com/pricing)"""
image = "🏢"
elif org_size >= 1000 or industry in high_risk_industries:
solution = "Enterprise"
description = f"""
#### 🏢 [Enterprise License](https://preamble.com/pricing)
Perfect for large or high-risk organizations:
- Complete compliance controls.
- Custom AI Assistant Development Support.
- Dedicated support team.
- Private AI Marketplace.
- Custom integrations.
- Private cloud/on-premise options.
- Free Shadow AI Tool {shadow_ai_blocker}
Starting at $27,000/month with discounts for multi-year deals
[Learn more about Preamble pricing options](https://preamble.com/pricing)"""
image = "🚀"
elif org_size >= 100:
solution = "SMB"
description = f"""
#### 🚀 [SMB](https://preamble.com/pricing)
Perfect for teams getting started with AI:
- Full platform features.
- Standard compliance templates.
- Custom AI Assistants.
- Safe AI Search Agent
- Secure Knowledge Base.
- SaaS Hosting.
- Free Shadow AI Tool {shadow_ai_blocker}
$50 per user/month
[Learn more about Preamble pricing options](https://preamble.com/pricing)"""
image = "🏢"
else:
solution = "Guardrails Only"
monthly_cost = api_calls * 0.005
description = f"""
#### ⚡ [Guardrails Only - Compliance](https://preamble.com/pricing)
Perfect for integrating with your existing AI application:
- Quick API integration.
- Pre-built security and privacy guardrails.
- Basic compliance templates.
- Agentless operation.
- Free Trial available.
- Free Shadow AI Tool {shadow_ai_blocker}
$0.005 per API call (Est. monthly cost: ${monthly_cost:,.2f} at {api_calls:,} calls/month)
[Learn more about Preamble pricing options](https://preamble.com/pricing)"""
image = "🛡️"
return {"solution": solution, "description": description, "image": image}
def calculate_build_vs_buy_comparison(initial_dev_cost=1000000, num_ai_personnel=1, avg_annual_salary=200000, annual_maintenance=500000, security_compliance=250000):
# Convert inputs to numbers if they aren't already
try:
initial_dev_cost = float(initial_dev_cost)
num_ai_personnel = int(num_ai_personnel)
avg_annual_salary = float(avg_annual_salary)
annual_maintenance = float(annual_maintenance)
security_compliance = float(security_compliance)
except (ValueError, TypeError):
# Default values if conversion fails
initial_dev_cost = 1000000.0
num_ai_personnel = 1
avg_annual_salary = 200000.0
annual_maintenance = 500000.0
security_compliance = 250000.0
first_year_cost = initial_dev_cost + (num_ai_personnel * avg_annual_salary) + security_compliance
ongoing_annual_cost = (num_ai_personnel * avg_annual_salary) + annual_maintenance + security_compliance
three_year_build_cost = first_year_cost + (ongoing_annual_cost * 2)
preamble_annual_cost = 27000 * 12
three_year_preamble_cost = preamble_annual_cost * 3
three_year_savings = three_year_build_cost - three_year_preamble_cost
savings_percentage = (three_year_savings / three_year_build_cost) * 100 if three_year_build_cost > 0 else 0
return {
"first_year_build": first_year_cost,
"ongoing_annual_build": ongoing_annual_cost,
"three_year_build": three_year_build_cost,
"annual_preamble": preamble_annual_cost,
"three_year_preamble": three_year_preamble_cost,
"three_year_savings": three_year_savings,
"savings_percentage": savings_percentage
}
def create_build_vs_buy_chart(comparison_data):
labels = ["Year 1", "Year 2", "Year 3", "3-Year Total"]
build_costs = [
comparison_data["first_year_build"],
comparison_data["ongoing_annual_build"],
comparison_data["ongoing_annual_build"],
comparison_data["three_year_build"]
]
preamble_costs = [
comparison_data["annual_preamble"],
comparison_data["annual_preamble"],
comparison_data["annual_preamble"],
comparison_data["three_year_preamble"]
]
fig = go.Figure()
fig.add_trace(go.Bar(
x=labels,
y=build_costs,
name="Build In-House",
marker_color=BRAND_COLORS['primary'],
opacity=0.9
))
fig.add_trace(go.Bar(
x=labels,
y=preamble_costs,
name="Preamble Enterprise",
marker_color=BRAND_COLORS['accent'],
opacity=0.9
))
fig.update_layout(
title="Build vs Buy: 3-Year Cost Comparison",
barmode='group',
xaxis_title="Timeline",
yaxis_title="Cost ($)",
legend=dict(
orientation="h",
yanchor="bottom",
y=1.02,
xanchor="center",
x=0.5,
font=dict(color=BRAND_COLORS['light_text'])
),
template="plotly_white",
font=dict(
family="Inter, sans-serif",
size=12,
color=BRAND_COLORS['light_text']
),
paper_bgcolor=BRAND_COLORS['dark_bg'],
plot_bgcolor=BRAND_COLORS['dark_bg'],
margin=dict(l=40, r=40, t=80, b=40)
)
return fig
def generate_recommendations(industry,
org_size,
monthly_budget,
has_ai_app,
dept_roi_results,
subscription_savings,
compliance_savings,
api_calls=10000,
initial_dev_cost=1000000,
num_ai_personnel=1,
avg_annual_salary=200000,
annual_maintenance=500000,
security_compliance=250000):
top_departments = dept_roi_results[:3]
solution_rec = recommend_preamble_solution(industry, org_size,
monthly_budget, has_ai_app,
api_calls)
total_dept_savings = sum(dept["Annual Cost Savings"]
for dept in dept_roi_results)
industry_risks = industry_ai_risks.get(industry,
industry_ai_risks["Other"])
comparison = calculate_build_vs_buy_comparison(
initial_dev_cost,
num_ai_personnel,
avg_annual_salary,
annual_maintenance,
security_compliance
)
dept_recommendations = ""
for i, dept in enumerate(top_departments):
dept_recommendations += f"\n{i+1}. **{dept['Department']}** (ROI: {dept['ROI']:.1f}%)\n"
dept_recommendations += f" - Annual cost savings: ${dept['Annual Cost Savings']:,.2f}\n"
dept_recommendations += f" - Hours saved annually: {dept['Annual Hours Saved']:,.0f}\n"
dept_recommendations += " - Top AI use cases:\n"
for use_case in dept["Use Cases"]:
dept_recommendations += f" - {use_case}\n"
security_text = "\n\n### Key Security Considerations\n"
for risk in industry_risks:
security_text += f"- {risk}\n"
subscription_text = "\n### Subscription & Tool Optimization\n"
subscription_text += f"- **Current annual spend:** ${subscription_savings['total_current_cost']:,.2f}\n"
subscription_text += f"- **Potential annual savings:** ${subscription_savings['total_savings']:,.2f} ({subscription_savings['savings_percentage']:.1f}%)\n"
subscription_text += "- **Recommendation:** Evaluate consolidation of overlapping tools with AI capabilities\n"
compliance_text = "\n### Compliance Risk Reduction\n"
compliance_text += f"- **Potential risk exposure reduction:** ${compliance_savings['total_savings']:,.2f}\n"
compliance_text += "- **Key regulations to address:**\n"
for reg in compliance_savings['key_regulations']:
compliance_text += f" - {reg['name']}: ${reg['cost']:,.2f} risk exposure\n"
build_vs_buy_text = "\n### Build vs Buy Analysis\n"
build_vs_buy_text += "- **Building in-house:**\n"
build_vs_buy_text += f" - First year cost: ${comparison['first_year_build']:,.2f}\n"
build_vs_buy_text += f" - Ongoing annual cost: ${comparison['ongoing_annual_build']:,.2f}\n"
build_vs_buy_text += f" - 3-year total cost: ${comparison['three_year_build']:,.2f}\n\n"
build_vs_buy_text += "- **Preamble Enterprise:**\n"
build_vs_buy_text += f" - Annual cost: ${comparison['annual_preamble']:,.2f}\n"
build_vs_buy_text += f" - 3-year total cost: ${comparison['three_year_preamble']:,.2f}\n\n"
build_vs_buy_text += f"- **3-year savings with Preamble:** ${comparison['three_year_savings']:,.2f} ({comparison['savings_percentage']:.1f}%)\n"
build_vs_buy_text += f"- **ROI:** {((comparison['three_year_savings'] / comparison['three_year_preamble']) * 100):,.1f}%\n"
# Improve formatting for Executive Summary with line breaks between items
executive_summary = "## Executive Summary\n"
executive_summary += f"- **Industry:** {industry}\n"
executive_summary += f"- **Organization Size:** {org_size:,} employees\n"
executive_summary += f"- **Monthly Budget:** ${monthly_budget:,.2f}\n"
executive_summary += f"- **Existing AI Application:** {'Yes' if has_ai_app else 'No'}\n"
executive_summary += f"- **Total Potential Annual Savings:** ${total_dept_savings + subscription_savings['total_savings'] + compliance_savings['total_savings']:,.2f}\n\n"
# Format implementation roadmap with proper line breaks
implementation_roadmap = "## Implementation Roadmap\n\n"
implementation_roadmap += "1. **Phase 1: Security Foundation** (1-2 months)\n"
implementation_roadmap += f" - Deploy Preamble {solution_rec['solution']}\n"
implementation_roadmap += " - Establish AI governance framework\n"
implementation_roadmap += " - Train key personnel\n\n"
implementation_roadmap += "2. **Phase 2: Department Pilots** (2-3 months)\n"
implementation_roadmap += f" - Implement AI use cases in {top_departments[0]['Department']}\n"
implementation_roadmap += " - Measure results\n\n"
implementation_roadmap += "3. **Phase 3: Expansion** (3-6 months)\n"
implementation_roadmap += " - Roll out to additional departments\n"
implementation_roadmap += " - Begin subscription consolidation\n"
implementation_roadmap += " - Scale security controls\n\n"
report = (
f"# AI Implementation & Security Recommendation\n{executive_summary}"
f"## Recommended Preamble Solution\n{solution_rec['image']} {solution_rec['description']}\n\n"
f"{build_vs_buy_text}\n"
f"## Department Recommendations\nThe following departments show the highest potential ROI for AI implementation:{dept_recommendations}\n"
f"{subscription_text}{compliance_text}{security_text}\n\n{implementation_roadmap}"
f"\n[Learn more about Preamble solutions and pricing](https://preamble.com/pricing)"
)
return report, comparison
CUSTOM_CSS = f"""
/* General Styles */
.gradio-container {{
max-width: 1200px !important;
margin: auto !important;
padding: 2rem !important;
background-color: {BRAND_COLORS['dark_bg']} !important;
font-family: 'Inter', sans-serif !important;
color: {BRAND_COLORS['light_text']} !important;
border-radius: 12px !important;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15) !important;
font-size: 16px !important;
}}
/* Main container */
.main-container {{
display: flex !important;
flex-direction: column !important;
gap: 2rem !important;
}}
/* Section styling */
.section-container {{
background-color: {BRAND_COLORS['secondary']} !important;
border-radius: 12px !important;
padding: 2.5rem !important;
margin-bottom: 2rem !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !important;
border: 1px solid {BRAND_COLORS['primary']} !important;
transition: all 0.3s ease !important;
}}
.section-title {{
font-size: 2.2rem !important;
color: {BRAND_COLORS['accent']} !important;
font-weight: 700 !important;
margin-bottom: 1.5rem !important;
line-height: 1.3 !important;
text-align: center !important;
text-shadow: 0px 1px 2px rgba(0,0,0,0.2) !important;
}}
.subsection-title {{
color: {BRAND_COLORS['dark_text']} !important;
font-size: 1.6rem !important;
font-weight: 600 !important;
margin: 1.5rem 0 1rem !important;
border-bottom: 2px solid {BRAND_COLORS['accent']} !important;
padding-bottom: 0.5rem !important;
display: inline-block !important;
}}
/* Input fields styling */
.input-row {{
display: grid !important;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)) !important;
gap: 1.5rem !important;
margin: 1.5rem 0 !important;
}}
.number-input, .text-input, .dropdown-input, .radio-input {{
background-color: {BRAND_COLORS['primary']} !important;
border: 2px solid {BRAND_COLORS['light_bg']} !important;
border-radius: 10px !important;
padding: 1rem !important;
color: {BRAND_COLORS['light_text']} !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
transition: all 0.2s ease-in-out !important;
font-size: 16px !important;
}}
.number-input:focus, .text-input:focus, .dropdown-input:focus, .radio-input:focus {{
border-color: {BRAND_COLORS['accent']} !important;
box-shadow: 0 0 0 4px rgba(255, 199, 0, 0.3) !important;
outline: none !important;
transform: translateY(-2px) !important;
}}
/* Input Labels - Use the defined label_text color */
.label-text, .textinput label, .dropdown-input label, .radio-input label, .number-input label {{ color: {BRAND_COLORS['accent']} !important;
margin-bottom: 0.75rem !important;
font-weight: 600 !important;
font-size: 17px !important;
display: block !important;
letter-spacing: 0.5px !important;
}}
/* Table/Dataframe styling */
.table-container {{
background-color: {BRAND_COLORS['light_bg']} !important;
border-radius: 10px !important;
margin: 1.5rem 0 !important;
overflow: auto !important; /* Changed from 'hidden' to 'auto' to allow scrolling when needed */
border: 2px solid {BRAND_COLORS['primary']} !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
max-height: 400px !important; /* Set maximum height */
}}
.table-container table {{
color: {BRAND_COLORS['input_text']} !important;
width: 100% !important;
border-collapse: collapse !important;
font-size: 16px !important;
display: table !important; /* Ensure proper table display */
table-layout: fixed !important; /* Fixed layout for better control */
}}
.table-container th {{
background-color: {BRAND_COLORS['table_header']} !important;
color: #FFFFFF !important;
padding: 1rem !important;
text-align: left !important;
border-bottom: 2px solid {BRAND_COLORS['primary']} !important;
font-size: 16px !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
}}
.table-container td {{
padding: 1rem !important;
text-align: left !important;
border-bottom: 1px solid {BRAND_COLORS['table_header']} !important;
}}
.table-container tr:nth-child(odd) {{
background-color: {BRAND_COLORS['table_row_odd']} !important;
}}
.table-container tr:nth-child(even) {{
background-color: {BRAND_COLORS['table_row_even']} !important;
}}
.table-container tr:hover {{
background-color: rgba(255, 199, 0, 0.1) !important;
}}
/* Department table specific styling */
.department-table {{
height: 350px !important;
min-height: 350px !important;
overflow-y: visible !important;
}}
.department-table table {{
height: auto !important;
}}
.department-table td {{
white-space: normal !important;
overflow: visible !important;
text-overflow: clip !important;
padding: 12px !important;
}}
/* Results container - General background and text */
.results-container {{
background-color: {BRAND_COLORS['result_bg']} !important;
border-radius: 12px !important;
padding: 2.5rem !important;
margin-top: 2rem !important;
color: {BRAND_COLORS['result_text']} !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !important;
}}
/* Result Card - Specific overrides */
.result-card {{
background-color: {BRAND_COLORS['result_bg']} !important;
border-radius: 10px !important;
padding: 2rem !important;
margin: 1.5rem 0 !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
font-size: 16px !important;
color: {BRAND_COLORS['result_text']} !important;
border-left: 5px solid {BRAND_COLORS['accent']} !important;
}}
/* Enhanced Markdown Rendering - All heading levels */
.result-card h1 {{
font-size: 2.2rem !important;
margin: 1.5rem 0 1.2rem !important;
color: {BRAND_COLORS['accent']} !important;
font-weight: 700 !important;
border-bottom: 2px solid {BRAND_COLORS['accent']} !important;
padding-bottom: 0.6rem !important;
}}
.result-card h2 {{
font-size: 2rem !important;
margin: 1.4rem 0 1rem !important;
color: {BRAND_COLORS['result_text']} !important;
font-weight: 700 !important;
border-bottom: 1px solid {BRAND_COLORS['accent']} !important;
padding-bottom: 0.5rem !important;
}}
.result-card h3 {{
font-size: 1.8rem !important;
margin: 1.3rem 0 1rem !important;
color: {BRAND_COLORS['result_text']} !important;
font-weight: 600 !important;
border-bottom: 1px solid rgba(255, 199, 0, 0.5) !important;
padding-bottom: 0.4rem !important;
display: inline-block !important;
}}
.result-card h4 {{
font-size: 1.5rem !important;
margin: 1.2rem 0 0.8rem !important;
color: {BRAND_COLORS['result_text']} !important;
font-weight: 600 !important;
}}
.result-card h5 {{
font-size: 1.25rem !important;
margin: 1rem 0 0.6rem !important;
color: {BRAND_COLORS['result_text']} !important;
font-weight: 600 !important;
}}
/* Result card text elements */
.result-card p {{
color: {BRAND_COLORS['result_text']} !important;
font-size: 16px !important;
line-height: 1.7 !important;
margin-bottom: 1rem !important;
}}
.result-card strong, .result-card b {{
color: {BRAND_COLORS['accent']} !important;
font-weight: 600 !important;
}}
.result-card em, .result-card i {{
font-style: italic !important;
}}
.result-card a {{
color: {BRAND_COLORS['accent']} !important;
text-decoration: underline !important;
transition: all 0.2s ease !important;
}}
.result-card a:hover {{
opacity: 0.8 !important;
}}
/* Lists styling */
.result-card ul, .result-card ol {{
padding-left: 1.8rem !important;
margin: 0.8rem 0 1.2rem 0.5rem !important;
}}
.result-card li {{
margin-bottom: 0.7rem !important;
color: {BRAND_COLORS['result_text']} !important;
}}
/* Code blocks */
.result-card code {{
background-color: rgba(0, 0, 0, 0.3) !important;
padding: 0.2rem 0.4rem !important;
border-radius: 4px !important;
font-family: monospace !important;
font-size: 0.9rem !important;
}}
.result-card pre {{
background-color: rgba(0, 0, 0, 0.3) !important;
padding: 1rem !important;
border-radius: 6px !important;
overflow-x: auto !important;
margin: 1rem 0 !important;
}}
/* Blockquotes */
.result-card blockquote {{
border-left: 4px solid {BRAND_COLORS['accent']} !important;
padding-left: 1rem !important;
margin-left: 0 !important;
margin-right: 0 !important;
font-style: italic !important;
color: rgba(255, 255, 255, 0.9) !important;
}}
/* Tables */
.result-card table {{
width: 100% !important;
border-collapse: collapse !important;
margin: 1.5rem 0 !important;
}}
.result-card th {{
background-color: {BRAND_COLORS['primary']} !important;
color: {BRAND_COLORS['light_text']} !important;
padding: 0.8rem !important;
text-align: left !important;
font-weight: 600 !important;
}}
.result-card td {{
border: 1px solid rgba(255, 255, 255, 0.2) !important;
padding: 0.8rem !important;
}}
.result-card tr:nth-child(even) {{
background-color: rgba(0, 0, 0, 0.2) !important;
}}
/* Buttons styling */
.calculate-button {{
background-color: {BRAND_COLORS['accent']} !important;
color: {BRAND_COLORS['button_text']} !important;
font-weight: 600 !important;
padding: 1rem 2rem !important;
border-radius: 50px !important;
margin-top: 2rem !important;
font-size: 1.2rem !important;
min-width: 200px !important;
transition: all 0.3s ease !important;
display: inline-block !important;
border: none !important;
cursor: pointer !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
text-align: center !important;
letter-spacing: 0.5px !important;
}}
.calculate-button:hover {{
background-color: #e6b400 !important;
box-shadow: 0 6px 10px rgba(255, 199, 0, 0.3) !important;
transform: translateY(-2px) !important;
}}
.back-button {{
background-color: transparent !important;
color: {BRAND_COLORS['light_text']} !important;
border: 2px solid {BRAND_COLORS['light_text']} !important;
font-weight: 600 !important;
padding: 0.8rem 1.5rem !important;
border-radius: 50px !important;
margin-top: 2rem !important;
font-size: 1.1rem !important;
min-width: 150px !important;
transition: all 0.3s ease !important;
display: inline-block !important;
cursor: pointer !important;
text-align: center !important;
}}
.back-button:hover {{
background-color: rgba(255, 255, 255, 0.1) !important;
box-shadow: 0 2px 4px rgba(255, 255, 255, 0.1) !important;
}}
/* Button container */
.button-container {{
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-top: 2rem !important;
gap: 1rem !important;
}}
.center-button-container {{
display: flex !important;
justify-content: center !important;
align-items: center !important;
margin-top: 2rem !important;
gap: 1rem !important;
}}
/* Chart container */
.chart-container {{
background-color: {BRAND_COLORS['light_bg']} !important;
border-radius: 12px !important;
padding: 2rem !important;
margin: 1.5rem 0 !important;
height: 500px !important;
border: 2px solid {BRAND_COLORS['primary']} !important;
color: {BRAND_COLORS['input_text']} !important;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
}}
/* Tab styling */
.tab-nav {{
padding: 0 !important;
margin-bottom: 2rem !important;
display: flex !important;
justify-content: center !important;
gap: 0.5rem !important;
flex-wrap: wrap !important;
}}
.tab-nav button {{
color: {BRAND_COLORS['light_text']} !important;
padding: 0.8rem 1.8rem !important;
border-radius: 50px !important;
opacity: 0.9 !important;
border: 2px solid {BRAND_COLORS['primary']} !important;
background-color: {BRAND_COLORS['secondary']} !important;
cursor: pointer !important;
font-size: 16px !important;
font-weight: 600 !important;
transition: all 0.3s ease !important;
min-width: 180px !important;
text-align: center !important;
}}
.tab-nav button.selected {{
background-color: {BRAND_COLORS['primary']} !important;
color: {BRAND_COLORS['light_text']} !important;
opacity: 1 !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
}}
.tab-nav button:hover {{
transform: translateY(-2px) !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
}}
/* Timeline progress indicator */
.timeline-container {{
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin: 0 auto 2rem auto !important;
position: relative !important;
max-width: 800px !important;
padding: 15px 20px !important;
background-color: {BRAND_COLORS['secondary']} !important;
border-radius: 8px !important;
}}
.timeline-container:after {{
content: "" !important;
position: absolute !important;
height: 3px !important;
background-color: {BRAND_COLORS['primary']} !important;
top: 50% !important;
left: 0 !important;
right: 0 !important;
z-index: 1 !important;
}}
.timeline-step {{
padding: 8px 15px !important;
border-radius: 6px !important;
font-weight: 600 !important;
font-size: 14px !important;
color: {BRAND_COLORS['light_text']} !important;
background-color: {BRAND_COLORS['primary']} !important;
z-index: 2 !important;
position: relative !important;
transition: all 0.3s ease !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2) !important;
cursor: default !important;
}}
.timeline-step.active {{
background-color: {BRAND_COLORS['accent']} !important;
color: {BRAND_COLORS['dark_text']} !important;
transform: translateY(-2px) !important;
box-shadow: 0 4px 8px rgba(255, 199, 0, 0.3) !important;
}}
@media (max-width: 768px) {{
.timeline-container {{
flex-direction: column !important;
}}
.timeline-container {{
gap: 10px !important;
}}
.timeline-container:after {{
display: none !important;
}}
.timeline-step {{
width: 100% !important;
text-align: center !important;
}}
}}
/* Info card */
.info-card {{
background-color: rgba(255, 199, 0, 0.1) !important;
border-left: 4px solid {BRAND_COLORS['accent']} !important;
padding: 1.2rem !important;
margin: 1.5rem 0 !important;
border-radius: 0 8px 8px 0 !important;
}}
.info-card-title {{
font-weight: 600 !important;
margin-bottom: 0.5rem !important;
color: {BRAND_COLORS['accent']} !important;
}}
.helper-text {{
color: {BRAND_COLORS['accent']} !important;
font-size: 14px !important;
margin-top: 0.5rem !important;
opacity: 0.9 !important;
}}
/* Responsive adjustments */
@media (max-width: 768px) {{
.progress-container:after {{
left: 0 !important;
right: 0 !important;
}}
.section-title {{
font-size: 1.8rem !important;
}}
.subsection-title {{
font-size: 1.4rem !important;
}}
.calculate-button, .back-button {{
width: 100% !important;
}}
}}
/* Responsive adjustments for smaller screens */
@media (max-width: 768px) {{
.input-row {{
grid-template-columns: 1fr !important; /* Stack inputs vertically */
}}
}}
"""
def create_app():
with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default()) as roi_app:
current_step = gr.State(value=1)
total_employees_state = gr.State(value=90)
with gr.Column(elem_classes="main-container"):
gr.Markdown("# Preamble AI Security ROI Calculator",
elem_classes="section-title")
with gr.Row(elem_classes="timeline-container"):
step1_indicator = gr.Markdown(
"Organization Profile",
elem_classes="timeline-step active",
elem_id="step1-indicator")
step2_indicator = gr.Markdown(
"Department Assessment",
elem_classes="timeline-step",
elem_id="step2-indicator")
step3_indicator = gr.Markdown(
"Tools & Compliance",
elem_classes="timeline-step",
elem_id="step3-indicator")
step4_indicator = gr.Markdown(
"Results",
elem_classes="timeline-step",
elem_id="step4-indicator")
with gr.Column(visible=True,
elem_id="step1",
elem_classes="section-container") as step1:
gr.Markdown("## Organization Profile",
elem_classes="section-title")
gr.Markdown("""<div class="info-card">
<div class="info-card-title">Getting Started</div>
Let's understand your organization's needs better. Fill out the basic information below to help us provide tailored recommendations.
</div>""")
with gr.Row(elem_classes="input-row"):
industry = gr.Dropdown(label="Industry",
choices=list(
industry_ai_risks.keys()),
value="Financial Services",
elem_classes="dropdown-input")
gr.Markdown(
"""<div class="helper-text">Your industry helps us identify specific AI security risks and compliance requirements.</div>"""
)
with gr.Row(elem_classes="input-row"):
org_size = gr.Number(label="Number of Employees",
value=90,
minimum=10,
elem_classes="number-input",
precision=0)
gr.Markdown(
"""<div class="helper-text">This helps us scale recommendations appropriately for your organization size (minimum 10 employees).</div>"""
)
with gr.Row(elem_classes="input-row"):
monthly_budget = gr.Number(
label="Monthly Budget for AI Security ($)",
value=30000,
elem_classes="number-input",
precision=0)
gr.Markdown(
"""<div class="helper-text">We'll recommend solutions that fit within your budget constraints.</div>"""
)
with gr.Row(elem_classes="input-row"):
has_ai_app = gr.Radio(
label=
"Do you have an existing in-house AI application?",
choices=[("Yes", True), ("No", False)],
value=False,
elem_classes="radio-input")
gr.Markdown(
"""<div class="helper-text">This helps determine if we should focus on securing existing AI systems or implementing new ones.</div>"""
)
with gr.Row(elem_classes="input-row"):
api_calls = gr.Number(label="Estimated Monthly API Calls",
value=10000,
elem_classes="number-input",
precision=0)
gr.Markdown(
"""<div class="helper-text">For organizations with existing AI systems, this helps estimate the cost of our Guardrails solution (based on 8hr workday, 5 days/week).</div>"""
)
with gr.Row(elem_classes="button-container"):
next_button1 = gr.Button("Next: Department Assessment →",
elem_classes="calculate-button")
with gr.Column(visible=False,
elem_id="step2",
elem_classes="section-container") as step2:
gr.Markdown("## Department Assessment",
elem_classes="section-title")
gr.Markdown("""<div class="info-card">
<div class="info-card-title">Department Breakdown</div>
Review and customize the department data below to match your organization's structure. This helps us identify which departments will benefit most from AI implementation.
</div>""")
gr.Markdown(
"#### Edit the table below to match your organization",
elem_classes="subsection-title")
department_data = gr.Dataframe(
value=default_departments,
headers=[
"Department", "Number of Employees", "Average Salary",
"Hours Per Week on Manual Tasks"
],
datatype=["str", "number", "number", "number"],
col_count=(4, "fixed"),
elem_classes="table-container department-table",
interactive=True)
gr.Markdown("""<div class="helper-text">
✓ Add or modify departments as needed<br>
✓ Update employee counts to reflect your team structure<br>
✓ Estimate time spent on tasks that could be automated with AI
</div>""")
with gr.Row(elem_classes="button-container"):
back_button2 = gr.Button("← Back",
elem_classes="back-button")
next_button2 = gr.Button("Next: Tools & Compliance →",
elem_classes="calculate-button")
with gr.Column(visible=False,
elem_id="step3",
elem_classes="section-container") as step3:
gr.Markdown("## Tools & Compliance",
elem_classes="section-title")
gr.Markdown("""<div class="info-card">
<div class="info-card-title">Optimize Costs & Reduce Risk</div>
In this section, we'll identify potential savings from consolidating tools with AI capabilities and estimate compliance risk reduction based on your industry.
</div>""")
with gr.Tabs():
with gr.Tab("Technology & Subscriptions"):
gr.Markdown("#### Current Software & Tools",
elem_classes="subsection-title")
gr.Markdown(
"""Review and edit your current technology expenses that could be optimized with AI solutions."""
)
subscription_data = gr.Dataframe(
value=default_subscriptions,
headers=[
"Tool Category",
"Current Monthly Cost per User",
"Number of Users", "Estimated Reduction %"
],
datatype=["str", "number", "number", "number"],
col_count=(4, "fixed"),
elem_classes="table-container",
interactive=True)
gr.Markdown("""<div class="helper-text">
Adjust the "Estimated Reduction %" to reflect how much you believe AI could help reduce costs in each category.
</div>""")
with gr.Tab("Compliance & Risk"):
gr.Markdown("#### Regulatory Requirements",
elem_classes="subsection-title")
gr.Markdown(
"""These compliance requirements are tailored to your industry. Edit to match your specific situation."""
)
compliance_data = gr.Dataframe(
value=industry_compliance_data[
"Financial Services"],
headers=[
"Regulation", "Potential Violations",
"Penalty", "Attorney Cost"
],
datatype=["str", "number", "number", "number"],
col_count=(4, "fixed"),
elem_classes="table-container",
interactive=True)
gr.Markdown("""<div class="helper-text">
✓ "Potential Violations" estimates how many compliance issues AI security could prevent<br>
✓ "Penalty" represents average regulatory fines per violation<br>
✓ "Attorney Cost" includes legal expenses for addressing violations
</div>""")
with gr.Row(elem_classes="button-container"):
back_button3 = gr.Button("← Back",
elem_classes="back-button")
next_button3 = gr.Button("Next: Build vs Buy Comparison →",
elem_classes="calculate-button")
calculate_button = gr.Button(
"Generate Recommendations ✨",
elem_classes="calculate-button")
with gr.Column(visible=False,
elem_id="step3_5",
elem_classes="section-container") as step3_5:
gr.Markdown("## Build vs Buy Analysis",
elem_classes="section-title")
gr.Markdown("""<div class="info-card">
<div class="info-card-title">Compare Building In-House vs Preamble</div>
Adjust the values below to compare the cost of building and maintaining your own AI security platform versus using Preamble's enterprise solution.
</div>""")
with gr.Row(elem_classes="input-row"):
initial_dev_cost = gr.Number(
label="Initial Development Cost ($)",
value=1000000,
elem_classes="number-input",
precision=0)
with gr.Row(elem_classes="input-row"):
num_ai_personnel = gr.Number(
label="Number of AI Personnel",
value=1,
elem_classes="number-input",
precision=0)
avg_annual_salary = gr.Number(
label="Average Annual Salary ($)",
value=200000,
elem_classes="number-input",
precision=0)
with gr.Row(elem_classes="input-row"):
annual_maintenance = gr.Number(
label="Annual Maintenance ($)",
value=500000,
elem_classes="number-input",
precision=0)
security_compliance = gr.Number(
label="Security & Compliance ($)",
value=250000,
elem_classes="number-input",
precision=0)
with gr.Row(elem_classes="button-container"):
back_button3_5 = gr.Button("← Back",
elem_classes="back-button")
calculate_button_with_comparison = gr.Button(
"Generate Recommendations with Comparison ✨",
elem_classes="calculate-button")
with gr.Column(visible=False,
elem_id="step4",
elem_classes="section-container") as step4:
gr.Markdown("## Your Personalized AI Security Plan",
elem_classes="section-title")
gr.Markdown("""<div class="info-card">
<div class="info-card-title">Your Customized Recommendation</div>
Based on your inputs, we've generated a comprehensive AI security implementation plan tailored to your organization's needs, budget, and industry requirements.
</div>""")
# Simplified output without tabs and plots for better performance
recommendation_output = gr.Markdown(
elem_classes="result-card",
render=True)
gr.Markdown(
"""<div class="helper-text" style="margin-top: 20px; text-align: center;">
Want to learn more about implementing these recommendations? Contact our team at <a href="mailto:sales@preamble.com" style="color: #FFC700;">sales@preamble.com</a>
</div>""")
with gr.Row(elem_classes="center-button-container"):
restart_button = gr.Button("Start Over",
elem_classes="calculate-button")
def update_progress_indicator(step):
return [
gr.update(elem_classes="timeline-step active" if i ==
step else "timeline-step") for i in range(1, 5)
]
def go_to_step1(step):
indicators = update_progress_indicator(1)
return (gr.update(visible=True), gr.update(visible=False),
gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), 1, *indicators)
def go_to_step2(org_size, step):
indicators = update_progress_indicator(2)
# Ensure org_size is valid
try:
total_employees = int(org_size) if org_size is not None else 0
if total_employees < 0:
total_employees = 0
except (ValueError, TypeError):
total_employees = 0
# Create copies of dataframes only once
updated_departments = default_departments.copy()
updated_subscriptions = default_subscriptions.copy()
# Update department employee count efficiently
if total_employees > 0:
current_total = updated_departments['Number of Employees'].sum()
if total_employees != current_total:
# Distribute employees proportionally across departments
if current_total > 0:
ratio = total_employees / current_total
for idx in updated_departments.index:
new_count = round(updated_departments.at[idx, 'Number of Employees'] * ratio)
updated_departments.at[idx, 'Number of Employees'] = max(1, new_count) # Ensure at least 1 employee per department
else:
# If current total is 0, distribute evenly
dept_count = len(updated_departments)
base_count = total_employees // dept_count
remainder = total_employees % dept_count
for idx in updated_departments.index:
if idx < remainder:
updated_departments.at[idx, 'Number of Employees'] = base_count + 1
else:
updated_departments.at[idx, 'Number of Employees'] = base_count
# Adjust to ensure exact total (due to rounding)
current_sum = updated_departments['Number of Employees'].sum()
if current_sum != total_employees:
diff = total_employees - current_sum
# Add or subtract the difference from the largest department to minimize impact
largest_dept_idx = updated_departments['Number of Employees'].idxmax()
updated_departments.at[largest_dept_idx, 'Number of Employees'] += diff
# Ensure no negative values after adjustment
if updated_departments.at[largest_dept_idx, 'Number of Employees'] < 1:
# If the largest department would go negative, redistribute
updated_departments.at[largest_dept_idx, 'Number of Employees'] = 1
remaining_diff = diff + 1 - updated_departments.at[largest_dept_idx, 'Number of Employees']
# Distribute remaining difference across other departments
for idx in updated_departments.index:
if idx != largest_dept_idx and remaining_diff != 0:
if remaining_diff < 0 and updated_departments.at[idx, 'Number of Employees'] > 1:
updated_departments.at[idx, 'Number of Employees'] -= 1
remaining_diff += 1
elif remaining_diff > 0:
updated_departments.at[idx, 'Number of Employees'] += 1
remaining_diff -= 1
if remaining_diff == 0:
break
# Update all subscription users at once
updated_subscriptions['Number of Users'] = total_employees
# Return updates all at once
return (gr.update(visible=False), gr.update(visible=True),
gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), gr.update(value=2),
gr.update(value=total_employees), gr.update(value=updated_departments),
gr.update(value=updated_subscriptions), *indicators)
def go_to_step3(industry, step):
indicators = update_progress_indicator(3)
new_compliance_data = industry_compliance_data.get(
industry, industry_compliance_data["Other"])
new_compliance_data.columns = [
"Regulation", "Potential Violations", "Penalty",
"Attorney Cost"
]
return (gr.update(visible=False), gr.update(visible=False),
gr.update(visible=True), gr.update(visible=False),
gr.update(visible=False), gr.update(value=new_compliance_data),
gr.update(value=3), *indicators)
def go_to_step3_5(step):
indicators = update_progress_indicator(3)
return (gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), gr.update(visible=True),
gr.update(visible=False), gr.update(value=3), *indicators)
def generate_recommendations_and_go_to_step4(
industry, org_size, monthly_budget, has_ai_app, api_calls,
department_df, subscription_df, compliance_df, step):
dept_roi_results = calculate_department_roi(department_df)
sub_savings = calculate_subscription_savings(subscription_df)
comp_savings = calculate_compliance_savings(compliance_df)
report = generate_recommendations(industry, org_size,
monthly_budget, has_ai_app,
dept_roi_results,
sub_savings, comp_savings,
api_calls)[0] # Only get the report
indicators = update_progress_indicator(4)
return (gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), gr.update(visible=False),
gr.update(visible=True), report, *indicators)
def generate_recommendations_with_comparison(
industry, org_size, monthly_budget, has_ai_app, api_calls,
department_df, subscription_df, compliance_df,
initial_dev_cost, num_ai_personnel, avg_annual_salary,
annual_maintenance, security_compliance, step):
try:
# Convert inputs to appropriate types with error handling
try:
org_size_val = int(org_size) if org_size is not None else 90
except (ValueError, TypeError):
org_size_val = 90
try:
monthly_budget_val = float(monthly_budget) if monthly_budget is not None else 30000
except (ValueError, TypeError):
monthly_budget_val = 30000.0
try:
api_calls_val = int(api_calls) if api_calls is not None else 10000
except (ValueError, TypeError):
api_calls_val = 10000
try:
initial_dev_cost_val = float(initial_dev_cost) if initial_dev_cost is not None else 1000000
except (ValueError, TypeError):
initial_dev_cost_val = 1000000.0
try:
num_ai_personnel_val = int(num_ai_personnel) if num_ai_personnel is not None else 1
except (ValueError, TypeError):
num_ai_personnel_val = 1
try:
avg_annual_salary_val = float(avg_annual_salary) if avg_annual_salary is not None else 200000
except (ValueError, TypeError):
avg_annual_salary_val = 200000.0
try:
annual_maintenance_val = float(annual_maintenance) if annual_maintenance is not None else 500000
except (ValueError, TypeError):
annual_maintenance_val = 500000.0
try:
security_compliance_val = float(security_compliance) if security_compliance is not None else 250000
except (ValueError, TypeError):
security_compliance_val = 250000.0
# Validate dataframes and convert to default if invalid
if department_df is None or department_df.empty:
department_df = default_departments
if subscription_df is None or subscription_df.empty:
subscription_df = default_subscriptions
if compliance_df is None or compliance_df.empty:
compliance_df = industry_compliance_data.get(industry, industry_compliance_data["Other"])
# Calculate ROIs and savings
dept_roi_results = calculate_department_roi(department_df)
sub_savings = calculate_subscription_savings(subscription_df)
comp_savings = calculate_compliance_savings(compliance_df)
report, comparison = generate_recommendations(
industry, org_size_val, monthly_budget_val, has_ai_app,
dept_roi_results, sub_savings, comp_savings, api_calls_val,
initial_dev_cost_val, num_ai_personnel_val, avg_annual_salary_val,
annual_maintenance_val, security_compliance_val)
indicators = update_progress_indicator(4)
return (gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), gr.update(visible=False),
gr.update(visible=True), report, *indicators)
except Exception as e:
# Provide a graceful error message instead of crashing
error_message = f"An error occurred while generating recommendations: {str(e)}"
indicators = update_progress_indicator(4)
return (gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), gr.update(visible=False),
gr.update(visible=True), error_message, *indicators)
next_button1.click(fn=go_to_step2,
inputs=[org_size, current_step],
outputs=[
step1, step2, step3, step3_5, step4, current_step,
total_employees_state, department_data,
subscription_data, step1_indicator,
step2_indicator, step3_indicator, step4_indicator
])
back_button2.click(fn=go_to_step1,
inputs=[current_step],
outputs=[
step1, step2, step3, step3_5, step4, current_step,
step1_indicator, step2_indicator, step3_indicator,
step4_indicator
])
next_button2.click(fn=go_to_step3,
inputs=[industry, current_step],
outputs=[
step1, step2, step3, step3_5, step4, compliance_data,
current_step, step1_indicator, step2_indicator,
step3_indicator, step4_indicator
])
back_button3.click(fn=go_to_step2,
inputs=[org_size, current_step],
outputs=[
step1, step2, step3, step3_5, step4, current_step,
total_employees_state, department_data,
subscription_data, step1_indicator,
step2_indicator, step3_indicator, step4_indicator
])
next_button3.click(fn=go_to_step3_5,
inputs=[current_step],
outputs=[
step1, step2, step3, step3_5, step4,
current_step, step1_indicator, step2_indicator,
step3_indicator, step4_indicator
])
back_button3_5.click(fn=go_to_step3,
inputs=[industry, current_step],
outputs=[
step1, step2, step3, step3_5, step4, compliance_data,
current_step, step1_indicator, step2_indicator,
step3_indicator, step4_indicator
])
calculate_button.click(fn=generate_recommendations_and_go_to_step4,
inputs=[
industry, org_size, monthly_budget,
has_ai_app, api_calls, department_data,
subscription_data, compliance_data,
current_step
],
outputs=[
step1, step2, step3, step3_5, step4,
recommendation_output, step1_indicator,
step2_indicator, step3_indicator, step4_indicator
])
calculate_button_with_comparison.click(
fn=generate_recommendations_with_comparison,
inputs=[
industry, org_size, monthly_budget, has_ai_app,
api_calls, department_data, subscription_data,
compliance_data, initial_dev_cost, num_ai_personnel,
avg_annual_salary, annual_maintenance,
security_compliance, current_step
],
outputs=[
step1, step2, step3, step3_5, step4,
recommendation_output, step1_indicator, step2_indicator,
step3_indicator, step4_indicator
]
)
restart_button.click(fn=go_to_step1,
inputs=[current_step],
outputs=[
step1, step2, step3, step3_5, step4, current_step,
step1_indicator, step2_indicator, step3_indicator,
step4_indicator
])
return roi_app
app = create_app()
if __name__ == "__main__":
app.launch()
#Preamble, Inc. 2025
#AI ROI Calc
#web https://preamble.com