FIN_ASSISTANT / app.py
QAway-to
New style APP (Tab Changes v2.1)
01a0a48
raw
history blame
6.95 kB
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()