Recommendations are now generated by AI, changed format for key findings, risks names are now bold

This commit is contained in:
2025-08-11 21:51:21 +02:00
parent 2d2dc7ed14
commit e68a0f615a
5 changed files with 89 additions and 26 deletions

View File

@@ -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)
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)

View File

@@ -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),
),
]

View File

@@ -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}"

View File

@@ -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 organizations 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 15), r_likelihood (inherent likelihood 15), risk_score
residual_impact, residual_likelihood, residual_risk_score (may be present)
controls: list of controls, each with control__name, weight (15 effectiveness), likelihood (15 occurrence modifier)
Task:
1) Compute a priority score per control = weight × likelihood. Aggregate scores across all risks and cluster into 35 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 35 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 12 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):
<23 sentence paragraph explaining that recommendations are prioritized by expected risk reduction based on the provided controls and aligned to the organizations context.>
<h3>Theme Title</h3>
- Bullet 1 (12 sentences, no IDs, years, or quarters)
- Bullet 2
- Bullet 3
- Bullet 4 (optional)
- Bullet 5 (optional)
Constraints:
- 35 themed subsections, each with 35 bullets.
- No preamble or postscript beyond the sections above.
- Do NOT reference or display control IDs, years, or quarters in any form.
Now produce the final Recommendations section using the actual inputs above.
Risks with controls:
{risks_with_controls}
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": prompt}]
)
recommendations = response.choices[0].message.content.strip()
return recommendations
def generate_key_findings(document, top_10_risks):
@@ -254,11 +309,11 @@ def generate_key_findings(document, top_10_risks):
The [Concise, professionally phrased description] part must be synthesized from the provided risk_description field (e.g., {{ item.risk_description }}) associated with that risk. Aim to create a polished, impactful summary that clearly explains the risk's context, severity, or contributing factors.
Return it as plain text in the following format:
Example Output Format:
Output Format(STRICT):
Introduction
- Risk 1: Brief description of Risk 1
- Risk 2: Brief description of Risk 2
- Risk 3: Brief description of Risk 3
- <b> Risk 1 </b> : Brief description of Risk 1
- <b> Risk 2 </b> : Brief description of Risk 2
- <b> Risk 3 </b> : Brief description of Risk 3
"""
response = client.chat.completions.create(