diff --git a/backend/accounts/tasks.py b/backend/accounts/tasks.py index 0c1475e..69af0a9 100644 --- a/backend/accounts/tasks.py +++ b/backend/accounts/tasks.py @@ -1,6 +1,6 @@ from celery import shared_task from backend.core.models import Organization, Document, Risk, Control, DocumentRiskControl -from backend.core.utils import get_top_risk, get_controls_for_risk, generate_key_findings +from backend.core.utils import get_top_risk, get_controls_for_risk, generate_key_findings, generate_recommendations from django.shortcuts import get_object_or_404, render from .utils import send_payment_email from backend.core.tables import get_risk_table @@ -59,4 +59,10 @@ def create_document_for_organization(confirmation_email): document.key_findings = key_findings document.save() - send_payment_email(confirmation_email) \ No newline at end of file + risk_for_recomendation = get_risk_table(document)[:10] + recommendations = generate_recommendations(risk_for_recomendation, organization) + if recommendations: + document.recomendations = recommendations + document.save() + + send_payment_email(confirmation_email) diff --git a/backend/core/migrations/0019_document_recomendations.py b/backend/core/migrations/0019_document_recomendations.py new file mode 100644 index 0000000..04cba5b --- /dev/null +++ b/backend/core/migrations/0019_document_recomendations.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2025-08-11 18:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0018_rename_paymentcode_democode'), + ] + + operations = [ + migrations.AddField( + model_name='document', + name='recomendations', + field=models.TextField(blank=True, help_text='Recommendations', null=True), + ), + ] diff --git a/backend/core/models.py b/backend/core/models.py index 3ef45cd..b031e81 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -106,7 +106,8 @@ class Document(models.Model): created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) key_findings = models.TextField(blank=True, null=True, help_text="Key findings") - + recomendations = models.TextField(blank=True, null=True, help_text="Recommendations") + def __str__(self): return f"Document for {self.organization.name}" diff --git a/backend/core/utils.py b/backend/core/utils.py index ab884ba..d5ffeed 100644 --- a/backend/core/utils.py +++ b/backend/core/utils.py @@ -210,6 +210,61 @@ def get_controls_for_risk(risk, organization): if not remaining_controls: break return selected_controls if len(selected_controls) == 10 else [] + + +def generate_recommendations(risks_with_controls, organization): + + client = OpenAI(api_key=settings.OPENAI_API_KEY) + + organization_details = extract_organization_details(organization) + + prompt = f""" + You are an AI assistant tasked with generating the Recommendations section for a cybersecurity assessment report. Use the organization’s context and the list of risks with their proposed controls to produce concise, actionable, and prioritized guidance. + + Inputs: + - Organization details: + {organization_details} + + - Risks with controls (Python-like list of dicts). Each item includes: + risk: id, name, category, risk_description (or similar) + r_impact (inherent impact 1–5), r_likelihood (inherent likelihood 1–5), risk_score + residual_impact, residual_likelihood, residual_risk_score (may be present) + controls: list of controls, each with control__name, weight (1–5 effectiveness), likelihood (1–5 occurrence modifier) + + Task: + 1) Compute a priority score per control = weight × likelihood. Aggregate scores across all risks and cluster into 3–5 thematic areas that best match the actual controls and risk names (e.g., Access Control & MFA, Patch & Vulnerability Management, Vendor/Third-Party Risk Management, Network Security & Segmentation, Logging/Monitoring/Detection, Incident Response & BCDR, Ransomware Prevention & Recovery, Cryptography & Key Management). Do not invent themes without support in the inputs. + 2) For each chosen theme, produce 3–5 concrete actions derived from the highest-priority controls. Tailor to the organization_details where appropriate. Prefer steps that reduce both likelihood and impact. + 3) Each bullet should be 1–2 sentences: start with a clear, imperative recommendation, and (optionally) add a brief explanation or context. Still keep it concise and actionable. + 4) Use only the control__name for reference—do NOT include or reference control IDs, years (e.g., 2024), or quarter references (Q1, Q2, Q3, Q4) anywhere in the output. + 5) Do not introduce controls that are not represented in the provided controls list. + + Output format (STRICT): + <2–3 sentence paragraph explaining that recommendations are prioritized by expected risk reduction based on the provided controls and aligned to the organization’s context.> + +