Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from services.llm_client import llm_service | |
| from core.analyzer import PortfolioAnalyzer | |
| from core.comparer import PortfolioComparer | |
| from core.chat import ChatAssistant | |
| from core.metrics import show_metrics_table | |
| from core.visualization import build_alpha_chart | |
| MODEL_NAME = "meta-llama/Meta-Llama-3.1-8B-Instruct" | |
| analyzer = PortfolioAnalyzer(llm_service, MODEL_NAME) | |
| comparer = PortfolioComparer(llm_service, MODEL_NAME) | |
| chatbot = ChatAssistant(llm_service, MODEL_NAME) | |
| # === Bloomberg-style dark theme === | |
| dark_theme = gr.themes.Base( | |
| primary_hue="violet", | |
| secondary_hue="gray", | |
| neutral_hue="zinc", | |
| ).set( | |
| body_background_fill="#0d1117", # main background (dark navy) | |
| body_text_color="#e6edf3", # main text | |
| block_background_fill="#161b22", # card background | |
| block_border_color="#30363d", # subtle border | |
| button_primary_background_fill="#4f46e5",# indigo-violet accent | |
| button_primary_background_fill_hover="#6366f1", | |
| button_primary_text_color="#ffffff", | |
| input_background_fill="#0d1117", | |
| block_shadow="0 2px 6px rgba(0,0,0,0.3)", | |
| block_label_text_color="#9da5b4", | |
| block_label_text_size="sm", | |
| ) | |
| with gr.Blocks(theme=dark_theme, css=""" | |
| /* === Bloomberg / Dark Finance Style === */ | |
| .gradio-container { | |
| max-width: 1000px !important; | |
| margin: auto !important; | |
| font-family: 'Inter', sans-serif; | |
| background-color: #0d1117 !important; | |
| } | |
| /* === LLM Commentary Styling === */ | |
| #llm_comment_box textarea { | |
| max-height: 420px !important; /* ограничение высоты */ | |
| overflow-y: auto !important; /* вертикальный скроллинг */ | |
| background-color: #161b22 !important; | |
| color: #f0f6fc !important; | |
| border: 1px solid #30363d !important; | |
| border-radius: 6px !important; | |
| font-family: 'JetBrains Mono', monospace !important; | |
| font-size: 14px !important; | |
| line-height: 1.5 !important; | |
| padding: 12px !important; | |
| } | |
| /* === Comparison Table === */ | |
| #comparison_table { | |
| margin-top: 8px !important; | |
| } | |
| h2, h3, .gr-markdown { | |
| font-weight: 600; | |
| color: #f0f6fc !important; | |
| } | |
| .gr-button { | |
| border-radius: 6px !important; | |
| font-weight: 600 !important; | |
| letter-spacing: 0.3px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.25); | |
| } | |
| .gr-textbox, .gr-dataframe { | |
| border-radius: 6px !important; | |
| } | |
| .gr-button.primary { | |
| background: linear-gradient(90deg, #6366f1, #4f46e5); | |
| border: none !important; | |
| } | |
| .gr-tab { | |
| background-color: #161b22 !important; | |
| color: #c9d1d9 !important; | |
| } | |
| .gr-tabs { | |
| border-bottom: 1px solid #30363d !important; | |
| } | |
| .gr-plot { | |
| background: #0d1117 !important; | |
| } | |
| /* Fix Gradio plot overlay */ | |
| #alpha_chart svg { | |
| display: none !important; | |
| } | |
| #alpha_chart .wrap { | |
| background: transparent !important; | |
| box-shadow: none !important; | |
| } | |
| /* === Styled comparison table === */ | |
| .gr-dataframe table { | |
| border-collapse: collapse !important; | |
| width: 100% !important; | |
| color: #c9d1d9 !important; | |
| background-color: #161b22 !important; | |
| } | |
| .gr-dataframe th { | |
| background-color: #21262d !important; | |
| color: #f0f6fc !important; | |
| font-weight: 600 !important; | |
| text-transform: uppercase; | |
| border-bottom: 1px solid #30363d !important; | |
| } | |
| .gr-dataframe td { | |
| border-top: 1px solid #30363d !important; | |
| padding: 8px !important; | |
| } | |
| """) as demo: | |
| gr.Markdown("## Investment Portfolio Analyzer") | |
| gr.Markdown( | |
| "A professional dashboard for analyzing and comparing investment portfolios using AI insights.", | |
| elem_classes="subtitle", | |
| ) | |
| with gr.Tabs(): | |
| # --- Analysis Tab --- | |
| with gr.TabItem("Analysis"): | |
| portfolio_input = gr.Textbox( | |
| label="Portfolio ID or Link", | |
| placeholder="Enter a portfolio ID (e.g. ea856c1b-...)", | |
| lines=1, | |
| value='b1ef37aa-5b9a-41b4-9394-8823f2de36bb', | |
| ) | |
| analyze_button = gr.Button("Run Analysis", variant="primary") | |
| analyze_output = gr.Textbox(label="Analysis Result", lines=15) | |
| analyze_button.click(fn=analyzer.run, inputs=portfolio_input, outputs=analyze_output) | |
| # --- Comparison Table Tab --- | |
| with gr.TabItem("Comparison Table"): | |
| comp_input_1 = gr.Textbox(label="Portfolio A", value="3852a354-e66e-4bc5-97e9-55124e31e687") | |
| comp_input_2 = gr.Textbox(label="Portfolio B", value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb") | |
| comp_button = gr.Button("Load Comparison", variant="primary") | |
| # комментарий теперь над таблицей | |
| comp_output_comment = gr.Textbox( | |
| label="AI Commentary", | |
| lines=8, | |
| interactive=False, | |
| show_copy_button=True, | |
| elem_id="llm_comment_box", | |
| ) | |
| comp_output_table = gr.Dataframe( | |
| label="Comparative Metrics", | |
| wrap=True, | |
| elem_id="comparison_table", | |
| ) | |
| from core.comparison_table import show_comparison_table | |
| comp_button.click( | |
| fn=show_comparison_table, | |
| inputs=[comp_input_1, comp_input_2], | |
| outputs=[comp_output_table, comp_output_comment], | |
| ) | |
| # --- Chat Assistant Tab --- | |
| with gr.TabItem("Assistant"): | |
| chat_input = gr.Textbox(label="Ask about investments or analysis") | |
| chat_button = gr.Button("Send Question", variant="primary") | |
| chat_output = gr.Textbox(label="AI Response", lines=8) | |
| chat_button.click(fn=chatbot.run, inputs=chat_input, outputs=chat_output) | |
| # --- Metrics Table Tab --- | |
| with gr.TabItem("Metrics Table"): | |
| metrics_input = gr.Textbox(label="Portfolio ID", value='b1ef37aa-5b9a-41b4-9394-8823f2de36bb') | |
| metrics_button = gr.Button("Load Metrics", variant="primary") | |
| metrics_output = gr.Dataframe(label="Portfolio Metrics", wrap=True) | |
| metrics_button.click(fn=show_metrics_table, inputs=metrics_input, outputs=metrics_output) | |
| # --- AlphaBTC Chart Tab (fixed overlay) --- | |
| with gr.TabItem("AlphaBTC Chart"): | |
| chart_input = gr.Textbox(label="Portfolio ID", value="3852a354-e66e-4bc5-97e9-55124e31e687") | |
| chart_button = gr.Button("Generate Chart", variant="primary") | |
| chart_output = gr.Plot( | |
| label="Alpha vs BTC", | |
| show_label=False, | |
| elem_id="alpha_chart", | |
| ) | |
| chart_button.click(fn=build_alpha_chart, inputs=chart_input, outputs=chart_output) | |
| gr.Markdown("---") | |
| gr.Markdown( | |
| "<center><small style='color:#6e7681;'>Developed with Featherless.ai • Powered by OpenAI-compatible API</small></center>", | |
| elem_classes="footer", | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |