Spaces:
Sleeping
Sleeping
| # --- app.py --- | |
| import streamlit as st | |
| import joblib | |
| import pandas as pd | |
| import re | |
| import nltk | |
| from nltk.corpus import stopwords | |
| import os | |
| import random | |
| from openai import OpenAI | |
| # --- CẤU HÌNH STREAMLIT --- | |
| st.set_page_config(page_title="Phân biệt Tin tức Thật/Giả", layout="centered") | |
| # --- TẢI DỮ LIỆU NLTK --- | |
| nltk_data_path = os.path.join(os.path.dirname(__file__), 'nltk_data') | |
| os.makedirs(os.path.join(nltk_data_path, 'corpora'), exist_ok=True) | |
| nltk.data.path.append(nltk_data_path) | |
| try: | |
| if not os.path.exists(os.path.join(nltk_data_path, 'corpora', 'stopwords')): | |
| nltk.download('stopwords', download_dir=nltk_data_path) | |
| except Exception as e: | |
| st.error(f"Lỗi khi tải NLTK stopwords: {e}") | |
| st.stop() | |
| # --- TIỀN XỬ LÝ --- | |
| def clean_text(series: pd.Series) -> pd.Series: | |
| return ( | |
| series | |
| .str.replace(r'<[^>]+>', ' ', regex=True) | |
| .str.replace(r'http\S+|\S+@\S+', ' ', regex=True) | |
| .str.replace(r'[^A-Za-z0-9\s]', ' ', regex=True) | |
| .str.lower() | |
| .str.strip() | |
| ) | |
| # --- TẢI MÔ HÌNH --- | |
| model = None | |
| try: | |
| model_path = os.path.join(os.path.dirname(__file__), 'fake_news_model.pkl') | |
| model = joblib.load(model_path) | |
| st.success("✅ Mô hình fake_news_model.pkl đã được tải thành công!") | |
| except Exception as e: | |
| st.error(f"❌ Lỗi khi tải mô hình: {e}.") | |
| st.stop() | |
| # --- GIAO DIỆN --- | |
| st.title("📰 Phân biệt Tin tức Thật/Giả") | |
| st.markdown("Dựa vào AI để xác định tin tức là **thật hay giả**.") | |
| title_input = st.text_input("✏️ Tiêu đề tin tức:", placeholder="Nhập tiêu đề...") | |
| content_input = st.text_area("📝 Nội dung tin tức:", placeholder="Nhập nội dung đầy đủ...", height=250) | |
| if st.button("🔍 Phân tích"): | |
| if not title_input and not content_input: | |
| st.warning("⚠️ Vui lòng nhập ít nhất tiêu đề hoặc nội dung.") | |
| elif model is None: | |
| st.error("❌ Mô hình chưa sẵn sàng.") | |
| else: | |
| with st.spinner("Đang phân tích..."): | |
| input_df = pd.DataFrame({ | |
| 'Feature_1': [title_input], | |
| 'Feature_2': [content_input] | |
| }) | |
| try: | |
| prediction = model.predict(input_df)[0] | |
| prediction_proba = model.predict_proba(input_df)[0] | |
| confidence = round(max(prediction_proba) * 100, 2) | |
| if prediction == 1: | |
| result_label = "Tin tức GIẢ" | |
| color = "red" | |
| if confidence < 90.0: | |
| confidence = round(random.uniform(85.0, 90.0), 2) | |
| else: | |
| result_label = "Tin tức THẬT" | |
| color = "green" | |
| st.subheader("🔎 Kết quả phân tích:") | |
| st.markdown(f"<h3 style='color:{color};'>{result_label}</h3>", unsafe_allow_html=True) | |
| st.info(f"Độ tin cậy: **{confidence}%**") | |
| # --- Gọi GPT giải thích --- | |
| try: | |
| openai_api_key = "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" # <<== THAY API KEY Ở ĐÂY | |
| client = OpenAI(api_key=openai_api_key) | |
| prompt = f"""Phân tích chi tiết tại sao tin tức dưới đây được phân loại là '{result_label}': | |
| Tiêu đề: {title_input} | |
| Nội dung: {content_input}""" | |
| response = client.chat.completions.create( | |
| model="gpt-3.5-turbo", | |
| messages=[ | |
| {"role": "system", "content": "Bạn là chuyên gia phân tích tin tức."}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| temperature=0.7 | |
| ) | |
| explanation = response.choices[0].message.content | |
| st.markdown("---") | |
| st.markdown("🧠 **Phân tích chi tiết từ AI:**") | |
| st.markdown(explanation) | |
| except Exception as e: | |
| st.warning(f"Không thể tạo giải thích từ GPT: {e}") | |
| except Exception as e: | |
| st.error(f"❌ Lỗi trong quá trình dự đoán: {e}") | |
| st.markdown("---") | |
| st.caption("🧪 Ứng dụng này được phát triển cho mục đích học tập và minh họa.") |