import logging from celery import shared_task logger = logging.getLogger(__name__) POSITIVE_WORDS = { "excellent", "amazing", "wonderful", "great", "good", "fantastic", "outstanding", "helpful", "friendly", "professional", "kind", "caring", "clean", "comfortable", "satisfied", "impressed", "thankful", "grateful", "appreciate", "perfect", "superb", "brilliant", "exceptional", "positive", "recommend", "pleasant", "courteous", "efficient", "prompt", "compassionate", "skilled", "best", } NEGATIVE_WORDS = { "terrible", "awful", "horrible", "bad", "poor", "worst", "rude", "unprofessional", "dirty", "uncomfortable", "dissatisfied", "disappointed", "frustrated", "angry", "slow", "waiting", "waited", "delay", "delayed", "neglect", "neglected", "ignored", "complaint", "unacceptable", "never", "not", "no", "cannot", "painful", "careless", "arrogant", "unhelpful", "overpriced", "expensive", "messy", "noisy", "unsafe", "incompetent", "wrong", "mistake", "error", } def _analyze_text(text): if not text: return 0.0, 0, 0 words = text.lower().split() total = len(words) or 1 positive_hits = sum(1 for w in words if w in POSITIVE_WORDS) negative_hits = sum(1 for w in words if w in NEGATIVE_WORDS) score = (positive_hits - negative_hits) / total return max(-1.0, min(1.0, score)), positive_hits, negative_hits @shared_task def analyze_feedback_sentiment(feedback_id): from apps.feedback.models import Feedback, SentimentChoices try: feedback = Feedback.objects.get(id=feedback_id) except Feedback.DoesNotExist: logger.error(f"Feedback {feedback_id} not found") return {"status": "error", "reason": "not_found"} title_score, title_pos, title_neg = _analyze_text(feedback.title or "") message_score, msg_pos, msg_neg = _analyze_text(feedback.message or "") total_pos = title_pos + msg_pos total_neg = title_neg + msg_neg combined_score = (title_score + message_score) / 2 if (title_score or message_score) else 0.0 if combined_score > 0.05: sentiment = SentimentChoices.POSITIVE elif combined_score < -0.05: sentiment = SentimentChoices.NEGATIVE else: sentiment = SentimentChoices.NEUTRAL sentiment_score = round(combined_score, 4) feedback.sentiment = sentiment feedback.sentiment_score = sentiment_score feedback.save(update_fields=["sentiment", "sentiment_score"]) logger.info( f"Sentiment analysis for feedback {feedback_id}: " f"sentiment={sentiment}, score={sentiment_score} " f"(pos={total_pos}, neg={total_neg})" ) return { "status": "success", "feedback_id": str(feedback_id), "sentiment": sentiment, "sentiment_score": sentiment_score, "positive_hits": total_pos, "negative_hits": total_neg, } @shared_task def process_pending_sentiment_analysis(): from apps.feedback.models import Feedback pending = Feedback.objects.filter(sentiment="neutral", sentiment_score__isnull=True)[:100] dispatched = 0 for feedback in pending: analyze_feedback_sentiment.delay(str(feedback.id)) dispatched += 1 logger.info(f"Dispatched sentiment analysis for {dispatched} pending feedbacks") return {"dispatched": dispatched}