Spaces:
Sleeping
Sleeping
""" | |
Gradio interface components for the equity calculator | |
""" | |
import gradio as gr | |
from typing import Tuple, List, Optional | |
from models import create_cap_table, EquityCalculator, ExitScenario | |
from charts import EquityCharts, format_equity_summary | |
def create_cap_table_inputs(): | |
"""Create the cap table input components""" | |
with gr.Column(): | |
gr.Markdown("## Cap Table Structure") | |
total_shares = gr.Number(label="Total Fully Diluted Shares", value=10000000, precision=0) | |
your_options = gr.Number(label="Your Option Grant", value=0, precision=0) | |
strike_price = gr.Number(label="Strike Price per Share ($)", value=0.10, precision=4) | |
gr.Markdown("## Funding Rounds") | |
with gr.Accordion("Seed Round", open=False): | |
seed_shares = gr.Number(label="Seed Shares Issued", value=0, precision=0) | |
seed_capital = gr.Number(label="Seed Capital Raised ($)", value=0, precision=0) | |
seed_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1) | |
seed_participating = gr.Checkbox(label="Participating Preferred", value=False) | |
with gr.Accordion("Series A", open=False): | |
series_a_shares = gr.Number(label="Series A Shares Issued", value=0, precision=0) | |
series_a_capital = gr.Number(label="Series A Capital Raised ($)", value=0, precision=0) | |
series_a_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1) | |
series_a_participating = gr.Checkbox(label="Participating Preferred", value=False) | |
with gr.Accordion("Series B", open=False): | |
series_b_shares = gr.Number(label="Series B Shares Issued", value=0, precision=0) | |
series_b_capital = gr.Number(label="Series B Capital Raised ($)", value=0, precision=0) | |
series_b_multiple = gr.Number(label="Liquidation Multiple", value=1.0, precision=1) | |
series_b_participating = gr.Checkbox(label="Participating Preferred", value=False) | |
return [ | |
total_shares, your_options, strike_price, | |
seed_shares, seed_capital, seed_multiple, seed_participating, | |
series_a_shares, series_a_capital, series_a_multiple, series_a_participating, | |
series_b_shares, series_b_capital, series_b_multiple, series_b_participating | |
] | |
def create_scenario_inputs(): | |
"""Create the exit scenario input components""" | |
with gr.Column(): | |
gr.Markdown("## Exit Scenarios") | |
gr.Markdown("*Define multiple exit scenarios to compare side-by-side*") | |
with gr.Row(): | |
with gr.Column(): | |
scenario_1_name = gr.Textbox(label="Scenario 1 Name", value="Conservative", placeholder="e.g., Conservative") | |
exit_scenario_1 = gr.Number(label="Exit Valuation ($)", value=25000000, precision=0) | |
with gr.Column(): | |
scenario_2_name = gr.Textbox(label="Scenario 2 Name", value="Base Case", placeholder="e.g., Base Case") | |
exit_scenario_2 = gr.Number(label="Exit Valuation ($)", value=50000000, precision=0) | |
with gr.Row(): | |
with gr.Column(): | |
scenario_3_name = gr.Textbox(label="Scenario 3 Name", value="Optimistic", placeholder="e.g., Optimistic") | |
exit_scenario_3 = gr.Number(label="Exit Valuation ($)", value=100000000, precision=0) | |
with gr.Column(): | |
scenario_4_name = gr.Textbox(label="Scenario 4 Name", value="", placeholder="e.g., Moon Shot") | |
exit_scenario_4 = gr.Number(label="Exit Valuation ($)", value=0, precision=0) | |
with gr.Row(): | |
with gr.Column(): | |
scenario_5_name = gr.Textbox(label="Scenario 5 Name", value="", placeholder="e.g., IPO") | |
exit_scenario_5 = gr.Number(label="Exit Valuation ($)", value=0, precision=0) | |
calculate_btn = gr.Button("π Calculate All Scenarios", variant="primary", size="lg") | |
results_text = gr.Markdown() | |
return [ | |
exit_scenario_1, scenario_1_name, | |
exit_scenario_2, scenario_2_name, | |
exit_scenario_3, scenario_3_name, | |
exit_scenario_4, scenario_4_name, | |
exit_scenario_5, scenario_5_name, | |
calculate_btn, results_text | |
] | |
def create_output_components(): | |
"""Create the output chart components""" | |
with gr.Row(): | |
comparison_plot = gr.Plot(label="Multi-Scenario Comparison") | |
with gr.Row(): | |
waterfall_plot = gr.Plot(label="Detailed Waterfall (Best Scenario)") | |
roi_plot = gr.Plot(label="Return on Investment") | |
return [comparison_plot, waterfall_plot, roi_plot] | |
def process_inputs( | |
# Cap table inputs | |
total_shares, your_options, strike_price, | |
seed_shares, seed_capital, seed_multiple, seed_participating, | |
series_a_shares, series_a_capital, series_a_multiple, series_a_participating, | |
series_b_shares, series_b_capital, series_b_multiple, series_b_participating, | |
# Scenario inputs | |
exit_scenario_1, scenario_1_name, | |
exit_scenario_2, scenario_2_name, | |
exit_scenario_3, scenario_3_name, | |
exit_scenario_4, scenario_4_name, | |
exit_scenario_5, scenario_5_name | |
) -> Tuple[str, Optional[gr.Plot], Optional[gr.Plot], Optional[gr.Plot]]: | |
"""Process all inputs and return formatted results and charts""" | |
# Handle None values with defaults | |
total_shares = total_shares or 10000000 | |
your_options = your_options or 0 | |
strike_price = strike_price or 0.10 | |
# Validate inputs | |
if total_shares <= 0: | |
return "Invalid inputs - please check your values", None, None, None | |
# Create cap table | |
try: | |
cap_table = create_cap_table( | |
total_shares=total_shares, | |
your_options=your_options, | |
strike_price=strike_price, | |
seed_shares=seed_shares or 0, | |
seed_capital=seed_capital or 0, | |
seed_multiple=seed_multiple or 1.0, | |
seed_participating=seed_participating or False, | |
series_a_shares=series_a_shares or 0, | |
series_a_capital=series_a_capital or 0, | |
series_a_multiple=series_a_multiple or 1.0, | |
series_a_participating=series_a_participating or False, | |
series_b_shares=series_b_shares or 0, | |
series_b_capital=series_b_capital or 0, | |
series_b_multiple=series_b_multiple or 1.0, | |
series_b_participating=series_b_participating or False | |
) | |
except Exception as e: | |
return f"Error creating cap table: {str(e)}", None, None, None | |
# Create scenarios | |
scenarios = [] | |
scenario_data = [ | |
(exit_scenario_1 or 0, scenario_1_name or "Scenario 1"), | |
(exit_scenario_2 or 0, scenario_2_name or "Scenario 2"), | |
(exit_scenario_3 or 0, scenario_3_name or "Scenario 3"), | |
(exit_scenario_4 or 0, scenario_4_name or "Scenario 4"), | |
(exit_scenario_5 or 0, scenario_5_name or "Scenario 5") | |
] | |
for exit_val, name in scenario_data: | |
if exit_val > 0: | |
scenarios.append(ExitScenario(name=name, exit_valuation=exit_val)) | |
if not scenarios: | |
return "Please enter at least one exit scenario with a positive value", None, None, None | |
# Calculate results | |
calculator = EquityCalculator(cap_table) | |
try: | |
results = calculator.calculate_multiple_scenarios(scenarios) | |
summary = calculator.get_liquidation_summary() | |
except Exception as e: | |
return f"Error calculating results: {str(e)}", None, None, None | |
if not results: | |
return "No valid scenarios to calculate", None, None, None | |
# Generate charts | |
charts = EquityCharts() | |
try: | |
# Multi-scenario comparison | |
comparison_chart = charts.create_multi_scenario_comparison(results) | |
# Detailed waterfall for best scenario | |
best_result = max(results, key=lambda x: x.option_value) | |
waterfall_chart = charts.create_liquidation_waterfall( | |
cap_table, | |
best_result.exit_valuation, | |
best_result.scenario_name | |
) | |
# ROI analysis | |
investment_cost = cap_table.your_options * cap_table.strike_price | |
roi_chart = charts.create_roi_analysis(results, investment_cost) | |
except Exception as e: | |
return f"Error generating charts: {str(e)}", None, None, None | |
# Format summary | |
try: | |
summary_text = format_equity_summary(summary, results) | |
except Exception as e: | |
return f"Error formatting summary: {str(e)}", comparison_chart, waterfall_chart, roi_chart | |
return summary_text, comparison_chart, waterfall_chart, roi_chart | |
def create_help_section(): | |
"""Create the help/documentation section""" | |
gr.Markdown(""" | |
## π How to Use This Calculator | |
### π― Multi-Scenario Analysis | |
**This is where the real value lies!** Instead of guessing one exit value, define multiple realistic scenarios: | |
- **Conservative**: What if growth is slower than expected? | |
- **Base Case**: Most likely scenario based on current trajectory | |
- **Optimistic**: If everything goes right | |
- **Moon Shot**: Best case scenario (10x+ returns) | |
### π Key Outputs | |
1. **Comparison Table**: Side-by-side option values across all scenarios | |
2. **Visual Charts**: See how your returns scale with different exits | |
3. **ROI Analysis**: Understand your return on investment potential | |
4. **Detailed Waterfall**: How liquidation preferences affect distributions | |
### π‘ Decision Framework | |
Use this to evaluate: | |
- **Risk vs Reward**: How much upside vs downside? | |
- **Opportunity Cost**: Compare to other job offers or investments | |
- **Negotiation Power**: Understanding your equity's potential value range | |
### π§ Liquidation Preferences | |
- **Non-Participating**: Investors choose preference OR convert to common (better for employees) | |
- **Participating**: Investors get preference AND share upside (worse for employees) | |
- **Multiples**: How many times their investment investors get back first | |
**Pro Tip**: Try toggling participating preferred on/off to see the dramatic impact on your equity value! | |
""") |