HH/apps/ai_engine/utils.py
2025-12-24 14:10:18 +03:00

279 lines
6.5 KiB
Python

"""
AI Engine utility functions
"""
from typing import Optional
from django.contrib.contenttypes.models import ContentType
from .models import SentimentResult
def get_sentiment_badge_class(sentiment: str) -> str:
"""
Get Bootstrap badge class for sentiment.
Args:
sentiment: Sentiment value ('positive', 'neutral', 'negative')
Returns:
Bootstrap badge class
"""
badge_classes = {
'positive': 'bg-success',
'neutral': 'bg-secondary',
'negative': 'bg-danger',
}
return badge_classes.get(sentiment, 'bg-secondary')
def get_sentiment_icon(sentiment: str) -> str:
"""
Get icon for sentiment.
Args:
sentiment: Sentiment value ('positive', 'neutral', 'negative')
Returns:
Icon class or emoji
"""
icons = {
'positive': '😊',
'neutral': '😐',
'negative': '😞',
}
return icons.get(sentiment, '😐')
def format_sentiment_score(score: float) -> str:
"""
Format sentiment score for display.
Args:
score: Sentiment score (-1 to 1)
Returns:
Formatted score string
"""
return f"{score:+.2f}"
def format_confidence(confidence: float) -> str:
"""
Format confidence as percentage.
Args:
confidence: Confidence value (0 to 1)
Returns:
Formatted percentage string
"""
return f"{confidence * 100:.1f}%"
def get_sentiment_color(sentiment: str) -> str:
"""
Get color code for sentiment.
Args:
sentiment: Sentiment value ('positive', 'neutral', 'negative')
Returns:
Hex color code
"""
colors = {
'positive': '#28a745', # Green
'neutral': '#6c757d', # Gray
'negative': '#dc3545', # Red
}
return colors.get(sentiment, '#6c757d')
def get_emotion_icon(emotion: str) -> str:
"""
Get icon/emoji for emotion.
Args:
emotion: Emotion name
Returns:
Emoji representing the emotion
"""
icons = {
'joy': '😄',
'anger': '😠',
'sadness': '😢',
'fear': '😨',
'surprise': '😲',
'disgust': '🤢',
'trust': '🤝',
'anticipation': '🤔',
}
return icons.get(emotion, '😐')
def has_sentiment_analysis(obj) -> bool:
"""
Check if an object has sentiment analysis.
Args:
obj: Django model instance
Returns:
True if sentiment analysis exists
"""
content_type = ContentType.objects.get_for_model(obj)
return SentimentResult.objects.filter(
content_type=content_type,
object_id=obj.id
).exists()
def get_latest_sentiment(obj) -> Optional[SentimentResult]:
"""
Get the latest sentiment analysis for an object.
Args:
obj: Django model instance
Returns:
SentimentResult instance or None
"""
content_type = ContentType.objects.get_for_model(obj)
return SentimentResult.objects.filter(
content_type=content_type,
object_id=obj.id
).first()
def get_sentiment_summary(sentiment_score: float) -> str:
"""
Get human-readable sentiment summary.
Args:
sentiment_score: Sentiment score (-1 to 1)
Returns:
Human-readable summary
"""
if sentiment_score >= 0.6:
return "Very Positive"
elif sentiment_score >= 0.2:
return "Positive"
elif sentiment_score >= -0.2:
return "Neutral"
elif sentiment_score >= -0.6:
return "Negative"
else:
return "Very Negative"
def calculate_sentiment_trend(results: list) -> dict:
"""
Calculate sentiment trend from a list of results.
Args:
results: List of SentimentResult instances
Returns:
Dictionary with trend information
"""
if not results:
return {
'direction': 'stable',
'change': 0,
'description': 'No data'
}
# Calculate average scores for first and second half
mid_point = len(results) // 2
first_half = results[:mid_point]
second_half = results[mid_point:]
if not first_half or not second_half:
return {
'direction': 'stable',
'change': 0,
'description': 'Insufficient data'
}
first_avg = sum(float(r.sentiment_score) for r in first_half) / len(first_half)
second_avg = sum(float(r.sentiment_score) for r in second_half) / len(second_half)
change = second_avg - first_avg
if change > 0.1:
direction = 'improving'
description = 'Sentiment is improving'
elif change < -0.1:
direction = 'declining'
description = 'Sentiment is declining'
else:
direction = 'stable'
description = 'Sentiment is stable'
return {
'direction': direction,
'change': change,
'description': description
}
def get_top_keywords(results: list, limit: int = 10) -> list:
"""
Get top keywords from a list of sentiment results.
Args:
results: List of SentimentResult instances
limit: Maximum number of keywords to return
Returns:
List of (keyword, count) tuples
"""
from collections import Counter
all_keywords = []
for result in results:
all_keywords.extend(result.keywords)
keyword_counts = Counter(all_keywords)
return keyword_counts.most_common(limit)
def get_sentiment_distribution(results: list) -> dict:
"""
Get sentiment distribution from a list of results.
Args:
results: List of SentimentResult instances
Returns:
Dictionary with sentiment counts and percentages
"""
total = len(results)
if total == 0:
return {
'positive': {'count': 0, 'percentage': 0},
'neutral': {'count': 0, 'percentage': 0},
'negative': {'count': 0, 'percentage': 0},
}
positive = sum(1 for r in results if r.sentiment == 'positive')
neutral = sum(1 for r in results if r.sentiment == 'neutral')
negative = sum(1 for r in results if r.sentiment == 'negative')
return {
'positive': {
'count': positive,
'percentage': round((positive / total) * 100, 1)
},
'neutral': {
'count': neutral,
'percentage': round((neutral / total) * 100, 1)
},
'negative': {
'count': negative,
'percentage': round((negative / total) * 100, 1)
},
}