File size: 3,736 Bytes
ef78361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""λΈŒλžœλ“œ x ν‚€μ›Œλ“œ ꡐ차 뢄석 + LLM 이유 νƒœκ·Έ."""
import html

import pandas as pd
import plotly.graph_objects as go
import streamlit as st

from core.api_client import ChainShiftClient


def render_brand_keyword_cross(data: dict, competitor: bool = False):
    """λΈŒλžœλ“œ x ν‚€μ›Œλ“œ ꡐ차 뢄석 + LLM 이유 νƒœκ·Έ."""
    brand_label = "κ²½μŸμ‚¬" if competitor else "μžμ‚¬"
    st.markdown(f"**{brand_label} λΈŒλžœλ“œ x ν‚€μ›Œλ“œ ꡐ차 뢄석**")
    st.caption(f"ν‚€μ›Œλ“œλ³„λ‘œ {brand_label} λΈŒλžœλ“œκ°€ μ–΄λ–€ λ§₯λ½μ—μ„œ μ–ΈκΈ‰λ˜λŠ”μ§€ λΆ„μ„ν•©λ‹ˆλ‹€")

    try:
        client = ChainShiftClient(api_key=data.get("api_key"), access_token=data.get("access_token"))
        response = client.get_keyword_brand_analysis(data["campaign_id"], competitor=competitor)
        resp_data = response.get("data", {})
        items = resp_data.get("items", [])
    except Exception as e:
        st.error(f"λΈŒλžœλ“œxν‚€μ›Œλ“œ 뢄석 λ‘œλ“œ μ‹€νŒ¨: {e}")
        return

    if not items:
        st.info("λΈŒλžœλ“œxν‚€μ›Œλ“œ ꡐ차 데이터가 μ—†μŠ΅λ‹ˆλ‹€")
        return

    # Cross table
    rows = []
    for item in items:
        keyword = item.get("keyword", "")
        brand = item.get("brand", "")
        total = item.get("total", 0)
        sent = item.get("sentiment", {})
        pos = sent.get("positive", 0)
        neu = sent.get("neutral", 0)
        neg = sent.get("negative", 0)
        reason_tags = item.get("reason_tags", [])
        top_tags = ", ".join(rt.get("tag", "") for rt in reason_tags[:3])

        rows.append({
            "ν‚€μ›Œλ“œ": keyword,
            "λΈŒλžœλ“œ": brand,
            "총 건수": total,
            "긍정": pos,
            "쀑립": neu,
            "λΆ€μ •": neg,
            "μ£Όμš” 이유 νƒœκ·Έ": top_tags,
        })

    if rows:
        df = pd.DataFrame(rows).sort_values("λΆ€μ •", ascending=False)
        st.dataframe(df, use_container_width=True, hide_index=True)

    # LLM Reason Tag Analysis
    st.markdown("---")
    st.markdown("**🏷️ LLM 이유 νƒœκ·Έ 뢄석**")
    st.caption("LLM이 μžλ™ μƒμ„±ν•œ 이유 νƒœκ·Έ λΉˆλ„")

    # Aggregate all reason tags
    tag_counts: dict[str, int] = {}
    tag_examples: dict[str, str] = {}
    for item in items:
        for rt in item.get("reason_tags", []):
            tag = rt.get("tag", "")
            count = rt.get("count", 0)
            if tag:
                tag_counts[tag] = tag_counts.get(tag, 0) + count
                if tag not in tag_examples and rt.get("example_sentence"):
                    tag_examples[tag] = rt["example_sentence"]

    if tag_counts:
        # Bar chart for top tags
        sorted_tags = sorted(tag_counts.items(), key=lambda x: -x[1])[:15]
        tag_names = [t[0] for t in sorted_tags]
        tag_vals = [t[1] for t in sorted_tags]

        fig = go.Figure(go.Bar(
            x=tag_vals,
            y=tag_names,
            orientation="h",
            marker_color="#059669",
        ))
        fig.update_layout(
            height=max(250, len(sorted_tags) * 30),
            margin=dict(l=20, r=20, t=10, b=10),
            yaxis=dict(autorange="reversed"),
        )
        st.plotly_chart(fig, use_container_width=True, config={"displayModeBar": False})

        # Tag detail table
        tag_rows = []
        for tag, count in sorted_tags:
            example = tag_examples.get(tag, "")
            tag_rows.append({
                "νƒœκ·Έ": tag,
                "λΉˆλ„": count,
                "μ˜ˆμ‹œ λ¬Έμž₯": example[:100] if example else "",
            })
        st.dataframe(pd.DataFrame(tag_rows), use_container_width=True, hide_index=True)
    else:
        st.info("LLM 이유 νƒœκ·Έ 데이터가 μ—†μŠ΅λ‹ˆλ‹€")