Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import feedparser | |
| import pandas as pd | |
| import numpy as np | |
| import faiss | |
| import matplotlib.pyplot as plt | |
| import re | |
| from collections import Counter | |
| from sentence_transformers import SentenceTransformer | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline | |
| import torch | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # Global değişkenler | |
| model = None | |
| sentiment_analyzer = None | |
| summarizer = None | |
| df = None | |
| index = None | |
| embeddings = None | |
| def initialize_models(): | |
| """FinBERT ve özetleme modellerini yükle""" | |
| global model, sentiment_analyzer, summarizer | |
| try: | |
| if model is None: | |
| model = SentenceTransformer('all-MiniLM-L6-v2') | |
| if sentiment_analyzer is None: | |
| # FinBERT modelini yükle | |
| tokenizer = AutoTokenizer.from_pretrained("ProsusAI/finbert") | |
| finbert_model = AutoModelForSequenceClassification.from_pretrained("ProsusAI/finbert") | |
| sentiment_analyzer = pipeline( | |
| "sentiment-analysis", | |
| model=finbert_model, | |
| tokenizer=tokenizer, | |
| device=-1 # CPU kullan (GPU için 0) | |
| ) | |
| if summarizer is None: | |
| # Özetleme modeli | |
| summarizer = pipeline( | |
| "summarization", | |
| model="facebook/bart-large-cnn", | |
| device=-1 | |
| ) | |
| return "✅ FinBERT ve özetleme modelleri başarıyla yüklendi!" | |
| except Exception as e: | |
| return f"❌ Model yükleme hatası: {str(e)}" | |
| def fetch_news(): | |
| """RSS feedlerinden haberleri topla""" | |
| global df, index, embeddings | |
| RSS_URLS = [ | |
| "https://cointelegraph.com/rss", | |
| "https://cryptonews.com/news/feed", | |
| "https://www.coindesk.com/arc/outboundfeeds/rss/", | |
| "https://tr.investing.com/rss/302.rss" | |
| ] | |
| all_entries = [] | |
| status_messages = [] | |
| for url in RSS_URLS: | |
| try: | |
| feed = feedparser.parse(url) | |
| for entry in feed.entries[:30]: | |
| all_entries.append({ | |
| "title": entry.get("title", ""), | |
| "link": entry.get("link", ""), | |
| "summary": entry.get("summary", ""), | |
| "published": entry.get("published", "") | |
| }) | |
| status_messages.append(f"✓ {url.split('/')[2]} - {len(feed.entries[:30])} haber") | |
| except Exception as e: | |
| status_messages.append(f"✗ {url.split('/')[2]} - Hata") | |
| df = pd.DataFrame(all_entries).drop_duplicates(subset="title").reset_index(drop=True) | |
| # FinBERT ile sentiment analizi | |
| if df is not None and len(df) > 0: | |
| def analyze_sentiment_finbert(text): | |
| try: | |
| # FinBERT maksimum 512 token kabul eder | |
| text = text[:512] | |
| result = sentiment_analyzer(text)[0] | |
| # FinBERT çıktıları: positive, negative, neutral | |
| label = result['label'].lower() | |
| score = result['score'] | |
| return label, score | |
| except Exception as e: | |
| return "neutral", 0.5 | |
| df["sentiment_label"], df["sentiment_score"] = zip(*df["title"].apply(analyze_sentiment_finbert)) | |
| # FAISS index oluştur | |
| corpus = df['title'].tolist() | |
| embeddings = model.encode(corpus) | |
| dimension = embeddings.shape[1] | |
| index = faiss.IndexFlatL2(dimension) | |
| index.add(embeddings.astype('float32')) | |
| status = "\n".join(status_messages) | |
| status += f"\n\n✅ Toplam {len(df)} benzersiz haber toplandı ve FinBERT ile analiz edildi!" | |
| return status, df[["title", "sentiment_label", "published"]].head(10) | |
| def generate_news_summary(): | |
| """Haberlerin genel özetini oluştur""" | |
| global df | |
| if df is None or len(df) == 0: | |
| return "⚠️ Önce haberleri toplamalısınız!", None, None | |
| try: | |
| # Sentiment istatistikleri | |
| sentiment_counts = df["sentiment_label"].value_counts() | |
| total_news = len(df) | |
| positive_count = sentiment_counts.get('positive', 0) | |
| negative_count = sentiment_counts.get('negative', 0) | |
| neutral_count = sentiment_counts.get('neutral', 0) | |
| positive_pct = (positive_count / total_news) * 100 | |
| negative_pct = (negative_count / total_news) * 100 | |
| neutral_pct = (neutral_count / total_news) * 100 | |
| # Genel duygu | |
| if positive_pct > 50: | |
| overall_sentiment = "📈 POZITIF" | |
| sentiment_emoji = "🟢" | |
| elif negative_pct > 50: | |
| overall_sentiment = "📉 NEGATIF" | |
| sentiment_emoji = "🔴" | |
| else: | |
| overall_sentiment = "➡️ NÖTR" | |
| sentiment_emoji = "🟡" | |
| # En çok bahsedilen kelimeler | |
| all_titles = " ".join(df["title"].tolist()) | |
| potential_coins = re.findall(r'\b[A-Z][a-zA-Z]+\b', all_titles) | |
| stop_words = { | |
| "Coin", "Price", "Market", "News", "Today", "Crypto", "Token", | |
| "The", "This", "That", "What", "When", "Where", "How", "Why", | |
| "And", "But", "For", "From", "With", "About", "After", "Before" | |
| } | |
| filtered_tokens = [t for t in potential_coins if t not in stop_words] | |
| trending = Counter(filtered_tokens).most_common(5) | |
| # En önemli haberler | |
| top_positive = df.nlargest(3, "sentiment_score")[["title", "sentiment_score"]] | |
| top_negative = df.nsmallest(3, "sentiment_score")[["title", "sentiment_score"]] | |
| # Özet metni oluştur | |
| summary_text = f""" | |
| # 🌐 GÜNCEL KRİPTO HABER ÖZETİ | |
| ## {sentiment_emoji} Genel Durum: {overall_sentiment} | |
| ### 📊 Sentiment Dağılımı | |
| - **Toplam Haber:** {total_news} | |
| - 🟢 **Pozitif:** {positive_count} (%{positive_pct:.1f}) | |
| - 🔴 **Negatif:** {negative_count} (%{negative_pct:.1f}) | |
| - 🟡 **Nötr:** {neutral_count} (%{neutral_pct:.1f}) | |
| ### 🔥 En Çok Bahsedilen Konular | |
| """ | |
| for i, (term, count) in enumerate(trending, 1): | |
| summary_text += f"{i}. **{term}** - {count} kez bahsedildi\n" | |
| summary_text += "\n### ⭐ En Pozitif Haberler\n" | |
| for idx, row in top_positive.iterrows(): | |
| summary_text += f"- {row['title'][:100]}... (Skor: {row['sentiment_score']:.3f})\n" | |
| summary_text += "\n### ⚠️ En Negatif Haberler\n" | |
| for idx, row in top_negative.iterrows(): | |
| summary_text += f"- {row['title'][:100]}... (Skor: {row['sentiment_score']:.3f})\n" | |
| # Grafik oluştur | |
| fig, axes = plt.subplots(1, 2, figsize=(14, 5)) | |
| # Sentiment dağılımı | |
| ax1 = axes[0] | |
| color_map = { | |
| 'positive': '#2ecc71', | |
| 'negative': '#e74c3c', | |
| 'neutral': '#95a5a6' | |
| } | |
| colors = [color_map.get(x, '#95a5a6') for x in sentiment_counts.index] | |
| ax1.pie(sentiment_counts.values, labels=sentiment_counts.index, autopct='%1.1f%%', | |
| colors=colors, startangle=90, textprops={'fontsize': 12, 'fontweight': 'bold'}) | |
| ax1.set_title('Genel Sentiment Dağılımı', fontweight='bold', fontsize=14) | |
| # Trend grafiği | |
| ax2 = axes[1] | |
| if len(trending) > 0: | |
| terms, counts = zip(*trending) | |
| ax2.barh(terms, counts, color='#3498db', alpha=0.7) | |
| ax2.set_xlabel('Frekans', fontweight='bold', fontsize=11) | |
| ax2.set_title('En Popüler 5 Konu', fontweight='bold', fontsize=14) | |
| ax2.invert_yaxis() | |
| ax2.grid(axis='x', alpha=0.3) | |
| plt.tight_layout() | |
| # Özet tablo | |
| summary_table = pd.DataFrame({ | |
| 'Metric': ['Toplam Haber', 'Pozitif', 'Negatif', 'Nötr', 'Genel Durum'], | |
| 'Value': [total_news, positive_count, negative_count, neutral_count, overall_sentiment] | |
| }) | |
| return summary_text, fig, summary_table | |
| except Exception as e: | |
| return f"❌ Özet oluşturma hatası: {str(e)}", None, None | |
| def search_similar_news(query, top_k=5): | |
| """Semantik arama""" | |
| global df, index, model | |
| if df is None or index is None: | |
| return "⚠️ Önce haberleri toplamalısınız!", None | |
| try: | |
| q_embedding = model.encode([query]) | |
| distances, indices = index.search(q_embedding.astype('float32'), k=min(top_k, len(df))) | |
| results = [] | |
| for idx, dist in zip(indices[0], distances[0]): | |
| news = df.iloc[idx] | |
| results.append({ | |
| "Başlık": news['title'], | |
| "Sentiment": news['sentiment_label'], | |
| "Skor": f"{news['sentiment_score']:.3f}", | |
| "Link": news['link'] | |
| }) | |
| results_df = pd.DataFrame(results) | |
| message = f"🔎 '{query}' için {len(results)} sonuç bulundu" | |
| return message, results_df | |
| except Exception as e: | |
| return f"❌ Hata: {str(e)}", None | |
| def analyze_coin_sentiment(coin_name): | |
| """Coin bazlı sentiment analizi""" | |
| global df | |
| if df is None: | |
| return "⚠️ Önce haberleri toplamalısınız!", None, None | |
| filtered = df[df["title"].str.contains(coin_name, case=False, na=False)] | |
| if len(filtered) == 0: | |
| return f"⚠️ '{coin_name}' hakkında haber bulunamadı.", None, None | |
| # Sentiment dağılımı | |
| sentiment_dist = filtered["sentiment_label"].value_counts() | |
| # Grafik oluştur | |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) | |
| # Renk haritası (FinBERT için) | |
| color_map = { | |
| 'positive': '#2ecc71', | |
| 'negative': '#e74c3c', | |
| 'neutral': '#95a5a6' | |
| } | |
| colors = [color_map.get(x, '#95a5a6') for x in sentiment_dist.index] | |
| # Bar chart | |
| ax1.bar(sentiment_dist.index, sentiment_dist.values, color=colors, alpha=0.7) | |
| ax1.set_title(f'{coin_name} - Sentiment Dağılımı (FinBERT)', fontweight='bold') | |
| ax1.set_ylabel('Haber Sayısı') | |
| ax1.grid(axis='y', alpha=0.3) | |
| # Pie chart | |
| ax2.pie(sentiment_dist.values, labels=sentiment_dist.index, autopct='%1.1f%%', | |
| colors=colors, startangle=90) | |
| ax2.set_title(f'{coin_name} - Yüzdelik Dağılım', fontweight='bold') | |
| plt.tight_layout() | |
| # Metin rapor | |
| total = len(filtered) | |
| report = f""" | |
| 📊 **{coin_name.upper()} ANALİZ RAPORU (FinBERT)** | |
| 📰 Toplam Haber: {total} | |
| 💭 **Sentiment Dağılımı:** | |
| """ | |
| for label, count in sentiment_dist.items(): | |
| percentage = (count / total) * 100 | |
| report += f"\n• {label.capitalize()}: {count} haber (%{percentage:.1f})" | |
| # En pozitif haberler | |
| top_positive = filtered.nlargest(3, "sentiment_score")[["title", "sentiment_score"]] | |
| report += "\n\n⭐ **En Pozitif 3 Haber:**\n" | |
| for idx, row in top_positive.iterrows(): | |
| report += f"\n• {row['title'][:80]}...\n Skor: {row['sentiment_score']:.3f}" | |
| # Tablo | |
| table_data = filtered[["title", "sentiment_label", "sentiment_score", "link"]].head(10) | |
| return report, fig, table_data | |
| def get_trending_topics(): | |
| """Trend analizi""" | |
| global df | |
| if df is None: | |
| return "⚠️ Önce haberleri toplamalısınız!", None, None | |
| all_titles = " ".join(df["title"].tolist()) | |
| potential_coins = re.findall(r'\b[A-Z][a-zA-Z]+\b', all_titles) | |
| stop_words = { | |
| "Coin", "Price", "Market", "News", "Today", "Crypto", "Token", | |
| "The", "This", "That", "What", "When", "Where", "How", "Why", | |
| "And", "But", "For", "From", "With", "About", "After", "Before" | |
| } | |
| filtered_tokens = [t for t in potential_coins if t not in stop_words] | |
| trending = Counter(filtered_tokens).most_common(10) | |
| # Grafik | |
| fig, ax = plt.subplots(figsize=(10, 6)) | |
| terms, counts = zip(*trending) | |
| ax.barh(terms, counts, color='#3498db', alpha=0.7) | |
| ax.set_xlabel('Frekans', fontweight='bold') | |
| ax.set_title('En Çok Bahsedilen 10 Terim', fontweight='bold', fontsize=14) | |
| ax.invert_yaxis() | |
| ax.grid(axis='x', alpha=0.3) | |
| plt.tight_layout() | |
| # Tablo | |
| trend_df = pd.DataFrame(trending, columns=["Terim", "Frekans"]) | |
| message = f"🔥 En popüler terim: **{trending[0][0]}** ({trending[0][1]} kez bahsedildi)" | |
| return message, fig, trend_df | |
| def create_overview_chart(): | |
| """Genel sentiment grafiği""" | |
| global df | |
| if df is None: | |
| return "⚠️ Önce haberleri toplamalısınız!" | |
| fig, axes = plt.subplots(2, 2, figsize=(12, 10)) | |
| fig.suptitle('Kripto Haber Analizi - Genel Bakış (FinBERT)', fontsize=16, fontweight='bold') | |
| # Renk haritası | |
| color_map = { | |
| 'positive': '#2ecc71', | |
| 'negative': '#e74c3c', | |
| 'neutral': '#95a5a6' | |
| } | |
| # 1. Genel sentiment | |
| ax1 = axes[0, 0] | |
| sentiment_counts = df["sentiment_label"].value_counts() | |
| colors = [color_map.get(x, '#95a5a6') for x in sentiment_counts.index] | |
| ax1.bar(sentiment_counts.index, sentiment_counts.values, color=colors, alpha=0.7) | |
| ax1.set_title('Tüm Haberlerde Sentiment', fontweight='bold') | |
| ax1.set_ylabel('Haber Sayısı') | |
| ax1.grid(axis='y', alpha=0.3) | |
| # 2. Skor dağılımı | |
| ax2 = axes[0, 1] | |
| positive_scores = df[df["sentiment_label"] == "positive"]["sentiment_score"] | |
| negative_scores = df[df["sentiment_label"] == "negative"]["sentiment_score"] | |
| neutral_scores = df[df["sentiment_label"] == "neutral"]["sentiment_score"] | |
| ax2.hist([positive_scores, negative_scores, neutral_scores], bins=15, | |
| label=['Positive', 'Negative', 'Neutral'], | |
| color=['#2ecc71', '#e74c3c', '#95a5a6'], alpha=0.6) | |
| ax2.set_title('Sentiment Skor Dağılımı', fontweight='bold') | |
| ax2.set_xlabel('Güven Skoru') | |
| ax2.legend() | |
| ax2.grid(axis='y', alpha=0.3) | |
| # 3. Kaynak dağılımı | |
| ax3 = axes[1, 0] | |
| sources = df["link"].apply(lambda x: x.split('/')[2] if '/' in x else 'Unknown') | |
| source_counts = sources.value_counts().head(5) | |
| ax3.barh(source_counts.index, source_counts.values, color='#9b59b6', alpha=0.7) | |
| ax3.set_title('En Çok Haber Kaynağı', fontweight='bold') | |
| ax3.set_xlabel('Haber Sayısı') | |
| ax3.invert_yaxis() | |
| # 4. Pie chart | |
| ax4 = axes[1, 1] | |
| ax4.pie(sentiment_counts.values, labels=sentiment_counts.index, autopct='%1.1f%%', | |
| colors=colors, startangle=90) | |
| ax4.set_title('Sentiment Yüzdesi', fontweight='bold') | |
| plt.tight_layout() | |
| return fig | |
| # Gradio arayüzü | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Kripto Haber Analiz Platformu - FinBERT") as app: | |
| gr.Markdown(""" | |
| # 🚀 Kripto Haber Analiz Platformu (FinBERT) | |
| Bu uygulama kripto para haberlerini toplar ve **FinBERT** modeli ile finansal sentiment analizi yapar. | |
| ### 📋 Kullanım Adımları: | |
| 1. **"FinBERT Modelini Başlat"** butonuna tıklayın | |
| 2. **"Haberleri Topla ve Analiz Et"** butonuna tıklayın | |
| 3. **"Genel Özet"** sekmesinden haberlerin özetini görün | |
| 4. Diğer sekmeleri kullanarak detaylı analiz yapın | |
| ### 🎯 FinBERT Nedir? | |
| FinBERT, finansal metinler üzerinde eğitilmiş özel bir BERT modelidir. | |
| Kripto ve finans haberlerinde daha doğru sentiment analizi sağlar. | |
| """) | |
| with gr.Tab("🏠 Başlangıç"): | |
| gr.Markdown("### Sistemi Başlatın") | |
| init_btn = gr.Button("🔧 FinBERT Modelini Başlat (İlk adım)", variant="primary", size="lg") | |
| init_output = gr.Textbox(label="Durum", lines=2) | |
| gr.Markdown("---") | |
| fetch_btn = gr.Button("📰 Haberleri Topla ve Analiz Et (İkinci adım)", variant="primary", size="lg") | |
| fetch_output = gr.Textbox(label="Toplama Durumu", lines=10) | |
| fetch_table = gr.Dataframe(label="İlk 10 Haber") | |
| init_btn.click(initialize_models, outputs=init_output) | |
| fetch_btn.click(fetch_news, outputs=[fetch_output, fetch_table]) | |
| with gr.Tab("📰 Genel Özet"): | |
| gr.Markdown("### Tüm Haberlerin Genel Özeti") | |
| gr.Markdown("Toplanan tüm haberlerin sentiment analizi, en önemli haberler ve trend konuları.") | |
| summary_btn = gr.Button("📰 Genel Özet Oluştur", variant="primary", size="lg") | |
| summary_text = gr.Markdown(label="Özet Rapor") | |
| summary_chart = gr.Plot(label="Özet Grafikler") | |
| summary_table = gr.Dataframe(label="İstatistikler") | |
| summary_btn.click(generate_news_summary, outputs=[summary_text, summary_chart, summary_table]) | |
| with gr.Tab("🔍 Haber Arama"): | |
| gr.Markdown("### Semantik Arama ile Benzer Haberleri Bulun") | |
| with gr.Row(): | |
| search_input = gr.Textbox(label="Arama Sorgusu", placeholder="Örn: Bitcoin, Ethereum, NFT...") | |
| search_k = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Sonuç Sayısı") | |
| search_btn = gr.Button("🔎 Ara", variant="primary") | |
| search_status = gr.Textbox(label="Durum") | |
| search_results = gr.Dataframe(label="Sonuçlar") | |
| search_btn.click(search_similar_news, inputs=[search_input, search_k], | |
| outputs=[search_status, search_results]) | |
| with gr.Tab("📊 Coin Analizi"): | |
| gr.Markdown("### Belirli Bir Coin için Detaylı Sentiment Analizi (FinBERT)") | |
| coin_input = gr.Textbox(label="Coin Adı", placeholder="Örn: Bitcoin, Ethereum, Solana...") | |
| analyze_btn = gr.Button("📊 Analiz Et", variant="primary") | |
| coin_report = gr.Markdown(label="Rapor") | |
| coin_chart = gr.Plot(label="Grafikler") | |
| coin_table = gr.Dataframe(label="Detaylı Haberler") | |
| analyze_btn.click(analyze_coin_sentiment, inputs=coin_input, | |
| outputs=[coin_report, coin_chart, coin_table]) | |
| with gr.Tab("🔥 Trend Analizi"): | |
| gr.Markdown("### En Çok Bahsedilen Konular") | |
| trend_btn = gr.Button("🔥 Trendleri Göster", variant="primary") | |
| trend_status = gr.Markdown(label="Özet") | |
| trend_chart = gr.Plot(label="Trend Grafiği") | |
| trend_table = gr.Dataframe(label="Trend Tablosu") | |
| trend_btn.click(get_trending_topics, outputs=[trend_status, trend_chart, trend_table]) | |
| with gr.Tab("📈 Genel Bakış"): | |
| gr.Markdown("### Tüm Verilerin Genel Görünümü") | |
| overview_btn = gr.Button("📈 Genel İstatistikleri Göster", variant="primary") | |
| overview_chart = gr.Plot(label="Genel Grafikler") | |
| overview_btn.click(create_overview_chart, outputs=overview_chart) | |
| gr.Markdown(""" | |
| --- | |
| ### 💡 İpuçları: | |
| - FinBERT ilk çalıştırmada yüklendiği için biraz zaman alabilir | |
| - Haberler RSS feedlerinden gerçek zamanlı olarak çekilir | |
| - **Genel Özet** sekmesi tüm haberlerin analizini sunar | |
| - FinBERT finansal metinler için özelleştirilmiştir | |
| - FAISS kullanarak semantik benzerlik hesaplanır | |
| ### 🛠️ Kullanılan Teknolojiler: | |
| - **FinBERT (ProsusAI/finbert)**: Finansal sentiment analizi | |
| - **Sentence Transformers**: Semantik embedding | |
| - **FAISS**: Hızlı benzerlik araması | |
| - **Gradio**: Kullanıcı arayüzü | |
| ### 📊 FinBERT Çıktıları: | |
| - **Positive**: Pozitif finansal sentiment | |
| - **Negative**: Negatif finansal sentiment | |
| - **Neutral**: Nötr finansal sentiment | |
| """) | |
| # Uygulamayı başlat | |
| if __name__ == "__main__": | |
| app.launch() |