Really-amin's picture
Upload 317 files
eebf5c4 verified
#!/usr/bin/env python3
"""
ادغام مدل‌های HuggingFace برای تحلیل هوش مصنوعی
HuggingFace Models Integration for AI Analysis
"""
import asyncio
from typing import List, Dict, Optional, Any
from datetime import datetime
import logging
try:
from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification
TRANSFORMERS_AVAILABLE = True
except ImportError:
TRANSFORMERS_AVAILABLE = False
logging.warning("⚠️ transformers not installed. AI features will be limited.")
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class HuggingFaceAnalyzer:
"""
تحلیل‌گر هوش مصنوعی با استفاده از مدل‌های HuggingFace
AI Analyzer using HuggingFace models
"""
def __init__(self):
self.models_loaded = False
self.sentiment_analyzer = None
self.zero_shot_classifier = None
if TRANSFORMERS_AVAILABLE:
self._load_models()
def _load_models(self):
"""بارگذاری مدل‌های HuggingFace"""
try:
logger.info("🤗 Loading HuggingFace models...")
# Sentiment Analysis Model - FinBERT (specialized for financial text)
try:
self.sentiment_analyzer = pipeline(
"sentiment-analysis",
model="ProsusAI/finbert",
tokenizer="ProsusAI/finbert"
)
logger.info("✅ Loaded FinBERT for sentiment analysis")
except Exception as e:
logger.warning(f"⚠️ Could not load FinBERT: {e}")
# Fallback to general sentiment model
try:
self.sentiment_analyzer = pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english"
)
logger.info("✅ Loaded DistilBERT for sentiment analysis (fallback)")
except Exception as e2:
logger.error(f"❌ Could not load sentiment model: {e2}")
# Zero-shot Classification (for categorizing news/tweets)
try:
self.zero_shot_classifier = pipeline(
"zero-shot-classification",
model="facebook/bart-large-mnli"
)
logger.info("✅ Loaded BART for zero-shot classification")
except Exception as e:
logger.warning(f"⚠️ Could not load zero-shot classifier: {e}")
self.models_loaded = True
logger.info("🎉 HuggingFace models loaded successfully!")
except Exception as e:
logger.error(f"❌ Error loading models: {e}")
self.models_loaded = False
async def analyze_news_sentiment(self, news_text: str) -> Dict[str, Any]:
"""
تحلیل احساسات یک خبر
Analyze sentiment of a news article
"""
if not self.models_loaded or not self.sentiment_analyzer:
return {
"sentiment": "neutral",
"confidence": 0.0,
"error": "Model not available"
}
try:
# Truncate text to avoid token limit
max_length = 512
text = news_text[:max_length]
# Run sentiment analysis
result = self.sentiment_analyzer(text)[0]
# Map FinBERT labels to standard format
label_map = {
"positive": "bullish",
"negative": "bearish",
"neutral": "neutral"
}
sentiment = label_map.get(result['label'].lower(), result['label'].lower())
return {
"sentiment": sentiment,
"confidence": round(result['score'], 4),
"raw_label": result['label'],
"text_analyzed": text[:100] + "...",
"model": "finbert",
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"❌ Sentiment analysis error: {e}")
return {
"sentiment": "neutral",
"confidence": 0.0,
"error": str(e)
}
async def analyze_news_batch(self, news_list: List[Dict]) -> List[Dict]:
"""
تحلیل دسته‌ای احساسات اخبار
Batch sentiment analysis for news
"""
results = []
for news in news_list:
text = f"{news.get('title', '')} {news.get('description', '')}"
sentiment_result = await self.analyze_news_sentiment(text)
results.append({
**news,
"ai_sentiment": sentiment_result['sentiment'],
"ai_confidence": sentiment_result['confidence'],
"ai_analysis": sentiment_result
})
# Small delay to avoid overloading
await asyncio.sleep(0.1)
return results
async def categorize_news(self, news_text: str) -> Dict[str, Any]:
"""
دسته‌بندی اخبار با zero-shot classification
Categorize news using zero-shot classification
"""
if not self.models_loaded or not self.zero_shot_classifier:
return {
"category": "general",
"confidence": 0.0,
"error": "Model not available"
}
try:
# Define categories
categories = [
"price_movement",
"regulation",
"technology",
"adoption",
"security",
"defi",
"nft",
"exchange",
"mining",
"general"
]
# Truncate text
text = news_text[:512]
# Run classification
result = self.zero_shot_classifier(text, categories)
return {
"category": result['labels'][0],
"confidence": round(result['scores'][0], 4),
"all_categories": [
{"label": label, "score": round(score, 4)}
for label, score in zip(result['labels'][:3], result['scores'][:3])
],
"model": "bart-mnli",
"timestamp": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"❌ Categorization error: {e}")
return {
"category": "general",
"confidence": 0.0,
"error": str(e)
}
async def calculate_aggregated_sentiment(
self,
news_list: List[Dict],
symbol: Optional[str] = None
) -> Dict[str, Any]:
"""
محاسبه احساسات جمعی از چندین خبر
Calculate aggregated sentiment from multiple news items
"""
if not news_list:
return {
"overall_sentiment": "neutral",
"sentiment_score": 0.0,
"confidence": 0.0,
"news_count": 0
}
# Filter by symbol if provided
if symbol:
news_list = [
n for n in news_list
if symbol.upper() in [c.upper() for c in n.get('coins', [])]
]
if not news_list:
return {
"overall_sentiment": "neutral",
"sentiment_score": 0.0,
"confidence": 0.0,
"news_count": 0,
"note": f"No news found for {symbol}"
}
# Analyze each news item
analyzed_news = await self.analyze_news_batch(news_list[:20]) # Limit to 20
# Calculate weighted sentiment
bullish_count = 0
bearish_count = 0
neutral_count = 0
total_confidence = 0.0
for news in analyzed_news:
sentiment = news.get('ai_sentiment', 'neutral')
confidence = news.get('ai_confidence', 0.0)
if sentiment == 'bullish':
bullish_count += confidence
elif sentiment == 'bearish':
bearish_count += confidence
else:
neutral_count += confidence
total_confidence += confidence
# Calculate overall sentiment score (-100 to +100)
if total_confidence > 0:
sentiment_score = ((bullish_count - bearish_count) / total_confidence) * 100
else:
sentiment_score = 0.0
# Determine overall classification
if sentiment_score > 30:
overall = "bullish"
elif sentiment_score < -30:
overall = "bearish"
else:
overall = "neutral"
return {
"overall_sentiment": overall,
"sentiment_score": round(sentiment_score, 2),
"confidence": round(total_confidence / len(analyzed_news), 2) if analyzed_news else 0.0,
"news_count": len(analyzed_news),
"bullish_weight": round(bullish_count, 2),
"bearish_weight": round(bearish_count, 2),
"neutral_weight": round(neutral_count, 2),
"symbol": symbol,
"timestamp": datetime.now().isoformat()
}
async def predict_price_direction(
self,
symbol: str,
recent_news: List[Dict],
current_price: float,
historical_prices: List[float]
) -> Dict[str, Any]:
"""
پیش‌بینی جهت قیمت بر اساس اخبار و روند قیمت
Predict price direction based on news sentiment and price trend
"""
# Get news sentiment
news_sentiment = await self.calculate_aggregated_sentiment(recent_news, symbol)
# Calculate price trend
if len(historical_prices) >= 2:
price_change = ((current_price - historical_prices[0]) / historical_prices[0]) * 100
else:
price_change = 0.0
# Combine signals
# News sentiment weight: 60%
# Price momentum weight: 40%
news_score = news_sentiment['sentiment_score'] * 0.6
momentum_score = min(50, max(-50, price_change * 10)) * 0.4
combined_score = news_score + momentum_score
# Determine prediction
if combined_score > 20:
prediction = "bullish"
direction = "up"
elif combined_score < -20:
prediction = "bearish"
direction = "down"
else:
prediction = "neutral"
direction = "sideways"
# Calculate confidence
confidence = min(1.0, abs(combined_score) / 100)
return {
"symbol": symbol,
"prediction": prediction,
"direction": direction,
"confidence": round(confidence, 2),
"combined_score": round(combined_score, 2),
"news_sentiment_score": round(news_score / 0.6, 2),
"price_momentum_score": round(momentum_score / 0.4, 2),
"current_price": current_price,
"price_change_pct": round(price_change, 2),
"news_analyzed": news_sentiment['news_count'],
"timestamp": datetime.now().isoformat(),
"model": "combined_analysis"
}
class SimpleHuggingFaceAnalyzer:
"""
نسخه ساده برای زمانی که transformers نصب نیست
Simplified version when transformers is not available
Uses simple keyword-based sentiment
"""
async def analyze_news_sentiment(self, news_text: str) -> Dict[str, Any]:
"""Simple keyword-based sentiment"""
text_lower = news_text.lower()
# Bullish keywords
bullish_keywords = [
'bullish', 'surge', 'rally', 'gain', 'rise', 'soar',
'adoption', 'breakthrough', 'positive', 'growth', 'boom'
]
# Bearish keywords
bearish_keywords = [
'bearish', 'crash', 'plunge', 'drop', 'fall', 'decline',
'regulation', 'ban', 'hack', 'scam', 'negative', 'crisis'
]
bullish_count = sum(1 for word in bullish_keywords if word in text_lower)
bearish_count = sum(1 for word in bearish_keywords if word in text_lower)
if bullish_count > bearish_count:
sentiment = "bullish"
confidence = min(0.8, bullish_count * 0.2)
elif bearish_count > bullish_count:
sentiment = "bearish"
confidence = min(0.8, bearish_count * 0.2)
else:
sentiment = "neutral"
confidence = 0.5
return {
"sentiment": sentiment,
"confidence": confidence,
"method": "keyword_based",
"timestamp": datetime.now().isoformat()
}
# Factory function
def get_analyzer() -> Any:
"""Get appropriate analyzer based on availability"""
if TRANSFORMERS_AVAILABLE:
return HuggingFaceAnalyzer()
else:
logger.warning("⚠️ Using simple analyzer (transformers not available)")
return SimpleHuggingFaceAnalyzer()
async def main():
"""Test HuggingFace models"""
print("\n" + "="*70)
print("🤗 Testing HuggingFace AI Models")
print("="*70)
analyzer = get_analyzer()
# Test sentiment analysis
test_news = [
"Bitcoin surges past $50,000 as institutional adoption accelerates",
"SEC delays decision on crypto ETF, causing market uncertainty",
"Ethereum network upgrade successfully completed without issues"
]
print("\n📊 Testing Sentiment Analysis:")
for i, news in enumerate(test_news, 1):
result = await analyzer.analyze_news_sentiment(news)
print(f"\n{i}. {news[:60]}...")
print(f" Sentiment: {result['sentiment']}")
print(f" Confidence: {result['confidence']:.2%}")
# Test if advanced features available
if isinstance(analyzer, HuggingFaceAnalyzer) and analyzer.models_loaded:
print("\n\n🎯 Testing News Categorization:")
categorization = await analyzer.categorize_news(test_news[0])
print(f" Category: {categorization['category']}")
print(f" Confidence: {categorization['confidence']:.2%}")
print("\n\n📈 Testing Aggregated Sentiment:")
mock_news = [
{"title": news, "description": "", "coins": ["BTC"]}
for news in test_news
]
agg_sentiment = await analyzer.calculate_aggregated_sentiment(mock_news, "BTC")
print(f" Overall: {agg_sentiment['overall_sentiment']}")
print(f" Score: {agg_sentiment['sentiment_score']}/100")
print(f" Confidence: {agg_sentiment['confidence']:.2%}")
if __name__ == "__main__":
asyncio.run(main())