
Content Analysis
- 3 installs
- 3 repo stars
- Updated December 23, 2025
- liangdabiao/claude-data-analysis-ultra
Helps with marketing & seo tasks.
About
content-analysis is a Claude Code skill for marketing & seo. It helps solo builders move faster with AI-assisted development.
- content-analysis
- Marketing & SEO
- AI-coding skill
Content Analysis by the numbers
- 3 all-time installs (skills.sh)
- Ranked #1,624 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/liangdabiao/claude-data-analysis-ultra --skill content-analysisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3 |
|---|---|
| repo stars | ★ 3 |
| Last updated | December 23, 2025 |
| Repository | liangdabiao/claude-data-analysis-ultra ↗ |
What it does
Helps with marketing & seo tasks.
Files
Content Analysis Skill
Analyze text content using advanced NLP techniques and LLM-powered insights to extract sentiment, topics, and actionable intelligence from various content sources.
Quick Start
This skill helps you: 1. Analyze sentiment using both traditional NLP and LLM methods 2. Extract topics and keywords from large text datasets 3. Classify and cluster content automatically 4. Identify viral content patterns and characteristics 5. Generate content insights and recommendations 6. Support multiple languages and content formats
When to Use
- Social Media Analysis: Facebook, Twitter, Instagram, Weibo posts
- Content Marketing: Blog posts, articles, marketing copy analysis
- Video Content: YouTube titles, descriptions, comments analysis
- Product Reviews: Amazon, e-commerce customer feedback
- News Analysis: Article categorization, sentiment tracking
- Customer Feedback: Support tickets, surveys, reviews analysis
Key Requirements
Traditional NLP Analysis
pip install pandas numpy matplotlib seaborn nltk scikit-learn wordcloudLLM-Enhanced Analysis (Optional)
pip install openai dashscope # For OpenAI and Qwen API accessSetup NLTK Data
import nltk
nltk.download('vader_lexicon')
nltk.download('punkt')
nltk.download('stopwords')Core Workflow
1. Data Preparation
Your data should include:
- Text Content: Main text to analyze (titles, descriptions, comments, etc.)
- Metadata: Optional (author, date, category, engagement metrics)
- Multiple Languages: Support for English, Chinese, and other languages
2. Analysis Process
1. Text Preprocessing: Clean, tokenize, and normalize text 2. Sentiment Analysis: Traditional VADER + LLM-enhanced analysis 3. Topic Extraction: TF-IDF keywords + LLM semantic topics 4. Content Classification: Automated categorization and clustering 5. Pattern Recognition: Identify viral content characteristics 6. Insight Generation: Actionable recommendations
3. Output Deliverables
- Sentiment analysis reports with confidence scores
- Topic models and keyword extractions
- Content classification results
- Viral content pattern analysis
- Optimization recommendations
Example Usage Scenarios
Social Media Content Analysis
# Analyze Twitter posts for brand sentiment
# Identify trending topics and hashtags
# Measure engagement patternsYouTube Video Analysis
# Analyze video titles and descriptions
# Extract topics from comments
# Identify viral content patternsProduct Review Analysis
# Analyze customer feedback sentiment
# Extract product feature mentions
# Identify improvement opportunitiesKey Analysis Methods
Traditional NLP Techniques
- VADER Sentiment Analysis: Rule-based sentiment scoring
- TF-IDF Keyword Extraction: Statistical term importance
- Text Clustering: K-means and hierarchical clustering
- Word Frequency Analysis: Term frequency and co-occurrence
- Language Detection: Automatic language identification
LLM-Enhanced Analysis
- Context-Aware Sentiment: Nuanced emotion understanding
- Semantic Topic Extraction: Meaning-based topic identification
- Content Summarization: Automatic text summarization
- Multi-Language Support: Cross-lingual analysis
- Zero-Shot Classification: Categorization without training data
Advanced Analytics
- Time Series Analysis: Content trends over time
- Engagement Prediction: Predict viral potential
- Competitive Analysis: Compare content performance
- Audience Insights: Demographic and preference analysis
Common Business Questions Answered
1. What is the overall sentiment toward our brand? 2. Which topics are trending in our industry? 3. What makes content go viral? 4. How does sentiment vary by demographic or region? 5. What are customers saying about our products? 6. Which content formats perform best?
Integration Examples
See examples/ directory for:
basic_content_analysis.py- Traditional NLP analysisllm_enhanced_analysis.py- LLM-powered analysissocial_media_analysis.py- Social media specific analysis- Sample datasets for testing
LLM Configuration
Supported LLM Providers
- OpenAI: GPT-3.5, GPT-4 models
- Qwen (通义千问): Chinese-optimized models
- Open Source: Local models via HuggingFace
API Setup Examples
# OpenAI Configuration
import openai
openai.api_key = 'your-api-key'
# Qwen Configuration
import dashscope
dashscope.api_key = 'your-api-key'Best Practices
1. Data Quality: Ensure clean, consistent text data 2. Sampling Strategy: Use representative samples for LLM analysis 3. Cost Management: Balance traditional NLP with LLM calls 4. Language Handling: Configure appropriate language models 5. Validation: Cross-validate sentiment analysis results 6. Privacy: Ensure compliance with data protection regulations
Performance Optimization
For Large Datasets
- Use data sampling for LLM analysis
- Implement batch processing
- Cache LLM responses when possible
- Use traditional NLP for initial filtering
Cost Management
- Prioritize important content for LLM analysis
- Use traditional NLP for bulk processing
- Implement smart sampling strategies
- Monitor API usage and costs
Advanced Features
- Real-time Analysis: Stream processing for live content
- Multi-modal Analysis: Text + image + video content
- Custom Models: Fine-tune models for specific domains
- Integration APIs: Connect with content management systems
- Automated Reporting: Scheduled analysis and reporting
Troubleshooting
Common Issues
1. Low Sentiment Accuracy: Check language settings and text preprocessing 2. High API Costs: Optimize sampling and caching strategies 3. Slow Processing: Implement parallel processing and batching 4. Language Support: Ensure appropriate models for non-English content
Performance Tips
- Pre-process text data effectively
- Use appropriate model sizes for tasks
- Implement result caching
- Monitor resource usage and optimize
"""
Basic Content Analysis Example
This example demonstrates how to use the Content Analysis skill
to perform traditional NLP analysis on text data.
"""
import pandas as pd
import numpy as np
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from scripts.text_analyzer import TextAnalyzer, SocialMediaAnalyzer
from scripts.sentiment_analyzer import SentimentAnalyzer
from scripts.topic_analyzer import TopicAnalyzer
from scripts.content_visualizer import ContentVisualizer
def create_sample_data():
"""
Create sample text data for analysis demonstration.
"""
sample_texts = [
"I absolutely love this new product! It's amazing and works perfectly.",
"The customer service was terrible. I'm very disappointed with the experience.",
"This is an okay product. Nothing special but it does the job.",
"Outstanding quality and great value for money. Highly recommended!",
"Poor packaging and the item arrived damaged. Not happy at all.",
"Average quality, meets expectations but doesn't exceed them.",
"Fantastic experience from start to finish. Will definitely buy again!",
"The product broke after just one week. Complete waste of money.",
"Good product for the price. Some minor issues but overall satisfied.",
"Excellent build quality and attention to detail. Worth every penny!",
"Slow shipping and the product doesn't match the description.",
"Decent product, but could be improved with better features.",
"Absolutely love it! Best purchase I've made this year.",
"Mediocre quality, expected more for this price point.",
"Great customer support and fast resolution of my issues.",
"Product stopped working after a few days. Very frustrated.",
"Solid product with good performance. Meets my needs well.",
"Terrible user manual and confusing setup process.",
"Impressed with the quality and fast delivery. Excellent service!",
"Not worth the price. There are better alternatives available."
]
# Create DataFrame
df = pd.DataFrame({
'text': sample_texts,
'category': np.random.choice(['Product', 'Service', 'Shipping'], len(sample_texts)),
'source': np.random.choice(['Twitter', 'Review', 'Email'], len(sample_texts)),
'date': pd.date_range('2024-01-01', periods=len(sample_texts), freq='D')
})
return df
def demonstrate_text_analysis():
"""
Demonstrate basic text analysis capabilities.
"""
print("=== Basic Text Analysis Demo ===\n")
# Sample text
sample_text = "I absolutely love this new product! It's amazing and works perfectly. The customer service was excellent too."
# Initialize analyzer
analyzer = TextAnalyzer()
# Clean text
cleaned = analyzer.clean_text(sample_text)
print(f"Original text: {sample_text}")
print(f"Cleaned text: {cleaned}")
# Tokenize
tokens = analyzer.tokenize_text(sample_text)
print(f"\nTokens: {tokens[:10]}...") # Show first 10 tokens
# Extract keywords
keywords = analyzer.extract_keywords(sample_text, top_k=5)
print(f"\nTop keywords: {keywords}")
# Calculate readability
readability = analyzer.calculate_readability(sample_text)
print(f"\nReadability metrics: {readability}")
# Get text statistics
stats = analyzer.get_text_statistics(sample_text)
print(f"\nText statistics: {stats}")
def demonstrate_sentiment_analysis():
"""
Demonstrate sentiment analysis capabilities.
"""
print("\n=== Sentiment Analysis Demo ===\n")
# Sample texts with different sentiments
texts = [
"I love this product! It's absolutely amazing.",
"This is terrible. I hate it and want my money back.",
"The product is okay. Nothing special but does the job.",
"Outstanding quality and excellent customer service!",
"Poor quality and terrible customer support."
]
# Initialize sentiment analyzer
analyzer = SentimentAnalyzer()
# Analyze each text
results = []
for text in texts:
result = analyzer.analyze_sentiment_vader(text)
result['text'] = text
results.append(result)
print(f"Text: {text}")
print(f"Sentiment: {result['label']} (Compound: {result['compound']:.3f})")
print(f"Positive: {result['positive']:.3f}, Negative: {result['negative']:.3f}, Neutral: {result['neutral']:.3f}")
print()
# Get sentiment distribution
distribution = analyzer.classify_sentiment_distribution(texts)
print("Sentiment Distribution:")
print(f"Positive: {distribution.get('positive_percent', 0):.1f}% ({distribution.get('positive_count', 0)} texts)")
print(f"Negative: {distribution.get('negative_percent', 0):.1f}% ({distribution.get('negative_count', 0)} texts)")
print(f"Neutral: {distribution.get('neutral_percent', 0):.1f}% ({distribution.get('neutral_count', 0)} texts)")
def demonstrate_topic_analysis():
"""
Demonstrate topic analysis capabilities.
"""
print("\n=== Topic Analysis Demo ===\n")
# Sample texts about different topics
texts = [
"The new smartphone has amazing camera quality and fast performance.",
"Customer service was excellent and resolved my issue quickly.",
"Fast shipping and great packaging. Product arrived in perfect condition.",
"The laptop battery life is impressive and the screen is very clear.",
"Technical support was very helpful and knowledgeable.",
"The delivery was delayed but the product quality is good.",
"Great value for money and the features are exactly what I needed.",
"Had to return the item due to manufacturing defects.",
"The tablet is lightweight and perfect for travel.",
"Prices are competitive but the warranty coverage is limited."
]
# Initialize topic analyzer
analyzer = TopicAnalyzer()
# Extract keywords using TF-IDF
tfidf_keywords = analyzer.extract_keywords_tfidf(texts, top_k=10)
print("TF-IDF Keywords:")
for keyword, score in tfidf_keywords:
print(f" {keyword}: {score:.4f}")
# Extract keywords using frequency
freq_keywords = analyzer.extract_keywords_frequency(texts, top_k=10)
print(f"\nFrequency Keywords:")
for keyword, freq in freq_keywords:
print(f" {keyword}: {freq}")
# Perform topic modeling
print(f"\nPerforming topic modeling...")
topic_results = analyzer.perform_lda_topic_modeling(texts, num_topics=3)
if topic_results and 'topics' in topic_results:
print(f"Discovered {topic_results['num_topics']} topics:")
for topic_key, topic_data in topic_results['topics'].items():
print(f"\n{topic_key.upper()}:")
print(f" Top words: {', '.join(topic_data['words'][:8])}")
def demonstrate_social_media_analysis():
"""
Demonstrate social media specific analysis.
"""
print("\n=== Social Media Analysis Demo ===\n")
# Sample social media posts
social_posts = [
"Just tried the new #iPhone15 and it's amazing! 📱 #Apple #Tech",
"Terrible customer service @CompanyXYZ. Waited 2 hours for support! 😤",
"Check out our latest sale! 50% off everything. #Shopping #Deals",
"@JohnDoe thanks for the recommendation! The product works great 👍",
"Retweet if you agree that we need better environmental policies! 🌍 #Climate",
"New blog post: 10 tips for better productivity. Link in bio! ✨",
"Can't believe they cancelled my order without notification! So frustrated 😠",
"Happy holidays everyone! 🎄 Wishing you joy and peace this season."
]
# Initialize social media analyzer
analyzer = SocialMediaAnalyzer()
# Analyze each post
print("Social Media Post Analysis:")
for i, post in enumerate(social_posts, 1):
hashtags = analyzer.extract_hashtags(post)
mentions = analyzer.extract_mentions(post)
engagement = analyzer.count_engagement_indicators(post)
platform = analyzer.detect_social_media_platform(post)
print(f"\nPost {i}:")
print(f" Text: {post}")
print(f" Platform: {platform}")
print(f" Hashtags: {hashtags}")
print(f" Mentions: {mentions}")
print(f" Engagement indicators: {engagement}")
def demonstrate_content_clustering():
"""
Demonstrate content clustering capabilities.
"""
print("\n=== Content Clustering Demo ===\n")
# Sample texts for clustering
texts = [
"The smartphone has excellent camera and battery life.",
"Great customer service and fast response time.",
"The tablet offers good value for money.",
"Technical support team was very helpful.",
"Laptop performance is outstanding for gaming.",
"Shipping was fast and packaging was secure.",
"The phone's user interface is intuitive.",
"Had issues with product registration.",
"Great warranty coverage and after-sales service.",
"The device is lightweight and portable."
]
# Initialize analyzer
analyzer = TopicAnalyzer()
# Perform clustering
print("Performing text clustering...")
cluster_results = analyzer.cluster_texts(texts, num_clusters=3)
if cluster_results and 'cluster_terms' in cluster_results:
print(f"Cluster Analysis Results:")
print(f"Number of clusters: {cluster_results['num_clusters']}")
print(f"Inertia (within-cluster sum of squares): {cluster_results['inertia']:.2f}")
print(f"\nTop terms by cluster:")
for cluster_id, terms in cluster_results['cluster_terms'].items():
print(f" Cluster {cluster_id}: {', '.join(terms[:5])}")
def create_visualizations():
"""
Create sample visualizations.
"""
print("\n=== Creating Visualizations ===\n")
# Sample sentiment data
sentiment_data = [
{'label': 'Positive', 'compound': 0.8},
{'label': 'Negative', 'compound': -0.6},
{'label': 'Neutral', 'compound': 0.1},
{'label': 'Positive', 'compound': 0.9},
{'label': 'Positive', 'compound': 0.7},
{'label': 'Negative', 'compound': -0.8},
{'label': 'Neutral', 'compound': 0.0},
{'label': 'Positive', 'compound': 0.6}
]
# Sample topic results
topic_results = {
'num_topics': 3,
'topics': {
'topic_0': {
'words': ['product', 'quality', 'excellent', 'great', 'value'],
'weights': [0.15, 0.12, 0.10, 0.09, 0.08]
},
'topic_1': {
'words': ['customer', 'service', 'support', 'help', 'response'],
'weights': [0.14, 0.13, 0.11, 0.09, 0.08]
},
'topic_2': {
'words': ['shipping', 'delivery', 'fast', 'packaging', 'condition'],
'weights': [0.16, 0.14, 0.11, 0.09, 0.07]
}
},
'doc_topic_distribution': [
[0.8, 0.1, 0.1],
[0.1, 0.8, 0.1],
[0.2, 0.2, 0.6],
[0.7, 0.2, 0.1],
[0.1, 0.7, 0.2],
[0.2, 0.1, 0.7]
]
}
# Initialize visualizer
visualizer = ContentVisualizer()
# Create sentiment distribution plot
print("Creating sentiment distribution visualization...")
sentiment_fig = visualizer.plot_sentiment_distribution(sentiment_data)
if sentiment_fig:
sentiment_fig.savefig('sentiment_distribution.png', dpi=300, bbox_inches='tight')
print("Saved: sentiment_distribution.png")
# Create topic modeling visualization
print("Creating topic modeling visualization...")
topic_fig = visualizer.plot_topic_modeling_results(topic_results)
if topic_fig:
topic_fig.savefig('topic_modeling_results.png', dpi=300, bbox_inches='tight')
print("Saved: topic_modeling_results.png")
# Create word cloud
print("Creating word cloud...")
sample_text = """
product quality excellent value customer service great support
shipping delivery fast packaging condition warranty coverage
technical helpful responsive resolution satisfaction recommendation
"""
wordcloud_fig = visualizer.create_word_cloud(sample_text, title="Content Analysis Word Cloud")
if wordcloud_fig:
wordcloud_fig.savefig('content_wordcloud.png', dpi=300, bbox_inches='tight')
print("Saved: content_wordcloud.png")
def main():
"""
Run complete basic content analysis example.
"""
print("Content Analysis Skill - Basic Analysis Example")
print("=" * 50)
# Create sample data
print("\n1. Creating sample data...")
df = create_sample_data()
print(f" Created dataset with {len(df)} text samples")
# Demonstrate text analysis
print("\n2. Demonstrating text analysis...")
demonstrate_text_analysis()
# Demonstrate sentiment analysis
print("\n3. Demonstrating sentiment analysis...")
demonstrate_sentiment_analysis()
# Demonstrate topic analysis
print("\n4. Demonstrating topic analysis...")
demonstrate_topic_analysis()
# Demonstrate social media analysis
print("\n5. Demonstrating social media analysis...")
demonstrate_social_media_analysis()
# Demonstrate content clustering
print("\n6. Demonstrating content clustering...")
demonstrate_content_clustering()
# Create visualizations
print("\n7. Creating visualizations...")
create_visualizations()
print("\n" + "=" * 50)
print("Basic Content Analysis Example Complete!")
print("\nGenerated files:")
print(" - sentiment_distribution.png")
print(" - topic_modeling_results.png")
print(" - content_wordcloud.png")
if __name__ == "__main__":
main()text,sentiment,category,source,date
"I absolutely love this new smartphone! The camera quality is amazing and the battery life is incredible.",positive,Product,Review,2024-01-15
"The customer service was excellent. They resolved my issue quickly and professionally.",positive,Service,Review,2024-01-16
"This product is terrible. It broke after just one week of use.",negative,Product,Review,2024-01-17
"Good value for money. The product meets my expectations but doesn't exceed them.",neutral,Product,Review,2024-01-18
"Outstanding quality and attention to detail. Highly recommend this brand!",positive,Product,Review,2024-01-19
"Poor packaging and the item arrived damaged. Very disappointed with the experience.",negative,Shipping,Review,2024-01-20
"The user interface is intuitive and easy to navigate. Great user experience!",positive,Product,Review,2024-01-21
"Average quality at best. There are better alternatives available in this price range.",negative,Product,Review,2024-01-22
"Fast shipping and secure packaging. Product arrived in perfect condition.",positive,Shipping,Review,2024-01-23
"Terrible customer support. Waited on hold for over an hour and then got disconnected.",negative,Service,Review,2024-01-24
"The laptop performance is outstanding for gaming. No lag whatsoever!",positive,Product,Review,2024-01-25
"Mediocre build quality. Expected more for this premium price point.",negative,Product,Review,2024-01-26
"Great warranty coverage and excellent after-sales support. Peace of mind purchase.",positive,Service,Review,2024-01-27
"The delivery was delayed by a week without any communication.",negative,Shipping,Review,2024-01-28
"Solid product with good features. Meets my daily needs perfectly.",positive,Product,Review,2024-01-29
"Difficult setup process and unclear instructions. Frustrating experience.",negative,Product,Review,2024-01-30
"Responsive customer service team that really cares about customer satisfaction.",positive,Service,Review,2024-01-31
"The product quality is okay but the price is too high for what you get.",negative,Product,Review,2024-02-01
"Eco-friendly packaging and fast delivery. Love the sustainable approach!",positive,Shipping,Review,2024-02-02
"Technical support was very knowledgeable and patient. Solved my complex issue.",positive,Service,Review,2024-02-03[
{
"id": 1,
"platform": "Twitter",
"text": "Just tried the new #iPhone15 and it's absolutely amazing! The camera quality is stunning 📱 @Apple",
"timestamp": "2024-01-15T10:30:00Z",
"likes": 245,
"retweets": 42,
"hashtags": ["iPhone15", "Apple"],
"mentions": ["Apple"],
"user": "tech_enthusiast"
},
{
"id": 2,
"platform": "Twitter",
"text": "Terrible customer service @CompanyXYZ. Waited 2 hours for support only to be disconnected! 😤 #Fail",
"timestamp": "2024-01-15T14:22:00Z",
"likes": 89,
"retweets": 15,
"hashtags": ["Fail"],
"mentions": ["CompanyXYZ"],
"user": "frustrated_customer"
},
{
"id": 3,
"platform": "Instagram",
"text": "Check out our latest summer collection! 50% off everything in store. #Shopping #Deals #SummerSale",
"timestamp": "2024-01-16T09:15:00Z",
"likes": 567,
"hashtags": ["Shopping", "Deals", "SummerSale"],
"mentions": [],
"user": "fashion_brand"
},
{
"id": 4,
"platform": "Twitter",
"text": "@JohnDoe thanks for the recommendation! The noise-cancelling headphones work perfectly 👍 #HappyCustomer",
"timestamp": "2024-01-16T16:45:00Z",
"likes": 23,
"retweets": 3,
"hashtags": ["HappyCustomer"],
"mentions": ["JohnDoe"],
"user": "satisfied_buyer"
},
{
"id": 5,
"platform": "Facebook",
"text": "New blog post: 10 Productivity Tips That Changed My Life. Link in bio! ✨ #Productivity #SelfImprovement",
"timestamp": "2024-01-17T08:00:00Z",
"likes": 124,
"shares": 28,
"hashtags": ["Productivity", "SelfImprovement"],
"mentions": [],
"user": "productivity_guru"
},
{
"id": 6,
"platform": "Twitter",
"text": "Can't believe they cancelled my order without any notification! So frustrated with this company 😠",
"timestamp": "2024-01-17T19:30:00Z",
"likes": 67,
"retweets": 8,
"hashtags": [],
"mentions": [],
"user": "angry_shopper"
},
{
"id": 7,
"platform": "Instagram",
"text": "Beautiful sunset from my balcony today. Nature never ceases to amaze me! 🌅 #Nature #Sunset #Blessed",
"timestamp": "2024-01-18T18:15:00Z",
"likes": 892,
"hashtags": ["Nature", "Sunset", "Blessed"],
"mentions": [],
"user": "nature_lover"
},
{
"id": 8,
"platform": "Twitter",
"text": "Just launched my new podcast about entrepreneurship! First episode is live 🎙️ #Startup #Business",
"timestamp": "2024-01-19T11:00:00Z",
"likes": 156,
"retweets": 34,
"hashtags": ["Startup", "Business"],
"mentions": [],
"user": "entrepreneur_pod"
},
{
"id": 9,
"platform": "Facebook",
"text": "Retweet if you agree that we need better environmental policies! 🌍 Our planet deserves better #ClimateAction",
"timestamp": "2024-01-20T07:45:00Z",
"likes": 423,
"shares": 189,
"hashtags": ["ClimateAction"],
"mentions": [],
"user": "environmental_activist"
},
{
"id": 10,
"platform": "Twitter",
"text": "The new software update is amazing! So many useful features and the UI is much cleaner now @TechCorp",
"timestamp": "2024-01-20T15:20:00Z",
"likes": 78,
"retweets": 12,
"hashtags": [],
"mentions": ["TechCorp"],
"user": "software_developer"
}
]Content Analysis Skill
This skill provides comprehensive content analysis capabilities combining traditional NLP techniques with modern LLM-powered insights for deep text understanding and actionable intelligence.
Overview
The Content Analysis Skill enables sophisticated text analysis across multiple domains including social media, marketing content, product reviews, and video content. It offers both traditional statistical NLP methods and advanced LLM-enhanced analysis for maximum accuracy and insight generation.
Features
Core Capabilities
- Dual-Mode Analysis: Traditional NLP + LLM-enhanced methods
- Multi-Language Support: English, Chinese, and other languages
- Sentiment Analysis: From basic polarity to nuanced emotion detection
- Topic Extraction: Statistical and semantic topic identification
- Content Classification: Automated categorization and clustering
- Viral Content Detection: Pattern recognition for trending content
Analysis Types
1. Sentiment Intelligence: Emotion detection, tone analysis, mood tracking 2. Topic Modeling: Keyword extraction, semantic themes, trend identification 3. Content Quality: Engagement prediction, readability assessment 4. Competitive Intelligence: Content comparison, market positioning 5. Audience Insights: Demographic analysis, preference modeling
File Structure
content-analysis/
├── SKILL.md # Main skill definition
├── README.md # This file
├── scripts/ # Core analysis modules
│ ├── text_analyzer.py # Text preprocessing utilities
│ ├── sentiment_analyzer.py # Sentiment analysis tools
│ ├── topic_analyzer.py # Topic extraction and modeling
│ ├── llm_analyzer.py # LLM-powered analysis
│ └── content_visualizer.py # Visualization tools
└── examples/ # Usage examples
├── basic_content_analysis.py # Traditional NLP analysis
├── llm_enhanced_analysis.py # LLM-enhanced analysis
├── social_media_analysis.py # Social media specific analysis
└── sample_data/ # Example datasetsGetting Started
Prerequisites
Basic Requirements:
pip install pandas numpy matplotlib seaborn nltk scikit-learn wordcloudLLM Enhancement (Optional):
pip install openai dashscope requestsNLTK Setup:
import nltk
nltk.download('vader_lexicon')
nltk.download('punkt')
nltk.download('stopwords')
nltk.download('wordnet')Basic Usage
1. Prepare your content data with text fields and optional metadata 2. Choose analysis mode: Traditional NLP, LLM-enhanced, or hybrid 3. Configure analysis parameters: Language, sentiment model, topic extraction 4. Run analysis and generate insights 5. Visualize results with interactive charts and reports
Data Format Requirements
Your data should include:
- Text Content: Primary text fields (titles, descriptions, comments, etc.)
- Optional Metadata: Author, date, category, engagement metrics
- Language Information: Language codes for multi-language analysis
Examples
Basic Sentiment Analysis
from scripts.sentiment_analyzer import SentimentAnalyzer
analyzer = SentimentAnalyzer()
results = analyzer.analyze_batch(text_data)
analyzer.visualize_sentiment_distribution(results)LLM-Enhanced Topic Extraction
from scripts.llm_analyzer import LLMAnalyzer
llm = LLMAnalyzer(provider='openai')
topics = llm.extract_topics(content_list, topics_per_item=5)
summaries = llm.generate_summaries(content_by_category)Social Media Analysis
from scripts.text_analyzer import SocialMediaAnalyzer
sma = SocialMediaAnalyzer()
trends = sma.analyze_hashtags(social_data)
viral_patterns = sma.identify_viral_content(content_data)Common Use Cases
Social Media Management
- Brand Monitoring: Track brand sentiment across platforms
- Campaign Analysis: Measure campaign effectiveness and engagement
- Influencer Identification: Find trending content and creators
- Crisis Detection: Early warning for negative sentiment spikes
Content Marketing
- SEO Optimization: Keyword and topic analysis for content strategy
- Performance Prediction: Predict content engagement and virality
- Competitive Analysis: Compare content performance against competitors
- Audience Understanding: Analyze audience preferences and behaviors
Product and Service Analysis
- Customer Feedback: Analyze reviews and support tickets
- Feature Requests: Extract product improvement suggestions
- Market Research: Identify market trends and opportunities
- Quality Assurance: Monitor product mentions and sentiment
Video Content Analysis
- YouTube Optimization: Title and description analysis for discoverability
- Comment Analysis: Understand audience engagement and feedback
- Trend Identification: Spot emerging video trends and topics
- Content Strategy: Data-driven video content planning
Advanced Analytics
Sentiment Intelligence
- Fine-grained Emotions: Joy, anger, fear, sadness, surprise detection
- Temporal Sentiment: Track sentiment changes over time
- Comparative Analysis: Compare sentiment across brands or products
- Context Understanding: Detect sarcasm, irony, and complex emotions
Topic Intelligence
- Emerging Topics: Identify new and trending topics
- Topic Evolution: Track how topics change over time
- Cross-Domain Topics: Find topics spanning multiple categories
- Semantic Clustering: Group content by meaning rather than keywords
Content Performance
- Engagement Prediction: Forecast likes, shares, comments
- Virality Factors: Identify characteristics of viral content
- Optimization Recommendations: Suggest content improvements
- A/B Testing Analysis: Compare different content variations
Best Practices
Data Preparation
- Text Cleaning: Remove noise, normalize format, handle special characters
- Language Detection: Automatically identify and process different languages
- Quality Filtering: Remove low-quality or spam content
- Metadata Enrichment: Add context information for better analysis
Analysis Strategy
- Multi-Method Approach: Combine traditional NLP with LLM analysis
- Sampling Techniques: Use representative samples for large datasets
- Validation: Cross-validate results with human annotation
- Iterative Refinement: Continuously improve models and parameters
Cost and Performance
- Smart Sampling: Use LLM analysis for high-value content only
- Batch Processing: Optimize API calls and processing efficiency
- Caching: Store results for repeated analysis
- Resource Monitoring: Track usage and optimize resource allocation
Integration Options
API Integration
- REST APIs: Connect with content management systems
- Webhooks: Real-time content analysis triggers
- Scheduled Jobs: Automated periodic analysis
- Stream Processing: Real-time content stream analysis
Platform Integration
- Social Media APIs: Twitter, Facebook, Instagram integration
- Content Management: WordPress, Drupal, CMS integration
- Analytics Platforms: Google Analytics, Adobe Analytics
- CRM Systems: Salesforce, HubSpot integration
Troubleshooting
Common Issues
1. Low Analysis Accuracy
- Check text preprocessing and cleaning
- Verify language detection and model selection
- Ensure sufficient training data for custom models
2. High API Costs
- Optimize sampling strategies
- Implement caching mechanisms
- Use traditional NLP for bulk processing
3. Performance Bottlenecks
- Implement parallel processing
- Use batch operations for API calls
- Optimize data structures and algorithms
4. Language Support Issues
- Verify language code settings
- Check model availability for target languages
- Implement language-specific preprocessing
Performance Optimization
- Memory Management: Process large datasets in chunks
- CPU Optimization: Use vectorized operations and parallel processing
- I/O Optimization: Minimize disk access and use efficient data formats
- Network Optimization: Batch API calls and handle network issues
Extension Possibilities
- Multi-modal Analysis: Analyze text + images + videos together
- Real-time Processing: Stream processing for live content analysis
- Custom Models: Fine-tune models for specific domains or industries
- Advanced Visualization: Interactive dashboards and 3D visualizations
- Automated Actions: Trigger automated responses based on analysis results
Security and Privacy
- Data Protection: Ensure compliance with GDPR, CCPA, and other regulations
- API Security: Secure API key management and access control
- Content Filtering: Remove sensitive or private information
- Audit Trails: Track analysis operations and results
"""
Content Visualization Tools
This module provides comprehensive visualization capabilities for content analysis
including sentiment plots, topic visualizations, and interactive dashboards.
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.offline as pyo
from typing import List, Dict, Optional, Tuple, Union
from wordcloud import WordCloud
import matplotlib.patches as mpatches
from matplotlib.gridspec import GridSpec
import warnings
# Set matplotlib parameters for better Chinese font support
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
class ContentVisualizer:
"""
Comprehensive content visualization toolkit.
Provides various visualization types for content analysis results
including sentiment analysis, topic modeling, and performance metrics.
"""
def __init__(self, style: str = 'seaborn-v0_8', figsize: Tuple[int, int] = (12, 8)):
"""
Initialize the ContentVisualizer.
Args:
style: Matplotlib style to use
figsize: Default figure size
"""
self.style = style
self.figsize = figsize
self.color_palette = sns.color_palette("husl", 10)
# Set matplotlib style
try:
plt.style.use(style)
except:
plt.style.use('default')
# Configure seaborn
sns.set_palette("husl")
def plot_sentiment_distribution(self, sentiment_data: List[Dict],
title: str = "Sentiment Analysis Results",
interactive: bool = False) -> Union[plt.Figure, go.Figure]:
"""
Plot sentiment distribution analysis.
Args:
sentiment_data: List of sentiment analysis results
title: Plot title
interactive: Whether to create interactive plot
Returns:
Matplotlib or Plotly figure
"""
if not sentiment_data:
return None
# Extract sentiment labels
sentiments = [result.get('label', result.get('sentiment', 'Neutral'))
for result in sentiment_data]
# Count sentiments
sentiment_counts = pd.Series(sentiments).value_counts()
if interactive:
# Create interactive plot with Plotly
fig = make_subplots(
rows=1, cols=2,
specs=[[{"type": "pie"}, {"type": "bar"}]],
subplot_titles=("Sentiment Distribution", "Sentiment Counts"),
horizontal_spacing=0.1
)
# Pie chart
colors = ['#2E8B57', '#DC143C', '#708090'] # Green, Red, Gray
fig.add_trace(
go.Pie(
labels=sentiment_counts.index,
values=sentiment_counts.values,
name="Sentiment",
marker_colors=colors[:len(sentiment_counts)]
),
row=1, col=1
)
# Bar chart
fig.add_trace(
go.Bar(
x=sentiment_counts.index,
y=sentiment_counts.values,
marker_color=colors[:len(sentiment_counts)],
name="Count"
),
row=1, col=2
)
fig.update_layout(
title=title,
showlegend=False,
height=500
)
return fig
else:
# Create static plot with Matplotlib
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# Pie chart
colors = ['#2E8B57', '#DC143C', '#708090']
wedges, texts, autotexts = ax1.pie(
sentiment_counts.values,
labels=sentiment_counts.index,
colors=colors[:len(sentiment_counts)],
autopct='%1.1f%%',
startangle=90
)
ax1.set_title('Sentiment Distribution', fontweight='bold')
# Bar chart
bars = ax2.bar(sentiment_counts.index, sentiment_counts.values,
color=colors[:len(sentiment_counts)])
ax2.set_title('Sentiment Counts', fontweight='bold')
ax2.set_ylabel('Number of Texts')
# Add value labels on bars
for bar, count in zip(bars, sentiment_counts.values):
ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,
str(count), ha='center', va='bottom')
plt.suptitle(title, fontsize=16, fontweight='bold')
plt.tight_layout()
return fig
def plot_sentiment_timeline(self, sentiment_data: List[Dict],
timestamps: List[str] = None,
time_window: str = 'daily',
title: str = "Sentiment Trends Over Time") -> Union[plt.Figure, go.Figure]:
"""
Plot sentiment trends over time.
Args:
sentiment_data: List of sentiment analysis results
timestamps: List of timestamps corresponding to data
time_window: Time aggregation window ('daily', 'weekly', 'monthly')
title: Plot title
Returns:
Matplotlib or Plotly figure
"""
if not sentiment_data:
return None
# Create DataFrame
df = pd.DataFrame(sentiment_data)
# Extract sentiment scores
if 'compound' in df.columns:
df['sentiment_score'] = df['compound']
elif 'confidence' in df.columns:
# Convert sentiment to numeric
sentiment_map = {'positive': 1, 'negative': -1, 'neutral': 0}
df['sentiment_score'] = df['sentiment'].map(sentiment_map) * df['confidence']
else:
# Simple sentiment mapping
sentiment_map = {'positive': 1, 'negative': -1, 'neutral': 0}
df['sentiment_score'] = df['sentiment'].map(sentiment_map)
# Add timestamps if provided
if timestamps:
df['timestamp'] = pd.to_datetime(timestamps)
df.set_index('timestamp', inplace=True)
# Aggregate by time window
if time_window == 'daily':
df_resampled = df.resample('D')
elif time_window == 'weekly':
df_resampled = df.resample('W')
elif time_window == 'monthly':
df_resampled = df.resample('M')
else:
df_resampled = df.resample('D')
sentiment_trends = df_resampled['sentiment_score'].mean()
# Create interactive plot
fig = go.Figure()
fig.add_trace(go.Scatter(
x=sentiment_trends.index,
y=sentiment_trends.values,
mode='lines+markers',
name='Average Sentiment',
line=dict(color='blue', width=2),
marker=dict(size=6)
))
# Add zero line
fig.add_hline(y=0, line_dash="dash", line_color="gray")
fig.update_layout(
title=title,
xaxis_title="Date",
yaxis_title="Sentiment Score",
hovermode='x unified'
)
return fig
else:
# Simple line plot
fig, ax = plt.subplots(figsize=self.figsize)
ax.plot(range(len(df)), df['sentiment_score'], marker='o', linewidth=2, markersize=4)
ax.axhline(y=0, color='gray', linestyle='--', alpha=0.7)
ax.set_title(title, fontweight='bold')
ax.set_xlabel('Text Index')
ax.set_ylabel('Sentiment Score')
ax.grid(True, alpha=0.3)
return fig
def plot_topic_modeling_results(self, topic_results: Dict,
title: str = "Topic Modeling Analysis") -> plt.Figure:
"""
Plot comprehensive topic modeling results.
Args:
topic_results: Results from topic modeling
title: Plot title
Returns:
Matplotlib figure
"""
if not topic_results:
return None
num_topics = topic_results.get('num_topics', 0)
if num_topics == 0:
return None
# Create figure with subplots
fig = plt.figure(figsize=(20, 15))
gs = GridSpec(3, 3, figure=fig, hspace=0.3, wspace=0.3)
# 1. Topic prevalence (top left)
ax1 = fig.add_subplot(gs[0, 0])
if 'doc_topic_distribution' in topic_results:
doc_topic_dist = pd.DataFrame(topic_results['doc_topic_distribution'])
avg_topic_dist = doc_topic_dist.mean()
ax1.bar(range(len(avg_topic_dist)), avg_topic_dist.values, color=self.color_palette[:len(avg_topic_dist)])
ax1.set_title('Average Topic Prevalence', fontweight='bold')
ax1.set_xlabel('Topic ID')
ax1.set_ylabel('Average Probability')
ax1.set_xticks(range(len(avg_topic_dist)))
ax1.set_xticklabels([f'T{i}' for i in range(len(avg_topic_dist))])
# 2. Dominant topic distribution (top middle)
ax2 = fig.add_subplot(gs[0, 1])
if 'doc_topic_distribution' in topic_results:
doc_topic_dist = pd.DataFrame(topic_results['doc_topic_distribution'])
dominant_topics = doc_topic_dist.idxmax(axis=1)
topic_counts = dominant_topics.value_counts().sort_index()
ax2.bar(topic_counts.index, topic_counts.values, color=self.color_palette[:len(topic_counts)])
ax2.set_title('Dominant Topic Distribution', fontweight='bold')
ax2.set_xlabel('Topic ID')
ax2.set_ylabel('Number of Documents')
# 3. Topic correlation heatmap (top right)
ax3 = fig.add_subplot(gs[0, 2])
if 'doc_topic_distribution' in topic_results:
doc_topic_dist = pd.DataFrame(topic_results['doc_topic_distribution'])
topic_corr = doc_topic_dist.corr()
im = ax3.imshow(topic_corr.values, cmap='coolwarm', aspect='auto', vmin=-1, vmax=1)
ax3.set_xticks(range(len(topic_corr.columns)))
ax3.set_yticks(range(len(topic_corr.columns)))
ax3.set_xticklabels([f'T{i}' for i in range(len(topic_corr.columns))])
ax3.set_yticklabels([f'T{i}' for i in range(len(topic_corr.columns))])
ax3.set_title('Topic Correlation Matrix', fontweight='bold')
# Add colorbar
plt.colorbar(im, ax=ax3, shrink=0.8)
# 4-6. Top words for topics (middle row)
topics = topic_results.get('topics', {})
for i in range(min(3, num_topics)):
ax = fig.add_subplot(gs[1, i])
topic_key = f'topic_{i}'
if topic_key in topics:
topic_data = topics[topic_key]
words = topic_data.get('words', [])[:10]
weights = topic_data.get('weights', [])[:10]
if words and weights:
y_pos = range(len(words))
bars = ax.barh(y_pos, weights, color=self.color_palette[i])
ax.set_yticks(y_pos)
ax.set_yticklabels(words)
ax.set_title(f'Topic {i} Top Words', fontweight='bold')
ax.set_xlabel('Weight')
ax.invert_yaxis()
# 7-9. Topic word clouds (bottom row)
for i in range(min(3, num_topics)):
ax = fig.add_subplot(gs[2, i])
topic_key = f'topic_{i}'
if topic_key in topics:
topic_data = topics[topic_key]
words = topic_data.get('words', [])
weights = topic_data.get('weights', [])
if words and weights:
# Create word frequency dictionary
word_freq = {word: weight for word, weight in zip(words, weights)}
# Create word cloud
wordcloud = WordCloud(
width=400, height=300,
background_color='white',
colormap='viridis',
max_words=20
).generate_from_frequencies(word_freq)
ax.imshow(wordcloud, interpolation='bilinear')
ax.axis('off')
ax.set_title(f'Topic {i} Word Cloud', fontweight='bold')
plt.suptitle(title, fontsize=18, fontweight='bold')
return fig
def plot_content_quality_analysis(self, quality_data: List[Dict],
title: str = "Content Quality Analysis") -> plt.Figure:
"""
Plot content quality analysis results.
Args:
quality_data: List of quality analysis results
title: Plot title
Returns:
Matplotlib figure
"""
if not quality_data:
return None
# Extract quality metrics
df = pd.DataFrame(quality_data)
# Create figure
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes = axes.flatten()
# 1. Overall quality distribution
ax1 = axes[0]
if 'overall_score' in df.columns:
ax1.hist(df['overall_score'], bins=20, alpha=0.7, color='skyblue', edgecolor='black')
ax1.set_title('Overall Quality Score Distribution', fontweight='bold')
ax1.set_xlabel('Quality Score')
ax1.set_ylabel('Frequency')
ax1.axvline(df['overall_score'].mean(), color='red', linestyle='--',
label=f'Mean: {df["overall_score"].mean():.3f}')
ax1.legend()
# 2. Criteria scores radar chart
ax2 = axes[1]
if 'criteria_scores' in df.columns and not df['criteria_scores'].empty:
# Extract criteria names and average scores
all_criteria = set()
for scores in df['criteria_scores']:
all_criteria.update(scores.keys())
if all_criteria:
avg_scores = {}
for criterion in all_criteria:
scores = [item.get(criterion, {}).get('score', 0)
for item in df['criteria_scores'] if criterion in item]
avg_scores[criterion] = np.mean(scores) if scores else 0
# Create radar chart
criteria = list(avg_scores.keys())
scores = list(avg_scores.values())
# Add first point to close the circle
criteria += [criteria[0]]
scores += [scores[0]]
angles = np.linspace(0, 2 * np.pi, len(criteria))
ax2.plot(angles, scores, 'o-', linewidth=2, color='green')
ax2.fill(angles, scores, alpha=0.25, color='green')
ax2.set_xticks(angles[:-1])
ax2.set_xticklabels(criteria[:-1], rotation=45, ha='right')
ax2.set_title('Average Criteria Scores', fontweight='bold')
ax2.set_ylim(0, 1)
ax2.grid(True)
# 3. Quality vs Length scatter plot
ax3 = axes[2]
if 'overall_score' in df.columns:
# Calculate text lengths if available
text_lengths = []
for item in quality_data:
if 'text' in item:
text_lengths.append(len(item['text']))
else:
text_lengths.append(0)
if text_lengths:
ax3.scatter(text_lengths, df['overall_score'], alpha=0.6, color='purple')
ax3.set_title('Quality vs Text Length', fontweight='bold')
ax3.set_xlabel('Text Length (characters)')
ax3.set_ylabel('Quality Score')
# Add trend line
z = np.polyfit(text_lengths, df['overall_score'], 1)
p = np.poly1d(z)
ax3.plot(text_lengths, p(text_lengths), "r--", alpha=0.8)
# 4. Quality categories
ax4 = axes[3]
if 'overall_score' in df.columns:
# Categorize quality scores
def categorize_score(score):
if score >= 0.8:
return 'Excellent'
elif score >= 0.6:
return 'Good'
elif score >= 0.4:
return 'Fair'
else:
return 'Poor'
quality_categories = df['overall_score'].apply(categorize_score)
category_counts = quality_categories.value_counts()
colors = ['#2E8B57', '#FFD700', '#FF8C00', '#DC143C']
bars = ax4.bar(category_counts.index, category_counts.values,
color=colors[:len(category_counts)])
ax4.set_title('Quality Categories Distribution', fontweight='bold')
ax4.set_ylabel('Number of Documents')
# Add value labels
for bar, count in zip(bars, category_counts.values):
ax4.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,
str(count), ha='center', va='bottom')
# 5. Improvement suggestions word cloud
ax5 = axes[4]
all_suggestions = []
for item in quality_data:
if 'suggestions' in item:
all_suggestions.extend(item['suggestions'])
if all_suggestions:
# Join suggestions and create word cloud
suggestions_text = ' '.join(all_suggestions)
wordcloud = WordCloud(
width=400, height=300,
background_color='white',
colormap='plasma',
max_words=50
).generate(suggestions_text)
ax5.imshow(wordcloud, interpolation='bilinear')
ax5.axis('off')
ax5.set_title('Common Improvement Suggestions', fontweight='bold')
# 6. Quality trend over time (if timestamps available)
ax6 = axes[5]
if 'overall_score' in df.columns:
# Simple index-based trend
ax6.plot(range(len(df)), df['overall_score'], marker='o', linewidth=2, markersize=4)
ax6.set_title('Quality Trend (Document Order)', fontweight='bold')
ax6.set_xlabel('Document Index')
ax6.set_ylabel('Quality Score')
ax6.grid(True, alpha=0.3)
# Add moving average
window = min(5, len(df) // 4)
if window > 1:
moving_avg = df['overall_score'].rolling(window=window).mean()
ax6.plot(range(len(df)), moving_avg, 'r-', linewidth=2,
label=f'{window}-point Moving Average')
ax6.legend()
plt.suptitle(title, fontsize=16, fontweight='bold')
plt.tight_layout()
return fig
def plot_content_performance_metrics(self, performance_data: Dict,
title: str = "Content Performance Metrics") -> plt.Figure:
"""
Plot content performance metrics dashboard.
Args:
performance_data: Dictionary with performance metrics
title: Plot title
Returns:
Matplotlib figure
"""
if not performance_data:
return None
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
axes = axes.flatten()
# 1. Engagement metrics
ax1 = axes[0]
if 'engagement' in performance_data:
engagement_data = performance_data['engagement']
metrics = list(engagement_data.keys())
values = list(engagement_data.values())
bars = ax1.bar(metrics, values, color=self.color_palette[:len(metrics)])
ax1.set_title('Engagement Metrics', fontweight='bold')
ax1.set_ylabel('Value')
ax1.tick_params(axis='x', rotation=45)
# Add value labels
for bar, value in zip(bars, values):
ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + max(values)*0.01,
f'{value:.2f}', ha='center', va='bottom')
# 2. Content categories performance
ax2 = axes[1]
if 'category_performance' in performance_data:
cat_data = performance_data['category_performance']
categories = list(cat_data.keys())
avg_scores = [item.get('avg_score', 0) for item in cat_data.values()]
bars = ax2.bar(categories, avg_scores, color=self.color_palette[:len(categories)])
ax2.set_title('Performance by Category', fontweight='bold')
ax2.set_ylabel('Average Score')
ax2.tick_params(axis='x', rotation=45)
# 3. Temporal performance trends
ax3 = axes[2]
if 'temporal_trends' in performance_data:
trends = performance_data['temporal_trends']
dates = list(trends.keys())
scores = list(trends.values())
ax3.plot(dates, scores, marker='o', linewidth=2, markersize=6)
ax3.set_title('Performance Trends Over Time', fontweight='bold')
ax3.set_xlabel('Date')
ax3.set_ylabel('Performance Score')
ax3.tick_params(axis='x', rotation=45)
ax3.grid(True, alpha=0.3)
# 4. Top performing content
ax4 = axes[3]
if 'top_content' in performance_data:
top_content = performance_data['top_content']
titles = [item.get('title', f'Content {i+1}') for i, item in enumerate(top_content)]
scores = [item.get('score', 0) for item in top_content]
# Truncate long titles
titles = [title[:20] + '...' if len(title) > 20 else title for title in titles]
bars = ax4.barh(titles, scores, color=self.color_palette[:len(titles)])
ax4.set_title('Top Performing Content', fontweight='bold')
ax4.set_xlabel('Performance Score')
ax4.invert_yaxis()
plt.suptitle(title, fontsize=16, fontweight='bold')
plt.tight_layout()
return fig
def create_interactive_dashboard(self, analysis_results: Dict,
title: str = "Content Analysis Dashboard") -> go.Figure:
"""
Create interactive dashboard with multiple analysis views.
Args:
analysis_results: Comprehensive analysis results
title: Dashboard title
Returns:
Plotly figure with subplots
"""
# Create subplot layout
fig = make_subplots(
rows=3, cols=2,
specs=[
[{"type": "pie"}, {"type": "bar"}],
[{"type": "scatter"}, {"type": "bar"}],
[{"type": "table"}, {"type": "indicator"}]
],
subplot_titles=[
"Sentiment Distribution", "Topic Prevalence",
"Sentiment Timeline", "Quality Metrics",
"Top Content", "Overall Performance"
],
vertical_spacing=0.08,
horizontal_spacing=0.1
)
# 1. Sentiment distribution pie chart
if 'sentiment_analysis' in analysis_results:
sentiment_data = analysis_results['sentiment_analysis']
if 'distribution' in sentiment_data:
labels = list(sentiment_data['distribution'].keys())
values = list(sentiment_data['distribution'].values())
fig.add_trace(
go.Pie(
labels=labels,
values=values,
name="Sentiment"
),
row=1, col=1
)
# 2. Topic prevalence bar chart
if 'topic_analysis' in analysis_results:
topic_data = analysis_results['topic_analysis']
if 'topic_prevalence' in topic_data:
topics = list(topic_data['topic_prevalence'].keys())
prevalence = list(topic_data['topic_prevalence'].values())
fig.add_trace(
go.Bar(
x=topics,
y=prevalence,
name="Topic Prevalence"
),
row=1, col=2
)
# 3. Sentiment timeline
if 'sentiment_timeline' in analysis_results:
timeline_data = analysis_results['sentiment_timeline']
dates = timeline_data.get('dates', [])
scores = timeline_data.get('scores', [])
if dates and scores:
fig.add_trace(
go.Scatter(
x=dates,
y=scores,
mode='lines+markers',
name="Sentiment Trend"
),
row=2, col=1
)
# 4. Quality metrics
if 'quality_analysis' in analysis_results:
quality_data = analysis_results['quality_analysis']
if 'metrics' in quality_data:
metrics = list(quality_data['metrics'].keys())
values = list(quality_data['metrics'].values())
fig.add_trace(
go.Bar(
x=metrics,
y=values,
name="Quality Metrics"
),
row=2, col=2
)
# 5. Top content table
if 'top_content' in analysis_results:
top_data = analysis_results['top_content'][:5] # Top 5 items
headers = ["Title", "Score", "Category"]
# Prepare table data
table_data = []
for item in top_data:
row = [
item.get('title', 'N/A')[:30], # Truncate long titles
f"{item.get('score', 0):.3f}",
item.get('category', 'N/A')
]
table_data.append(row)
fig.add_trace(
go.Table(
header=dict(values=headers, fill_color='lightblue'),
cells=dict(values=list(zip(*table_data)) if table_data else [[], [], []],
fill_color='lightgray')
),
row=3, col=1
)
# 6. Overall performance indicator
if 'overall_performance' in analysis_results:
overall_score = analysis_results['overall_performance'].get('score', 0)
fig.add_trace(
go.Indicator(
mode="gauge+number+delta",
value=overall_score,
domain={'x': [0, 1], 'y': [0, 1]},
title={'text': "Overall Performance"},
gauge={
'axis': {'range': [None, 1]},
'bar': {'color': "darkblue"},
'steps': [
{'range': [0, 0.3], 'color': "lightgray"},
{'range': [0.3, 0.7], 'color': "gray"},
{'range': [0.7, 1], 'color': "lightgreen"}
],
'threshold': {
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'value': 0.8
}
}
),
row=3, col=2
)
# Update layout
fig.update_layout(
title=title,
height=1200,
showlegend=False
)
return fig
def create_word_cloud(self, text_data: Union[str, List[str]],
title: str = "Word Cloud",
width: int = 800,
height: int = 400,
colormap: str = 'viridis') -> plt.Figure:
"""
Create word cloud visualization.
Args:
text_data: Text or list of texts to visualize
title: Plot title
width: Word cloud width
height: Word cloud height
colormap: Matplotlib colormap name
Returns:
Matplotlib figure
"""
if not text_data:
return None
# Combine text if list provided
if isinstance(text_data, list):
text = ' '.join(text_data)
else:
text = text_data
# Create word cloud
wordcloud = WordCloud(
width=width,
height=height,
background_color='white',
colormap=colormap,
max_words=100,
relative_scaling=0.5,
random_state=42
).generate(text)
# Create figure
fig, ax = plt.subplots(figsize=(width/100, height/100))
ax.imshow(wordcloud, interpolation='bilinear')
ax.axis('off')
ax.set_title(title, fontweight='bold', fontsize=16)
return fig
def save_visualization(self, fig: Union[plt.Figure, go.Figure],
filename: str,
format: str = 'png',
dpi: int = 300):
"""
Save visualization to file.
Args:
fig: Figure to save
filename: Output filename
format: Output format ('png', 'jpg', 'svg', 'html')
dpi: Resolution for raster formats
"""
try:
if isinstance(fig, go.Figure):
if format.lower() == 'html':
fig.write_html(filename)
else:
fig.write_image(filename, format=format, width=1200, height=800)
else:
fig.savefig(filename, format=format, dpi=dpi, bbox_inches='tight')
print(f"Visualization saved to {filename}")
except Exception as e:
print(f"Error saving visualization: {e}")"""
LLM-Enhanced Content Analysis
This module provides LLM-powered content analysis capabilities for
advanced text understanding, sentiment analysis, and topic extraction
using models like OpenAI GPT and Qwen (通义千问).
"""
import pandas as pd
import numpy as np
import json
import time
from typing import List, Dict, Optional, Union, Tuple
import requests
import warnings
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
class LLMAnalyzer:
"""
LLM-powered content analysis toolkit.
Provides advanced text analysis capabilities using Large Language Models
for nuanced understanding, emotion detection, and semantic analysis.
"""
def __init__(self, provider: str = 'openai', api_key: str = None, model: str = None):
"""
Initialize the LLMAnalyzer.
Args:
provider: LLM provider ('openai', 'qwen', 'local')
api_key: API key for the LLM service
model: Model name to use
"""
self.provider = provider
self.api_key = api_key
self.model = model
self.rate_limit_delay = 1.0 # Delay between API calls
self.max_retries = 3
# Configure default models
if provider == 'openai':
self.model = model or 'gpt-3.5-turbo'
self.api_base = 'https://api.openai.com/v1'
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
elif provider == 'qwen':
self.model = model or 'qwen-turbo'
self.api_base = 'https://dashscope.aliyuncs.com/api/v1'
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
else:
raise ValueError("Provider must be 'openai' or 'qwen'")
def _make_api_request(self, messages: List[Dict], **kwargs) -> Dict:
"""
Make API request to the LLM service.
Args:
messages: List of messages for the conversation
**kwargs: Additional parameters
Returns:
API response dictionary
"""
for attempt in range(self.max_retries):
try:
payload = {
'model': self.model,
'messages': messages,
**kwargs
}
response = requests.post(
f"{self.api_base}/chat/completions",
headers=self.headers,
json=payload,
timeout=30
)
if response.status_code == 200:
return response.json()
elif response.status_code == 429: # Rate limit
time.sleep(self.rate_limit_delay * (2 ** attempt))
continue
else:
response.raise_for_status()
except Exception as e:
if attempt == self.max_retries - 1:
raise e
time.sleep(self.rate_limit_delay * (2 ** attempt))
return {}
def _extract_content_from_response(self, response: Dict) -> str:
"""Extract content from LLM response."""
try:
if self.provider == 'openai':
return response['choices'][0]['message']['content']
elif self.provider == 'qwen':
return response['output']['choices'][0]['message']['content']
except (KeyError, IndexError):
return ""
def analyze_sentiment_llm(self, text: str,
context: str = None,
detailed: bool = False) -> Dict:
"""
Analyze sentiment using LLM for nuanced understanding.
Args:
text: Text to analyze
context: Additional context for analysis
detailed: Whether to return detailed analysis
Returns:
Dictionary with sentiment analysis results
"""
if not text or not text.strip():
return {
'sentiment': 'neutral',
'confidence': 0.0,
'emotions': [],
'explanation': 'No text provided'
}
# Build prompt
if detailed:
prompt = f"""
Analyze the sentiment of the following text in detail. Consider:
1. Overall sentiment (positive, negative, neutral)
2. Specific emotions present (joy, anger, fear, sadness, surprise, etc.)
3. Confidence level in your analysis
4. Brief explanation for your assessment
Text: {text}
Context: {context or 'No additional context provided'}
Please respond in JSON format:
{{
"sentiment": "positive/negative/neutral",
"confidence": 0.0-1.0,
"emotions": ["emotion1", "emotion2", ...],
"explanation": "Brief explanation"
}}
"""
else:
prompt = f"""
Analyze the sentiment of this text and respond with only "positive", "negative", or "neutral":
Text: {text}
Sentiment:"""
messages = [
{"role": "system", "content": "You are a sentiment analysis expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.1)
content = self._extract_content_from_response(response)
if detailed:
try:
# Parse JSON response
result = json.loads(content.strip())
return result
except json.JSONDecodeError:
# Fallback parsing
return {
'sentiment': 'neutral',
'confidence': 0.5,
'emotions': [],
'explanation': content
}
else:
# Simple sentiment classification
sentiment = content.strip().lower()
if sentiment in ['positive', 'negative', 'neutral']:
return {
'sentiment': sentiment,
'confidence': 0.8, # Default confidence
'text': text
}
else:
return {
'sentiment': 'neutral',
'confidence': 0.0,
'text': text
}
except Exception as e:
print(f"Error in LLM sentiment analysis: {e}")
return {
'sentiment': 'neutral',
'confidence': 0.0,
'error': str(e),
'text': text
}
def analyze_batch_sentiment_llm(self, texts: List[str],
context: str = None,
detailed: bool = False,
max_workers: int = 3) -> List[Dict]:
"""
Analyze sentiment for a batch of texts using LLM.
Args:
texts: List of texts to analyze
context: Additional context for analysis
detailed: Whether to return detailed analysis
max_workers: Maximum concurrent API calls
Returns:
List of sentiment analysis results
"""
results = []
# Use thread pool for concurrent processing
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# Submit all tasks
future_to_text = {
executor.submit(self.analyze_sentiment_llm, text, context, detailed): text
for text in texts
}
# Collect results as they complete
for future in as_completed(future_to_text):
text = future_to_text[future]
try:
result = future.result()
result['text'] = text
results.append(result)
# Rate limiting
time.sleep(self.rate_limit_delay)
except Exception as e:
results.append({
'text': text,
'sentiment': 'neutral',
'confidence': 0.0,
'error': str(e)
})
return results
def extract_topics_llm(self, texts: List[str],
topics_per_text: int = 3,
context: str = None) -> Dict:
"""
Extract topics using LLM for semantic understanding.
Args:
texts: List of texts to analyze
topics_per_text: Number of topics to extract per text
context: Additional context for analysis
Returns:
Dictionary with topic extraction results
"""
if not texts:
return {'topics': [], 'text_topics': {}}
# Build prompt
prompt = f"""
Analyze the following texts and extract the main topics and themes.
For each text, identify the top {topics_per_text} most relevant topics.
Consider the semantic meaning and context.
Context: {context or 'No additional context provided'}
Texts to analyze:
{chr(10).join([f"{i+1}. {text}" for i, text in enumerate(texts)])}
Please respond in JSON format:
{{
"overall_topics": ["topic1", "topic2", ...],
"text_topics": {{
"text_1": ["topic1", "topic2", ...],
"text_2": ["topic1", "topic2", ...],
...
}},
"topic_descriptions": {{
"topic1": "description of topic1",
...
}}
}}
"""
messages = [
{"role": "system", "content": "You are a topic analysis expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.3)
content = self._extract_content_from_response(response)
# Parse JSON response
try:
result = json.loads(content.strip())
# Map text indices to original texts
if 'text_topics' in result:
mapped_text_topics = {}
for i, text in enumerate(texts):
text_key = f"text_{i+1}"
if text_key in result['text_topics']:
mapped_text_topics[i] = result['text_topics'][text_key]
result['text_topics'] = mapped_text_topics
return result
except json.JSONDecodeError:
# Fallback - try simple parsing
return {
'overall_topics': [],
'text_topics': {},
'raw_response': content
}
except Exception as e:
print(f"Error in LLM topic extraction: {e}")
return {'error': str(e), 'overall_topics': [], 'text_topics': {}}
def classify_content_llm(self, texts: List[str],
categories: List[str],
context: str = None) -> Dict:
"""
Classify content into predefined categories using LLM.
Args:
texts: List of texts to classify
categories: List of possible categories
context: Additional context for classification
Returns:
Dictionary with classification results
"""
if not texts or not categories:
return {'classifications': [], 'uncategorized': []}
# Build prompt
categories_str = ", ".join(categories)
prompt = f"""
Classify the following texts into one of these categories: {categories_str}
Context: {context or 'No additional context provided'}
Texts to classify:
{chr(10).join([f"{i+1}. {text}" for i, text in enumerate(texts)])}
Please respond in JSON format:
{{
"classifications": [
{{"text_index": 1, "category": "category_name", "confidence": 0.95, "reasoning": "brief explanation"}},
...
]
}}
"""
messages = [
{"role": "system", "content": "You are a content classification expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.1)
content = self._extract_content_from_response(response)
# Parse JSON response
try:
result = json.loads(content.strip())
return result
except json.JSONDecodeError:
# Fallback - return empty classifications
return {'classifications': [], 'raw_response': content}
except Exception as e:
print(f"Error in LLM content classification: {e}")
return {'error': str(e), 'classifications': []}
def summarize_text_llm(self, text: str,
max_length: int = 150,
style: str = 'neutral') -> str:
"""
Generate a summary of text using LLM.
Args:
text: Text to summarize
max_length: Maximum length of summary
style: Summary style ('neutral', 'formal', 'casual')
Returns:
Generated summary text
"""
if not text or not text.strip():
return ""
style_instructions = {
'neutral': "Provide a balanced, objective summary.",
'formal': "Provide a professional, formal summary.",
'casual': "Provide a friendly, conversational summary."
}
prompt = f"""
Summarize the following text in no more than {max_length} words.
{style_instructions.get(style, style_instructions['neutral'])}
Text: {text}
Summary:"""
messages = [
{"role": "system", "content": "You are a text summarization expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.3)
return self._extract_content_from_response(response).strip()
except Exception as e:
print(f"Error in LLM text summarization: {e}")
return ""
def analyze_content_quality_llm(self, text: str,
criteria: List[str] = None) -> Dict:
"""
Analyze content quality using LLM.
Args:
text: Text to analyze
criteria: Quality criteria to evaluate
Returns:
Dictionary with quality analysis results
"""
if not text or not text.strip():
return {'overall_score': 0.0, 'criteria_scores': {}, 'suggestions': []}
if not criteria:
criteria = ['clarity', 'engagement', 'accuracy', 'relevance', 'structure']
criteria_str = ", ".join(criteria)
prompt = f"""
Analyze the quality of the following text based on these criteria: {criteria_str}
For each criterion, provide a score from 0.0 to 1.0 and brief feedback.
Also provide an overall quality score and suggestions for improvement.
Text: {text}
Please respond in JSON format:
{{
"overall_score": 0.0-1.0,
"criteria_scores": {{
"criterion1": {{"score": 0.0-1.0, "feedback": "brief feedback"}},
...
}},
"suggestions": ["suggestion1", "suggestion2", ...]
}}
"""
messages = [
{"role": "system", "content": "You are a content quality analysis expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.2)
content = self._extract_content_from_response(response)
# Parse JSON response
try:
result = json.loads(content.strip())
return result
except json.JSONDecodeError:
# Fallback - return basic structure
return {
'overall_score': 0.5,
'criteria_scores': {},
'raw_response': content
}
except Exception as e:
print(f"Error in LLM quality analysis: {e}")
return {'error': str(e), 'overall_score': 0.0}
def generate_content_insights_llm(self, texts: List[str],
analysis_type: str = 'general') -> Dict:
"""
Generate comprehensive content insights using LLM.
Args:
texts: List of texts to analyze
analysis_type: Type of analysis ('general', 'marketing', 'sentiment', 'engagement')
Returns:
Dictionary with insights and recommendations
"""
if not texts:
return {'insights': [], 'recommendations': [], 'patterns': []}
# Build analysis-specific prompt
analysis_prompts = {
'general': "Analyze these texts and provide general insights about content themes, patterns, and characteristics.",
'marketing': "Analyze these marketing texts and provide insights about messaging effectiveness, audience appeal, and optimization opportunities.",
'sentiment': "Analyze these texts focusing on emotional patterns, sentiment trends, and psychological insights.",
'engagement': "Analyze these texts for engagement potential, viral characteristics, and audience interaction factors."
}
prompt = f"""
{analysis_prompts.get(analysis_type, analysis_prompts['general'])}
Provide:
1. Key insights about the content
2. Notable patterns and trends
3. Specific recommendations for improvement
4. Target audience characteristics
Texts to analyze:
{chr(10).join([f"{i+1}. {text}" for i, text in enumerate(texts)])}
Please respond in JSON format:
{{
"insights": ["insight1", "insight2", ...],
"patterns": ["pattern1", "pattern2", ...],
"recommendations": ["recommendation1", "recommendation2", ...],
"target_audience": ["characteristic1", "characteristic2", ...]
}}
"""
messages = [
{"role": "system", "content": "You are a content analysis and strategy expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.3)
content = self._extract_content_from_response(response)
# Parse JSON response
try:
result = json.loads(content.strip())
return result
except json.JSONDecodeError:
# Fallback - try simple parsing
return {
'insights': [],
'patterns': [],
'recommendations': [],
'raw_response': content
}
except Exception as e:
print(f"Error in LLM insights generation: {e}")
return {'error': str(e), 'insights': [], 'recommendations': []}
def detect_viral_potential_llm(self, text: str) -> Dict:
"""
Detect viral potential of content using LLM.
Args:
text: Text to analyze for viral potential
Returns:
Dictionary with viral potential analysis
"""
if not text or not text.strip():
return {'viral_score': 0.0, 'factors': [], 'recommendations': []}
prompt = f"""
Analyze this text for viral potential. Consider factors like:
- Emotional appeal
- Shareability
- Novelty
- Controversy
- Practical value
- Entertainment value
Provide a viral potential score (0.0-1.0) and specific factors.
Text: {text}
Please respond in JSON format:
{{
"viral_score": 0.0-1.0,
"factors": [
{{"factor": "emotional_appeal", "score": 0.0-1.0, "explanation": "brief explanation"}},
...
],
"recommendations": ["recommendation1", "recommendation2", ...]
}}
"""
messages = [
{"role": "system", "content": "You are a viral content analysis expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.3)
content = self._extract_content_from_response(response)
# Parse JSON response
try:
result = json.loads(content.strip())
return result
except json.JSONDecodeError:
# Fallback - return basic structure
return {
'viral_score': 0.5,
'factors': [],
'raw_response': content
}
except Exception as e:
print(f"Error in viral potential detection: {e}")
return {'error': str(e), 'viral_score': 0.0}
def translate_content_llm(self, text: str,
target_language: str,
preserve_style: bool = True) -> Dict:
"""
Translate content using LLM.
Args:
text: Text to translate
target_language: Target language for translation
preserve_style: Whether to preserve original style
Returns:
Dictionary with translation results
"""
if not text or not text.strip():
return {'translated_text': '', 'confidence': 0.0}
style_instruction = " and preserve the original tone and style" if preserve_style else ""
prompt = f"""
Translate the following text to {target_language}{style_instruction}.
Text: {text}
Translation:"""
messages = [
{"role": "system", "content": f"You are a professional translator specializing in translation to {target_language}."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.1)
translated_text = self._extract_content_from_response(response).strip()
return {
'translated_text': translated_text,
'original_text': text,
'target_language': target_language,
'confidence': 0.9 # Default confidence
}
except Exception as e:
print(f"Error in LLM translation: {e}")
return {
'translated_text': '',
'error': str(e),
'original_text': text
}
def analyze_content_llm_comprehensive(self, text: str,
context: str = None) -> Dict:
"""
Perform comprehensive content analysis using LLM.
Args:
text: Text to analyze
context: Additional context for analysis
Returns:
Dictionary with comprehensive analysis results
"""
if not text or not text.strip():
return {}
prompt = f"""
Perform a comprehensive analysis of this text. Include:
1. Sentiment analysis with emotion detection
2. Key topics and themes
3. Content quality assessment
4. Audience identification
5. Engagement potential
6. Improvement recommendations
Context: {context or 'No additional context provided'}
Text: {text}
Please respond in JSON format:
{{
"sentiment": {{
"overall": "positive/negative/neutral",
"confidence": 0.0-1.0,
"emotions": ["emotion1", "emotion2", ...]
}},
"topics": ["topic1", "topic2", ...],
"quality": {{
"score": 0.0-1.0,
"clarity": 0.0-1.0,
"engagement": 0.0-1.0
}},
"audience": ["characteristic1", "characteristic2", ...],
"engagement_potential": {{
"score": 0.0-1.0,
"factors": ["factor1", "factor2", ...]
}},
"recommendations": ["recommendation1", "recommendation2", ...]
}}
"""
messages = [
{"role": "system", "content": "You are a comprehensive content analysis expert."},
{"role": "user", "content": prompt}
]
try:
response = self._make_api_request(messages, temperature=0.3)
content = self._extract_content_from_response(response)
# Parse JSON response
try:
result = json.loads(content.strip())
return result
except json.JSONDecodeError:
# Fallback - perform individual analyses
return {
'sentiment': self.analyze_sentiment_llm(text, context, detailed=True),
'topics': self.extract_topics_llm([text], context=context).get('overall_topics', []),
'raw_response': content
}
except Exception as e:
print(f"Error in comprehensive LLM analysis: {e}")
return {'error': str(e)}"""
Sentiment Analysis Tools
This module provides comprehensive sentiment analysis capabilities using both
traditional NLP methods (VADER) and LLM-enhanced analysis for nuanced emotion detection.
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from typing import List, Dict, Optional, Tuple, Union
import nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from wordcloud import WordCloud
import warnings
# Download VADER lexicon
try:
nltk.data.find('sentiment/vader_lexicon.zip')
except LookupError:
nltk.download('vader_lexicon')
class SentimentAnalyzer:
"""
Comprehensive sentiment analysis toolkit.
Provides traditional VADER sentiment analysis and preparation
for LLM-enhanced sentiment analysis.
"""
def __init__(self):
"""Initialize the SentimentAnalyzer."""
# Initialize VADER sentiment analyzer
self.vader_analyzer = SentimentIntensityAnalyzer()
# Sentiment labels
self.sentiment_labels = {
'positive': 'Positive',
'negative': 'Negative',
'neutral': 'Neutral'
}
# Extended sentiment labels for LLM analysis
self.extended_labels = {
'very_positive': 'Very Positive',
'positive': 'Positive',
'neutral': 'Neutral',
'negative': 'Negative',
'very_negative': 'Very Negative'
}
def analyze_sentiment_vader(self, text: str) -> Dict[str, float]:
"""
Analyze sentiment using VADER (Valence Aware Dictionary and sEntiment Reasoner).
Args:
text: Input text to analyze
Returns:
Dictionary with sentiment scores
"""
if not isinstance(text, str) or not text.strip():
return {
'compound': 0.0,
'positive': 0.0,
'negative': 0.0,
'neutral': 1.0,
'label': 'Neutral'
}
# Get VADER scores
scores = self.vader_analyzer.polarity_scores(text)
# Determine sentiment label based on compound score
if scores['compound'] >= 0.05:
label = 'Positive'
elif scores['compound'] <= -0.05:
label = 'Negative'
else:
label = 'Neutral'
return {
'compound': scores['compound'],
'positive': scores['pos'],
'negative': scores['neg'],
'neutral': scores['neu'],
'label': label
}
def analyze_batch_vader(self, texts: List[str]) -> List[Dict[str, Union[float, str]]]:
"""
Analyze sentiment for a batch of texts using VADER.
Args:
texts: List of texts to analyze
Returns:
List of sentiment analysis results
"""
results = []
for text in texts:
result = self.analyze_sentiment_vader(text)
result['text'] = text
results.append(result)
return results
def classify_sentiment_distribution(self, texts: List[str]) -> Dict[str, Union[int, float]]:
"""
Classify sentiment distribution across a collection of texts.
Args:
texts: List of texts to analyze
Returns:
Dictionary with sentiment distribution statistics
"""
if not texts:
return {'positive': 0, 'negative': 0, 'neutral': 0, 'total': 0}
# Analyze all texts
results = self.analyze_batch_vader(texts)
# Count sentiments
sentiment_counts = {'positive': 0, 'negative': 0, 'neutral': 0}
for result in results:
label = result['label'].lower()
sentiment_counts[label] += 1
# Calculate percentages
total = len(texts)
sentiment_percentages = {
f'{sentiment}_count': count for sentiment, count in sentiment_counts.items()
}
sentiment_percentages.update({
f'{sentiment}_percent': (count / total) * 100
for sentiment, count in sentiment_counts.items()
})
sentiment_percentages['total'] = total
return sentiment_percentages
def get_emotion_words(self, texts: List[str],
sentiment_type: str = 'positive',
top_k: int = 20) -> List[Tuple[str, int]]:
"""
Extract most frequent words associated with a specific sentiment.
Args:
texts: List of texts to analyze
sentiment_type: Type of sentiment ('positive', 'negative', 'neutral')
top_k: Number of top words to return
Returns:
List of (word, frequency) tuples
"""
from scripts.text_analyzer import TextAnalyzer
if not texts:
return []
# Initialize text analyzer
text_analyzer = TextAnalyzer()
# Analyze sentiment for each text
sentiment_texts = []
for text in texts:
result = self.analyze_sentiment_vader(text)
if result['label'].lower() == sentiment_type.lower():
sentiment_texts.append(text)
if not sentiment_texts:
return []
# Tokenize and count words
all_words = []
for text in sentiment_texts:
tokens = text_analyzer.tokenize_text(text)
all_words.extend(tokens)
# Count word frequencies
word_freq = {}
for word in all_words:
if len(word) > 2: # Filter out very short words
word_freq[word] = word_freq.get(word, 0) + 1
# Return top k words
return sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:top_k]
def create_sentiment_wordcloud(self, texts: List[str],
sentiment_type: str = 'positive',
width: int = 800,
height: int = 400) -> WordCloud:
"""
Create a word cloud for texts with specific sentiment.
Args:
texts: List of texts to analyze
sentiment_type: Type of sentiment to visualize
width: Word cloud width
height: Word cloud height
Returns:
WordCloud object
"""
# Get emotion words
emotion_words = self.get_emotion_words(texts, sentiment_type)
if not emotion_words:
return None
# Create word frequency dictionary
word_freq = dict(emotion_words)
# Create word cloud
if sentiment_type == 'positive':
colormap = 'Greens'
elif sentiment_type == 'negative':
colormap = 'Reds'
else:
colormap = 'Blues'
wordcloud = WordCloud(
width=width,
height=height,
background_color='white',
colormap=colormap,
max_words=100,
relative_scaling=0.5,
random_state=42
).generate_from_frequencies(word_freq)
return wordcloud
def plot_sentiment_distribution(self, texts: List[str],
title: str = "Sentiment Distribution",
figsize: Tuple[int, int] = (10, 6)) -> plt.Figure:
"""
Plot sentiment distribution for a collection of texts.
Args:
texts: List of texts to analyze
title: Plot title
figsize: Figure size tuple
Returns:
Matplotlib figure object
"""
# Get sentiment distribution
distribution = self.classify_sentiment_distribution(texts)
# Create figure
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize)
# Bar chart
sentiments = ['Positive', 'Negative', 'Neutral']
counts = [distribution.get('positive_count', 0),
distribution.get('negative_count', 0),
distribution.get('neutral_count', 0)]
bars = ax1.bar(sentiments, counts, color=['green', 'red', 'gray'])
ax1.set_title('Sentiment Count Distribution', fontweight='bold')
ax1.set_ylabel('Number of Texts')
# Add value labels on bars
for bar, count in zip(bars, counts):
ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.1,
str(count), ha='center', va='bottom')
# Pie chart
percentages = [distribution.get('positive_percent', 0),
distribution.get('negative_percent', 0),
distribution.get('neutral_percent', 0)]
colors = ['lightgreen', 'lightcoral', 'lightgray']
wedges, texts, autotexts = ax2.pie(percentages, labels=sentiments, colors=colors,
autopct='%1.1f%%', startangle=90)
ax2.set_title('Sentiment Percentage Distribution', fontweight='bold')
# Overall title
fig.suptitle(title, fontsize=16, fontweight='bold')
plt.tight_layout()
return fig
def analyze_sentiment_trends(self, texts: List[str],
timestamps: List[str] = None,
time_window: str = 'daily') -> pd.DataFrame:
"""
Analyze sentiment trends over time.
Args:
texts: List of texts to analyze
timestamps: List of timestamps corresponding to texts
time_window: Time aggregation window ('daily', 'weekly', 'monthly')
Returns:
DataFrame with sentiment trends
"""
if not texts:
return pd.DataFrame()
# Analyze sentiment for all texts
results = self.analyze_batch_vader(texts)
# Create DataFrame
df = pd.DataFrame(results)
# Add timestamps if provided
if timestamps:
df['timestamp'] = pd.to_datetime(timestamps)
df.set_index('timestamp', inplace=True)
# Aggregate by time window
if time_window == 'daily':
df_resampled = df.resample('D')
elif time_window == 'weekly':
df_resampled = df.resample('W')
elif time_window == 'monthly':
df_resampled = df.resample('M')
else:
df_resampled = df.resample('D')
# Calculate sentiment statistics
trends = df_resampled.agg({
'compound': ['mean', 'count'],
'positive': 'mean',
'negative': 'mean',
'neutral': 'mean'
}).round(3)
# Flatten column names
trends.columns = [f'{col[0]}_{col[1]}' for col in trends.columns]
return trends.reset_index()
else:
# Simple index-based trends
return df.reset_index(drop=True)
def compare_sentiment_between_groups(self,
group1_texts: List[str],
group2_texts: List[str],
group1_name: str = "Group 1",
group2_name: str = "Group 2") -> Dict:
"""
Compare sentiment between two groups of texts.
Args:
group1_texts: First group of texts
group2_texts: Second group of texts
group1_name: Name for first group
group2_name: Name for second group
Returns:
Dictionary with comparison results
"""
# Analyze sentiment for both groups
group1_results = self.analyze_batch_vader(group1_texts)
group2_results = self.analyze_batch_vader(group2_texts)
# Calculate statistics
group1_compound = [r['compound'] for r in group1_results]
group2_compound = [r['compound'] for r in group2_results]
comparison = {
'group1': {
'name': group1_name,
'count': len(group1_texts),
'mean_compound': np.mean(group1_compound),
'std_compound': np.std(group1_compound),
'positive_percent': len([r for r in group1_results if r['label'] == 'Positive']) / len(group1_results) * 100,
'negative_percent': len([r for r in group1_results if r['label'] == 'Negative']) / len(group1_results) * 100,
'neutral_percent': len([r for r in group1_results if r['label'] == 'Neutral']) / len(group1_results) * 100
},
'group2': {
'name': group2_name,
'count': len(group2_texts),
'mean_compound': np.mean(group2_compound),
'std_compound': np.std(group2_compound),
'positive_percent': len([r for r in group2_results if r['label'] == 'Positive']) / len(group2_results) * 100,
'negative_percent': len([r for r in group2_results if r['label'] == 'Negative']) / len(group2_results) * 100,
'neutral_percent': len([r for r in group2_results if r['label'] == 'Neutral']) / len(group2_results) * 100
}
}
# Statistical test (t-test)
from scipy import stats
t_stat, p_value = stats.ttest_ind(group1_compound, group2_compound)
comparison['statistical_test'] = {
't_statistic': t_stat,
'p_value': p_value,
'significant_difference': p_value < 0.05
}
return comparison
def get_sentiment_summary(self, texts: List[str]) -> Dict[str, Union[str, float, int]]:
"""
Get a comprehensive sentiment summary for a collection of texts.
Args:
texts: List of texts to analyze
Returns:
Dictionary with sentiment summary
"""
if not texts:
return {}
# Analyze all texts
results = self.analyze_batch_vader(texts)
# Extract scores
compound_scores = [r['compound'] for r in results]
positive_scores = [r['positive'] for r in results]
negative_scores = [r['negative'] for r in results]
neutral_scores = [r['neutral'] for r in results]
# Get distribution
distribution = self.classify_sentiment_distribution(texts)
# Create summary
summary = {
'total_texts': len(texts),
'average_compound_score': np.mean(compound_scores),
'median_compound_score': np.median(compound_scores),
'std_compound_score': np.std(compound_scores),
'min_compound_score': np.min(compound_scores),
'max_compound_score': np.max(compound_scores),
'positive_count': distribution.get('positive_count', 0),
'negative_count': distribution.get('negative_count', 0),
'neutral_count': distribution.get('neutral_count', 0),
'positive_percentage': distribution.get('positive_percent', 0),
'negative_percentage': distribution.get('negative_percent', 0),
'neutral_percentage': distribution.get('neutral_percent', 0),
'dominant_sentiment': max(['positive', 'negative', 'neutral'],
key=lambda x: distribution.get(f'{x}_count', 0))
}
return summary
def plot_sentiment_comparison(self, comparisons: Dict,
title: str = "Sentiment Comparison") -> plt.Figure:
"""
Plot sentiment comparison between groups.
Args:
comparisons: Comparison dictionary from compare_sentiment_between_groups
title: Plot title
Returns:
Matplotlib figure object
"""
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 10))
groups = [comparisons['group1'], comparisons['group2']]
group_names = [g['name'] for g in groups]
# Compound score comparison
compound_means = [g['mean_compound'] for g in groups]
compound_stds = [g['std_compound'] for g in groups]
ax1.bar(group_names, compound_means, yerr=compound_stds, capsize=5, color=['skyblue', 'lightcoral'])
ax1.set_title('Average Compound Score', fontweight='bold')
ax1.set_ylabel('Compound Score')
ax1.axhline(y=0, color='black', linestyle='-', alpha=0.3)
# Sentiment distribution comparison
sentiments = ['Positive', 'Negative', 'Neutral']
group1_percentages = [groups[0]['positive_percent'], groups[0]['negative_percent'], groups[0]['neutral_percent']]
group2_percentages = [groups[1]['positive_percent'], groups[1]['negative_percent'], groups[1]['neutral_percent']]
x = np.arange(len(sentiments))
width = 0.35
ax2.bar(x - width/2, group1_percentages, width, label=group_names[0], color='lightgreen')
ax2.bar(x + width/2, group2_percentages, width, label=group_names[1], color='lightcoral')
ax2.set_title('Sentiment Distribution Comparison', fontweight='bold')
ax2.set_ylabel('Percentage')
ax2.set_xticks(x)
ax2.set_xticklabels(sentiments)
ax2.legend()
# Text count comparison
text_counts = [g['count'] for g in groups]
ax3.bar(group_names, text_counts, color=['skyblue', 'lightcoral'])
ax3.set_title('Number of Texts Analyzed', fontweight='bold')
ax3.set_ylabel('Count')
# Statistical significance
if comparisons['statistical_test']['significant_difference']:
sig_text = f"Significant difference (p={comparisons['statistical_test']['p_value']:.4f})"
color = 'green'
else:
sig_text = f"No significant difference (p={comparisons['statistical_test']['p_value']:.4f})"
color = 'red'
ax4.text(0.5, 0.5, sig_text, ha='center', va='center', fontsize=14,
color=color, transform=ax4.transAxes, fontweight='bold')
ax4.set_title('Statistical Test Result', fontweight='bold')
ax4.axis('off')
plt.suptitle(title, fontsize=16, fontweight='bold')
plt.tight_layout()
return fig"""
Text Analysis Core Functions
This module provides comprehensive text preprocessing and analysis utilities
for content analysis tasks including cleaning, tokenization, and basic NLP operations.
"""
import pandas as pd
import numpy as np
import re
import string
from typing import List, Dict, Optional, Tuple, Union
from collections import Counter
import nltk
from nltk.tokenize import word_tokenize, sent_tokenize
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.metrics.pairwise import cosine_similarity
import warnings
# Download required NLTK data (only if not already downloaded)
def download_nltk_data():
"""Download required NLTK data packages."""
try:
nltk.data.find('tokenizers/punkt')
except LookupError:
nltk.download('punkt')
try:
nltk.data.find('corpora/stopwords')
except LookupError:
nltk.download('stopwords')
try:
nltk.data.find('corpora/wordnet')
except LookupError:
nltk.download('wordnet')
download_nltk_data()
class TextAnalyzer:
"""
Comprehensive text analysis toolkit.
Provides text preprocessing, cleaning, tokenization, and basic NLP analysis
for content analysis tasks.
"""
def __init__(self, language='english'):
"""
Initialize the TextAnalyzer.
Args:
language: Language for stopwords and processing (default: 'english')
"""
self.language = language
self.lemmatizer = WordNetLemmatizer()
# Load stopwords for specified language
try:
self.stop_words = set(stopwords.words(language))
except OSError:
# Fallback to English if language not found
self.stop_words = set(stopwords.words('english'))
# Add custom stopwords
custom_stopwords = {'http', 'https', 'www', 'com', 'org', 'net'}
self.stop_words.update(custom_stopwords)
def clean_text(self, text: str,
remove_urls: bool = True,
remove_mentions: bool = True,
remove_hashtags: bool = False,
remove_numbers: bool = False,
remove_punctuation: bool = True,
lowercase: bool = True) -> str:
"""
Clean text by removing unwanted elements.
Args:
text: Input text to clean
remove_urls: Whether to remove URLs
remove_mentions: Whether to remove @mentions
remove_hashtags: Whether to remove #hashtags (keep text without #)
remove_numbers: Whether to remove numbers
remove_punctuation: Whether to remove punctuation
lowercase: Whether to convert to lowercase
Returns:
Cleaned text string
"""
if not isinstance(text, str):
return ""
# Remove URLs
if remove_urls:
text = re.sub(r'https?://\S+|www\.\S+', '', text)
# Remove mentions (@username)
if remove_mentions:
text = re.sub(r'@\w+', '', text)
# Remove hashtags (keep text, remove #)
if remove_hashtags:
text = re.sub(r'#(\w+)', r'\1', text)
# Remove numbers
if remove_numbers:
text = re.sub(r'\d+', '', text)
# Remove punctuation
if remove_punctuation:
text = text.translate(str.maketrans('', '', string.punctuation))
# Convert to lowercase
if lowercase:
text = text.lower()
# Remove extra whitespace
text = re.sub(r'\s+', ' ', text).strip()
return text
def tokenize_text(self, text: str,
remove_stopwords: bool = True,
lemmatize: bool = True) -> List[str]:
"""
Tokenize text into words.
Args:
text: Input text to tokenize
remove_stopwords: Whether to remove stopwords
lemmatize: Whether to lemmatize tokens
Returns:
List of tokens
"""
# Clean text first
cleaned_text = self.clean_text(text)
if not cleaned_text:
return []
# Tokenize
tokens = word_tokenize(cleaned_text)
# Remove stopwords
if remove_stopwords:
tokens = [token for token in tokens if token not in self.stop_words]
# Remove single character tokens
tokens = [token for token in tokens if len(token) > 1]
# Lemmatize
if lemmatize:
tokens = [self.lemmatizer.lemmatize(token) for token in tokens]
return tokens
def extract_keywords(self, text: str,
top_k: int = 10,
method: str = 'frequency') -> List[Tuple[str, float]]:
"""
Extract keywords from text.
Args:
text: Input text
top_k: Number of top keywords to return
method: Keyword extraction method ('frequency' or 'tfidf')
Returns:
List of (keyword, score) tuples
"""
if not text:
return []
# Tokenize text
tokens = self.tokenize_text(text)
if not tokens:
return []
if method == 'frequency':
# Simple frequency counting
word_freq = Counter(tokens)
return word_freq.most_common(top_k)
elif method == 'tfidf':
# TF-IDF scoring
try:
tfidf = TfidfVectorizer(max_features=1000, stop_words='english')
tfidf_matrix = tfidf.fit_transform([text])
# Get feature names and scores
feature_names = tfidf.get_feature_names_out()
tfidf_scores = tfidf_matrix.toarray()[0]
# Create keyword-score pairs
keywords = [(feature_names[i], tfidf_scores[i])
for i in range(len(feature_names))
if tfidf_scores[i] > 0]
# Sort by score and return top k
keywords.sort(key=lambda x: x[1], reverse=True)
return keywords[:top_k]
except Exception:
# Fallback to frequency method
word_freq = Counter(tokens)
return word_freq.most_common(top_k)
else:
raise ValueError("Method must be 'frequency' or 'tfidf'")
def calculate_readability(self, text: str) -> Dict[str, float]:
"""
Calculate basic readability metrics.
Args:
text: Input text
Returns:
Dictionary with readability metrics
"""
if not text:
return {}
# Clean text for analysis
cleaned_text = self.clean_text(text, remove_punctuation=False)
# Split into sentences and words
sentences = sent_tokenize(cleaned_text)
words = word_tokenize(cleaned_text)
# Filter out punctuation
words = [word for word in words if word.isalpha()]
if not sentences or not words:
return {}
# Calculate metrics
num_sentences = len(sentences)
num_words = len(words)
num_syllables = sum(self._count_syllables(word) for word in words)
# Average values
avg_sentence_length = num_words / num_sentences
avg_syllables_per_word = num_syllables / num_words
# Flesch Reading Ease (simplified version)
flesch_score = 206.835 - (1.015 * avg_sentence_length) - (84.6 * avg_syllables_per_word)
return {
'num_sentences': num_sentences,
'num_words': num_words,
'avg_sentence_length': avg_sentence_length,
'avg_syllables_per_word': avg_syllables_per_word,
'flesch_reading_ease': max(0, min(100, flesch_score)), # Clamp to 0-100
'reading_level': self._get_reading_level(flesch_score)
}
def _count_syllables(self, word: str) -> int:
"""Simple syllable counting (approximate)."""
vowels = "aeiouy"
word = word.lower()
syllable_count = 0
prev_char_was_vowel = False
for char in word:
is_vowel = char in vowels
if is_vowel and not prev_char_was_vowel:
syllable_count += 1
prev_char_was_vowel = is_vowel
# Handle silent 'e' at the end
if word.endswith('e'):
syllable_count -= 1
return max(1, syllable_count)
def _get_reading_level(self, flesch_score: float) -> str:
"""Get reading level from Flesch score."""
if flesch_score >= 90:
return "Very Easy"
elif flesch_score >= 80:
return "Easy"
elif flesch_score >= 70:
return "Fairly Easy"
elif flesch_score >= 60:
return "Standard"
elif flesch_score >= 50:
return "Fairly Difficult"
elif flesch_score >= 30:
return "Difficult"
else:
return "Very Difficult"
def cluster_texts(self, texts: List[str],
num_clusters: int = 5,
method: str = 'kmeans') -> Dict:
"""
Cluster texts by similarity.
Args:
texts: List of texts to cluster
num_clusters: Number of clusters to create
method: Clustering method ('kmeans')
Returns:
Dictionary with clustering results
"""
if not texts or len(texts) < num_clusters:
return {}
# Preprocess and vectorize texts
cleaned_texts = [self.clean_text(text) for text in texts]
cleaned_texts = [text for text in cleaned_texts if text] # Remove empty texts
if len(cleaned_texts) < num_clusters:
return {}
try:
# TF-IDF vectorization
tfidf = TfidfVectorizer(max_features=1000,
stop_words='english',
ngram_range=(1, 2))
tfidf_matrix = tfidf.fit_transform(cleaned_texts)
if method == 'kmeans':
# K-means clustering
kmeans = KMeans(n_clusters=num_clusters, random_state=42)
cluster_labels = kmeans.fit_predict(tfidf_matrix)
# Get cluster centers and feature names
feature_names = tfidf.get_feature_names_out()
cluster_centers = kmeans.cluster_centers_
# Extract top terms for each cluster
cluster_terms = {}
for i in range(num_clusters):
top_indices = cluster_centers[i].argsort()[-10:][::-1]
cluster_terms[i] = [feature_names[idx] for idx in top_indices]
return {
'cluster_labels': cluster_labels.tolist(),
'cluster_terms': cluster_terms,
'num_clusters': num_clusters,
'feature_names': feature_names.tolist()
}
except Exception as e:
print(f"Error in clustering: {e}")
return {}
def find_similar_texts(self, query_text: str,
text_corpus: List[str],
top_k: int = 5) -> List[Tuple[int, float]]:
"""
Find most similar texts to a query text.
Args:
query_text: Query text
text_corpus: List of texts to search through
top_k: Number of most similar texts to return
Returns:
List of (index, similarity_score) tuples
"""
if not query_text or not text_corpus:
return []
# Prepare texts
all_texts = [query_text] + text_corpus
cleaned_texts = [self.clean_text(text) for text in all_texts]
cleaned_texts = [text for text in cleaned_texts if text]
if len(cleaned_texts) < 2:
return []
try:
# TF-IDF vectorization
tfidf = TfidfVectorizer(max_features=1000, stop_words='english')
tfidf_matrix = tfidf.fit_transform(cleaned_texts)
# Calculate cosine similarity
similarities = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:]).flatten()
# Get top k most similar texts
top_indices = similarities.argsort()[-top_k:][::-1]
return [(int(idx), float(similarities[idx])) for idx in top_indices]
except Exception as e:
print(f"Error in similarity calculation: {e}")
return []
def extract_entities(self, text: str) -> Dict[str, List[str]]:
"""
Extract basic entities from text (simplified version).
Args:
text: Input text
Returns:
Dictionary with extracted entities
"""
if not text:
return {}
# Clean and tokenize
cleaned_text = self.clean_text(text, remove_numbers=False)
tokens = word_tokenize(cleaned_text)
# Simple pattern-based entity extraction
entities = {
'emails': [],
'phone_numbers': [],
'hashtags': [],
'mentions': [],
'urls': [],
'numbers': []
}
# Email pattern
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
entities['emails'] = re.findall(email_pattern, text)
# Phone number pattern (simplified)
phone_pattern = r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b'
entities['phone_numbers'] = re.findall(phone_pattern, text)
# Hashtag pattern
hashtag_pattern = r'#\w+'
entities['hashtags'] = re.findall(hashtag_pattern, text)
# Mention pattern
mention_pattern = r'@\w+'
entities['mentions'] = re.findall(mention_pattern, text)
# URL pattern
url_pattern = r'https?://\S+|www\.\S+'
entities['urls'] = re.findall(url_pattern, text)
# Number pattern
number_pattern = r'\b\d+\.?\d*\b'
entities['numbers'] = re.findall(number_pattern, text)
return entities
def get_text_statistics(self, text: str) -> Dict[str, Union[int, float]]:
"""
Get comprehensive text statistics.
Args:
text: Input text
Returns:
Dictionary with text statistics
"""
if not text:
return {}
# Basic counts
char_count = len(text)
char_count_no_spaces = len(text.replace(' ', ''))
word_count = len(word_tokenize(text))
sentence_count = len(sent_tokenize(text))
# Token statistics
tokens = self.tokenize_text(text)
unique_words = len(set(tokens))
# Average lengths
avg_word_length = np.mean([len(word) for word in word_tokenize(text)]) if word_count > 0 else 0
avg_sentence_length = word_count / sentence_count if sentence_count > 0 else 0
return {
'character_count': char_count,
'character_count_no_spaces': char_count_no_spaces,
'word_count': word_count,
'sentence_count': sentence_count,
'unique_word_count': unique_words,
'avg_word_length': avg_word_length,
'avg_sentence_length': avg_sentence_length,
'lexical_diversity': unique_words / word_count if word_count > 0 else 0
}
class SocialMediaAnalyzer(TextAnalyzer):
"""
Specialized analyzer for social media content.
"""
def __init__(self):
super().__init__()
# Add social media specific stopwords
social_stopwords = {'rt', 'retweet', 'like', 'follow', 'follower', 'share'}
self.stop_words.update(social_stopwords)
def extract_hashtags(self, text: str) -> List[str]:
"""Extract hashtags from social media text."""
hashtag_pattern = r'#\w+'
hashtags = re.findall(hashtag_pattern, text)
return [tag[1:] for tag in hashtags] # Remove # symbol
def extract_mentions(self, text: str) -> List[str]:
"""Extract mentions from social media text."""
mention_pattern = r'@\w+'
return re.findall(mention_pattern, text)
def count_engagement_indicators(self, text: str) -> Dict[str, int]:
"""Count engagement indicators in social media text."""
indicators = {
'emojis': len(re.findall(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F1E0-\U0001F1FF]', text)),
'exclamations': text.count('!'),
'questions': text.count('?'),
'uppercase_words': len([word for word in text.split() if word.isupper()]),
'mentions': len(self.extract_mentions(text)),
'hashtags': len(self.extract_hashtags(text))
}
return indicators
def detect_social_media_platform(self, text: str) -> str:
"""Detect which social media platform the text is from."""
text_lower = text.lower()
if 'rt @' in text_lower or 'retweet' in text_lower:
return 'Twitter'
elif 'instagram.com' in text_lower or 'insta' in text_lower:
return 'Instagram'
elif 'facebook.com' in text_lower or 'fb.com' in text_lower:
return 'Facebook'
elif 'linkedin.com' in text_lower:
return 'LinkedIn'
elif 'tiktok.com' in text_lower or 'tiktok' in text_lower:
return 'TikTok'
else:
return 'Unknown'