ALwrity version 0.5.5
This commit is contained in:
458
backend/api/content_planning/quality_analysis_routes.py
Normal file
458
backend/api/content_planning/quality_analysis_routes.py
Normal file
@@ -0,0 +1,458 @@
|
||||
"""
|
||||
Quality Analysis API Routes
|
||||
Provides endpoints for AI-powered quality assessment and recommendations.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends, Query
|
||||
from typing import Dict, Any, List
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from services.ai_quality_analysis_service import AIQualityAnalysisService, QualityAnalysisResult
|
||||
from services.database import get_db
|
||||
from models.enhanced_strategy_models import EnhancedContentStrategy
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/quality-analysis", tags=["quality-analysis"])
|
||||
|
||||
@router.post("/{strategy_id}/analyze")
|
||||
async def analyze_strategy_quality(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Analyze strategy quality using AI and return comprehensive results."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Initialize quality analysis service
|
||||
quality_service = AIQualityAnalysisService()
|
||||
|
||||
# Perform quality analysis
|
||||
analysis_result = await quality_service.analyze_strategy_quality(strategy_id)
|
||||
|
||||
# Convert result to dictionary for API response
|
||||
result_dict = {
|
||||
"strategy_id": analysis_result.strategy_id,
|
||||
"overall_score": analysis_result.overall_score,
|
||||
"overall_status": analysis_result.overall_status.value,
|
||||
"confidence_score": analysis_result.confidence_score,
|
||||
"analysis_timestamp": analysis_result.analysis_timestamp.isoformat(),
|
||||
"metrics": [
|
||||
{
|
||||
"name": metric.name,
|
||||
"score": metric.score,
|
||||
"weight": metric.weight,
|
||||
"status": metric.status.value,
|
||||
"description": metric.description,
|
||||
"recommendations": metric.recommendations
|
||||
}
|
||||
for metric in analysis_result.metrics
|
||||
],
|
||||
"recommendations": analysis_result.recommendations
|
||||
}
|
||||
|
||||
logger.info(f"Quality analysis completed for strategy {strategy_id}")
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": result_dict,
|
||||
"message": "Quality analysis completed successfully"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error analyzing strategy quality for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to analyze strategy quality: {str(e)}"
|
||||
)
|
||||
|
||||
@router.get("/{strategy_id}/metrics")
|
||||
async def get_quality_metrics(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get quality metrics for a strategy."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Initialize quality analysis service
|
||||
quality_service = AIQualityAnalysisService()
|
||||
|
||||
# Perform quick quality analysis (cached if available)
|
||||
analysis_result = await quality_service.analyze_strategy_quality(strategy_id)
|
||||
|
||||
# Return metrics in a simplified format
|
||||
metrics_data = [
|
||||
{
|
||||
"name": metric.name,
|
||||
"score": metric.score,
|
||||
"status": metric.status.value,
|
||||
"description": metric.description
|
||||
}
|
||||
for metric in analysis_result.metrics
|
||||
]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"strategy_id": strategy_id,
|
||||
"overall_score": analysis_result.overall_score,
|
||||
"overall_status": analysis_result.overall_status.value,
|
||||
"metrics": metrics_data,
|
||||
"last_updated": analysis_result.analysis_timestamp.isoformat()
|
||||
},
|
||||
"message": "Quality metrics retrieved successfully"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting quality metrics for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to get quality metrics: {str(e)}"
|
||||
)
|
||||
|
||||
@router.get("/{strategy_id}/recommendations")
|
||||
async def get_quality_recommendations(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get AI-powered quality improvement recommendations."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Initialize quality analysis service
|
||||
quality_service = AIQualityAnalysisService()
|
||||
|
||||
# Perform quality analysis to get recommendations
|
||||
analysis_result = await quality_service.analyze_strategy_quality(strategy_id)
|
||||
|
||||
# Get recommendations by category
|
||||
recommendations_by_category = {}
|
||||
for metric in analysis_result.metrics:
|
||||
if metric.recommendations:
|
||||
recommendations_by_category[metric.name] = metric.recommendations
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"strategy_id": strategy_id,
|
||||
"overall_recommendations": analysis_result.recommendations,
|
||||
"recommendations_by_category": recommendations_by_category,
|
||||
"priority_areas": [
|
||||
metric.name for metric in analysis_result.metrics
|
||||
if metric.status.value in ["needs_attention", "poor"]
|
||||
],
|
||||
"last_updated": analysis_result.analysis_timestamp.isoformat()
|
||||
},
|
||||
"message": "Quality recommendations retrieved successfully"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting quality recommendations for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to get quality recommendations: {str(e)}"
|
||||
)
|
||||
|
||||
@router.get("/{strategy_id}/history")
|
||||
async def get_quality_history(
|
||||
strategy_id: int,
|
||||
days: int = Query(30, description="Number of days to look back"),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get quality analysis history for a strategy."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Initialize quality analysis service
|
||||
quality_service = AIQualityAnalysisService()
|
||||
|
||||
# Get quality history
|
||||
history = await quality_service.get_quality_history(strategy_id, days)
|
||||
|
||||
# Convert history to API format
|
||||
history_data = [
|
||||
{
|
||||
"timestamp": result.analysis_timestamp.isoformat(),
|
||||
"overall_score": result.overall_score,
|
||||
"overall_status": result.overall_status.value,
|
||||
"confidence_score": result.confidence_score
|
||||
}
|
||||
for result in history
|
||||
]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"strategy_id": strategy_id,
|
||||
"history": history_data,
|
||||
"days": days,
|
||||
"total_analyses": len(history_data)
|
||||
},
|
||||
"message": "Quality history retrieved successfully"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting quality history for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to get quality history: {str(e)}"
|
||||
)
|
||||
|
||||
@router.get("/{strategy_id}/trends")
|
||||
async def get_quality_trends(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get quality trends and patterns for a strategy."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Initialize quality analysis service
|
||||
quality_service = AIQualityAnalysisService()
|
||||
|
||||
# Get quality trends
|
||||
trends = await quality_service.get_quality_trends(strategy_id)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"strategy_id": strategy_id,
|
||||
"trends": trends,
|
||||
"last_updated": datetime.utcnow().isoformat()
|
||||
},
|
||||
"message": "Quality trends retrieved successfully"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting quality trends for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to get quality trends: {str(e)}"
|
||||
)
|
||||
|
||||
@router.post("/{strategy_id}/quick-assessment")
|
||||
async def quick_quality_assessment(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Perform a quick quality assessment without full AI analysis."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Perform quick assessment based on data completeness
|
||||
completeness_score = self._calculate_completeness_score(strategy)
|
||||
|
||||
# Determine status based on score
|
||||
if completeness_score >= 80:
|
||||
status = "excellent"
|
||||
elif completeness_score >= 65:
|
||||
status = "good"
|
||||
elif completeness_score >= 45:
|
||||
status = "needs_attention"
|
||||
else:
|
||||
status = "poor"
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"strategy_id": strategy_id,
|
||||
"completeness_score": completeness_score,
|
||||
"status": status,
|
||||
"assessment_type": "quick",
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"message": "Quick assessment completed based on data completeness"
|
||||
},
|
||||
"message": "Quick quality assessment completed"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error performing quick assessment for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to perform quick assessment: {str(e)}"
|
||||
)
|
||||
|
||||
def _calculate_completeness_score(self, strategy: EnhancedContentStrategy) -> float:
|
||||
"""Calculate completeness score based on filled fields."""
|
||||
try:
|
||||
# Define required fields for each category
|
||||
required_fields = {
|
||||
"business_context": [
|
||||
'business_objectives', 'target_metrics', 'content_budget',
|
||||
'team_size', 'implementation_timeline', 'market_share'
|
||||
],
|
||||
"audience_intelligence": [
|
||||
'content_preferences', 'consumption_patterns', 'audience_pain_points',
|
||||
'buying_journey', 'seasonal_trends', 'engagement_metrics'
|
||||
],
|
||||
"competitive_intelligence": [
|
||||
'top_competitors', 'competitor_content_strategies', 'market_gaps',
|
||||
'industry_trends', 'emerging_trends'
|
||||
],
|
||||
"content_strategy": [
|
||||
'preferred_formats', 'content_mix', 'content_frequency',
|
||||
'optimal_timing', 'quality_metrics', 'editorial_guidelines', 'brand_voice'
|
||||
],
|
||||
"performance_analytics": [
|
||||
'traffic_sources', 'conversion_rates', 'content_roi_targets',
|
||||
'ab_testing_capabilities'
|
||||
]
|
||||
}
|
||||
|
||||
total_fields = 0
|
||||
filled_fields = 0
|
||||
|
||||
for category, fields in required_fields.items():
|
||||
total_fields += len(fields)
|
||||
for field in fields:
|
||||
if hasattr(strategy, field) and getattr(strategy, field) is not None:
|
||||
filled_fields += 1
|
||||
|
||||
if total_fields == 0:
|
||||
return 0.0
|
||||
|
||||
return (filled_fields / total_fields) * 100
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error calculating completeness score: {e}")
|
||||
return 0.0
|
||||
|
||||
@router.get("/{strategy_id}/dashboard")
|
||||
async def get_quality_dashboard(
|
||||
strategy_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get comprehensive quality dashboard data."""
|
||||
try:
|
||||
# Check if strategy exists
|
||||
strategy = db.query(EnhancedContentStrategy).filter(
|
||||
EnhancedContentStrategy.id == strategy_id
|
||||
).first()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Strategy with ID {strategy_id} not found"
|
||||
)
|
||||
|
||||
# Initialize quality analysis service
|
||||
quality_service = AIQualityAnalysisService()
|
||||
|
||||
# Get comprehensive analysis
|
||||
analysis_result = await quality_service.analyze_strategy_quality(strategy_id)
|
||||
|
||||
# Get trends
|
||||
trends = await quality_service.get_quality_trends(strategy_id)
|
||||
|
||||
# Prepare dashboard data
|
||||
dashboard_data = {
|
||||
"strategy_id": strategy_id,
|
||||
"overall_score": analysis_result.overall_score,
|
||||
"overall_status": analysis_result.overall_status.value,
|
||||
"confidence_score": analysis_result.confidence_score,
|
||||
"metrics": [
|
||||
{
|
||||
"name": metric.name,
|
||||
"score": metric.score,
|
||||
"status": metric.status.value,
|
||||
"description": metric.description,
|
||||
"recommendations": metric.recommendations
|
||||
}
|
||||
for metric in analysis_result.metrics
|
||||
],
|
||||
"recommendations": analysis_result.recommendations,
|
||||
"trends": trends,
|
||||
"priority_areas": [
|
||||
metric.name for metric in analysis_result.metrics
|
||||
if metric.status.value in ["needs_attention", "poor"]
|
||||
],
|
||||
"strengths": [
|
||||
metric.name for metric in analysis_result.metrics
|
||||
if metric.status.value == "excellent"
|
||||
],
|
||||
"last_updated": analysis_result.analysis_timestamp.isoformat()
|
||||
}
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": dashboard_data,
|
||||
"message": "Quality dashboard data retrieved successfully"
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting quality dashboard for {strategy_id}: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to get quality dashboard: {str(e)}"
|
||||
)
|
||||
Reference in New Issue
Block a user