HH/apps/feedback/tasks.py
2026-04-08 17:13:35 +03:00

162 lines
3.5 KiB
Python

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}