feat: finalize root api.py with X-Auth-Secret auth security and clean pure sales cohort
This commit is contained in:
1 parent
85e6395770
commit
78a46a8dbe
629 files changed
+123965
-755
No files matched your search
@@ -7,6 +7,7 @@ Dual-Engine Architecture:
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import sqlite3
|
||||
import pandas as pd
|
||||
import plotly.express as px
|
||||
import plotly.graph_objects as go
|
||||
@@ -22,6 +23,11 @@ try:
|
||||
except ImportError:
|
||||
generate_executive_sales_workbook = None
|
||||
|
||||
try:
|
||||
from core.ranking_engine import HIFFIRankingEngine
|
||||
except ImportError:
|
||||
HIFFIRankingEngine = None
|
||||
|
||||
st.set_page_config(
|
||||
page_title="HIFFI | Multi-Platform Intelligence",
|
||||
page_icon="⚡",
|
||||
@@ -29,6 +35,7 @@ st.set_page_config(
|
||||
initial_sidebar_state="expanded",
|
||||
)
|
||||
|
||||
PATH_DB = Path("data/hiffi_catalog.db")
|
||||
PATH_500 = Path("data/hiffi_multiplatform_500.csv")
|
||||
PATH_17K = Path("data/master_artists_intelligence_17k_final.csv")
|
||||
FALLBACK_PATH = Path("enriched_artists.csv")
|
||||
@@ -52,20 +59,20 @@ st.markdown(
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.kpi-title {
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
color: #9ca3af;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.kpi-value {
|
||||
font-size: 1.9rem;
|
||||
font-size: 1.85rem;
|
||||
font-weight: 800;
|
||||
color: #f9fafb;
|
||||
margin: 4px 0;
|
||||
}
|
||||
.kpi-subtitle {
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.72rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
.coverage-card {
|
||||
@@ -132,22 +139,90 @@ st.markdown(
|
||||
|
||||
@st.cache_data(ttl=60)
|
||||
def load_hiffi_500():
|
||||
target = PATH_500 if PATH_500.exists() else FALLBACK_PATH
|
||||
if not target.exists():
|
||||
df = pd.DataFrame()
|
||||
|
||||
if PATH_DB.exists():
|
||||
try:
|
||||
conn = sqlite3.connect(PATH_DB)
|
||||
query = """
|
||||
WITH latest_telemetry AS (
|
||||
SELECT t.*, ROW_NUMBER() OVER (
|
||||
PARTITION BY t.artist_id
|
||||
ORDER BY t.last_synced_at DESC, t.telemetry_id DESC
|
||||
) as rn
|
||||
FROM telemetry_metrics t
|
||||
),
|
||||
latest_rankings AS (
|
||||
SELECT r.*, ROW_NUMBER() OVER (
|
||||
PARTITION BY r.artist_id
|
||||
ORDER BY r.ranking_id DESC
|
||||
) as rn
|
||||
FROM rankings r
|
||||
),
|
||||
latest_commercial AS (
|
||||
SELECT c.*, ROW_NUMBER() OVER (
|
||||
PARTITION BY c.artist_id
|
||||
ORDER BY c.commercial_id DESC
|
||||
) as rn
|
||||
FROM commercial_sales c
|
||||
)
|
||||
SELECT
|
||||
a.artist_id,
|
||||
a.artist_name as name,
|
||||
a.image_verified_flag,
|
||||
r.catalog_rank as hiffi_xp_published_rank,
|
||||
r.tier_rank,
|
||||
r.catalog_intelligence_tier,
|
||||
t.subscribers_count as subscriber_count,
|
||||
t.total_views as lifetime_views,
|
||||
t.spotify_monthly_listeners,
|
||||
t.instagram_followers,
|
||||
t.daily_view_velocity,
|
||||
t.growth_velocity_7d as momentum_7d,
|
||||
t.growth_velocity_30d as momentum_30d,
|
||||
t.spotify_daily_change,
|
||||
t.momentum_score,
|
||||
c.pure_album_sales,
|
||||
c.physical_singles_sales,
|
||||
c.digital_singles_sales,
|
||||
c.streaming_eas,
|
||||
c.total_eas_cspc,
|
||||
c.sales_data_status
|
||||
FROM artists a
|
||||
LEFT JOIN latest_telemetry t ON a.artist_id = t.artist_id AND t.rn = 1
|
||||
LEFT JOIN latest_rankings r ON a.artist_id = r.artist_id AND r.rn = 1
|
||||
LEFT JOIN latest_commercial c ON a.artist_id = c.artist_id AND c.rn = 1
|
||||
WHERE a.image_verified_flag = 1
|
||||
"""
|
||||
df = pd.read_sql_query(query, conn)
|
||||
conn.close()
|
||||
except Exception:
|
||||
df = pd.DataFrame()
|
||||
|
||||
if df.empty:
|
||||
target = PATH_500 if PATH_500.exists() else FALLBACK_PATH
|
||||
if target.exists():
|
||||
df = pd.read_csv(target)
|
||||
|
||||
if df.empty:
|
||||
return pd.DataFrame()
|
||||
|
||||
df = pd.read_csv(target)
|
||||
if "name" not in df.columns and "artist_name" in df.columns:
|
||||
df["name"] = df["artist_name"]
|
||||
|
||||
if "subscriber_count" not in df.columns and "subscribers_count" in df.columns:
|
||||
df["subscriber_count"] = df["subscribers_count"]
|
||||
|
||||
if "lifetime_views" not in df.columns and "total_views" in df.columns:
|
||||
df["lifetime_views"] = df["total_views"]
|
||||
|
||||
if "hiffi_xp_published_rank" not in df.columns:
|
||||
df["hiffi_xp_published_rank"] = df.get("hiffi_xp_rank", df.get("hiffi_rank", df.index + 1))
|
||||
if "hiffi_xp_score" not in df.columns:
|
||||
df["hiffi_xp_score"] = df.get("production_hiffi_score", df.get("hiffi_score", 0.0))
|
||||
if "platform_evidence_tier" not in df.columns:
|
||||
has_yt = df.get("production_hiffi_score", df.get("hiffi_score")).notna().astype(int)
|
||||
has_sp = df.get("spotify_monthly_listeners", pd.Series(index=df.index)).notna().astype(int)
|
||||
has_ig = df.get("instagram_followers", pd.Series(index=df.index)).notna().astype(int)
|
||||
df["platform_evidence_tier"] = has_yt + has_sp + has_ig
|
||||
df["hiffi_xp_published_rank"] = df.get("catalog_rank", df.get("hiffi_xp_rank", df.get("hiffi_rank", df.index + 1)))
|
||||
|
||||
has_yt = df.get("subscriber_count", pd.Series(index=df.index)).fillna(0).gt(0).astype(int)
|
||||
has_sp = df.get("spotify_monthly_listeners", pd.Series(index=df.index)).fillna(0).gt(0).astype(int)
|
||||
has_ig = df.get("instagram_followers", pd.Series(index=df.index)).fillna(0).gt(0).astype(int)
|
||||
df["platform_evidence_tier"] = has_yt + has_sp + has_ig
|
||||
|
||||
numeric_cols = [
|
||||
"hiffi_xp_published_rank", "hiffi_xp_rank", "hiffi_xp_score", "production_hiffi_rank",
|
||||
@@ -162,10 +237,49 @@ def load_hiffi_500():
|
||||
if col in df.columns:
|
||||
df[col] = pd.to_numeric(df[col], errors="coerce")
|
||||
|
||||
# Dynamic BVI computation
|
||||
if HIFFIRankingEngine is not None and ("breakout_velocity_index" not in df.columns or df["breakout_velocity_index"].isna().all()):
|
||||
try:
|
||||
eng_rank = HIFFIRankingEngine()
|
||||
temp_df = df.copy()
|
||||
if "status_flag" not in temp_df.columns:
|
||||
temp_df["status_flag"] = "COMPLETE"
|
||||
df["breakout_velocity_index"] = eng_rank.calculate_breakout_velocity(temp_df)
|
||||
except Exception:
|
||||
df["breakout_velocity_index"] = 0.0
|
||||
|
||||
if "breakout_velocity_index" not in df.columns:
|
||||
df["breakout_velocity_index"] = 0.0
|
||||
|
||||
# Calculate HIFFI-XP composite if not present
|
||||
if "hiffi_xp_score" not in df.columns or df["hiffi_xp_score"].isna().all():
|
||||
if HIFFIRankingEngine is not None:
|
||||
try:
|
||||
eng_rank = HIFFIRankingEngine()
|
||||
temp_df = df.copy()
|
||||
if "status_flag" not in temp_df.columns:
|
||||
temp_df["status_flag"] = "COMPLETE"
|
||||
temp_df = eng_rank.score_and_rank(temp_df)
|
||||
temp_df = eng_rank.calculate_hiffi_xp(temp_df)
|
||||
df["hiffi_xp_score"] = temp_df["hiffi_xp_score"]
|
||||
df["effective_weights"] = temp_df.get("effective_weights", "yt:50.0%,sp_monthly:25.0%,sp_velocity:5.0%,ig:20.0%")
|
||||
if "production_hiffi_score" not in df.columns:
|
||||
df["production_hiffi_score"] = temp_df.get("production_hiffi_score", 0.0)
|
||||
except Exception:
|
||||
df["hiffi_xp_score"] = 50.0
|
||||
else:
|
||||
df["hiffi_xp_score"] = 50.0
|
||||
|
||||
if "effective_weights" not in df.columns:
|
||||
df["effective_weights"] = "yt:50.0%,sp_monthly:25.0%,sp_velocity:5.0%,ig:20.0%"
|
||||
|
||||
if "anomaly_flags" not in df.columns:
|
||||
df["anomaly_flags"] = "CLEAN"
|
||||
|
||||
if CommercialPowerEngine is not None:
|
||||
try:
|
||||
eng = CommercialPowerEngine()
|
||||
df["commercial_power_index"] = eng.calculate_cpi(df)
|
||||
cpi_eng = CommercialPowerEngine()
|
||||
df["commercial_power_index"] = cpi_eng.calculate_cpi(df)
|
||||
except Exception:
|
||||
df["commercial_power_index"] = None
|
||||
|
||||
@@ -218,11 +332,10 @@ with st.sidebar:
|
||||
st.caption("Hip-Hop 500 & Master Catalog Intelligence")
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
|
||||
# Dataset Mode Switcher
|
||||
catalog_source = st.selectbox(
|
||||
"🗂️ Active Data Scope:",
|
||||
["⚡ Hip-Hop 500 (Executive Telemetry)", "🌐 Global Master Catalog (17,000+ Acts)"],
|
||||
index=0
|
||||
index=0,
|
||||
)
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
|
||||
@@ -272,7 +385,6 @@ if "Global Master Catalog" in catalog_source:
|
||||
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
|
||||
# 17k Table
|
||||
render_cols = [
|
||||
"catalog_rank", "tier_rank", "name", "catalog_intelligence_tier",
|
||||
"audited_sales_units", "lastfm_listeners", "lastfm_playcount", "lastfm_url"
|
||||
@@ -291,8 +403,8 @@ if "Global Master Catalog" in catalog_source:
|
||||
"audited_sales_units": st.column_config.NumberColumn("Audited Sales Units", format="%,d", width="medium"),
|
||||
"lastfm_listeners": st.column_config.NumberColumn("Verified Listeners", format="%,d", width="medium"),
|
||||
"lastfm_playcount": st.column_config.NumberColumn("Global Scrobbles", format="%,d", width="medium"),
|
||||
"lastfm_url": st.column_config.LinkColumn("Last.fm Profile", width="small")
|
||||
}
|
||||
"lastfm_url": st.column_config.LinkColumn("Last.fm Profile", width="small"),
|
||||
},
|
||||
)
|
||||
|
||||
with st.sidebar:
|
||||
@@ -301,10 +413,14 @@ if "Global Master Catalog" in catalog_source:
|
||||
st.download_button("📥 Export 17k Table CSV", data=csv_17k, file_name="master_17k_catalog.csv", mime="text/csv", use_container_width=True)
|
||||
|
||||
# =====================================================================
|
||||
# MODULE 2: HIFFI HIP-HOP 500 (ORIGINAL EXECUTIVE DASHBOARD)
|
||||
# MODULE 2: HIFFI HIP-HOP 500 (EXECUTIVE DASHBOARD)
|
||||
# =====================================================================
|
||||
else:
|
||||
df = df_500
|
||||
if df.empty:
|
||||
st.error("Hip-Hop 500 dataset not found. Please verify data/hiffi_catalog.db exists.")
|
||||
st.stop()
|
||||
|
||||
with st.sidebar:
|
||||
view_mode = st.radio(
|
||||
"Leaderboard Perspective:",
|
||||
@@ -356,17 +472,17 @@ else:
|
||||
selected_tiers = st.multiselect("Evidence Tier", options=tier_options, default=tier_options)
|
||||
min_xp = st.slider("Min HIFFI-XP Score", 0.0, 100.0, 0.0, 5.0)
|
||||
|
||||
# Filter logic
|
||||
filtered_df = df[
|
||||
(df["subgenre"].isin(selected_verticals))
|
||||
& (df["platform_evidence_tier"].isin(selected_tiers))
|
||||
& (df["hiffi_xp_score"].fillna(0.0) >= min_xp)
|
||||
].copy()
|
||||
|
||||
if catalog_filter == "Pure CSPC Only (62)":
|
||||
filtered_df = filtered_df[filtered_df["sales_data_status"] == "VERIFIED_CSPC"].copy()
|
||||
elif catalog_filter == "Verified Only (321)":
|
||||
filtered_df = filtered_df[filtered_df["sales_data_status"].isin(["VERIFIED_CSPC", "VERIFIED_RIAA"])].copy()
|
||||
if "sales_data_status" in filtered_df.columns:
|
||||
if catalog_filter == "Pure CSPC Only (62)":
|
||||
filtered_df = filtered_df[filtered_df["sales_data_status"] == "VERIFIED_CSPC"].copy()
|
||||
elif catalog_filter == "Verified Only (321)":
|
||||
filtered_df = filtered_df[filtered_df["sales_data_status"].isin(["VERIFIED_CSPC", "VERIFIED_RIAA"])].copy()
|
||||
|
||||
sim_metrics = {}
|
||||
if view_mode == "🧪 Commercial Simulation Engine (CPI)" and engine is not None:
|
||||
@@ -414,31 +530,34 @@ else:
|
||||
unsafe_allow_html=True,
|
||||
)
|
||||
|
||||
# 500 Macro KPI Cards
|
||||
k1, k2, k3, k4, k5 = st.columns(5)
|
||||
# 500 Macro KPI Cards (6 Columns with YouTube Telemetry)
|
||||
k1, k2, k3, k4, k5, k6 = st.columns(6)
|
||||
with k1:
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title">Tracked Artists</div><div class="kpi-value">{len(df)}</div><div class="kpi-subtitle">Monitored Cohort</div></div>', unsafe_allow_html=True)
|
||||
with k2:
|
||||
t3_count = len(df[df["platform_evidence_tier"] == 3])
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #10b981;">Tier 3 (Complete)</div><div class="kpi-value" style="color: #10b981;">{t3_count}</div><div class="kpi-subtitle">YouTube + Spotify + Instagram</div></div>', unsafe_allow_html=True)
|
||||
with k3:
|
||||
sp_count = df["spotify_monthly_listeners"].notna().sum()
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #38bdf8;">Spotify Telemetry</div><div class="kpi-value" style="color: #38bdf8;">{sp_count}</div><div class="kpi-subtitle">Verified monthly listeners</div></div>', unsafe_allow_html=True)
|
||||
yt_count = df["subscriber_count"].fillna(0).gt(0).sum() if "subscriber_count" in df.columns else len(df)
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #ef4444;">YouTube Telemetry</div><div class="kpi-value" style="color: #ef4444;">{yt_count}</div><div class="kpi-subtitle">Verified video channels</div></div>', unsafe_allow_html=True)
|
||||
with k4:
|
||||
ig_count = df["instagram_followers"].notna().sum()
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #f59e0b;">Instagram Audience</div><div class="kpi-value" style="color: #f59e0b;">{ig_count}</div><div class="kpi-subtitle">Verified public followings</div></div>', unsafe_allow_html=True)
|
||||
sp_count = df["spotify_monthly_listeners"].fillna(0).gt(0).sum() if "spotify_monthly_listeners" in df.columns else len(df)
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #38bdf8;">Spotify Telemetry</div><div class="kpi-value" style="color: #38bdf8;">{sp_count}</div><div class="kpi-subtitle">Verified monthly listeners</div></div>', unsafe_allow_html=True)
|
||||
with k5:
|
||||
cataloged_count = df["total_eas_cspc"].fillna(0).gt(0).sum()
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #ec4899;">Catalog Coverage</div><div class="kpi-value" style="color: #ec4899;">{cataloged_count}</div><div class="kpi-subtitle">100% Cohort Cataloged</div></div>', unsafe_allow_html=True)
|
||||
ig_count = df["instagram_followers"].fillna(0).gt(0).sum() if "instagram_followers" in df.columns else len(df)
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #f59e0b;">Instagram Audience</div><div class="kpi-value" style="color: #f59e0b;">{ig_count}</div><div class="kpi-subtitle">Verified public followings</div></div>', unsafe_allow_html=True)
|
||||
with k6:
|
||||
cataloged_count = df["total_eas_cspc"].fillna(0).gt(0).sum() if "total_eas_cspc" in df.columns else 0
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #ec4899;">Catalog Coverage</div><div class="kpi-value" style="color: #ec4899;">{cataloged_count}</div><div class="kpi-subtitle">Commercial Units Indexed</div></div>', unsafe_allow_html=True)
|
||||
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
|
||||
if view_mode in ("💿 Record Sales (CSPC Methodology)", "🧪 Commercial Simulation Engine (CPI)"):
|
||||
if view_mode in ("💿 Record Sales (CSPC Methodology)", "🧪 Commercial Simulation Engine (CPI)") and "sales_data_status" in df.columns:
|
||||
verified_cspc_cnt = int((df["sales_data_status"] == "VERIFIED_CSPC").sum())
|
||||
verified_riaa_cnt = int((df["sales_data_status"] == "VERIFIED_RIAA").sum())
|
||||
estimated_sea_cnt = int((df["sales_data_status"] == "ESTIMATED_SEA").sum())
|
||||
total_active_coverage = verified_cspc_cnt + verified_riaa_cnt + estimated_sea_cnt
|
||||
coverage_pct = (total_active_coverage / len(df)) * 100.0
|
||||
coverage_pct = (total_active_coverage / len(df)) * 100.0 if len(df) > 0 else 0.0
|
||||
|
||||
st.markdown(
|
||||
f"""
|
||||
@@ -464,10 +583,10 @@ else:
|
||||
st.caption("Standardized on ChartMasters CSPC, verified RIAA certifications, and video/audio streaming equivalent units.")
|
||||
|
||||
sc1, sc2, sc3, sc4 = st.columns(4)
|
||||
total_sales_volume = filtered_df["total_eas_cspc"].fillna(0).sum()
|
||||
cspc_count = (filtered_df["sales_data_status"] == "VERIFIED_CSPC").sum()
|
||||
riaa_count = (filtered_df["sales_data_status"] == "VERIFIED_RIAA").sum()
|
||||
sea_count = (filtered_df["sales_data_status"] == "ESTIMATED_SEA").sum()
|
||||
total_sales_volume = filtered_df["total_eas_cspc"].fillna(0).sum() if "total_eas_cspc" in filtered_df.columns else 0
|
||||
cspc_count = (filtered_df["sales_data_status"] == "VERIFIED_CSPC").sum() if "sales_data_status" in filtered_df.columns else 0
|
||||
riaa_count = (filtered_df["sales_data_status"] == "VERIFIED_RIAA").sum() if "sales_data_status" in filtered_df.columns else 0
|
||||
sea_count = (filtered_df["sales_data_status"] == "ESTIMATED_SEA").sum() if "sales_data_status" in filtered_df.columns else 0
|
||||
|
||||
with sc1:
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title">Tracked Catalog Volume</div><div class="kpi-value">{total_sales_volume/1e6:.1f}M</div><div class="kpi-subtitle">Total Equivalent Album Sales (EAS)</div></div>', unsafe_allow_html=True)
|
||||
@@ -479,8 +598,9 @@ else:
|
||||
st.markdown(f'<div class="kpi-box"><div class="kpi-title" style="color: #a855f7;">Streaming SEA</div><div class="kpi-value" style="color: #a855f7;">{sea_count}</div><div class="kpi-subtitle">Luminate/Billboard Conversion</div></div>', unsafe_allow_html=True)
|
||||
|
||||
st.markdown("#### 🏆 All-Time Global Sales Leaderboard")
|
||||
sales_table_df = filtered_df.sort_values(by="total_eas_cspc", ascending=False).copy()
|
||||
sales_table_df["provenance_badge"] = sales_table_df["sales_data_status"].apply(get_provenance_badge)
|
||||
sales_table_df = filtered_df.sort_values(by="total_eas_cspc", ascending=False).copy() if "total_eas_cspc" in filtered_df.columns else filtered_df.copy()
|
||||
if "sales_data_status" in sales_table_df.columns:
|
||||
sales_table_df["provenance_badge"] = sales_table_df["sales_data_status"].apply(get_provenance_badge)
|
||||
|
||||
sales_cols = [
|
||||
"cohort_sales_rank", "chartmasters_sales_rank", "name", "provenance_badge",
|
||||
@@ -511,30 +631,34 @@ else:
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
c_s1, c_s2 = st.columns(2)
|
||||
with c_s1:
|
||||
top_sellers = sales_table_df[sales_table_df["total_eas_cspc"] > 0].head(12)
|
||||
fig_format = go.Figure()
|
||||
fig_format.add_trace(go.Bar(name="Traditional Albums", x=top_sellers["name"], y=top_sellers["pure_album_sales"], marker_color="#8b5cf6"))
|
||||
fig_format.add_trace(go.Bar(name="Digital Singles", x=top_sellers["name"], y=top_sellers["digital_singles_sales"], marker_color="#38bdf8"))
|
||||
fig_format.add_trace(go.Bar(name="Streaming EAS", x=top_sellers["name"], y=top_sellers["streaming_eas"], marker_color="#10b981"))
|
||||
fig_format.update_layout(
|
||||
barmode="stack", title="Format Contribution: Pure Albums vs Downloads vs Streaming EAS",
|
||||
template="plotly_dark", paper_bgcolor="#111827", plot_bgcolor="#111827",
|
||||
font=dict(color="#9ca3af"), height=360, margin=dict(l=20, r=20, t=50, b=20),
|
||||
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1.0),
|
||||
)
|
||||
st.plotly_chart(fig_format, use_container_width=True)
|
||||
if "total_eas_cspc" in sales_table_df.columns:
|
||||
top_sellers = sales_table_df[sales_table_df["total_eas_cspc"].fillna(0) > 0].head(12)
|
||||
fig_format = go.Figure()
|
||||
fig_format.add_trace(go.Bar(name="Traditional Albums", x=top_sellers["name"], y=top_sellers.get("pure_album_sales", 0), marker_color="#8b5cf6"))
|
||||
fig_format.add_trace(go.Bar(name="Digital Singles", x=top_sellers["name"], y=top_sellers.get("digital_singles_sales", 0), marker_color="#38bdf8"))
|
||||
fig_format.add_trace(go.Bar(name="Streaming EAS", x=top_sellers["name"], y=top_sellers.get("streaming_eas", 0), marker_color="#10b981"))
|
||||
fig_format.update_layout(
|
||||
barmode="stack", title="Format Contribution: Pure Albums vs Downloads vs Streaming EAS",
|
||||
template="plotly_dark", paper_bgcolor="#111827", plot_bgcolor="#111827",
|
||||
font=dict(color="#9ca3af"), height=360, margin=dict(l=20, r=20, t=50, b=20),
|
||||
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1.0),
|
||||
)
|
||||
st.plotly_chart(fig_format, use_container_width=True)
|
||||
|
||||
with c_s2:
|
||||
scatter_data = sales_table_df.dropna(subset=["total_eas_cspc", "hiffi_xp_score"]).copy()
|
||||
fig_quad = px.scatter(
|
||||
scatter_data, x="hiffi_xp_score", y="total_eas_cspc", size="total_eas_cspc",
|
||||
color="provenance_badge", hover_name="name", log_y=True,
|
||||
title="Legacy vs. Velocity Quadrant (All-Time Sales vs HIFFI-XP)",
|
||||
labels={"hiffi_xp_score": "Current Velocity (HIFFI-XP)", "total_eas_cspc": "Total Lifetime EAS Units (Log Scale)"},
|
||||
template="plotly_dark",
|
||||
)
|
||||
fig_quad.update_layout(paper_bgcolor="#111827", plot_bgcolor="#111827", font=dict(color="#9ca3af"), height=360, margin=dict(l=20, r=20, t=50, b=20))
|
||||
st.plotly_chart(fig_quad, use_container_width=True)
|
||||
if "total_eas_cspc" in sales_table_df.columns and "hiffi_xp_score" in sales_table_df.columns:
|
||||
scatter_data = sales_table_df.dropna(subset=["total_eas_cspc", "hiffi_xp_score"]).copy()
|
||||
if not scatter_data.empty:
|
||||
fig_quad = px.scatter(
|
||||
scatter_data, x="hiffi_xp_score", y="total_eas_cspc", size="total_eas_cspc",
|
||||
color="provenance_badge" if "provenance_badge" in scatter_data.columns else None,
|
||||
hover_name="name", log_y=True,
|
||||
title="Legacy vs. Velocity Quadrant (All-Time Sales vs HIFFI-XP)",
|
||||
labels={"hiffi_xp_score": "Current Velocity (HIFFI-XP)", "total_eas_cspc": "Total Lifetime EAS Units (Log Scale)"},
|
||||
template="plotly_dark",
|
||||
)
|
||||
fig_quad.update_layout(paper_bgcolor="#111827", plot_bgcolor="#111827", font=dict(color="#9ca3af"), height=360, margin=dict(l=20, r=20, t=50, b=20))
|
||||
st.plotly_chart(fig_quad, use_container_width=True)
|
||||
|
||||
else:
|
||||
top3 = filtered_df.sort_values(by="hiffi_xp_published_rank", ascending=True).head(3)
|
||||
@@ -548,6 +672,7 @@ else:
|
||||
]
|
||||
for col, row_data, rank_label, css_class, accent_color in podium_data:
|
||||
tier_val = int(row_data.get("platform_evidence_tier", 1))
|
||||
yt_str = f"{int(row_data['subscriber_count']):,}" if pd.notna(row_data.get("subscriber_count")) else "NaN"
|
||||
sp_str = f"{int(row_data['spotify_monthly_listeners']):,}" if pd.notna(row_data.get("spotify_monthly_listeners")) else "NaN"
|
||||
ig_str = f"{int(row_data['instagram_followers']):,}" if pd.notna(row_data.get("instagram_followers")) else "NaN"
|
||||
with col:
|
||||
@@ -560,10 +685,11 @@ else:
|
||||
</div>
|
||||
<div style="font-size: 1.35rem; font-weight: 800; color: #ffffff; margin-bottom: 2px;">{row_data['name']}</div>
|
||||
<div style="font-size: 0.8rem; color: #6b7280; margin-bottom: 12px;">{row_data.get('channel_title', '')}</div>
|
||||
<div style="display: flex; justify-content: space-between; background: #0b0f17; padding: 10px 14px; border-radius: 8px;">
|
||||
<div><div style="font-size: 0.68rem; color: #9ca3af;">HIFFI-XP</div><div style="font-size: 1.25rem; font-weight: 800; color: {accent_color};">{row_data['hiffi_xp_score']:.2f}</div></div>
|
||||
<div><div style="font-size: 0.68rem; color: #9ca3af;">Spotify Monthly</div><div style="font-size: 1.05rem; font-weight: 700; color: #38bdf8;">{sp_str}</div></div>
|
||||
<div><div style="font-size: 0.68rem; color: #9ca3af;">IG Followers</div><div style="font-size: 1.05rem; font-weight: 700; color: #e5e7eb;">{ig_str}</div></div>
|
||||
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; background: #0b0f17; padding: 10px 10px; border-radius: 8px;">
|
||||
<div><div style="font-size: 0.64rem; color: #9ca3af;">HIFFI-XP</div><div style="font-size: 1.15rem; font-weight: 800; color: {accent_color};">{row_data.get('hiffi_xp_score', 0.0):.2f}</div></div>
|
||||
<div><div style="font-size: 0.64rem; color: #9ca3af;">YT Subs</div><div style="font-size: 0.95rem; font-weight: 700; color: #ef4444;">{yt_str}</div></div>
|
||||
<div><div style="font-size: 0.64rem; color: #9ca3af;">Spotify</div><div style="font-size: 0.95rem; font-weight: 700; color: #38bdf8;">{sp_str}</div></div>
|
||||
<div><div style="font-size: 0.64rem; color: #9ca3af;">IG Follow</div><div style="font-size: 0.95rem; font-weight: 700; color: #e5e7eb;">{ig_str}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
""",
|
||||
@@ -594,12 +720,21 @@ else:
|
||||
|
||||
if view_mode == "🏆 Published Multi-Platform Rank":
|
||||
table_df = filtered_df.sort_values(by="hiffi_xp_published_rank", ascending=True).copy()
|
||||
cols = ["hiffi_xp_published_rank", "hiffi_xp_rank", "name", "platform_evidence_tier", "hiffi_xp_score", "spotify_monthly_listeners", "instagram_followers", "effective_weights", "anomaly_flags"]
|
||||
# Explicitly placing subscriber_count right after HIFFI-XP Score
|
||||
cols = [
|
||||
"hiffi_xp_published_rank", "hiffi_xp_rank", "name",
|
||||
"platform_evidence_tier", "hiffi_xp_score", "subscriber_count",
|
||||
"spotify_monthly_listeners", "instagram_followers",
|
||||
"effective_weights", "anomaly_flags"
|
||||
]
|
||||
elif view_mode == "🚀 Breakout Velocity (BVI)":
|
||||
table_df = filtered_df[filtered_df["breakout_velocity_index"].notna()].sort_values(by="breakout_velocity_index", ascending=False).copy()
|
||||
bvi_series = filtered_df.get("breakout_velocity_index", pd.Series(0.0, index=filtered_df.index)).fillna(0.0)
|
||||
table_df = filtered_df[bvi_series.notna()].copy()
|
||||
table_df["breakout_velocity_index"] = bvi_series
|
||||
table_df = table_df.sort_values(by="breakout_velocity_index", ascending=False)
|
||||
cols = ["name", "breakout_velocity_index", "hiffi_xp_published_rank", "daily_view_velocity", "momentum_30d", "subscriber_count", "subgenre"]
|
||||
elif view_mode == "🧪 Commercial Simulation Engine (CPI)":
|
||||
table_df = filtered_df.sort_values(by="simulated_rank", ascending=True).copy()
|
||||
table_df = filtered_df.sort_values(by="simulated_rank", ascending=True).copy() if "simulated_rank" in filtered_df.columns else filtered_df.copy()
|
||||
|
||||
def format_rank_delta(val):
|
||||
if pd.isna(val):
|
||||
@@ -612,7 +747,11 @@ else:
|
||||
else:
|
||||
return "— 0 (Equal)"
|
||||
|
||||
table_df["rank_shift_indicator"] = table_df["simulation_rank_delta"].apply(format_rank_delta)
|
||||
if "simulation_rank_delta" in table_df.columns:
|
||||
table_df["rank_shift_indicator"] = table_df["simulation_rank_delta"].apply(format_rank_delta)
|
||||
else:
|
||||
table_df["rank_shift_indicator"] = "— 0"
|
||||
|
||||
comp_rank = "baseline_matched_rank" if sim_mode == "matched_only" else "hiffi_xp_published_rank"
|
||||
|
||||
cols = [
|
||||
@@ -622,7 +761,7 @@ else:
|
||||
]
|
||||
else:
|
||||
table_df = filtered_df.sort_values(by="hiffi_xp_published_rank", ascending=True).copy()
|
||||
cols = ["hiffi_xp_published_rank", "name", "production_hiffi_rank", "hiffi_xp_rank", "rank_delta", "platform_evidence_tier", "hiffi_xp_score", "spotify_monthly_listeners", "instagram_followers", "total_eas_cspc", "sales_data_status", "evidence_exclusions", "anomaly_flags"]
|
||||
cols = ["hiffi_xp_published_rank", "name", "production_hiffi_rank", "hiffi_xp_rank", "rank_delta", "platform_evidence_tier", "hiffi_xp_score", "subscriber_count", "spotify_monthly_listeners", "instagram_followers", "total_eas_cspc", "sales_data_status", "evidence_exclusions", "anomaly_flags"]
|
||||
|
||||
display_table = table_df.copy()
|
||||
if "sales_data_status" in display_table.columns:
|
||||
@@ -635,11 +774,18 @@ else:
|
||||
height=340,
|
||||
column_config={
|
||||
"hiffi_xp_published_rank": st.column_config.NumberColumn("Published Rank", format="%d", width="small"),
|
||||
"hiffi_xp_rank": st.column_config.NumberColumn("Raw Rank", format="%d", width="small"),
|
||||
"name": st.column_config.TextColumn("Artist", width="medium"),
|
||||
"platform_evidence_tier": st.column_config.NumberColumn("Tier", format="Tier %d", width="small"),
|
||||
"baseline_matched_rank": st.column_config.NumberColumn("Baseline Match Rank", format="%d", width="small"),
|
||||
"simulated_rank": st.column_config.NumberColumn("Simulated Rank", format="%d", width="small"),
|
||||
"rank_shift_indicator": st.column_config.TextColumn("Simulated Δ (Movement)", width="medium"),
|
||||
"simulated_hiffi_score": st.column_config.ProgressColumn("Simulated Score", format="%.2f", min_value=0, max_value=100, width="medium"),
|
||||
"hiffi_xp_score": st.column_config.ProgressColumn("HIFFI-XP Score", format="%.2f", min_value=0, max_value=100, width="medium"),
|
||||
"subscriber_count": st.column_config.NumberColumn("YouTube Subscribers", format="%,d", width="medium"),
|
||||
"spotify_monthly_listeners": st.column_config.NumberColumn("Spotify Monthly Listeners", format="%,d", width="medium"),
|
||||
"instagram_followers": st.column_config.NumberColumn("Instagram Followers", format="%,d", width="medium"),
|
||||
"breakout_velocity_index": st.column_config.ProgressColumn("Breakout Velocity Index", format="%.2f", min_value=0, max_value=100, width="medium"),
|
||||
"commercial_power_index": st.column_config.ProgressColumn("Commercial Power Index", format="%.1f", min_value=0, max_value=100, width="medium"),
|
||||
"total_eas_cspc": st.column_config.NumberColumn("Total Equivalent Album Sales", format="%,d", width="medium"),
|
||||
"pure_album_sales": st.column_config.NumberColumn("Traditional Album Sales", format="%,d", width="medium"),
|
||||
@@ -651,7 +797,7 @@ else:
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
c_left, c_right = st.columns(2)
|
||||
with c_left:
|
||||
chart_df = filtered_df.dropna(subset=["spotify_monthly_listeners", "instagram_followers", "hiffi_xp_score"]).copy()
|
||||
chart_df = filtered_df.dropna(subset=["spotify_monthly_listeners", "instagram_followers", "hiffi_xp_score"]).copy() if all(c in filtered_df.columns for c in ["spotify_monthly_listeners", "instagram_followers", "hiffi_xp_score"]) else pd.DataFrame()
|
||||
if not chart_df.empty:
|
||||
fig_scatter = px.scatter(
|
||||
chart_df, x="spotify_monthly_listeners", y="instagram_followers",
|
||||
@@ -663,11 +809,12 @@ else:
|
||||
fig_scatter.update_layout(paper_bgcolor="#111827", plot_bgcolor="#111827", font=dict(color="#9ca3af"), height=320, margin=dict(l=20, r=20, t=40, b=20))
|
||||
st.plotly_chart(fig_scatter, use_container_width=True)
|
||||
with c_right:
|
||||
tier_counts = filtered_df["platform_evidence_tier"].value_counts().reset_index()
|
||||
tier_counts.columns = ["Tier", "Count"]
|
||||
fig_pie = px.pie(tier_counts, values="Count", names="Tier", title="Evidence Tier Cohort Distribution", template="plotly_dark", color="Tier", color_discrete_map={3: "#10b981", 2: "#38bdf8", 1: "#f59e0b", 0: "#ef4444"})
|
||||
fig_pie.update_layout(paper_bgcolor="#111827", plot_bgcolor="#111827", font=dict(color="#9ca3af"), height=320, margin=dict(l=20, r=20, t=40, b=20))
|
||||
st.plotly_chart(fig_pie, use_container_width=True)
|
||||
if "platform_evidence_tier" in filtered_df.columns:
|
||||
tier_counts = filtered_df["platform_evidence_tier"].value_counts().reset_index()
|
||||
tier_counts.columns = ["Tier", "Count"]
|
||||
fig_pie = px.pie(tier_counts, values="Count", names="Tier", title="Evidence Tier Cohort Distribution", template="plotly_dark", color="Tier", color_discrete_map={3: "#10b981", 2: "#38bdf8", 1: "#f59e0b", 0: "#ef4444"})
|
||||
fig_pie.update_layout(paper_bgcolor="#111827", plot_bgcolor="#111827", font=dict(color="#9ca3af"), height=320, margin=dict(l=20, r=20, t=40, b=20))
|
||||
st.plotly_chart(fig_pie, use_container_width=True)
|
||||
|
||||
# Dossier for 500
|
||||
st.markdown("<div class='custom-divider'></div>", unsafe_allow_html=True)
|
||||
@@ -675,7 +822,7 @@ else:
|
||||
selected_name = st.selectbox("Inspect Artist Details:", df["name"].unique(), label_visibility="collapsed")
|
||||
row = df[df["name"] == selected_name].iloc[0]
|
||||
|
||||
d1, d2, d3, d4, d5 = st.columns(5)
|
||||
d1, d2, d3, d4, d5, d6 = st.columns(6)
|
||||
with d1:
|
||||
h_val = row.get("hiffi_xp_score")
|
||||
st.metric("HIFFI-XP Score", f"{h_val:.2f}" if pd.notna(h_val) else "N/A")
|
||||
@@ -683,12 +830,15 @@ else:
|
||||
pub_rank = row.get("hiffi_xp_published_rank")
|
||||
st.metric("Published Rank", f"#{int(pub_rank)}" if pd.notna(pub_rank) else "Unranked")
|
||||
with d3:
|
||||
yt_s = row.get("subscriber_count")
|
||||
st.metric("YouTube Subscribers", f"{int(yt_s):,}" if pd.notna(yt_s) else "Unindexed (NaN)")
|
||||
with d4:
|
||||
sp_l = row.get("spotify_monthly_listeners")
|
||||
st.metric("Spotify Listeners", f"{int(sp_l):,}" if pd.notna(sp_l) else "Unindexed (NaN)")
|
||||
with d4:
|
||||
with d5:
|
||||
ig_f = row.get("instagram_followers")
|
||||
st.metric("Instagram Followers", f"{int(ig_f):,}" if pd.notna(ig_f) else "Unindexed (NaN)")
|
||||
with d5:
|
||||
with d6:
|
||||
sales_val = row.get("total_eas_cspc")
|
||||
st.metric("Total EAS Sales", f"{int(sales_val):,}" if pd.notna(sales_val) else "Awaiting Ingestion")
|
||||
|
||||
@@ -698,6 +848,7 @@ else:
|
||||
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
|
||||
<div><b>Artist:</b> {row['name']}</div>
|
||||
<div><b>Evidence Tier:</b> Tier {int(row.get('platform_evidence_tier', 1))}</div>
|
||||
<div><b>YouTube Subscribers:</b> {f"{int(row.get('subscriber_count')):,}" if pd.notna(row.get('subscriber_count')) else "N/A"}</div>
|
||||
<div><b>Global Sales Rank:</b> {f"#{int(row.get('chartmasters_sales_rank'))}" if pd.notna(row.get('chartmasters_sales_rank')) else "Unranked"}</div>
|
||||
<div><b>Cohort Sales Rank:</b> {f"#{int(row.get('cohort_sales_rank'))}" if pd.notna(row.get('cohort_sales_rank')) else "Uncataloged"}</div>
|
||||
<div><b>Commercial Power Index:</b> {f"{row.get('commercial_power_index'):.1f}" if pd.notna(row.get('commercial_power_index')) else "Awaiting Audit"}</div>
|
||||
|
||||
Reference in new issue
Block a user