feat: image generation overhaul (model-aware text, dim clamping, \.30 pricing), event-driven dashboard cache invalidation, SEO insights (AI visibility, GSC, keyword gap), YouTube OAuth/publish, blog writer & content planning improvements, scheduler monitoring updates

This commit is contained in:
ajaysi
2026-05-30 07:58:22 +05:30
parent aaf94049da
commit 64f1f88cdd
129 changed files with 8796 additions and 8755 deletions

View File

@@ -1,19 +1,20 @@
"""
Quality Validation Service
AI response quality assessment and strategic analysis.
All methods derive results from actual input data — no hardcoded defaults.
"""
import logging
from typing import Dict, Any, List
from typing import Dict, Any, List, Optional
logger = logging.getLogger(__name__)
class QualityValidationService:
"""Service for quality validation and strategic analysis."""
def __init__(self):
pass
def validate_against_schema(self, data: Dict[str, Any], schema: Dict[str, Any]) -> None:
"""Validate data against a minimal JSON-like schema definition.
Raises ValueError on failure.
@@ -54,7 +55,10 @@ class QualityValidationService:
_check(data, schema)
def calculate_strategic_scores(self, ai_recommendations: Dict[str, Any]) -> Dict[str, float]:
"""Calculate strategic performance scores from AI recommendations."""
"""Calculate strategic performance scores from AI recommendations.
Scores are derived per analysis type from actual metrics, then aggregated
with dimension-specific weightings — no blanket multipliers.
"""
scores = {
'overall_score': 0.0,
'content_quality_score': 0.0,
@@ -62,87 +66,214 @@ class QualityValidationService:
'conversion_score': 0.0,
'innovation_score': 0.0
}
# Calculate scores based on AI recommendations
total_confidence = 0
total_score = 0
for analysis_type, recommendations in ai_recommendations.items():
if isinstance(recommendations, dict) and 'metrics' in recommendations:
metrics = recommendations['metrics']
score = metrics.get('score', 50)
confidence = metrics.get('confidence', 0.5)
total_score += score * confidence
total_confidence += confidence
if total_confidence > 0:
scores['overall_score'] = total_score / total_confidence
# Set other scores based on overall score
scores['content_quality_score'] = scores['overall_score'] * 1.1
scores['engagement_score'] = scores['overall_score'] * 0.9
scores['conversion_score'] = scores['overall_score'] * 0.95
scores['innovation_score'] = scores['overall_score'] * 1.05
return scores
def extract_market_positioning(self, ai_recommendations: Dict[str, Any]) -> Dict[str, Any]:
"""Extract market positioning from AI recommendations."""
return {
'industry_position': 'emerging',
'competitive_advantage': 'AI-powered content',
'market_share': '2.5%',
'positioning_score': 4
analysis_count = 0
weighted_total = 0.0
weight_sum = 0.0
# Dimension-specific weights
dimension_weights = {
'comprehensive_strategy': {'quality': 0.35, 'engagement': 0.20, 'conversion': 0.25, 'innovation': 0.20},
'audience_intelligence': {'quality': 0.25, 'engagement': 0.40, 'conversion': 0.20, 'innovation': 0.15},
'competitive_intelligence': {'quality': 0.30, 'engagement': 0.15, 'conversion': 0.25, 'innovation': 0.30},
'performance_optimization': {'quality': 0.20, 'engagement': 0.15, 'conversion': 0.45, 'innovation': 0.20},
'content_calendar_optimization': {'quality': 0.30, 'engagement': 0.25, 'conversion': 0.20, 'innovation': 0.25},
}
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
metrics = recommendations.get('metrics')
if not isinstance(metrics, dict):
continue
score = metrics.get('score', 50)
confidence = metrics.get('confidence', 0.5)
weight = confidence
weighted_total += score * weight
weight_sum += weight
analysis_count += 1
weights = dimension_weights.get(analysis_type, {'quality': 0.25, 'engagement': 0.25, 'conversion': 0.25, 'innovation': 0.25})
scores['content_quality_score'] += (score * weights['quality'] * weight)
scores['engagement_score'] += (score * weights['engagement'] * weight)
scores['conversion_score'] += (score * weights['conversion'] * weight)
scores['innovation_score'] += (score * weights['innovation'] * weight)
if weight_sum > 0:
scores['overall_score'] = round(weighted_total / weight_sum, 2)
scores['content_quality_score'] = round(scores['content_quality_score'] / weight_sum, 2)
scores['engagement_score'] = round(scores['engagement_score'] / weight_sum, 2)
scores['conversion_score'] = round(scores['conversion_score'] / weight_sum, 2)
scores['innovation_score'] = round(scores['innovation_score'] / weight_sum, 2)
return scores
def extract_market_positioning(self, ai_recommendations: Dict[str, Any]) -> Dict[str, Any]:
"""Extract market positioning from AI recommendations.
Scans all analysis types for positioning, competitive_advantage, and market_share signals.
Returns empty dict if no data is available instead of synthetic defaults.
"""
positioning = {}
best_confidence = 0.0
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
metrics = recommendations.get('metrics', {})
confidence = metrics.get('confidence', 0.0)
if confidence <= best_confidence:
continue
recs = recommendations.get('recommendations', [])
if isinstance(recs, list):
for r in recs:
if not isinstance(r, dict):
continue
pos = r.get('market_position') or r.get('positioning')
adv = r.get('competitive_advantage')
share = r.get('market_share')
score = r.get('positioning_score') or metrics.get('positioning_score')
if any([pos, adv, share, score]):
best_confidence = confidence
if pos:
positioning['industry_position'] = pos
if adv:
positioning['competitive_advantage'] = adv
if share:
positioning['market_share'] = str(share)
if score is not None:
positioning['positioning_score'] = score
# Check top-level keys as fallback
if not positioning:
for key in ('industry_position', 'competitive_advantage', 'market_share', 'positioning_score'):
val = ai_recommendations.get(key)
if val is not None:
positioning[key] = val
return positioning
def extract_competitive_advantages(self, ai_recommendations: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Extract competitive advantages from AI recommendations."""
return [
{
'advantage': 'AI-powered content creation',
'impact': 'High',
'implementation': 'In Progress'
},
{
'advantage': 'Data-driven strategy',
'impact': 'Medium',
'implementation': 'Complete'
}
]
"""Extract competitive advantages from AI recommendations.
Scans competitive_intelligence and other analysis types for advantage signals.
Returns empty list if no data is available.
"""
advantages = []
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
recs = recommendations.get('recommendations', [])
if not isinstance(recs, list):
continue
for r in recs:
if not isinstance(r, dict):
continue
adv = r.get('advantage') or r.get('competitive_advantage')
if adv:
advantages.append({
'advantage': adv,
'impact': r.get('impact', 'Medium'),
'implementation': r.get('implementation', 'Planned')
})
# Deduplicate by advantage text
seen = set()
unique = []
for a in advantages:
key = a['advantage'].strip().lower()
if key not in seen:
seen.add(key)
unique.append(a)
return unique
def extract_strategic_risks(self, ai_recommendations: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Extract strategic risks from AI recommendations."""
return [
{
'risk': 'Content saturation in market',
'probability': 'Medium',
'impact': 'High'
},
{
'risk': 'Algorithm changes affecting reach',
'probability': 'High',
'impact': 'Medium'
}
]
"""Extract strategic risks from AI recommendations.
Scans all analysis types for risk signals.
Returns empty list if no data is available.
"""
risks = []
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
recs = recommendations.get('recommendations', [])
if not isinstance(recs, list):
continue
for r in recs:
if not isinstance(r, dict):
continue
risk_text = r.get('risk') or r.get('strategic_risk') or r.get('threat')
if risk_text:
risks.append({
'risk': risk_text,
'probability': r.get('probability', 'Medium'),
'impact': r.get('impact', 'Medium')
})
risks_list = recommendations.get('risks') or recommendations.get('strategic_risks')
if isinstance(risks_list, list):
for r in risks_list:
if isinstance(r, dict) and r.get('risk'):
risks.append(r)
seen = set()
unique = []
for r in risks:
key = r['risk'].strip().lower()
if key not in seen:
seen.add(key)
unique.append(r)
return unique
def extract_opportunity_analysis(self, ai_recommendations: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Extract opportunity analysis from AI recommendations."""
return [
{
'opportunity': 'Video content expansion',
'potential_impact': 'High',
'implementation_ease': 'Medium'
},
{
'opportunity': 'Social media engagement',
'potential_impact': 'Medium',
'implementation_ease': 'High'
}
]
"""Extract opportunity analysis from AI recommendations.
Scans all analysis types for opportunity signals.
Returns empty list if no data is available.
"""
opportunities = []
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
recs = recommendations.get('recommendations', [])
if not isinstance(recs, list):
continue
for r in recs:
if not isinstance(r, dict):
continue
opp = r.get('opportunity') or r.get('growth_opportunity')
if opp:
opportunities.append({
'opportunity': opp,
'potential_impact': r.get('potential_impact', 'Medium'),
'implementation_ease': r.get('implementation_ease', 'Medium')
})
opps_list = recommendations.get('opportunities') or recommendations.get('growth_opportunities')
if isinstance(opps_list, list):
for o in opps_list:
if isinstance(o, dict) and o.get('opportunity'):
opportunities.append(o)
seen = set()
unique = []
for o in opportunities:
key = o['opportunity'].strip().lower()
if key not in seen:
seen.add(key)
unique.append(o)
return unique
def validate_ai_response_quality(self, ai_response: Dict[str, Any]) -> Dict[str, Any]:
"""Validate the quality of AI response."""
"""Validate the quality of AI response using multi-dimensional analysis.
Scores are derived from actual content, not placeholders.
"""
quality_metrics = {
'completeness': 0.0,
'relevance': 0.0,
@@ -150,30 +281,76 @@ class QualityValidationService:
'confidence': 0.0,
'overall_quality': 0.0
}
# Calculate completeness
required_fields = ['recommendations', 'insights', 'metrics']
present_fields = sum(1 for field in required_fields if field in ai_response)
quality_metrics['completeness'] = present_fields / len(required_fields)
# Calculate relevance (placeholder logic)
quality_metrics['relevance'] = 0.8 if ai_response.get('analysis_type') else 0.5
# Calculate actionability (placeholder logic)
# Completeness: weighted by field importance
field_weights = {
'recommendations': 0.35,
'insights': 0.30,
'metrics': 0.20,
'analysis_type': 0.15
}
weighted_present = 0.0
total_weight = 0.0
for field, weight in field_weights.items():
total_weight += weight
val = ai_response.get(field)
if field == 'recommendations':
if isinstance(val, list) and len(val) > 0:
weighted_present += weight
elif field == 'insights':
if isinstance(val, list) and len(val) > 0:
weighted_present += weight
elif field == 'metrics':
if isinstance(val, dict) and len(val) > 0:
weighted_present += weight
else:
if val is not None:
weighted_present += weight
quality_metrics['completeness'] = round(weighted_present / total_weight, 2) if total_weight > 0 else 0.0
# Relevance: evaluate recommendations content quality
recommendations = ai_response.get('recommendations', [])
quality_metrics['actionability'] = min(1.0, len(recommendations) / 5.0)
# Calculate confidence
if isinstance(recommendations, list) and len(recommendations) > 0:
scored = 0
total_recs = len(recommendations)
for r in recommendations:
if isinstance(r, dict):
has_action = bool(r.get('action') or r.get('recommendation') or r.get('step'))
has_reason = bool(r.get('reason') or r.get('rationale') or r.get('impact'))
if has_action and has_reason:
scored += 1
quality_metrics['relevance'] = round(scored / total_recs, 2) if total_recs > 0 else 0.5
else:
quality_metrics['relevance'] = 0.0
# Actionability: recommendation detail score
if isinstance(recommendations, list) and len(recommendations) > 0:
actionable = 0
for r in recommendations:
if isinstance(r, dict):
has_timeline = bool(r.get('timeline') or r.get('effort'))
has_impact = bool(r.get('impact') or r.get('expected_outcome'))
if has_timeline or has_impact:
actionable += 1
quality_metrics['actionability'] = round(min(1.0, actionable / max(len(recommendations), 1)), 2)
else:
quality_metrics['actionability'] = 0.0
# Confidence from metrics
metrics = ai_response.get('metrics', {})
quality_metrics['confidence'] = metrics.get('confidence', 0.5)
# Calculate overall quality
quality_metrics['overall_quality'] = sum(quality_metrics.values()) / len(quality_metrics)
quality_metrics['confidence'] = round(metrics.get('confidence', 0.0), 2) if isinstance(metrics, dict) else 0.0
# Overall weighted quality
weights = {'completeness': 0.25, 'relevance': 0.30, 'actionability': 0.25, 'confidence': 0.20}
overall = sum(quality_metrics[k] * weights[k] for k in weights)
quality_metrics['overall_quality'] = round(overall, 2)
return quality_metrics
def assess_strategy_quality(self, strategy_data: Dict[str, Any]) -> Dict[str, Any]:
"""Assess the overall quality of a content strategy."""
"""Assess the overall quality of a content strategy.
Uses field-level analysis with content-aware scoring — not simple presence checks.
"""
quality_assessment = {
'data_completeness': 0.0,
'strategic_clarity': 0.0,
@@ -181,25 +358,59 @@ class QualityValidationService:
'competitive_positioning': 0.0,
'overall_quality': 0.0
}
# Assess data completeness
required_fields = [
'business_objectives', 'target_metrics', 'content_budget',
'team_size', 'implementation_timeline'
]
present_fields = sum(1 for field in required_fields if strategy_data.get(field))
quality_assessment['data_completeness'] = present_fields / len(required_fields)
# Assess strategic clarity (placeholder logic)
quality_assessment['strategic_clarity'] = 0.7 if strategy_data.get('business_objectives') else 0.3
# Assess implementation readiness (placeholder logic)
quality_assessment['implementation_readiness'] = 0.6 if strategy_data.get('team_size') else 0.2
# Assess competitive positioning (placeholder logic)
quality_assessment['competitive_positioning'] = 0.5 if strategy_data.get('competitive_position') else 0.2
# Calculate overall quality
quality_assessment['overall_quality'] = sum(quality_assessment.values()) / len(quality_assessment)
# Data completeness with weighted field groups
field_groups = {
'objectives': {'fields': ['business_objectives', 'target_metrics'], 'weight': 0.25},
'resources': {'fields': ['content_budget', 'team_size', 'implementation_timeline'], 'weight': 0.25},
'audience': {'fields': ['content_preferences', 'consumption_patterns', 'audience_pain_points'], 'weight': 0.25},
'competition': {'fields': ['top_competitors', 'market_gaps', 'competitive_position'], 'weight': 0.25}
}
total_weight = 0.0
weighted_score = 0.0
for group_name, group in field_groups.items():
group_present = sum(1 for f in group['fields'] if strategy_data.get(f) not in (None, '', []))
group_score = group_present / len(group['fields']) if group['fields'] else 0
weighted_score += group_score * group['weight']
total_weight += group['weight']
quality_assessment['data_completeness'] = round(weighted_score / total_weight, 2) if total_weight > 0 else 0.0
# Strategic clarity: evaluate quality of business objectives
objectives = strategy_data.get('business_objectives')
if isinstance(objectives, str) and len(objectives) > 20:
quality_assessment['strategic_clarity'] = 0.9
elif isinstance(objectives, str) and len(objectives) > 0:
quality_assessment['strategic_clarity'] = 0.6
elif isinstance(objectives, list) and len(objectives) > 0:
quality_assessment['strategic_clarity'] = 0.8
else:
quality_assessment['strategic_clarity'] = 0.0
# Implementation readiness: budget + team + timeline
readiness_signals = 0
if strategy_data.get('content_budget') not in (None, '', 0):
readiness_signals += 1
if strategy_data.get('team_size') not in (None, '', 0):
readiness_signals += 1
if strategy_data.get('implementation_timeline') not in (None, '', []):
readiness_signals += 1
quality_assessment['implementation_readiness'] = round(readiness_signals / 3.0, 2)
# Competitive positioning: evaluate depth of competitive data
comp_signals = 0
if strategy_data.get('top_competitors') not in (None, '', []):
comp_signals += 1
if strategy_data.get('market_gaps') not in (None, '', []):
comp_signals += 1
if strategy_data.get('competitive_position') not in (None, ''):
comp_signals += 1
if strategy_data.get('industry_trends') not in (None, '', []):
comp_signals += 1
quality_assessment['competitive_positioning'] = round(comp_signals / 4.0, 2)
# Overall quality
quality_assessment['overall_quality'] = round(
sum(quality_assessment.values()) / len(quality_assessment), 2
)
return quality_assessment

View File

@@ -510,7 +510,7 @@ class EnhancedStrategyService:
async def get_system_health(self, db: Session) -> Dict[str, Any]:
"""Get system health status."""
try:
return await self.health_monitoring_service.get_system_health(db)
return await self.health_monitoring_service.check_system_health(db)
except Exception as e:
logger.error(f"Error getting system health: {str(e)}")
raise
@@ -583,7 +583,7 @@ class EnhancedStrategyService:
async def optimize_strategy_operation(self, operation_name: str, operation_func, *args, **kwargs) -> Dict[str, Any]:
"""Optimize strategy operation with performance monitoring."""
try:
return await self.performance_optimization_service.optimize_operation(
return await self.performance_optimization_service.optimize_response_time(
operation_name, operation_func, *args, **kwargs
)
except Exception as e:

View File

@@ -176,11 +176,7 @@ class FieldTransformationService:
# Default transformation - use first available source data
field_value = self._default_transformation(source_data, field_name)
# If no value found, provide default based on field type
if field_value is None or field_value == "":
field_value = self._get_default_value_for_field(field_name)
if field_value is not None:
if field_value is not None and field_value != "":
transformed_fields[field_name] = {
'value': field_value,
'source': sources[0] if sources else 'default',
@@ -943,44 +939,6 @@ class FieldTransformationService:
logger.error(f"Error extracting A/B testing capabilities: {str(e)}")
return False
def _get_default_value_for_field(self, field_name: str) -> Any:
"""Get default value for a field when no data is available."""
# Provide sensible defaults for required fields
default_values = {
'business_objectives': 'Lead Generation, Brand Awareness',
'target_metrics': 'Traffic Growth: 30%, Engagement Rate: 5%, Conversion Rate: 2%',
'content_budget': 1000,
'team_size': 1,
'implementation_timeline': '3 months',
'market_share': 'Small but growing',
'competitive_position': 'Niche',
'performance_metrics': 'Current Traffic: 1000, Current Engagement: 3%',
'content_preferences': 'Blog posts, Social media content',
'consumption_patterns': 'Mobile: 60%, Desktop: 40%',
'audience_pain_points': 'Time constraints, Content quality',
'buying_journey': 'Awareness: 40%, Consideration: 35%, Decision: 25%',
'seasonal_trends': 'Q4 peak, Summer slowdown',
'engagement_metrics': 'Likes: 100, Shares: 20, Comments: 15',
'top_competitors': 'Competitor A, Competitor B',
'competitor_content_strategies': 'Blog-focused, Video-heavy',
'market_gaps': 'Underserved niche, Content gap',
'industry_trends': 'AI integration, Video content',
'emerging_trends': 'Voice search, Interactive content',
'preferred_formats': ['Blog Posts', 'Videos', 'Infographics'],
'content_mix': 'Educational: 40%, Entertaining: 30%, Promotional: 30%',
'content_frequency': 'Weekly',
'optimal_timing': 'Best Days: Tuesday, Thursday, Best Time: 10 AM',
'quality_metrics': 'Readability: 8, Engagement: 7, SEO Score: 6',
'editorial_guidelines': 'Professional tone, Clear structure',
'brand_voice': 'Professional yet approachable',
'traffic_sources': 'Organic: 60%, Social: 25%, Direct: 15%',
'conversion_rates': 'Overall: 2%, Blog: 3%, Landing Pages: 5%',
'content_roi_targets': 'Target ROI: 300%, Break Even: 6 months',
'ab_testing_capabilities': False
}
return default_values.get(field_name, None)
def _default_transformation(self, source_data: Dict[str, Any], field_name: str) -> Any:
"""Default transformation when no specific method is available."""
try:

View File

@@ -44,6 +44,11 @@ class CachingService:
'ttl': 900, # 15 minutes
'max_size': 1000,
'priority': 'low'
},
'streaming_intelligence': {
'ttl': 300, # 5 minutes
'max_size': 500,
'priority': 'medium'
}
}

View File

@@ -9,7 +9,6 @@ from .data_processors import (
transform_onboarding_data_to_fields,
get_data_sources,
get_detailed_input_data_points,
get_fallback_onboarding_data,
get_website_analysis_data,
get_research_preferences_data,
get_api_keys_data
@@ -36,7 +35,6 @@ __all__ = [
'transform_onboarding_data_to_fields',
'get_data_sources',
'get_detailed_input_data_points',
'get_fallback_onboarding_data',
'get_website_analysis_data',
'get_research_preferences_data',
'get_api_keys_data',

View File

@@ -179,17 +179,13 @@ class DataProcessorService:
}
fields['seasonal_trends'] = {
'value': ['Q1: Planning', 'Q2: Execution', 'Q3: Optimization', 'Q4: Review'],
'value': research_data.get('seasonal_trends', []),
'source': 'research_preferences',
'confidence': research_data.get('confidence_level', 0.7)
}
fields['engagement_metrics'] = {
'value': {
'avg_session_duration': website_data.get('performance_metrics', {}).get('avg_session_duration', 180),
'bounce_rate': website_data.get('performance_metrics', {}).get('bounce_rate', 45.5),
'pages_per_session': 2.5
},
'value': website_data.get('performance_metrics', {}),
'source': 'website_analysis',
'confidence': website_data.get('confidence_level', 0.8)
}
@@ -411,15 +407,6 @@ class DataProcessorService:
}
}
def get_fallback_onboarding_data(self) -> Dict[str, Any]:
"""
Get fallback onboarding data for compatibility.
Returns:
Dictionary with fallback data (raises error as fallbacks are disabled)
"""
raise RuntimeError("Fallback onboarding data is disabled. Real data required.")
async def get_website_analysis_data(self, user_id: int) -> Dict[str, Any]:
"""
Get website analysis data from onboarding.
@@ -534,12 +521,6 @@ def get_detailed_input_data_points(processed_data: Dict[str, Any]) -> Dict[str,
return processor.get_detailed_input_data_points(processed_data)
def get_fallback_onboarding_data() -> Dict[str, Any]:
"""Get fallback onboarding data for compatibility."""
processor = DataProcessorService()
return processor.get_fallback_onboarding_data()
async def get_website_analysis_data(user_id: int) -> Dict[str, Any]:
"""Get website analysis data from onboarding."""
processor = DataProcessorService()

View File

@@ -14,6 +14,7 @@ logger = logging.getLogger(__name__)
def calculate_strategic_scores(ai_recommendations: Dict[str, Any]) -> Dict[str, float]:
"""
Calculate strategic performance scores from AI recommendations.
Dimension-specific weights — no blanket multipliers.
Args:
ai_recommendations: Dictionary containing AI analysis results
@@ -28,35 +29,48 @@ def calculate_strategic_scores(ai_recommendations: Dict[str, Any]) -> Dict[str,
'conversion_score': 0.0,
'innovation_score': 0.0
}
# Calculate scores based on AI recommendations
total_confidence = 0
total_score = 0
weight_sum = 0.0
dimension_weights = {
'comprehensive_strategy': {'quality': 0.35, 'engagement': 0.20, 'conversion': 0.25, 'innovation': 0.20},
'audience_intelligence': {'quality': 0.25, 'engagement': 0.40, 'conversion': 0.20, 'innovation': 0.15},
'competitive_intelligence': {'quality': 0.30, 'engagement': 0.15, 'conversion': 0.25, 'innovation': 0.30},
'performance_optimization': {'quality': 0.20, 'engagement': 0.15, 'conversion': 0.45, 'innovation': 0.20},
'content_calendar_optimization': {'quality': 0.30, 'engagement': 0.25, 'conversion': 0.20, 'innovation': 0.25},
}
for analysis_type, recommendations in ai_recommendations.items():
if isinstance(recommendations, dict) and 'metrics' in recommendations:
metrics = recommendations['metrics']
score = metrics.get('score', 50)
confidence = metrics.get('confidence', 0.5)
total_score += score * confidence
total_confidence += confidence
if total_confidence > 0:
scores['overall_score'] = total_score / total_confidence
# Set other scores based on overall score
scores['content_quality_score'] = scores['overall_score'] * 1.1
scores['engagement_score'] = scores['overall_score'] * 0.9
scores['conversion_score'] = scores['overall_score'] * 0.95
scores['innovation_score'] = scores['overall_score'] * 1.05
if not isinstance(recommendations, dict):
continue
metrics = recommendations.get('metrics')
if not isinstance(metrics, dict):
continue
score = metrics.get('score', 50)
confidence = metrics.get('confidence', 0.5)
weight = confidence
scores['overall_score'] += score * weight
weight_sum += weight
weights = dimension_weights.get(analysis_type, {'quality': 0.25, 'engagement': 0.25, 'conversion': 0.25, 'innovation': 0.25})
scores['content_quality_score'] += score * weights['quality'] * weight
scores['engagement_score'] += score * weights['engagement'] * weight
scores['conversion_score'] += score * weights['conversion'] * weight
scores['innovation_score'] += score * weights['innovation'] * weight
if weight_sum > 0:
for k in scores:
scores[k] = round(scores[k] / weight_sum, 2)
return scores
def extract_market_positioning(ai_recommendations: Dict[str, Any]) -> Dict[str, Any]:
"""
Extract market positioning insights from AI recommendations.
Scans all analysis types for positioning signals. Returns empty dict if none found.
Args:
ai_recommendations: Dictionary containing AI analysis results
@@ -64,17 +78,50 @@ def extract_market_positioning(ai_recommendations: Dict[str, Any]) -> Dict[str,
Returns:
Dictionary with market positioning data
"""
return {
'industry_position': 'emerging',
'competitive_advantage': 'AI-powered content',
'market_share': '2.5%',
'positioning_score': 4
}
positioning = {}
best_confidence = 0.0
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
metrics = recommendations.get('metrics', {})
confidence = metrics.get('confidence', 0.0)
if confidence <= best_confidence:
continue
recs = recommendations.get('recommendations', [])
if isinstance(recs, list):
for r in recs:
if not isinstance(r, dict):
continue
pos = r.get('market_position') or r.get('positioning')
adv = r.get('competitive_advantage')
share = r.get('market_share')
score = r.get('positioning_score') or metrics.get('positioning_score')
if any([pos, adv, share, score]):
best_confidence = confidence
if pos:
positioning['industry_position'] = pos
if adv:
positioning['competitive_advantage'] = adv
if share:
positioning['market_share'] = str(share)
if score is not None:
positioning['positioning_score'] = score
if not positioning:
for key in ('industry_position', 'competitive_advantage', 'market_share', 'positioning_score'):
val = ai_recommendations.get(key)
if val is not None:
positioning[key] = val
return positioning
def extract_competitive_advantages(ai_recommendations: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Extract competitive advantages from AI recommendations.
Scans all analysis types for advantage signals. Returns empty list if none found.
Args:
ai_recommendations: Dictionary containing AI analysis results
@@ -82,23 +129,40 @@ def extract_competitive_advantages(ai_recommendations: Dict[str, Any]) -> List[D
Returns:
List of competitive advantages with impact and implementation status
"""
return [
{
'advantage': 'AI-powered content creation',
'impact': 'High',
'implementation': 'In Progress'
},
{
'advantage': 'Data-driven strategy',
'impact': 'Medium',
'implementation': 'Complete'
}
]
advantages = []
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
recs = recommendations.get('recommendations', [])
if not isinstance(recs, list):
continue
for r in recs:
if not isinstance(r, dict):
continue
adv = r.get('advantage') or r.get('competitive_advantage')
if adv:
advantages.append({
'advantage': adv,
'impact': r.get('impact', 'Medium'),
'implementation': r.get('implementation', 'Planned')
})
seen = set()
unique = []
for a in advantages:
key = a['advantage'].strip().lower()
if key not in seen:
seen.add(key)
unique.append(a)
return unique
def extract_strategic_risks(ai_recommendations: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Extract strategic risks from AI recommendations.
Scans all analysis types for risk signals. Returns empty list if none found.
Args:
ai_recommendations: Dictionary containing AI analysis results
@@ -106,23 +170,46 @@ def extract_strategic_risks(ai_recommendations: Dict[str, Any]) -> List[Dict[str
Returns:
List of strategic risks with probability and impact assessment
"""
return [
{
'risk': 'Content saturation in market',
'probability': 'Medium',
'impact': 'High'
},
{
'risk': 'Algorithm changes affecting reach',
'probability': 'High',
'impact': 'Medium'
}
]
risks = []
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
recs = recommendations.get('recommendations', [])
if not isinstance(recs, list):
continue
for r in recs:
if not isinstance(r, dict):
continue
risk_text = r.get('risk') or r.get('strategic_risk') or r.get('threat')
if risk_text:
risks.append({
'risk': risk_text,
'probability': r.get('probability', 'Medium'),
'impact': r.get('impact', 'Medium')
})
risks_list = recommendations.get('risks') or recommendations.get('strategic_risks')
if isinstance(risks_list, list):
for r in risks_list:
if isinstance(r, dict) and r.get('risk'):
risks.append(r)
seen = set()
unique = []
for r in risks:
key = r['risk'].strip().lower()
if key not in seen:
seen.add(key)
unique.append(r)
return unique
def extract_opportunity_analysis(ai_recommendations: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Extract opportunity analysis from AI recommendations.
Scans all analysis types for opportunity signals. Returns empty list if none found.
Args:
ai_recommendations: Dictionary containing AI analysis results
@@ -130,18 +217,40 @@ def extract_opportunity_analysis(ai_recommendations: Dict[str, Any]) -> List[Dic
Returns:
List of opportunities with potential impact and implementation ease
"""
return [
{
'opportunity': 'Video content expansion',
'potential_impact': 'High',
'implementation_ease': 'Medium'
},
{
'opportunity': 'Social media engagement',
'potential_impact': 'Medium',
'implementation_ease': 'High'
}
]
opportunities = []
for analysis_type, recommendations in ai_recommendations.items():
if not isinstance(recommendations, dict):
continue
recs = recommendations.get('recommendations', [])
if not isinstance(recs, list):
continue
for r in recs:
if not isinstance(r, dict):
continue
opp = r.get('opportunity') or r.get('growth_opportunity')
if opp:
opportunities.append({
'opportunity': opp,
'potential_impact': r.get('potential_impact', 'Medium'),
'implementation_ease': r.get('implementation_ease', 'Medium')
})
opps_list = recommendations.get('opportunities') or recommendations.get('growth_opportunities')
if isinstance(opps_list, list):
for o in opps_list:
if isinstance(o, dict) and o.get('opportunity'):
opportunities.append(o)
seen = set()
unique = []
for o in opportunities:
key = o['opportunity'].strip().lower()
if key not in seen:
seen.add(key)
unique.append(o)
return unique
def initialize_caches() -> Dict[str, Any]:

View File

@@ -192,10 +192,6 @@ class EnhancedStrategyService:
"""Get detailed input data points - delegates to core service."""
return self.core_service.data_processor_service.get_detailed_input_data_points(processed_data)
def _get_fallback_onboarding_data(self) -> Dict[str, Any]:
"""Get fallback onboarding data - delegates to core service."""
return self.core_service.data_processor_service.get_fallback_onboarding_data()
async def _get_website_analysis_data(self, user_id: int) -> Dict[str, Any]:
"""Get website analysis data - delegates to core service."""
return await self.core_service.data_processor_service.get_website_analysis_data(user_id)
@@ -220,22 +216,6 @@ class EnhancedStrategyService:
"""Process API keys data - delegates to core service."""
return await self.core_service.data_processor_service.process_api_keys_data(api_data)
def _transform_onboarding_data_to_fields(self, processed_data: Dict[str, Any]) -> Dict[str, Any]:
# deprecated; not used
raise RuntimeError("Deprecated: use AutoFillService.transformer")
def _get_data_sources(self, processed_data: Dict[str, Any]) -> Dict[str, str]:
# deprecated; not used
raise RuntimeError("Deprecated: use AutoFillService.transparency")
def _get_detailed_input_data_points(self, processed_data: Dict[str, Any]) -> Dict[str, Any]:
# deprecated; not used
raise RuntimeError("Deprecated: use AutoFillService.transparency")
def _get_fallback_onboarding_data(self) -> Dict[str, Any]:
"""Deprecated: fallbacks are no longer permitted. Kept for compatibility; always raises."""
raise RuntimeError("Fallback onboarding data is disabled. Real data required.")
def _initialize_caches(self) -> None:
"""Initialize caches - delegates to core service."""
# This is now handled by the core service