# ---------------- APP ---------------- # This is the main file to run the Gradio application. # It imports logic from logic.py and configuration from config.py import gradio as gr # Import constants needed for the UI from config import CRISIS_PERIODS, EXAMPLE_PORTFOLIOS, CRISIS_SUMMARY # Import the main simulation function from logic import run_crisis_simulation # --- UI Helper Functions --- def load_example(example_name): """Updates ticker and weight textboxes based on selection.""" portfolio = EXAMPLE_PORTFOLIOS.get(example_name, {"tickers": "", "weights": ""}) return gr.update(value=portfolio["tickers"]), gr.update(value=portfolio["weights"]) def update_crisis_summary(crisis_name): """Updates the crisis summary text when a crisis is selected.""" summary = CRISIS_SUMMARY.get(crisis_name, "") if summary: return f"**Crisis summary:** _{summary}_" return "" # ---------------- UI DEFINITION ---------------- with gr.Blocks(title="Crisis Lens (India)") as demo: gr.Markdown( """ # 🇮🇳 Crisis Lens — Indian Stock Stress Simulator How would your portfolio have performed during a major market crisis? Select a historical crisis and your portfolio to find out. """ ) with gr.Row(): with gr.Column(scale=2): crisis_dd = gr.Dropdown( list(CRISIS_PERIODS.keys()), label="Select Crisis", value="COVID-19 Crash (India)", ) crisis_info = gr.Markdown( f"**Crisis summary:** _{CRISIS_SUMMARY['COVID-19 Crash (India)']}_", elem_classes="crisis-summary", ) with gr.Column(scale=1): example_loader_dd = gr.Dropdown( list(EXAMPLE_PORTFOLIOS.keys()), label="Load Example Portfolio", value="Select Example...", # will be overridden by .load() ) with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 1. Define Your Portfolio") upload_csv = gr.File( label="Upload Portfolio CSV (Ticker,Weight)", file_types=[".csv"] ) gr.Markdown("...or enter manually below:") tickers_input = gr.Textbox( label="Tickers (comma separated)", value="" ) weights_input = gr.Textbox( label="Weights (comma separated)", value="" ) add_etf_cb = gr.Checkbox( label="Add 5% NIFTYBEES.NS to portfolio (diversify)", value=False ) gr.Markdown("---") gr.Markdown("### 🤖 2. AI Insights (Optional)") gemini_api_key_in = gr.Textbox( label="Gemini API Key (optional, not stored)", placeholder="Paste your Gemini API key here to get AI-generated insights", type="password", ) gemini_extra_prompt_in = gr.Textbox( label="Extra instructions for AI (optional)", placeholder="e.g., Focus more on risk, or write in simple language, etc.", lines=2, ) gr.Markdown("---") run_btn = gr.Button("Run Simulation", variant="primary") logs_txt = gr.Textbox(label="Status / Logs", interactive=False) with gr.Column(scale=3): gr.Markdown("### 3. Analyze the Results") plot_performance = gr.Plot() with gr.Row(): metrics_output = gr.Markdown() pie_chart = gr.Plot() with gr.Row(): sector_plot_output = gr.Plot() insights_output = gr.Markdown() gr.Markdown("### 🤖 AI-Generated Insights") gemini_insights_md = gr.Markdown( value="*AI insights will appear here after running simulation with a Gemini API key.*" ) # ---------------- EVENT HANDLERS ---------------- crisis_dd.change( fn=update_crisis_summary, inputs=[crisis_dd], outputs=[crisis_info], ) example_loader_dd.change( fn=load_example, inputs=[example_loader_dd], outputs=[tickers_input, weights_input], ) run_btn.click( run_crisis_simulation, inputs=[ crisis_dd, upload_csv, tickers_input, weights_input, add_etf_cb, gemini_api_key_in, gemini_extra_prompt_in, ], outputs=[ plot_performance, metrics_output, sector_plot_output, insights_output, pie_chart, logs_txt, gemini_insights_md, ], ) def load_default_example(): default_name = "Large-Cap (Default)" portfolio = EXAMPLE_PORTFOLIOS.get(default_name, {"tickers": "", "weights": ""}) summary = CRISIS_SUMMARY.get("COVID-19 Crash (India)", "") return ( gr.update(value=default_name), gr.update(value=portfolio["tickers"]), gr.update(value=portfolio["weights"]), f"**Crisis summary:** _{summary}_", ) demo.load( fn=load_default_example, inputs=None, outputs=[example_loader_dd, tickers_input, weights_input, crisis_info], ) # ---------------- LAUNCH ---------------- if __name__ == "__main__": demo.launch(share=True, debug=True)