File size: 5,624 Bytes
384f5e4
bfd4ab7
ebf358a
0a4103c
 
384f5e4
febef4d
717fe8c
c42b00b
 
ebf358a
8b3a49e
717fe8c
0a4103c
 
 
 
 
bfd4ab7
0a4103c
 
 
 
 
 
 
 
 
 
717fe8c
0a4103c
 
 
 
 
8b3a49e
0a4103c
 
 
ebf358a
0a4103c
 
ebf358a
0a4103c
ebf358a
d10e98d
8b3a49e
1ae5cf1
242b668
 
 
 
 
0a4103c
ebf358a
febef4d
d10e98d
242b668
5a80960
 
0a4103c
 
 
 
5a80960
 
 
 
 
 
 
 
0a4103c
 
 
 
 
 
 
 
 
ebf358a
8b3a49e
ebf358a
0a4103c
bfd4ab7
 
 
717fe8c
0a4103c
 
8b3a49e
ebf358a
0a4103c
 
 
 
ebf358a
 
384f5e4
ebf358a
0a4103c
 
 
384f5e4
bfd4ab7
0a4103c
bfd4ab7
8b3a49e
0a4103c
ebf358a
 
0a4103c
 
 
 
ebf358a
95eccad
0a4103c
ebf358a
0a4103c
384f5e4
 
 
0a4103c
 
ebf358a
 
0a4103c
 
 
 
ebf358a
0a4103c
 
 
ebf358a
 
 
 
 
 
0a4103c
 
8b3a49e
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
import streamlit as st
import requests
import matplotlib.pyplot as plt
from transformers import pipeline
import openai
import pandas as pd
import os

OPENAI_API_KEY="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"

# OpenAI API ํ‚ค ์„ค์ •
openai.api_key = os.getenv("OPENAI_API_KEY", "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")  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋˜๋Š” ์ง์ ‘ ํ‚ค ์ž…๋ ฅ

# ๋„ค์ด๋ฒ„ ๋‰ด์Šค API๋ฅผ ํ†ตํ•ด ์‹ค์ œ ๋‰ด์Šค ๊ธฐ์‚ฌ ๊ฐ€์ ธ์˜ค๊ธฐ
def fetch_naver_news(query, display=5):
    client_id = "I_8koTJh3R5l4wLurQbG"  # ๋„ค์ด๋ฒ„ ๊ฐœ๋ฐœ์ž ์„ผํ„ฐ์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ Client ID
    client_secret = "W5oWYlAgur"  # ๋„ค์ด๋ฒ„ ๊ฐœ๋ฐœ์ž ์„ผํ„ฐ์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ Client Secret

    url = "https://openapi.naver.com/v1/search/news.json"
    headers = {
        "X-Naver-Client-Id": client_id,
        "X-Naver-Client-Secret": client_secret,
    }
    params = {
        "query": query,
        "display": display,
        "start": 1,
        "sort": "date",  # ์ตœ์‹ ์ˆœ์œผ๋กœ ์ •๋ ฌ
    }

    response = requests.get(url, headers=headers, params=params)
    if response.status_code == 200:
        news_data = response.json()
        return news_data['items']  # ๋‰ด์Šค ๊ธฐ์‚ฌ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
    else:
        st.error("๋‰ด์Šค ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")
        return []

# ์ •์น˜ ์„ฑํ–ฅ ๋ถ„์„ ๋ชจ๋ธ ๋กœ๋“œ
def load_sentiment_model():
    classifier = pipeline("text-classification", model="bucketresearch/politicalBiasBERT")
    return classifier

# GPT-4๋ฅผ ์ด์šฉํ•ด ๋ฐ˜๋Œ€ ๊ด€์  ๊ธฐ์‚ฌ ์ƒ์„ฑ
def generate_article_gpt4(prompt):
    try:
        response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": "You are a helpful assistant that generates articles."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=512,
            temperature=0.7
        )
        return response.choices[0].message.content
    except Exception as e:
        return f"Error generating text: {e}"

# ์ •์น˜ ์„ฑํ–ฅ ๋ถ„์„
def analyze_article_sentiment(text, classifier):
    result = classifier(text[:512])  # ๋„ˆ๋ฌด ๊ธด ํ…์ŠคํŠธ๋Š” ์ž˜๋ผ์„œ ๋ถ„์„
    label = result[0]["label"]
    score = result[0]["score"]

    # ๋ชจ๋ธ์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ผ๋ฒจ์„ "์ง„๋ณด", "๋ณด์ˆ˜", "์ค‘๋ฆฝ"์œผ๋กœ ๋งคํ•‘
    if label == "LEFT":
        return "์ง„๋ณด", score
    elif label == "RIGHT":
        return "๋ณด์ˆ˜", score
    else:
        return "์ค‘๋ฆฝ", score

# ์ •์น˜์  ๊ด€์  ๋น„๊ต ๋ฐ ๋ฐ˜๋Œ€ ๊ด€์  ์ƒ์„ฑ
def analyze_news_political_viewpoint(query):
    # ๋‰ด์Šค ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
    news_items = fetch_naver_news(query)
    if not news_items:
        return [], {}

    classifier = load_sentiment_model()
    results = []
    sentiment_counts = {"์ง„๋ณด": 0, "๋ณด์ˆ˜": 0, "์ค‘๋ฆฝ": 0}  # ๋งคํ•‘๋œ ๋ผ๋ฒจ์— ๋งž๊ฒŒ ์ดˆ๊ธฐํ™”

    for item in news_items:
        title = item["title"]
        description = item["description"]
        combined_text = f"{title}. {description}"

        # ๊ธฐ์‚ฌ ์„ฑํ–ฅ ๋ถ„์„
        sentiment, score = analyze_article_sentiment(combined_text, classifier)
        sentiment_counts[sentiment] += 1  # ๋งคํ•‘๋œ ํ‚ค๋กœ ์นด์šดํŠธ ์ฆ๊ฐ€

        # ๋ฐ˜๋Œ€ ๊ด€์  ๊ธฐ์‚ฌ ์ƒ์„ฑ
        opposite_perspective = "๋ณด์ˆ˜์ " if sentiment == "์ง„๋ณด" else "์ง„๋ณด์ "
        prompt = f"{combined_text}๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ {opposite_perspective} ๊ด€์ ์˜ ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”."
        opposite_article = generate_article_gpt4(prompt)

        results.append({
            "์ œ๋ชฉ": title,
            "์›๋ณธ ๊ธฐ์‚ฌ": description,
            "์„ฑํ–ฅ": sentiment,
            "์„ฑํ–ฅ ์ ์ˆ˜": score,
            "๋Œ€์กฐ ๊ด€์  ๊ธฐ์‚ฌ": opposite_article
        })

    return results, sentiment_counts


# ์„ฑํ–ฅ ๋ถ„ํฌ ์‹œ๊ฐํ™”
def visualize_sentiment_distribution(sentiment_counts):
    fig, ax = plt.subplots()
    labels = list(sentiment_counts.keys())
    sizes = list(sentiment_counts.values())
    ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90, colors=["blue", "red", "gray"])
    ax.axis("equal")
    st.pyplot(fig)

# Streamlit ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
st.title("์ •์น˜์  ๊ด€์  ๋น„๊ต ๋ถ„์„ ๋„๊ตฌ")
st.markdown("๋‰ด์Šค ๊ธฐ์‚ฌ์˜ ์ •์น˜ ์„ฑํ–ฅ ๋ถ„์„๊ณผ ๋ฐ˜๋Œ€ ๊ด€์  ๊ธฐ์‚ฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.")

query = st.text_input("๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”", value="์ •์น˜")
if st.button("๋ถ„์„ ์‹œ์ž‘"):
    with st.spinner("๋ถ„์„ ์ค‘..."):
        analysis_results, sentiment_counts = analyze_news_political_viewpoint(query)

        if analysis_results:
            st.success("๋‰ด์Šค ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
            
            # ์„ฑํ–ฅ ๋ถ„ํฌ ์‹œ๊ฐํ™”
            st.subheader("์„ฑํ–ฅ ๋ถ„ํฌ ์‹œ๊ฐํ™”")
            visualize_sentiment_distribution(sentiment_counts)
            
            # ์ƒ์„ธ ๋ถ„์„ ๊ฒฐ๊ณผ ์ถœ๋ ฅ
            st.subheader("์ƒ์„ธ ๋ถ„์„ ๊ฒฐ๊ณผ")
            for result in analysis_results:
                st.write(f"#### ์ œ๋ชฉ: {result['์ œ๋ชฉ']}")
                st.write(f"- **์›๋ณธ ๊ธฐ์‚ฌ**: {result['์›๋ณธ ๊ธฐ์‚ฌ']}")
                st.write(f"- **์„ฑํ–ฅ**: {result['์„ฑํ–ฅ']} (์ ์ˆ˜: {result['์„ฑํ–ฅ ์ ์ˆ˜']:.2f})")
                st.write(f"- **๋Œ€์กฐ ๊ด€์  ๊ธฐ์‚ฌ**: {result['๋Œ€์กฐ ๊ด€์  ๊ธฐ์‚ฌ']}")
                st.write("---")
        else:
            st.error("๋ถ„์„๋œ ๋‰ด์Šค ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")