Spaces:
Running
Running
File size: 9,711 Bytes
ab0a6c9 5d3d9da f6d1946 a6ab183 6388752 b9435d1 5d3d9da ed8fc2e 84de7fa 985f897 b2d5b74 8370475 b9435d1 6388752 5d3d9da b9435d1 eadb379 5d3d9da a312a60 9a4ad78 f6d1946 a312a60 5d3d9da a312a60 b9435d1 eadb379 5d3d9da a312a60 5d3d9da eadb379 b9435d1 5d3d9da eadb379 b9435d1 5d3d9da b9435d1 5d3d9da a41be0f b9435d1 a41be0f 5d3d9da a41be0f 5d3d9da 978bdd6 e55ebde 5d3d9da e55ebde 343fdcb a41be0f 343fdcb a41be0f 343fdcb a41be0f 343fdcb a41be0f 343fdcb a41be0f 08efbfa f6d1946 343fdcb a41be0f 3d06875 8caee6c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
import gradio as gr
from application.metrics_table import show_metrics_table
from application.portfolio_analyzer import PortfolioAnalyzer
from application.portfolio_comparer import PortfolioComparer
from infrastructure.llm_client import llm_service
from core.news_digest import fetch_crypto_news, summarize_news
from presentation.components.crypto_dashboard import (
build_crypto_dashboard,
) # Plotly dashboard + KPI-line
from presentation.components.comparison_table import show_comparison_table
from presentation.components.visual_comparison import (
build_comparison_chart,
build_volatility_chart,
preload_pairs,
) # Interactive pair comparison
# === CSS loader ===
def load_css(path: str) -> str:
with open(path, "r", encoding="utf-8") as f:
return f.read()
# === Styles ===
base_css = load_css("presentation/styles/themes/base.css")
crypto_css = load_css("presentation/styles/themes/crypto_dashboard.css")
# === Model setup ===
MODEL_NAME = "meta-llama/Meta-Llama-3.1-8B-Instruct"
analyzer = PortfolioAnalyzer(llm_service, MODEL_NAME)
comparer = PortfolioComparer(llm_service, MODEL_NAME)
# === Main Interface ===
with gr.Blocks(css=base_css) as demo:
gr.Markdown("## Investment Portfolio Analyzer", elem_classes="page-title")
gr.Markdown(
"Professional AI-driven analytics for investment and crypto markets.",
elem_classes="subtitle",
)
with gr.Tabs(elem_id="main_tabs"):
# --- Analysis ---
with gr.TabItem("Portfolio Insights"):
portfolio_input = gr.Textbox(
label="Portfolio ID or Link",
placeholder="Enter portfolio ID (uuid)",
value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb",
)
analyze_btn = gr.Button("Run Analysis", variant="primary")
analyze_out = gr.HTML(value="", elem_id="analysis_output")
analyze_btn.click(
fn=analyzer.run,
inputs=portfolio_input,
outputs=analyze_out,
show_progress="minimal",
)
# --- Comparison Table ---
with gr.TabItem("Comparison Table"):
with gr.Row():
pid_a = gr.Textbox(
label="Portfolio A",
value="3852a354-e66e-4bc5-97e9-55124e31e687",
scale=1,
)
pid_b = gr.Textbox(
label="Portfolio B",
value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb",
scale=1,
)
compare_btn = gr.Button("Load Comparison", variant="primary")
comp_table = gr.Dataframe(
label="Comparative Metrics",
wrap=True,
elem_id="comparison_table",
)
comp_comment = gr.HTML(elem_id="llm_comment_box")
compare_btn.click(
fn=show_comparison_table,
inputs=[pid_a, pid_b],
outputs=[comp_table, comp_comment],
show_progress="minimal",
)
# --- Metrics Table ---
# with gr.TabItem("Metrics Table"):
# metrics_in = gr.Textbox(
# label="Portfolio ID",
# value="b1ef37aa-5b9a-41b4-9394-8823f2de36bb",
# )
# metrics_btn = gr.Button("Load Metrics", variant="primary")
# metrics_out = gr.Dataframe(label="Portfolio Metrics", wrap=True)
# metrics_btn.click(fn=show_metrics_table, inputs=metrics_in, outputs=metrics_out)
# --- Assistant (temporarily disabled; duplicate removed) ---
# with gr.TabItem("Assistant"):
# chat_in = gr.Textbox(label="Ask about investments or analysis")
# chat_btn = gr.Button("Send Question", variant="primary")
# chat_out = gr.Textbox(label="AI Response", lines=8, interactive=False)
# chat_btn.click(
# fn=chatbot.run,
# inputs=chat_in,
# outputs=chat_out,
# show_progress="minimal",
# )
# --- Crypto News Digest ---
with gr.TabItem("Crypto News Digest"):
gr.Markdown("### ποΈ Latest Crypto News (via NewsData.io)")
headlines_box = gr.Markdown("Fetching latest headlines...", elem_id="news_headlines")
ai_summary_box = gr.Textbox(
label="AI Market Summary",
lines=10,
interactive=False,
)
refresh_btn = gr.Button("π Refresh News", variant="primary")
def run_news():
headlines, ok = fetch_crypto_news()
if not ok:
return headlines, "β οΈ Summary will appear once fresh headlines are available."
summary = summarize_news(headlines)
return headlines, summary
refresh_btn.click(
fn=run_news,
inputs=None,
outputs=[headlines_box, ai_summary_box],
show_progress="minimal",
)
demo.load(
fn=run_news,
inputs=None,
outputs=[headlines_box, ai_summary_box],
)
# --- Visual Comparison (Interactive Plotly Edition) ---
with gr.TabItem("Visual Comparison"):
gr.Markdown("### π Market Pair Comparison β Interactive Plotly Edition")
available_pairs = [
("bitcoin", "ethereum"),
("ethereum", "bnb"),
("solana", "avalanche-2"),
("litecoin", "bitcoin-cash"),
("dogecoin", "shiba-inu"),
]
def _format_pair(pair: tuple[str, str]) -> str:
def _label(asset: str) -> str:
return asset.replace("-", " ").title()
a, b = pair
return f"{_label(a)} vs {_label(b)}"
pair_map = {_format_pair(pair): pair for pair in available_pairs}
default_label = _format_pair(available_pairs[0])
with gr.Row():
pair_selector = gr.Dropdown(
label="Select Pair for Comparison",
choices=list(pair_map.keys()),
value=default_label,
interactive=True,
scale=3,
)
normalize_toggle = gr.Checkbox(
label="Normalized Mode (%)",
value=False,
interactive=True,
scale=1,
)
price_plot = gr.Plot(label="Price Comparison")
vol_plot = gr.Plot(label="Volatility Comparison")
def update_visuals(selected_pair: str, normalized: bool):
pair = pair_map.get(selected_pair, available_pairs[0])
return (
build_comparison_chart(pair, normalized=normalized),
build_volatility_chart(pair),
)
pair_selector.change(
fn=update_visuals,
inputs=[pair_selector, normalize_toggle],
outputs=[price_plot, vol_plot],
)
normalize_toggle.change(
fn=update_visuals,
inputs=[pair_selector, normalize_toggle],
outputs=[price_plot, vol_plot],
)
def init_visuals():
preload_pairs(available_pairs)
return update_visuals(default_label, False)
demo.load(fn=init_visuals, inputs=None, outputs=[price_plot, vol_plot])
# --- Crypto Intelligence Dashboard (Plotly Edition + KPI line, auto-load) ---
with gr.TabItem("Crypto Intelligence Dashboard"):
gr.HTML(f"<style>{crypto_css}</style>")
with gr.Row(elem_id="kpi_row"):
kpi_line = gr.HTML(elem_id="kpi_line")
with gr.Row(elem_id="controls_row"):
top_slider = gr.Slider(
label="Top N coins",
minimum=20, maximum=100, step=10, value=50, scale=100,
)
with gr.Row(equal_height=True, elem_id="main_charts_row"):
with gr.Column(scale=70):
treemap_plot = gr.Plot(label="Market Composition")
with gr.Column(scale=30):
ai_box = gr.Textbox(label="AI Market Summary", lines=18, elem_id="ai_summary_sidebar")
with gr.Row(equal_height=True, elem_id="bottom_charts_row"):
movers_plot = gr.Plot(label="Top Movers", scale=50)
scatter_plot = gr.Plot(label="Market Cap vs Volume", scale=50)
def run_dash(n):
fig_treemap, fig_bar, fig_bubble, ai_comment, kpi_text = build_crypto_dashboard(n)
return fig_treemap, fig_bar, fig_bubble, ai_comment, f"<div class='kpi-line'>{kpi_text}</div>"
top_slider.change(
fn=run_dash,
inputs=top_slider,
outputs=[treemap_plot, movers_plot, scatter_plot, ai_box, kpi_line],
show_progress="minimal",
)
def init_crypto():
return run_dash(50)
demo.load(
fn=init_crypto,
inputs=None,
outputs=[treemap_plot, movers_plot, scatter_plot, ai_box, kpi_line],
)
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()
|