Initial commit: The Ultimate Antigravity Skills Collection (58 Skills)

This commit is contained in:
sck_0
2026-01-14 18:48:08 +01:00
commit 7f46ed8ca1
447 changed files with 110829 additions and 0 deletions

View File

@@ -0,0 +1,482 @@
"""
ASO scoring module for App Store Optimization.
Calculates comprehensive ASO health score across multiple dimensions.
"""
from typing import Dict, List, Any, Optional
class ASOScorer:
"""Calculates overall ASO health score and provides recommendations."""
# Score weights for different components (total = 100)
WEIGHTS = {
'metadata_quality': 25,
'ratings_reviews': 25,
'keyword_performance': 25,
'conversion_metrics': 25
}
# Benchmarks for scoring
BENCHMARKS = {
'title_keyword_usage': {'min': 1, 'target': 2},
'description_length': {'min': 500, 'target': 2000},
'keyword_density': {'min': 2, 'optimal': 5, 'max': 8},
'average_rating': {'min': 3.5, 'target': 4.5},
'ratings_count': {'min': 100, 'target': 5000},
'keywords_top_10': {'min': 2, 'target': 10},
'keywords_top_50': {'min': 5, 'target': 20},
'conversion_rate': {'min': 0.02, 'target': 0.10}
}
def __init__(self):
"""Initialize ASO scorer."""
self.score_breakdown = {}
def calculate_overall_score(
self,
metadata: Dict[str, Any],
ratings: Dict[str, Any],
keyword_performance: Dict[str, Any],
conversion: Dict[str, Any]
) -> Dict[str, Any]:
"""
Calculate comprehensive ASO score (0-100).
Args:
metadata: Title, description quality metrics
ratings: Rating average and count
keyword_performance: Keyword ranking data
conversion: Impression-to-install metrics
Returns:
Overall score with detailed breakdown
"""
# Calculate component scores
metadata_score = self.score_metadata_quality(metadata)
ratings_score = self.score_ratings_reviews(ratings)
keyword_score = self.score_keyword_performance(keyword_performance)
conversion_score = self.score_conversion_metrics(conversion)
# Calculate weighted overall score
overall_score = (
metadata_score * (self.WEIGHTS['metadata_quality'] / 100) +
ratings_score * (self.WEIGHTS['ratings_reviews'] / 100) +
keyword_score * (self.WEIGHTS['keyword_performance'] / 100) +
conversion_score * (self.WEIGHTS['conversion_metrics'] / 100)
)
# Store breakdown
self.score_breakdown = {
'metadata_quality': {
'score': metadata_score,
'weight': self.WEIGHTS['metadata_quality'],
'weighted_contribution': round(metadata_score * (self.WEIGHTS['metadata_quality'] / 100), 1)
},
'ratings_reviews': {
'score': ratings_score,
'weight': self.WEIGHTS['ratings_reviews'],
'weighted_contribution': round(ratings_score * (self.WEIGHTS['ratings_reviews'] / 100), 1)
},
'keyword_performance': {
'score': keyword_score,
'weight': self.WEIGHTS['keyword_performance'],
'weighted_contribution': round(keyword_score * (self.WEIGHTS['keyword_performance'] / 100), 1)
},
'conversion_metrics': {
'score': conversion_score,
'weight': self.WEIGHTS['conversion_metrics'],
'weighted_contribution': round(conversion_score * (self.WEIGHTS['conversion_metrics'] / 100), 1)
}
}
# Generate recommendations
recommendations = self.generate_recommendations(
metadata_score,
ratings_score,
keyword_score,
conversion_score
)
# Assess overall health
health_status = self._assess_health_status(overall_score)
return {
'overall_score': round(overall_score, 1),
'health_status': health_status,
'score_breakdown': self.score_breakdown,
'recommendations': recommendations,
'priority_actions': self._prioritize_actions(recommendations),
'strengths': self._identify_strengths(self.score_breakdown),
'weaknesses': self._identify_weaknesses(self.score_breakdown)
}
def score_metadata_quality(self, metadata: Dict[str, Any]) -> float:
"""
Score metadata quality (0-100).
Evaluates:
- Title optimization
- Description quality
- Keyword usage
"""
scores = []
# Title score (0-35 points)
title_keywords = metadata.get('title_keyword_count', 0)
title_length = metadata.get('title_length', 0)
title_score = 0
if title_keywords >= self.BENCHMARKS['title_keyword_usage']['target']:
title_score = 35
elif title_keywords >= self.BENCHMARKS['title_keyword_usage']['min']:
title_score = 25
else:
title_score = 10
# Adjust for title length usage
if title_length > 25: # Using most of available space
title_score += 0
else:
title_score -= 5
scores.append(min(title_score, 35))
# Description score (0-35 points)
desc_length = metadata.get('description_length', 0)
desc_quality = metadata.get('description_quality', 0.0) # 0-1 scale
desc_score = 0
if desc_length >= self.BENCHMARKS['description_length']['target']:
desc_score = 25
elif desc_length >= self.BENCHMARKS['description_length']['min']:
desc_score = 15
else:
desc_score = 5
# Add quality bonus
desc_score += desc_quality * 10
scores.append(min(desc_score, 35))
# Keyword density score (0-30 points)
keyword_density = metadata.get('keyword_density', 0.0)
if self.BENCHMARKS['keyword_density']['min'] <= keyword_density <= self.BENCHMARKS['keyword_density']['optimal']:
density_score = 30
elif keyword_density < self.BENCHMARKS['keyword_density']['min']:
# Too low - proportional scoring
density_score = (keyword_density / self.BENCHMARKS['keyword_density']['min']) * 20
else:
# Too high (keyword stuffing) - penalty
excess = keyword_density - self.BENCHMARKS['keyword_density']['optimal']
density_score = max(30 - (excess * 5), 0)
scores.append(density_score)
return round(sum(scores), 1)
def score_ratings_reviews(self, ratings: Dict[str, Any]) -> float:
"""
Score ratings and reviews (0-100).
Evaluates:
- Average rating
- Total ratings count
- Review velocity
"""
average_rating = ratings.get('average_rating', 0.0)
total_ratings = ratings.get('total_ratings', 0)
recent_ratings = ratings.get('recent_ratings_30d', 0)
# Rating quality score (0-50 points)
if average_rating >= self.BENCHMARKS['average_rating']['target']:
rating_quality_score = 50
elif average_rating >= self.BENCHMARKS['average_rating']['min']:
# Proportional scoring between min and target
proportion = (average_rating - self.BENCHMARKS['average_rating']['min']) / \
(self.BENCHMARKS['average_rating']['target'] - self.BENCHMARKS['average_rating']['min'])
rating_quality_score = 30 + (proportion * 20)
elif average_rating >= 3.0:
rating_quality_score = 20
else:
rating_quality_score = 10
# Rating volume score (0-30 points)
if total_ratings >= self.BENCHMARKS['ratings_count']['target']:
rating_volume_score = 30
elif total_ratings >= self.BENCHMARKS['ratings_count']['min']:
# Proportional scoring
proportion = (total_ratings - self.BENCHMARKS['ratings_count']['min']) / \
(self.BENCHMARKS['ratings_count']['target'] - self.BENCHMARKS['ratings_count']['min'])
rating_volume_score = 15 + (proportion * 15)
else:
# Very low volume
rating_volume_score = (total_ratings / self.BENCHMARKS['ratings_count']['min']) * 15
# Rating velocity score (0-20 points)
if recent_ratings > 100:
velocity_score = 20
elif recent_ratings > 50:
velocity_score = 15
elif recent_ratings > 10:
velocity_score = 10
else:
velocity_score = 5
total_score = rating_quality_score + rating_volume_score + velocity_score
return round(min(total_score, 100), 1)
def score_keyword_performance(self, keyword_performance: Dict[str, Any]) -> float:
"""
Score keyword ranking performance (0-100).
Evaluates:
- Top 10 rankings
- Top 50 rankings
- Ranking trends
"""
top_10_count = keyword_performance.get('top_10', 0)
top_50_count = keyword_performance.get('top_50', 0)
top_100_count = keyword_performance.get('top_100', 0)
improving_keywords = keyword_performance.get('improving_keywords', 0)
# Top 10 score (0-50 points) - most valuable rankings
if top_10_count >= self.BENCHMARKS['keywords_top_10']['target']:
top_10_score = 50
elif top_10_count >= self.BENCHMARKS['keywords_top_10']['min']:
proportion = (top_10_count - self.BENCHMARKS['keywords_top_10']['min']) / \
(self.BENCHMARKS['keywords_top_10']['target'] - self.BENCHMARKS['keywords_top_10']['min'])
top_10_score = 25 + (proportion * 25)
else:
top_10_score = (top_10_count / self.BENCHMARKS['keywords_top_10']['min']) * 25
# Top 50 score (0-30 points)
if top_50_count >= self.BENCHMARKS['keywords_top_50']['target']:
top_50_score = 30
elif top_50_count >= self.BENCHMARKS['keywords_top_50']['min']:
proportion = (top_50_count - self.BENCHMARKS['keywords_top_50']['min']) / \
(self.BENCHMARKS['keywords_top_50']['target'] - self.BENCHMARKS['keywords_top_50']['min'])
top_50_score = 15 + (proportion * 15)
else:
top_50_score = (top_50_count / self.BENCHMARKS['keywords_top_50']['min']) * 15
# Coverage score (0-10 points) - based on top 100
coverage_score = min((top_100_count / 30) * 10, 10)
# Trend score (0-10 points) - are rankings improving?
if improving_keywords > 5:
trend_score = 10
elif improving_keywords > 0:
trend_score = 5
else:
trend_score = 0
total_score = top_10_score + top_50_score + coverage_score + trend_score
return round(min(total_score, 100), 1)
def score_conversion_metrics(self, conversion: Dict[str, Any]) -> float:
"""
Score conversion performance (0-100).
Evaluates:
- Impression-to-install conversion rate
- Download velocity
"""
conversion_rate = conversion.get('impression_to_install', 0.0)
downloads_30d = conversion.get('downloads_last_30_days', 0)
downloads_trend = conversion.get('downloads_trend', 'stable') # 'up', 'stable', 'down'
# Conversion rate score (0-70 points)
if conversion_rate >= self.BENCHMARKS['conversion_rate']['target']:
conversion_score = 70
elif conversion_rate >= self.BENCHMARKS['conversion_rate']['min']:
proportion = (conversion_rate - self.BENCHMARKS['conversion_rate']['min']) / \
(self.BENCHMARKS['conversion_rate']['target'] - self.BENCHMARKS['conversion_rate']['min'])
conversion_score = 35 + (proportion * 35)
else:
conversion_score = (conversion_rate / self.BENCHMARKS['conversion_rate']['min']) * 35
# Download velocity score (0-20 points)
if downloads_30d > 10000:
velocity_score = 20
elif downloads_30d > 1000:
velocity_score = 15
elif downloads_30d > 100:
velocity_score = 10
else:
velocity_score = 5
# Trend bonus (0-10 points)
if downloads_trend == 'up':
trend_score = 10
elif downloads_trend == 'stable':
trend_score = 5
else:
trend_score = 0
total_score = conversion_score + velocity_score + trend_score
return round(min(total_score, 100), 1)
def generate_recommendations(
self,
metadata_score: float,
ratings_score: float,
keyword_score: float,
conversion_score: float
) -> List[Dict[str, Any]]:
"""Generate prioritized recommendations based on scores."""
recommendations = []
# Metadata recommendations
if metadata_score < 60:
recommendations.append({
'category': 'metadata_quality',
'priority': 'high',
'action': 'Optimize app title and description',
'details': 'Add more keywords to title, expand description to 1500-2000 characters, improve keyword density to 3-5%',
'expected_impact': 'Improve discoverability and ranking potential'
})
elif metadata_score < 80:
recommendations.append({
'category': 'metadata_quality',
'priority': 'medium',
'action': 'Refine metadata for better keyword targeting',
'details': 'Test variations of title/subtitle, optimize keyword field for Apple',
'expected_impact': 'Incremental ranking improvements'
})
# Ratings recommendations
if ratings_score < 60:
recommendations.append({
'category': 'ratings_reviews',
'priority': 'high',
'action': 'Improve rating quality and volume',
'details': 'Address top user complaints, implement in-app rating prompts, respond to negative reviews',
'expected_impact': 'Better conversion rates and trust signals'
})
elif ratings_score < 80:
recommendations.append({
'category': 'ratings_reviews',
'priority': 'medium',
'action': 'Increase rating velocity',
'details': 'Optimize timing of rating requests, encourage satisfied users to rate',
'expected_impact': 'Sustained rating quality'
})
# Keyword performance recommendations
if keyword_score < 60:
recommendations.append({
'category': 'keyword_performance',
'priority': 'high',
'action': 'Improve keyword rankings',
'details': 'Target long-tail keywords with lower competition, update metadata with high-potential keywords, build backlinks',
'expected_impact': 'Significant improvement in organic visibility'
})
elif keyword_score < 80:
recommendations.append({
'category': 'keyword_performance',
'priority': 'medium',
'action': 'Expand keyword coverage',
'details': 'Target additional related keywords, test seasonal keywords, localize for new markets',
'expected_impact': 'Broader reach and more discovery opportunities'
})
# Conversion recommendations
if conversion_score < 60:
recommendations.append({
'category': 'conversion_metrics',
'priority': 'high',
'action': 'Optimize store listing for conversions',
'details': 'Improve screenshots and icon, strengthen value proposition in description, add video preview',
'expected_impact': 'Higher impression-to-install conversion'
})
elif conversion_score < 80:
recommendations.append({
'category': 'conversion_metrics',
'priority': 'medium',
'action': 'Test visual asset variations',
'details': 'A/B test different icon designs and screenshot sequences',
'expected_impact': 'Incremental conversion improvements'
})
return recommendations
def _assess_health_status(self, overall_score: float) -> str:
"""Assess overall ASO health status."""
if overall_score >= 80:
return "Excellent - Top-tier ASO performance"
elif overall_score >= 65:
return "Good - Competitive ASO with room for improvement"
elif overall_score >= 50:
return "Fair - Needs strategic improvements"
else:
return "Poor - Requires immediate ASO overhaul"
def _prioritize_actions(
self,
recommendations: List[Dict[str, Any]]
) -> List[Dict[str, Any]]:
"""Prioritize actions by impact and urgency."""
# Sort by priority (high first) and expected impact
priority_order = {'high': 0, 'medium': 1, 'low': 2}
sorted_recommendations = sorted(
recommendations,
key=lambda x: priority_order[x['priority']]
)
return sorted_recommendations[:3] # Top 3 priority actions
def _identify_strengths(self, score_breakdown: Dict[str, Any]) -> List[str]:
"""Identify areas of strength (scores >= 75)."""
strengths = []
for category, data in score_breakdown.items():
if data['score'] >= 75:
strengths.append(
f"{category.replace('_', ' ').title()}: {data['score']}/100"
)
return strengths if strengths else ["Focus on building strengths across all areas"]
def _identify_weaknesses(self, score_breakdown: Dict[str, Any]) -> List[str]:
"""Identify areas needing improvement (scores < 60)."""
weaknesses = []
for category, data in score_breakdown.items():
if data['score'] < 60:
weaknesses.append(
f"{category.replace('_', ' ').title()}: {data['score']}/100 - needs improvement"
)
return weaknesses if weaknesses else ["All areas performing adequately"]
def calculate_aso_score(
metadata: Dict[str, Any],
ratings: Dict[str, Any],
keyword_performance: Dict[str, Any],
conversion: Dict[str, Any]
) -> Dict[str, Any]:
"""
Convenience function to calculate ASO score.
Args:
metadata: Metadata quality metrics
ratings: Ratings data
keyword_performance: Keyword ranking data
conversion: Conversion metrics
Returns:
Complete ASO score report
"""
scorer = ASOScorer()
return scorer.calculate_overall_score(
metadata,
ratings,
keyword_performance,
conversion
)