Files
Munich-news/backend/routes/interests_routes.py
2025-11-18 14:45:41 +01:00

240 lines
6.3 KiB
Python

"""
User Interest Profile API routes for Munich News Daily.
Provides endpoints to view and manage user interest profiles.
"""
from flask import Blueprint, request, jsonify
from services.interest_profiling_service import (
get_user_interests,
get_top_interests,
build_interests_from_history,
decay_user_interests,
get_interest_statistics,
delete_user_interests
)
interests_bp = Blueprint('interests', __name__)
@interests_bp.route('/api/interests/<email>', methods=['GET'])
def get_interests(email):
"""
Get user interest profile.
Args:
email: Email address of the user
Returns:
JSON response with user interest profile
"""
try:
profile = get_user_interests(email)
if not profile:
return jsonify({
'success': False,
'error': 'User profile not found'
}), 404
# Remove MongoDB _id field
if '_id' in profile:
del profile['_id']
return jsonify({
'success': True,
'profile': profile
}), 200
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@interests_bp.route('/api/interests/<email>/top', methods=['GET'])
def get_top_user_interests(email):
"""
Get user's top interests sorted by score.
Query parameters:
top_n: Number of top interests to return (default: 10)
Args:
email: Email address of the user
Returns:
JSON response with top categories and keywords
"""
try:
top_n = request.args.get('top_n', 10, type=int)
top_interests = get_top_interests(email, top_n)
return jsonify({
'success': True,
'email': email,
'top_categories': [
{'category': cat, 'score': score}
for cat, score in top_interests['top_categories']
],
'top_keywords': [
{'keyword': kw, 'score': score}
for kw, score in top_interests['top_keywords']
]
}), 200
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@interests_bp.route('/api/interests/<email>/rebuild', methods=['POST'])
def rebuild_interests(email):
"""
Rebuild user interest profile from click history.
Request body (optional):
{
"days_lookback": 30 // Number of days of history to analyze
}
Args:
email: Email address of the user
Returns:
JSON response with rebuilt profile
"""
try:
data = request.get_json() or {}
days_lookback = data.get('days_lookback', 30)
# Validate days_lookback
if not isinstance(days_lookback, int) or days_lookback < 1:
return jsonify({
'success': False,
'error': 'days_lookback must be a positive integer'
}), 400
profile = build_interests_from_history(email, days_lookback)
# Remove MongoDB _id field
if '_id' in profile:
del profile['_id']
return jsonify({
'success': True,
'message': f'Profile rebuilt from {days_lookback} days of history',
'profile': profile
}), 200
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@interests_bp.route('/api/interests/decay', methods=['POST'])
def decay_interests():
"""
Decay interest scores for inactive users.
Request body (optional):
{
"decay_factor": 0.95, // Multiplier for scores (default: 0.95)
"days_threshold": 7 // Only decay profiles older than N days
}
Returns:
JSON response with decay statistics
"""
try:
data = request.get_json() or {}
decay_factor = data.get('decay_factor', 0.95)
days_threshold = data.get('days_threshold', 7)
# Validate parameters
if not isinstance(decay_factor, (int, float)) or decay_factor <= 0 or decay_factor > 1:
return jsonify({
'success': False,
'error': 'decay_factor must be between 0 and 1'
}), 400
if not isinstance(days_threshold, int) or days_threshold < 1:
return jsonify({
'success': False,
'error': 'days_threshold must be a positive integer'
}), 400
result = decay_user_interests(decay_factor, days_threshold)
return jsonify({
'success': True,
'message': f'Decayed interests for profiles older than {days_threshold} days',
'statistics': result
}), 200
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@interests_bp.route('/api/interests/statistics', methods=['GET'])
def get_statistics():
"""
Get statistics about user interests across all users.
Returns:
JSON response with interest statistics
"""
try:
stats = get_interest_statistics()
return jsonify({
'success': True,
'statistics': stats
}), 200
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@interests_bp.route('/api/interests/<email>', methods=['DELETE'])
def delete_interests(email):
"""
Delete user interest profile (GDPR compliance).
Args:
email: Email address of the user
Returns:
JSON response with confirmation
"""
try:
deleted = delete_user_interests(email)
if not deleted:
return jsonify({
'success': False,
'error': 'User profile not found'
}), 404
return jsonify({
'success': True,
'message': f'Interest profile deleted for {email}'
}), 200
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500