""" Social Media UI views - Server-rendered templates for social media monitoring """ from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q, Count, Avg, Sum from django.http import JsonResponse from django.shortcuts import render, redirect from django.views.decorators.http import require_http_methods from .models import SocialMediaComment, SocialPlatform @login_required def social_comment_list(request): """ Social media comments list view with advanced filters and pagination. Features: - Server-side pagination - Advanced filters (platform, sentiment, date range, etc.) - Search by comment text, author - Export capability """ # Base queryset queryset = SocialMediaComment.objects.all() # Apply filters from request platform_filter = request.GET.get('platform') if platform_filter: queryset = queryset.filter(platform=platform_filter) sentiment_filter = request.GET.get('sentiment') if sentiment_filter: # Filter by sentiment in ai_analysis JSONField queryset = queryset.filter( ai_analysis__sentiment__classification__en=sentiment_filter ) analyzed_filter = request.GET.get('analyzed') if analyzed_filter == 'true': queryset = queryset.exclude(ai_analysis__isnull=True).exclude(ai_analysis={}) elif analyzed_filter == 'false': queryset = queryset.filter(ai_analysis__isnull=True) | queryset.filter(ai_analysis={}) # Date range filters date_from = request.GET.get('date_from') if date_from: queryset = queryset.filter(published_at__gte=date_from) date_to = request.GET.get('date_to') if date_to: queryset = queryset.filter(published_at__lte=date_to) # Minimum likes min_likes = request.GET.get('min_likes') if min_likes: queryset = queryset.filter(like_count__gte=min_likes) # Search search_query = request.GET.get('search') if search_query: queryset = queryset.filter( Q(comments__icontains=search_query) | Q(author__icontains=search_query) | Q(comment_id__icontains=search_query) ) # Ordering order_by = request.GET.get('order_by', '-published_at') queryset = queryset.order_by(order_by) # Pagination page_size = int(request.GET.get('page_size', 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get('page', 1) page_obj = paginator.get_page(page_number) # Get platform choices platforms = SocialPlatform.choices # Calculate statistics from queryset (using ai_analysis) total_comments = queryset.count() analyzed_comments = 0 positive_count = 0 negative_count = 0 neutral_count = 0 for comment in queryset: if comment.ai_analysis: analyzed_comments += 1 sentiment = comment.ai_analysis.get('sentiment', {}).get('classification', {}).get('en', 'neutral') if sentiment == 'positive': positive_count += 1 elif sentiment == 'negative': negative_count += 1 else: neutral_count += 1 stats = { 'total': total_comments, 'analyzed': analyzed_comments, 'unanalyzed': total_comments - analyzed_comments, 'positive': positive_count, 'negative': negative_count, 'neutral': neutral_count, } # Add platform-specific counts for platform_code, platform_name in platforms: stats[platform_code] = SocialMediaComment.objects.filter(platform=platform_code).count() context = { 'page_obj': page_obj, 'comments': page_obj.object_list, 'stats': stats, 'platforms': platforms, 'filters': request.GET, } return render(request, 'social/social_comment_list.html', context) @login_required def social_comment_detail(request, pk): """ Social media comment detail view. Features: - Full comment details - Raw data view - AI analysis results - Keywords and topics - Entities extracted """ from django.shortcuts import get_object_or_404 comment = get_object_or_404(SocialMediaComment, pk=pk) context = { 'comment': comment, } return render(request, 'social/social_comment_detail.html', context) @login_required def social_platform(request, platform): """ Platform-specific social media comments view. Features: - Filtered comments for specific platform - Platform-specific branding and metrics - Time-based filtering - Platform-specific trends """ # Validate platform valid_platforms = [choice[0] for choice in SocialPlatform.choices] if platform not in valid_platforms: messages.error(request, f"Invalid platform: {platform}") return redirect('social:social_comment_list') # Base queryset filtered by platform queryset = SocialMediaComment.objects.filter(platform=platform) # Apply additional filters sentiment_filter = request.GET.get('sentiment') if sentiment_filter: queryset = queryset.filter( ai_analysis__sentiment__classification__en=sentiment_filter ) date_from = request.GET.get('date_from') if date_from: queryset = queryset.filter(published_at__gte=date_from) date_to = request.GET.get('date_to') if date_to: queryset = queryset.filter(published_at__lte=date_to) search_query = request.GET.get('search') if search_query: queryset = queryset.filter( Q(comments__icontains=search_query) | Q(author__icontains=search_query) ) # Time-based view filter time_filter = request.GET.get('time_filter', 'all') from datetime import datetime, timedelta if time_filter == 'today': queryset = queryset.filter(published_at__date=datetime.now().date()) elif time_filter == 'week': queryset = queryset.filter(published_at__gte=datetime.now() - timedelta(days=7)) elif time_filter == 'month': queryset = queryset.filter(published_at__gte=datetime.now() - timedelta(days=30)) # Ordering order_by = request.GET.get('order_by', '-published_at') queryset = queryset.order_by(order_by) # Pagination page_size = int(request.GET.get('page_size', 25)) paginator = Paginator(queryset, page_size) page_number = request.GET.get('page', 1) page_obj = paginator.get_page(page_number) # Platform-specific statistics (using ai_analysis) total_comments = queryset.count() analyzed_comments = 0 positive_count = 0 negative_count = 0 neutral_count = 0 sentiment_scores = [] for comment in queryset: if comment.ai_analysis: analyzed_comments += 1 sentiment = comment.ai_analysis.get('sentiment', {}).get('classification', {}).get('en', 'neutral') score = comment.ai_analysis.get('sentiment', {}).get('score', 0) if sentiment == 'positive': positive_count += 1 elif sentiment == 'negative': negative_count += 1 else: neutral_count += 1 if score: sentiment_scores.append(score) avg_sentiment = sum(sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0 stats = { 'total': total_comments, 'analyzed': analyzed_comments, 'positive': positive_count, 'negative': negative_count, 'neutral': neutral_count, 'avg_sentiment': float(avg_sentiment), 'total_likes': int(queryset.aggregate(total=Sum('like_count'))['total'] or 0), 'total_replies': int(queryset.aggregate(total=Sum('reply_count'))['total'] or 0), } # Platform name for display platform_display = dict(SocialPlatform.choices).get(platform, platform) # Platform color for styling platform_colors = { 'facebook': '#1877F2', 'instagram': '#C13584', 'youtube': '#FF0000', 'twitter': '#1DA1F2', 'linkedin': '#0077B5', 'tiktok': '#000000', 'google': '#4285F4', } platform_color = platform_colors.get(platform, '#6c757d') context = { 'page_obj': page_obj, 'comments': page_obj.object_list, 'stats': stats, 'platform': platform, 'platform_display': platform_display, 'platform_color': platform_color, 'time_filter': time_filter, 'filters': request.GET, } return render(request, 'social/social_platform.html', context) @login_required def social_analytics(request): """ Social media analytics dashboard. Features: - Sentiment distribution - Platform distribution - Daily trends - Top keywords - Top topics - Engagement metrics """ queryset = SocialMediaComment.objects.all() # Platform filter platform_filter = request.GET.get('platform') if platform_filter: queryset = queryset.filter(platform=platform_filter) # Apply date range filter from datetime import datetime, timedelta # Check for custom date range first start_date = request.GET.get('start_date') end_date = request.GET.get('end_date') if start_date and end_date: # Custom date range specified queryset = queryset.filter(published_at__gte=start_date, published_at__lte=end_date) else: # Fall back to preset date range (backwards compatibility) date_range = int(request.GET.get('date_range', 30)) days_ago = datetime.now() - timedelta(days=date_range) queryset = queryset.filter(published_at__gte=days_ago) # Sentiment distribution (from ai_analysis) sentiment_counts = {'positive': 0, 'negative': 0, 'neutral': 0} sentiment_scores = {'positive': [], 'negative': [], 'neutral': []} for comment in queryset: if comment.ai_analysis: sentiment = comment.ai_analysis.get('sentiment', {}).get('classification', {}).get('en', 'neutral') score = comment.ai_analysis.get('sentiment', {}).get('score', 0) if sentiment in sentiment_counts: sentiment_counts[sentiment] += 1 if score: sentiment_scores[sentiment].append(score) sentiment_dist = [] for sentiment, count in sentiment_counts.items(): scores = sentiment_scores[sentiment] avg_score = sum(scores) / len(scores) if scores else 0 sentiment_dist.append({ 'sentiment': sentiment, 'count': count, 'avg_sentiment_score': avg_score }) # Platform distribution (add platform_display manually) - using ai_analysis platform_dist = [] for platform in SocialPlatform.choices: platform_code = platform[0] platform_name = platform[1] platform_data = queryset.filter(platform=platform_code) if platform_data.exists(): # Calculate avg sentiment from ai_analysis sentiment_scores = [] for comment in platform_data: if comment.ai_analysis: score = comment.ai_analysis.get('sentiment', {}).get('score', 0) if score: sentiment_scores.append(score) avg_sentiment = sum(sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0 platform_dist.append({ 'platform': platform_code, 'platform_display': platform_name, 'count': platform_data.count(), 'avg_sentiment': float(avg_sentiment), 'total_likes': int(platform_data.aggregate(total=Sum('like_count'))['total'] or 0), 'total_replies': int(platform_data.aggregate(total=Sum('reply_count'))['total'] or 0), }) # Daily trends (from ai_analysis) from collections import defaultdict daily_data = defaultdict(lambda: {'count': 0, 'positive': 0, 'negative': 0, 'neutral': 0, 'total_likes': 0}) for comment in queryset: if comment.published_at: day = comment.published_at.date() daily_data[day]['count'] += 1 daily_data[day]['total_likes'] += comment.like_count if comment.ai_analysis: sentiment = comment.ai_analysis.get('sentiment', {}).get('classification', {}).get('en', 'neutral') if sentiment in ['positive', 'negative', 'neutral']: daily_data[day][sentiment] += 1 daily_trends = [ { 'day': day, **stats } for day, stats in sorted(daily_data.items()) ] # Top keywords (from ai_analysis) all_keywords = [] for comment in queryset.exclude(ai_analysis__isnull=True).exclude(ai_analysis={}): keywords = comment.ai_analysis.get('keywords', {}).get('en', []) all_keywords.extend(keywords) from collections import Counter keyword_counts = Counter(all_keywords) top_keywords = [{'keyword': k, 'count': v} for k, v in keyword_counts.most_common(20)] # Top topics (from ai_analysis) all_topics = [] for comment in queryset.exclude(ai_analysis__isnull=True).exclude(ai_analysis={}): topics = comment.ai_analysis.get('topics', {}).get('en', []) all_topics.extend(topics) topic_counts = Counter(all_topics) top_topics = [{'topic': k, 'count': v} for k, v in topic_counts.most_common(10)] # Top entities (from ai_analysis) all_entities = [] for comment in queryset.exclude(ai_analysis__isnull=True).exclude(ai_analysis={}): entities = comment.ai_analysis.get('entities', []) for entity in entities: if isinstance(entity, dict): text_en = entity.get('text', {}).get('en', entity.get('text')) if text_en: all_entities.append(text_en) entity_counts = Counter(all_entities) top_entities = [{'entity': k, 'count': v} for k, v in entity_counts.most_common(15)] # Overall statistics (from ai_analysis) total_comments = queryset.count() analyzed_comments = 0 for comment in queryset: if comment.ai_analysis: analyzed_comments += 1 # Engagement metrics engagement_metrics = { 'avg_likes': float(queryset.aggregate(avg=Avg('like_count'))['avg'] or 0), 'avg_replies': float(queryset.aggregate(avg=Avg('reply_count'))['avg'] or 0), 'total_likes': int(queryset.aggregate(total=Sum('like_count'))['total'] or 0), 'total_replies': int(queryset.aggregate(total=Sum('reply_count'))['total'] or 0), } context = { 'sentiment_distribution': sentiment_dist, 'platform_distribution': platform_dist, 'daily_trends': daily_trends, 'top_keywords': top_keywords, 'top_topics': top_topics, 'top_entities': top_entities, 'total_comments': total_comments, 'analyzed_comments': analyzed_comments, 'unanalyzed_comments': total_comments - analyzed_comments, 'engagement_metrics': engagement_metrics, 'date_range': int(request.GET.get('date_range', 30)), 'start_date': start_date, 'end_date': end_date, } return render(request, 'social/social_analytics.html', context) @login_required @require_http_methods(["POST"]) def social_scrape_now(request): """ Trigger manual scraping for a platform. """ platform = request.POST.get('platform') if not platform: messages.error(request, "Please select a platform.") return redirect('social:social_analytics') try: # Trigger Celery task for scraping from .tasks import scrape_platform_comments task = scrape_platform_comments.delay(platform) messages.success( request, f"Scraping task initiated for {platform}. Task ID: {task.id}" ) except Exception as e: messages.error(request, f"Error initiating scraping: {str(e)}") return redirect('social:social_analytics') @login_required def social_export_csv(request): """Export social media comments to CSV""" import csv from django.http import HttpResponse from datetime import datetime # Get filtered queryset (reuse list view logic) queryset = SocialMediaComment.objects.all() # Apply filters platform_filter = request.GET.get('platform') if platform_filter: queryset = queryset.filter(platform=platform_filter) sentiment_filter = request.GET.get('sentiment') if sentiment_filter: queryset = queryset.filter( ai_analysis__sentiment__classification__en=sentiment_filter ) date_from = request.GET.get('date_from') if date_from: queryset = queryset.filter(published_at__gte=date_from) date_to = request.GET.get('date_to') if date_to: queryset = queryset.filter(published_at__lte=date_to) # Create CSV response response = HttpResponse(content_type='text/csv') timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') response['Content-Disposition'] = f'attachment; filename="social_comments_{timestamp}.csv"' writer = csv.writer(response) writer.writerow([ 'ID', 'Platform', 'Comment ID', 'Author', 'Comment', 'Published At', 'Scraped At', 'Sentiment', 'Sentiment Score', 'Confidence', 'Likes', 'Replies', 'Keywords', 'Topics' ]) for comment in queryset: # Extract data from ai_analysis sentiment = None sentiment_score = None confidence = None keywords = [] topics = [] if comment.ai_analysis: sentiment = comment.ai_analysis.get('sentiment', {}).get('classification', {}).get('en') sentiment_score = comment.ai_analysis.get('sentiment', {}).get('score') confidence = comment.ai_analysis.get('sentiment', {}).get('confidence') keywords = comment.ai_analysis.get('keywords', {}).get('en', []) topics = comment.ai_analysis.get('topics', {}).get('en', []) writer.writerow([ comment.id, comment.get_platform_display(), comment.comment_id, comment.author, comment.comments, comment.published_at, comment.scraped_at, sentiment, sentiment_score, confidence, comment.like_count, comment.reply_count, ', '.join(keywords), ', '.join(topics), ]) return response @login_required def social_export_excel(request): """Export social media comments to Excel""" import openpyxl from django.http import HttpResponse from datetime import datetime # Get filtered queryset queryset = SocialMediaComment.objects.all() # Apply filters platform_filter = request.GET.get('platform') if platform_filter: queryset = queryset.filter(platform=platform_filter) sentiment_filter = request.GET.get('sentiment') if sentiment_filter: queryset = queryset.filter( ai_analysis__sentiment__classification__en=sentiment_filter ) date_from = request.GET.get('date_from') if date_from: queryset = queryset.filter(published_at__gte=date_from) date_to = request.GET.get('date_to') if date_to: queryset = queryset.filter(published_at__lte=date_to) # Create workbook wb = openpyxl.Workbook() ws = wb.active ws.title = "Social Media Comments" # Headers headers = [ 'ID', 'Platform', 'Comment ID', 'Author', 'Comment', 'Published At', 'Scraped At', 'Sentiment', 'Sentiment Score', 'Confidence', 'Likes', 'Replies', 'Keywords', 'Topics', 'Entities' ] ws.append(headers) # Data rows for comment in queryset: # Extract data from ai_analysis sentiment = None sentiment_score = None confidence = None keywords = [] topics = [] entities_text = [] if comment.ai_analysis: sentiment = comment.ai_analysis.get('sentiment', {}).get('classification', {}).get('en') sentiment_score = comment.ai_analysis.get('sentiment', {}).get('score') confidence = comment.ai_analysis.get('sentiment', {}).get('confidence') keywords = comment.ai_analysis.get('keywords', {}).get('en', []) topics = comment.ai_analysis.get('topics', {}).get('en', []) entities = comment.ai_analysis.get('entities', []) for entity in entities: if isinstance(entity, dict): text_en = entity.get('text', {}).get('en', entity.get('text')) if text_en: entities_text.append(text_en) ws.append([ comment.id, comment.get_platform_display(), comment.comment_id, comment.author, comment.comments, comment.published_at.strftime('%Y-%m-%d %H:%M:%S') if comment.published_at else '', comment.scraped_at.strftime('%Y-%m-%d %H:%M:%S') if comment.scraped_at else '', sentiment, sentiment_score, confidence, comment.like_count, comment.reply_count, ', '.join(keywords), ', '.join(topics), ', '.join(entities_text), ]) # Create response response = HttpResponse( content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ) timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') response['Content-Disposition'] = f'attachment; filename="social_comments_{timestamp}.xlsx"' wb.save(response) return response