Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Add Gemini AI integration to SEO, GBP, and Social Media audits that generates contextual analysis summaries and prioritized action items with ready-to-use content (Schema.org, meta descriptions, social posts, GBP descriptions, review responses, content calendars). New files: - audit_ai_service.py: Central AI service with caching (7-day TTL) - blueprints/api/routes_audit_actions.py: 4 API endpoints - database/migrations/056_audit_actions.sql: 3 new tables - templates/partials/audit_ai_actions.html: Reusable UI component Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
202 lines
5.7 KiB
Python
202 lines
5.7 KiB
Python
"""
|
|
Audit AI Actions API Routes - API blueprint
|
|
|
|
Endpoints for AI-powered audit analysis and content generation.
|
|
Uses audit_ai_service.py for Gemini integration.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from flask import jsonify, request
|
|
from flask_login import current_user, login_required
|
|
|
|
from database import SessionLocal, Company
|
|
from . import bp
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@bp.route('/audit/analyze', methods=['POST'])
|
|
@login_required
|
|
def api_audit_analyze():
|
|
"""
|
|
Generate AI analysis for an audit.
|
|
|
|
Request JSON:
|
|
company_id: int (required)
|
|
audit_type: str - 'seo', 'gbp', or 'social' (required)
|
|
force: bool - Force regeneration even if cache valid (optional)
|
|
|
|
Returns:
|
|
JSON with summary and actions list
|
|
"""
|
|
import audit_ai_service
|
|
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'success': False, 'error': 'Brak danych w żądaniu'}), 400
|
|
|
|
company_id = data.get('company_id')
|
|
audit_type = data.get('audit_type')
|
|
force = data.get('force', False)
|
|
|
|
if not company_id or not audit_type:
|
|
return jsonify({'success': False, 'error': 'Wymagane: company_id i audit_type'}), 400
|
|
|
|
if audit_type not in ('seo', 'gbp', 'social'):
|
|
return jsonify({'success': False, 'error': 'audit_type musi być: seo, gbp lub social'}), 400
|
|
|
|
# Access control
|
|
if not current_user.can_edit_company(company_id):
|
|
return jsonify({'success': False, 'error': 'Brak uprawnień do analizy tej firmy'}), 403
|
|
|
|
result = audit_ai_service.generate_analysis(
|
|
company_id=company_id,
|
|
audit_type=audit_type,
|
|
user_id=current_user.id,
|
|
force=force,
|
|
)
|
|
|
|
if 'error' in result:
|
|
return jsonify({'success': False, 'error': result['error']}), 422
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'summary': result.get('summary', ''),
|
|
'actions': result.get('actions', []),
|
|
'cached': result.get('cached', False),
|
|
'generated_at': result.get('generated_at'),
|
|
})
|
|
|
|
|
|
@bp.route('/audit/generate-content', methods=['POST'])
|
|
@login_required
|
|
def api_audit_generate_content():
|
|
"""
|
|
Generate specific content for an audit action.
|
|
|
|
Request JSON:
|
|
company_id: int (required)
|
|
action_type: str (required) - e.g. 'generate_schema_org', 'generate_gbp_post'
|
|
context: dict (optional) - Extra context like platform, review_text
|
|
|
|
Returns:
|
|
JSON with generated content
|
|
"""
|
|
import audit_ai_service
|
|
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'success': False, 'error': 'Brak danych w żądaniu'}), 400
|
|
|
|
company_id = data.get('company_id')
|
|
action_type = data.get('action_type')
|
|
context = data.get('context', {})
|
|
|
|
if not company_id or not action_type:
|
|
return jsonify({'success': False, 'error': 'Wymagane: company_id i action_type'}), 400
|
|
|
|
# Access control
|
|
if not current_user.can_edit_company(company_id):
|
|
return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403
|
|
|
|
result = audit_ai_service.generate_content(
|
|
company_id=company_id,
|
|
action_type=action_type,
|
|
context=context,
|
|
user_id=current_user.id,
|
|
)
|
|
|
|
if 'error' in result:
|
|
return jsonify({'success': False, 'error': result['error']}), 422
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'content': result.get('content', ''),
|
|
'action_type': result.get('action_type'),
|
|
'model': result.get('model'),
|
|
})
|
|
|
|
|
|
@bp.route('/audit/actions/<slug>')
|
|
@login_required
|
|
def api_audit_actions_by_slug(slug):
|
|
"""
|
|
Get audit actions for a company.
|
|
|
|
Query params:
|
|
audit_type: str (optional) - Filter by 'seo', 'gbp', or 'social'
|
|
|
|
Returns:
|
|
JSON with list of actions
|
|
"""
|
|
import audit_ai_service
|
|
|
|
audit_type = request.args.get('audit_type')
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
company = db.query(Company).filter_by(slug=slug, status='active').first()
|
|
if not company:
|
|
return jsonify({'success': False, 'error': 'Firma nie znaleziona'}), 404
|
|
|
|
if not current_user.can_edit_company(company.id):
|
|
return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403
|
|
|
|
actions = audit_ai_service.get_actions_for_company(
|
|
company_id=company.id,
|
|
audit_type=audit_type,
|
|
)
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'company_id': company.id,
|
|
'actions': actions,
|
|
'count': len(actions),
|
|
})
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/audit/actions/<int:action_id>/status', methods=['POST'])
|
|
@login_required
|
|
def api_audit_action_update_status(action_id):
|
|
"""
|
|
Update the status of an audit action.
|
|
|
|
Request JSON:
|
|
status: str - 'implemented' or 'dismissed'
|
|
|
|
Returns:
|
|
JSON with updated status
|
|
"""
|
|
import audit_ai_service
|
|
from database import AuditAction
|
|
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'success': False, 'error': 'Brak danych'}), 400
|
|
|
|
new_status = data.get('status')
|
|
if not new_status:
|
|
return jsonify({'success': False, 'error': 'Wymagane: status'}), 400
|
|
|
|
# Verify access
|
|
db = SessionLocal()
|
|
try:
|
|
action = db.query(AuditAction).filter_by(id=action_id).first()
|
|
if not action:
|
|
return jsonify({'success': False, 'error': 'Akcja nie znaleziona'}), 404
|
|
|
|
if not current_user.can_edit_company(action.company_id):
|
|
return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403
|
|
finally:
|
|
db.close()
|
|
|
|
result = audit_ai_service.update_action_status(action_id, new_status)
|
|
|
|
if 'error' in result:
|
|
return jsonify({'success': False, 'error': result['error']}), 422
|
|
|
|
return jsonify({'success': True, **result})
|