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! | |
| """) |