Spaces:
Running
Running
| import json, pandas as pd, streamlit as st | |
| from typing import Dict, Any | |
| from helpers_function.helpers import _mean_effectiveness | |
| def _normalize_list(v): | |
| if v is None: return [] | |
| if isinstance(v, list): return [str(x) for x in v] | |
| return [s for s in str(v).splitlines() if s.strip()] | |
| def _to_dataframe(items, columns_map): | |
| import pandas as pd | |
| if not isinstance(items, list) or not items: | |
| return pd.DataFrame(columns=list(columns_map.values())) | |
| df = pd.DataFrame(items).rename(columns=columns_map) | |
| ordered_cols = [columns_map[k] for k in columns_map.keys() if columns_map[k] in df.columns] | |
| return df.reindex(columns=ordered_cols) | |
| def _search_dataframe(df, query): | |
| if not query or df.empty: return df | |
| mask = df.apply(lambda col: col.astype(str).str.contains(query, case=False, na=False)) | |
| return df[mask.any(axis=1)] | |
| def render_analyzer_results(analysis: Dict[str, Any]) -> None: | |
| if not isinstance(analysis, dict) or not analysis: | |
| st.warning("No analysis available."); return | |
| st.markdown( | |
| """<style> | |
| .metric-card{background:#0f172a;padding:14px 16px;border-radius:14px;border:1px solid #1f2937} | |
| .label{font-size:12px;color:#94a3b8;margin-bottom:6px} | |
| .value{font-size:16px;color:#e2e8f0} | |
| </style>""", | |
| unsafe_allow_html=True, | |
| ) | |
| va = analysis.get("video_analysis", {}) or {} | |
| storyboard = analysis.get("storyboard", []) or [] | |
| script = analysis.get("script", []) or [] | |
| metrics = va.get("video_metrics", []) or [] | |
| mean_score = _mean_effectiveness(metrics) | |
| m1,m2,m3,m4 = st.columns([1,1,1,1]) | |
| m1.markdown(f'<div class="metric-card"><div class="label">Scenes</div><div class="value">{len(storyboard)}</div></div>', unsafe_allow_html=True) | |
| m2.markdown(f'<div class="metric-card"><div class="label">Dialogue Lines</div><div class="value">{len(script)}</div></div>', unsafe_allow_html=True) | |
| m3.markdown(f'<div class="metric-card"><div class="label">Avg Effectiveness</div><div class="value">{mean_score}/10</div></div>', unsafe_allow_html=True) | |
| m4.markdown(f'<div class="metric-card"><div class="label">Improvements</div><div class="value">{len(analysis.get("timestamp_improvements", []) or [])}</div></div>', unsafe_allow_html=True) | |
| colA, colB = st.columns([1.3,1]) | |
| with colA: | |
| st.markdown("### Executive Summary") | |
| c1,c2 = st.columns(2) | |
| with c1: | |
| with st.expander("Brief", expanded=True): st.write(analysis.get("brief", "N/A")) | |
| with st.expander("Caption Details", expanded=False): st.write(analysis.get("caption_details", "N/A")) | |
| with c2: | |
| hook = analysis.get("hook", {}) or {} | |
| with st.expander("Hook", expanded=True): | |
| st.markdown(f"**Opening:** {hook.get('hook_text','N/A')}") | |
| st.markdown(f"**Principle:** {hook.get('principle','N/A')}") | |
| adv = _normalize_list(hook.get("advantages")) | |
| if adv: | |
| st.markdown("**Advantages:**") | |
| st.markdown("\n".join([f"- {a}" for a in adv])) | |
| st.divider() | |
| st.markdown("### Narrative & Copy Frameworks") | |
| with st.expander("Framework Analysis", expanded=True): st.write(analysis.get("framework_analysis", "N/A")) | |
| with colB: | |
| st.markdown("### Snapshot") | |
| st.caption("Top Drivers"); st.markdown(f'{va.get("effectiveness_factors","N/A")}</div>', unsafe_allow_html=True) | |
| st.markdown(""); st.caption("Psychological Triggers"); st.markdown(f'{va.get("psychological_triggers","N/A")}</div>', unsafe_allow_html=True) | |
| st.markdown(""); st.caption("Target Audience"); st.markdown(f'{va.get("target_audience","N/A")}</div>', unsafe_allow_html=True) | |
| st.divider() | |
| tabs = st.tabs(["Storyboard","Script","Scored Metrics","Improvements","Raw JSON"]) | |
| with tabs[0]: | |
| q = st.text_input("Search storyboard") | |
| if storyboard: | |
| df = _to_dataframe( | |
| storyboard, | |
| {"timeline":"Timeline","scene":"Scene","visuals":"Visuals","dialogue":"Dialogue","camera":"Camera","sound_effects":"Sound Effects"} | |
| ) | |
| st.dataframe(_search_dataframe(df, q), width='stretch', height=480) | |
| else: | |
| st.info("No storyboard available.") | |
| with tabs[1]: | |
| q2 = st.text_input("Search script") | |
| if script: | |
| df = _to_dataframe(script, {"timeline":"Timeline","dialogue":"Dialogue"}) | |
| st.dataframe(_search_dataframe(df, q2), width='stretch', height=480) | |
| else: | |
| st.info("No script breakdown available.") | |
| with tabs[2]: | |
| q3 = st.text_input("Search metrics") | |
| if metrics: | |
| dfm = _to_dataframe( | |
| metrics, | |
| {"timestamp":"Timestamp","element":"Element","current_approach":"Current Approach","effectiveness_score":"Effectiveness Score","notes":"Notes"} | |
| ) | |
| st.dataframe(_search_dataframe(dfm, q3), width='stretch', height=480) | |
| else: | |
| st.info("No video metrics available.") | |
| with tabs[3]: | |
| improvements = analysis.get("timestamp_improvements", []) or [] | |
| q4 = st.text_input("Search improvements") | |
| if improvements: | |
| imp_df = _to_dataframe( | |
| improvements, | |
| {"timestamp":"Timestamp","current_element":"Current Element","improvement_type":"Improvement Type", | |
| "recommended_change":"Recommended Change","expected_impact":"Expected Impact","priority":"Priority"} | |
| ) | |
| if "Priority" in imp_df.columns: | |
| order = pd.CategoricalDtype(["High","Medium","Low"], ordered=True) | |
| imp_df["Priority"] = imp_df["Priority"].astype(order) | |
| if "Timestamp" in imp_df.columns: | |
| imp_df = imp_df.sort_values(["Priority","Timestamp"]) | |
| st.dataframe(_search_dataframe(imp_df, q4), width='stretch', height=480) | |
| else: | |
| st.info("No timestamp-based improvements available.") | |
| with tabs[4]: | |
| res = json.dumps(analysis, indent=2, ensure_ascii=False) | |
| st.code(res, language="json") | |
| st.download_button( | |
| "Download JSON", | |
| data=res.encode("utf-8"), | |
| file_name="ad_analysis.json", | |
| mime="application/json", | |
| width='stretch' | |
| ) | |