QAway-to commited on
Commit
f2b5dca
·
1 Parent(s): c1d305f

New tabs and functions v3.0

Browse files
Files changed (5) hide show
  1. app.py +38 -13
  2. core/crypto_dashboard.py +42 -20
  3. core/multi_charts.py +67 -0
  4. core/ui_style.css +51 -19
  5. requirements.txt +2 -0
app.py CHANGED
@@ -63,25 +63,40 @@ with gr.Blocks(css=custom_css) as demo:
63
  metrics_out = gr.Dataframe(label="Portfolio Metrics", wrap=True)
64
  metrics_btn.click(fn=show_metrics_table, inputs=metrics_in, outputs=metrics_out)
65
 
66
- # --- AlphaBTC Chart ---
67
- with gr.TabItem("AlphaBTC Chart"):
68
- chart_in = gr.Textbox(label="Portfolio ID", value="3852a354-e66e-4bc5-97e9-55124e31e687")
69
- chart_btn = gr.Button("Generate Chart", variant="primary")
70
- chart_out = gr.Plot(label="Alpha vs BTC")
71
- chart_btn.click(fn=build_alpha_chart, inputs=chart_in, outputs=chart_out)
72
-
73
- # --- Crypto Intelligence Dashboard (Coinlore, Plotly Edition) ---
 
 
 
 
 
 
 
 
 
 
 
74
  with gr.TabItem("Crypto Intelligence Dashboard"):
75
  gr.Markdown("### 💹 Coinlore Market Dashboard (Plotly Edition)")
76
 
77
- # --- Controls ---
 
 
 
 
78
  with gr.Row():
79
  top_slider = gr.Slider(
80
  label="Top N coins", minimum=20, maximum=100, step=10, value=50, scale=70
81
  )
82
  load_btn = gr.Button("Generate Dashboard", variant="primary", scale=30)
83
 
84
- # --- Layout: Treemap + AI sidebar ---
85
  with gr.Row(equal_height=True):
86
  with gr.Column(scale=70):
87
  treemap_plot = gr.Plot(label="Market Composition")
@@ -90,7 +105,7 @@ with gr.Blocks(css=custom_css) as demo:
90
  label="AI Market Summary", lines=18, elem_id="ai_summary_sidebar"
91
  )
92
 
93
- # --- Layout: Lower charts (Movers + Scatter) ---
94
  with gr.Row(equal_height=True):
95
  movers_plot = gr.Plot(label="Top Movers", scale=50)
96
  scatter_plot = gr.Plot(label="Market Cap vs Volume", scale=50)
@@ -99,13 +114,23 @@ with gr.Blocks(css=custom_css) as demo:
99
 
100
 
101
  def run_dash(n):
102
- return build_crypto_dashboard(n)
 
 
 
 
 
 
 
 
 
 
103
 
104
 
105
  load_btn.click(
106
  fn=run_dash,
107
  inputs=top_slider,
108
- outputs=[treemap_plot, movers_plot, scatter_plot, ai_box],
109
  show_progress="minimal",
110
  )
111
 
 
63
  metrics_out = gr.Dataframe(label="Portfolio Metrics", wrap=True)
64
  metrics_btn.click(fn=show_metrics_table, inputs=metrics_in, outputs=metrics_out)
65
 
66
+ # --- Multi Visualization (ECharts + Highcharts) ---
67
+ with gr.TabItem("Visual Comparison (ECharts / Highcharts)"):
68
+ gr.Markdown("### 🌐 Multi Visualization Demo — ECharts & Highcharts")
69
+
70
+ from core.multi_charts import build_echarts_line, build_highcharts_demo
71
+
72
+ with gr.Row(equal_height=True):
73
+ echarts_html = gr.HTML(label="ECharts BTC/USD")
74
+ highcharts_html = gr.HTML(label="Highcharts ETH/USD")
75
+
76
+
77
+ def render_all():
78
+ return build_echarts_line(), build_highcharts_demo()
79
+
80
+
81
+ render_btn = gr.Button("Generate Charts", variant="primary")
82
+ render_btn.click(fn=render_all, outputs=[echarts_html, highcharts_html])
83
+
84
+ # --- Crypto Intelligence Dashboard (Plotly Edition + KPI) ---
85
  with gr.TabItem("Crypto Intelligence Dashboard"):
86
  gr.Markdown("### 💹 Coinlore Market Dashboard (Plotly Edition)")
87
 
88
+ # KPI row
89
+ with gr.Row():
90
+ kpi_html = gr.HTML(label="", elem_id="kpi_panel")
91
+
92
+ # Controls
93
  with gr.Row():
94
  top_slider = gr.Slider(
95
  label="Top N coins", minimum=20, maximum=100, step=10, value=50, scale=70
96
  )
97
  load_btn = gr.Button("Generate Dashboard", variant="primary", scale=30)
98
 
99
+ # Treemap + AI Summary
100
  with gr.Row(equal_height=True):
101
  with gr.Column(scale=70):
102
  treemap_plot = gr.Plot(label="Market Composition")
 
105
  label="AI Market Summary", lines=18, elem_id="ai_summary_sidebar"
106
  )
107
 
108
+ # Lower charts
109
  with gr.Row(equal_height=True):
110
  movers_plot = gr.Plot(label="Top Movers", scale=50)
111
  scatter_plot = gr.Plot(label="Market Cap vs Volume", scale=50)
 
114
 
115
 
116
  def run_dash(n):
117
+ figs = build_crypto_dashboard(n)
118
+ fig_treemap, fig_bar, fig_bubble, ai_comment, kpis = figs
119
+ kpi_html_str = "".join(
120
+ f"<div class='kpi-card' style='border-left:4px solid {c['color']}'>"
121
+ f"<span class='kpi-symbol'>{c['symbol']}</span>"
122
+ f"<span class='kpi-price'>{c['price']}</span>"
123
+ f"<span class='kpi-change' style='color:{c['color']}'>{c['change']}</span>"
124
+ "</div>"
125
+ for c in kpis
126
+ )
127
+ return fig_treemap, fig_bar, fig_bubble, ai_comment, kpi_html_str
128
 
129
 
130
  load_btn.click(
131
  fn=run_dash,
132
  inputs=top_slider,
133
+ outputs=[treemap_plot, movers_plot, scatter_plot, ai_box, kpi_html],
134
  show_progress="minimal",
135
  )
136
 
core/crypto_dashboard.py CHANGED
@@ -1,25 +1,48 @@
1
  """
2
- Crypto Dashboard — Plotly Edition (Coinlore API)
3
- Power BI–style visualization with dense layout.
 
4
  """
5
  import requests
6
  import pandas as pd
7
  import plotly.express as px
8
- import plotly.graph_objects as go
9
  from services.llm_client import llm_service
10
 
11
 
12
- # === Fetch data from Coinlore ===
13
  def fetch_coinlore_data(limit=100):
14
  url = "https://api.coinlore.net/api/tickers/"
15
  data = requests.get(url).json()["data"]
16
  df = pd.DataFrame(data)
17
- for col in ["price_usd", "market_cap_usd", "volume24",
18
- "percent_change_1h", "percent_change_24h", "percent_change_7d"]:
 
 
19
  df[col] = pd.to_numeric(df[col], errors="coerce")
20
  return df.head(limit)
21
 
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  # === Main Dashboard ===
24
  def build_crypto_dashboard(top_n=50):
25
  df = fetch_coinlore_data(top_n)
@@ -32,16 +55,16 @@ def build_crypto_dashboard(top_n=50):
32
  color="percent_change_24h",
33
  color_continuous_scale="RdYlGn",
34
  title="Market Composition by Market Cap (Top Coins)",
35
- height=400,
36
  )
37
  fig_treemap.update_layout(
38
  template="plotly_dark",
39
- margin=dict(l=0, r=0, t=40, b=0),
40
  paper_bgcolor="rgba(0,0,0,0)",
41
  plot_bgcolor="rgba(0,0,0,0)",
42
  )
43
 
44
- # --- Top Gainers (24h) ---
45
  top = df.sort_values("percent_change_24h", ascending=False).head(12)
46
  fig_bar = px.bar(
47
  top,
@@ -51,16 +74,16 @@ def build_crypto_dashboard(top_n=50):
51
  color="percent_change_24h",
52
  color_continuous_scale="Blues",
53
  title="Top 12 Gainers (24h)",
54
- height=350,
55
  )
56
  fig_bar.update_layout(
57
  template="plotly_dark",
58
- margin=dict(l=80, r=30, t=40, b=40),
59
  paper_bgcolor="rgba(0,0,0,0)",
60
  plot_bgcolor="rgba(0,0,0,0)",
61
  )
62
 
63
- # --- Market Cap vs Volume (Bubble) ---
64
  fig_bubble = px.scatter(
65
  df.head(60),
66
  x="market_cap_usd",
@@ -72,32 +95,31 @@ def build_crypto_dashboard(top_n=50):
72
  log_y=True,
73
  color_continuous_scale="RdYlGn",
74
  title="Market Cap vs 24h Volume",
75
- height=350,
76
  )
77
  fig_bubble.update_layout(
78
  template="plotly_dark",
79
- margin=dict(l=60, r=30, t=40, b=40),
80
  paper_bgcolor="rgba(0,0,0,0)",
81
  plot_bgcolor="rgba(0,0,0,0)",
82
  )
83
 
84
- # --- AI Summary ---
85
  summary = _generate_ai_summary(df)
86
-
87
- return fig_treemap, fig_bar, fig_bubble, summary
88
 
89
 
90
  def _generate_ai_summary(df):
91
  leaders = df.sort_values("percent_change_24h", ascending=False).head(3)["symbol"].tolist()
92
  laggards = df.sort_values("percent_change_24h").head(3)["symbol"].tolist()
93
-
94
  prompt = f"""
95
  Summarize today's crypto market based on Coinlore data.
96
  Top gainers: {', '.join(leaders)}.
97
  Top losers: {', '.join(laggards)}.
98
  Include:
99
- - overall market sentiment
100
- - volatility and liquidity notes
101
  - short-term outlook
102
  """
103
  summary = ""
 
1
  """
2
+ Crypto Dashboard — Plotly Edition + KPI Cards
3
+ Source: Coinlore API
4
+ Visual: Dense Power BI–style dashboard with live metrics.
5
  """
6
  import requests
7
  import pandas as pd
8
  import plotly.express as px
 
9
  from services.llm_client import llm_service
10
 
11
 
12
+ # === Load data ===
13
  def fetch_coinlore_data(limit=100):
14
  url = "https://api.coinlore.net/api/tickers/"
15
  data = requests.get(url).json()["data"]
16
  df = pd.DataFrame(data)
17
+ for col in [
18
+ "price_usd", "market_cap_usd", "volume24",
19
+ "percent_change_1h", "percent_change_24h", "percent_change_7d"
20
+ ]:
21
  df[col] = pd.to_numeric(df[col], errors="coerce")
22
  return df.head(limit)
23
 
24
 
25
+ # === KPI builder ===
26
+ def build_kpi_cards(df):
27
+ tracked = ["BTC", "ETH", "SOL", "DOGE"]
28
+ cards = []
29
+ for sym in tracked:
30
+ coin = df[df["symbol"] == sym]
31
+ if coin.empty:
32
+ continue
33
+ price = float(coin["price_usd"])
34
+ change = float(coin["percent_change_24h"])
35
+ arrow = "▲" if change > 0 else "▼"
36
+ color = "#4ade80" if change > 0 else "#f87171"
37
+ cards.append({
38
+ "symbol": sym,
39
+ "price": f"${price:,.0f}",
40
+ "change": f"{arrow} {abs(change):.2f}%",
41
+ "color": color,
42
+ })
43
+ return cards
44
+
45
+
46
  # === Main Dashboard ===
47
  def build_crypto_dashboard(top_n=50):
48
  df = fetch_coinlore_data(top_n)
 
55
  color="percent_change_24h",
56
  color_continuous_scale="RdYlGn",
57
  title="Market Composition by Market Cap (Top Coins)",
58
+ height=360,
59
  )
60
  fig_treemap.update_layout(
61
  template="plotly_dark",
62
+ margin=dict(l=10, r=10, t=25, b=10),
63
  paper_bgcolor="rgba(0,0,0,0)",
64
  plot_bgcolor="rgba(0,0,0,0)",
65
  )
66
 
67
+ # --- Top Gainers ---
68
  top = df.sort_values("percent_change_24h", ascending=False).head(12)
69
  fig_bar = px.bar(
70
  top,
 
74
  color="percent_change_24h",
75
  color_continuous_scale="Blues",
76
  title="Top 12 Gainers (24h)",
77
+ height=320,
78
  )
79
  fig_bar.update_layout(
80
  template="plotly_dark",
81
+ margin=dict(l=60, r=20, t=25, b=25),
82
  paper_bgcolor="rgba(0,0,0,0)",
83
  plot_bgcolor="rgba(0,0,0,0)",
84
  )
85
 
86
+ # --- Market Cap vs Volume ---
87
  fig_bubble = px.scatter(
88
  df.head(60),
89
  x="market_cap_usd",
 
95
  log_y=True,
96
  color_continuous_scale="RdYlGn",
97
  title="Market Cap vs 24h Volume",
98
+ height=320,
99
  )
100
  fig_bubble.update_layout(
101
  template="plotly_dark",
102
+ margin=dict(l=50, r=20, t=25, b=25),
103
  paper_bgcolor="rgba(0,0,0,0)",
104
  plot_bgcolor="rgba(0,0,0,0)",
105
  )
106
 
107
+ # --- AI summary ---
108
  summary = _generate_ai_summary(df)
109
+ kpis = build_kpi_cards(df)
110
+ return fig_treemap, fig_bar, fig_bubble, summary, kpis
111
 
112
 
113
  def _generate_ai_summary(df):
114
  leaders = df.sort_values("percent_change_24h", ascending=False).head(3)["symbol"].tolist()
115
  laggards = df.sort_values("percent_change_24h").head(3)["symbol"].tolist()
 
116
  prompt = f"""
117
  Summarize today's crypto market based on Coinlore data.
118
  Top gainers: {', '.join(leaders)}.
119
  Top losers: {', '.join(laggards)}.
120
  Include:
121
+ - overall sentiment
122
+ - volatility and liquidity
123
  - short-term outlook
124
  """
125
  summary = ""
core/multi_charts.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Multi Visualization Demo
3
+ Includes:
4
+ - ECharts (pyecharts)
5
+ - Highcharts (HTML embed)
6
+ """
7
+ from pyecharts.charts import Line
8
+ from pyecharts import options as opts
9
+ import pandas as pd, numpy as np, datetime, json
10
+
11
+
12
+ def build_echarts_line():
13
+ """ECharts Line (BTC simulated data)"""
14
+ now = datetime.datetime.now()
15
+ dates = [now - datetime.timedelta(days=i) for i in range(90)][::-1]
16
+ prices = np.cumsum(np.random.randn(90)) + 42000
17
+
18
+ line = (
19
+ Line(init_opts=opts.InitOpts(bg_color="#0d1117", height="360px"))
20
+ .add_xaxis([d.strftime("%d %b") for d in dates])
21
+ .add_yaxis(
22
+ "BTC/USD",
23
+ prices.tolist(),
24
+ is_smooth=True,
25
+ linestyle_opts=opts.LineStyleOpts(width=2, color="#4f46e5"),
26
+ label_opts=opts.LabelOpts(is_show=False),
27
+ areastyle_opts=opts.AreaStyleOpts(opacity=0.15, color="#6366f1"),
28
+ )
29
+ .set_global_opts(
30
+ title_opts=opts.TitleOpts(
31
+ title="ECharts: BTC/USD (Simulated)",
32
+ title_textstyle_opts=opts.TextStyleOpts(color="#f0f6fc")
33
+ ),
34
+ xaxis_opts=opts.AxisOpts(axisline_opts=opts.AxisLineOpts(line_style=opts.LineStyleOpts(color="#30363d"))),
35
+ yaxis_opts=opts.AxisOpts(axisline_opts=opts.AxisLineOpts(line_style=opts.LineStyleOpts(color="#30363d"))),
36
+ tooltip_opts=opts.TooltipOpts(trigger="axis"),
37
+ )
38
+ )
39
+ return line.render_embed()
40
+
41
+
42
+ def build_highcharts_demo():
43
+ """Highcharts HTML embed (ETH simulated data)"""
44
+ days = list(range(1, 91))
45
+ prices = (np.cumsum(np.random.randn(90)) * 15 + 2300).tolist()
46
+
47
+ js = f"""
48
+ <script src="https://code.highcharts.com/highcharts.js"></script>
49
+ <div id="highchart_eth" style="height:360px;"></div>
50
+ <script>
51
+ Highcharts.chart('highchart_eth', {{
52
+ chart: {{ backgroundColor: '#0d1117', style: {{ fontFamily: 'Inter' }} }},
53
+ title: {{ text: 'Highcharts: ETH/USD (Simulated)', style: {{ color: '#f0f6fc' }} }},
54
+ xAxis: {{ categories: {json.dumps(days)}, labels: {{ style: {{ color: '#9da5b4' }} }} }},
55
+ yAxis: {{ title: {{ text: 'Price (USD)', style: {{ color: '#9da5b4' }} }} }},
56
+ series: [{{
57
+ name: 'ETH/USD',
58
+ data: {json.dumps(prices)},
59
+ color: '#10b981',
60
+ }}],
61
+ legend: {{ itemStyle: {{ color: '#f0f6fc' }} }},
62
+ credits: {{ enabled: false }},
63
+ tooltip: {{ backgroundColor: '#161b22', borderColor: '#30363d', style: {{ color: '#f0f6fc' }} }}
64
+ }});
65
+ </script>
66
+ """
67
+ return js
core/ui_style.css CHANGED
@@ -14,6 +14,46 @@ h2, h3, .gr-markdown {
14
  font-weight: 600 !important;
15
  }
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  /* === Remove Gray Placeholder Icons === */
18
  [data-testid="plot-container"] svg {
19
  display: none !important;
@@ -23,28 +63,24 @@ h2, h3, .gr-markdown {
23
  box-shadow: none !important;
24
  }
25
 
26
- /* === Plot Size & Layout === */
27
  [data-testid="plot-container"] {
28
  width: 100% !important;
29
- margin: 0 auto 22px auto !important;
30
  }
31
  [data-testid="plot-container"] canvas {
32
  width: 100% !important;
33
  height: auto !important;
34
  }
35
 
36
- /* --- Chart height tuning --- */
37
- #root [label="Market Composition"] canvas {
38
- height: 400px !important;
39
- }
40
  #root [label="Top Movers"] canvas,
41
- #root [label="Market Cap vs Volume"] canvas {
42
- height: 350px !important;
43
- }
44
 
45
- /* === Sidebar (AI Summary) === */
46
  #ai_summary_sidebar textarea {
47
- height: 400px !important;
48
  background-color: #161b22 !important;
49
  color: #f0f6fc !important;
50
  border: 1px solid #30363d !important;
@@ -56,7 +92,7 @@ h2, h3, .gr-markdown {
56
  resize: none !important;
57
  }
58
 
59
- /* === Buttons & Sliders === */
60
  .gr-button {
61
  border-radius: 6px !important;
62
  font-weight: 600 !important;
@@ -64,7 +100,7 @@ h2, h3, .gr-markdown {
64
  height: 52px !important;
65
  background: linear-gradient(90deg, #4f46e5, #6366f1) !important;
66
  border: none !important;
67
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
68
  transition: all 0.2s ease-in-out;
69
  }
70
  .gr-button:hover {
@@ -78,7 +114,7 @@ h2, h3, .gr-markdown {
78
  background: #6366f1 !important;
79
  }
80
 
81
- /* === Tables & spacing === */
82
  .gr-dataframe table {
83
  width: 100% !important;
84
  color: #c9d1d9 !important;
@@ -95,8 +131,4 @@ h2, h3, .gr-markdown {
95
  border-top: 1px solid #30363d !important;
96
  padding: 8px !important;
97
  }
98
-
99
- /* === Dashboard Layout === */
100
- .gr-row {
101
- gap: 18px !important;
102
- }
 
14
  font-weight: 600 !important;
15
  }
16
 
17
+ /* === KPI Panel === */
18
+ #kpi_panel {
19
+ display: flex;
20
+ justify-content: space-between;
21
+ align-items: center;
22
+ margin: 12px 0 4px 0;
23
+ }
24
+ .kpi-card {
25
+ background-color: #161b22;
26
+ border-radius: 6px;
27
+ padding: 10px 14px;
28
+ width: 24%;
29
+ box-shadow: 0 1px 3px rgba(0,0,0,0.3);
30
+ display: flex;
31
+ flex-direction: column;
32
+ }
33
+ .kpi-symbol {
34
+ font-weight: 700;
35
+ font-size: 15px;
36
+ color: #f0f6fc;
37
+ }
38
+ .kpi-price {
39
+ font-size: 20px;
40
+ font-weight: 600;
41
+ color: #f9fafb;
42
+ }
43
+ .kpi-change {
44
+ font-size: 13px;
45
+ margin-top: 2px;
46
+ }
47
+
48
+ /* === Chart Embed (ECharts + Highcharts) === */
49
+ [data-testid="html"] {
50
+ width: 100% !important;
51
+ background: #0d1117 !important;
52
+ border: 1px solid #30363d !important;
53
+ border-radius: 6px !important;
54
+ overflow: hidden !important;
55
+ }
56
+
57
  /* === Remove Gray Placeholder Icons === */
58
  [data-testid="plot-container"] svg {
59
  display: none !important;
 
63
  box-shadow: none !important;
64
  }
65
 
66
+ /* === Plot Layout === */
67
  [data-testid="plot-container"] {
68
  width: 100% !important;
69
+ margin: 0 auto 16px auto !important;
70
  }
71
  [data-testid="plot-container"] canvas {
72
  width: 100% !important;
73
  height: auto !important;
74
  }
75
 
76
+ /* === Chart Heights === */
77
+ #root [label="Market Composition"] canvas { height: 360px !important; }
 
 
78
  #root [label="Top Movers"] canvas,
79
+ #root [label="Market Cap vs Volume"] canvas { height: 320px !important; }
 
 
80
 
81
+ /* === Sidebar === */
82
  #ai_summary_sidebar textarea {
83
+ height: 360px !important;
84
  background-color: #161b22 !important;
85
  color: #f0f6fc !important;
86
  border: 1px solid #30363d !important;
 
92
  resize: none !important;
93
  }
94
 
95
+ /* === Controls === */
96
  .gr-button {
97
  border-radius: 6px !important;
98
  font-weight: 600 !important;
 
100
  height: 52px !important;
101
  background: linear-gradient(90deg, #4f46e5, #6366f1) !important;
102
  border: none !important;
103
+ box-shadow: 0 2px 4px rgba(0,0,0,0.25);
104
  transition: all 0.2s ease-in-out;
105
  }
106
  .gr-button:hover {
 
114
  background: #6366f1 !important;
115
  }
116
 
117
+ /* === Table / Row spacing === */
118
  .gr-dataframe table {
119
  width: 100% !important;
120
  color: #c9d1d9 !important;
 
131
  border-top: 1px solid #30363d !important;
132
  padding: 8px !important;
133
  }
134
+ .gr-row { gap: 16px !important; }
 
 
 
 
requirements.txt CHANGED
@@ -8,3 +8,5 @@ plotly
8
  yfinance>=0.2.43
9
  plotly>=6.3.1
10
  altair
 
 
 
8
  yfinance>=0.2.43
9
  plotly>=6.3.1
10
  altair
11
+ pyecharts
12
+ jinja2