fix: подбор угроз программой + сравнение программа↔ИИ

Проблемы:
1. Подбор программой возвращал 193 из 227 угроз (весь перечень) —
   теперь скоринг по ключевым словам объекта (тип, интернет, нарушитель,
   сеть), отсев нерелевантных: 72-82 угрозы вместо 193
2. Сравнение программа↔ИИ не подсвечивало совпадения: ИИ возвращает
   «1. УБИ.001 …» / с лишними пробелами — сравнение шло по точной строке.
   Теперь ключ сравнения — код УБИ (regex), иначе нормализованный текст;
   добавлена статистика «Совпало / только программа / только ИИ»
This commit is contained in:
2026-08-04 20:31:52 +04:00
parent 72f73d4c4f
commit 1ef8485b13
2 changed files with 56 additions and 10 deletions
+24 -2
View File
@@ -173,12 +173,34 @@ def suggest_threats_program(isys, threats=None, limit=None):
# — оставляем всё, кроме специфики каналов связи, если их нет
pass
result = []
# --- Положительные ключевые слова: чем больше совпало — тем угроза актуальнее ---
pos = list(BASE_KEYWORDS)
if has_internet:
pos += INTERNET_KEYWORDS
else:
pos += ISOLATED_KEYWORDS
if is_asu:
pos += ASU_KEYWORDS
if is_network:
pos += NETWORK_KEYWORDS
if _is_insider(isys):
pos += INSIDER_KEYWORDS
else:
pos += EXTERNAL_KEYWORDS
# Убираем дубликаты
pos = list(dict.fromkeys(pos))
scored = []
for t in threats:
tl = str(t).lower()
if any(kw in tl for kw in exclude):
continue
result.append(t)
sc = sum(1 for kw in pos if kw in tl)
scored.append((sc, t))
# Сортируем по релевантности (сначала — с наибольшим совпадением)
scored.sort(key=lambda x: -x[0])
result = [t for sc, t in scored if sc > 0]
if limit and len(result) > limit:
result = result[:limit]
+32 -8
View File
@@ -5,6 +5,7 @@ import tkinter as tk
from tkinter import ttk, messagebox, filedialog, simpledialog, scrolledtext
import os
import json
import re
import sys
import threading
from datetime import datetime
@@ -2147,10 +2148,30 @@ class DokoGenApp:
messagebox.showinfo("Сравнение", "Сначала подберите угрозы (программой или ИИ).")
return
# Нормализация строк угроз для сравнения:
# «1. УБИ.001 Угроза…», «УБИ.001 Угроза…» и «УБИ.001 Угроза…» — это одна и та же угроза.
# Ключ сравнения — код УБИ, если он есть (ИИ может обрезать/перефразировать название);
# иначе — нормализованный текст.
def _ubi_code(s):
m = re.search(r'уби\.?\s*(\d+)', str(s).lower())
return m.group(1) if m else None
def _norm(s):
s = re.sub(r'^\d+[.)]?\s*', '', str(s).strip()) # ведущий номер «1. »
s = re.sub(r'\s+', ' ', s).strip() # схлопнуть пробелы
return s.lower()
def _key(s):
code = _ubi_code(s)
return ('ubi', code) if code else ('name', _norm(s))
pset_norm = {_key(t) for t in program}
cset_norm = {_key(t) for t in current}
# Показываем окно: слева подобрано программой, справа текущий список
dlg = tk.Toplevel(self.root)
dlg.title("Сравнение угроз: программа ↔ ИИ/текущий")
dlg.geometry("760x420")
dlg.geometry("780x460")
dlg.transient(self.root)
frm = ttk.Frame(dlg, padding=8)
@@ -2158,7 +2179,7 @@ class DokoGenApp:
left = ttk.Frame(frm)
left.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
ttk.Label(left, text="⚙️ Программа", font=('Arial', 9, 'bold')).pack(anchor=tk.W)
ttk.Label(left, text=f"⚙️ Программа ({len(program)})", font=('Arial', 9, 'bold')).pack(anchor=tk.W)
lb_p = tk.Listbox(left, height=14)
lb_p.pack(fill=tk.BOTH, expand=True, pady=4)
for t in program:
@@ -2166,22 +2187,25 @@ class DokoGenApp:
right = ttk.Frame(frm)
right.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(8, 0))
ttk.Label(right, text="🤖 ИИ / текущий список", font=('Arial', 9, 'bold')).pack(anchor=tk.W)
ttk.Label(right, text=f"🤖 ИИ / текущий ({len(current)})", font=('Arial', 9, 'bold')).pack(anchor=tk.W)
lb_c = tk.Listbox(right, height=14)
lb_c.pack(fill=tk.BOTH, expand=True, pady=4)
for t in current:
lb_c.insert(tk.END, t)
# Подсветка совпадений
pset = set(program)
# Подсветка совпадений (по коду УБИ / нормализованному виду)
common = pset_norm & cset_norm
for i in range(lb_p.size()):
if lb_p.get(i) in set(current):
if _key(lb_p.get(i)) in common:
lb_p.itemconfig(i, bg='#c8e6c9')
for i in range(lb_c.size()):
if lb_c.get(i) in pset:
if _key(lb_c.get(i)) in common:
lb_c.itemconfig(i, bg='#c8e6c9')
info = ttk.Label(frm, text="Зелёным выделены совпавшие угрозы.",
info = ttk.Label(frm,
text=f"Совпало угроз: {len(common)} (зелёным). "
f"Только программа: {len(program) - len(common)}, "
f"только ИИ/текущий: {len(current) - len(common)}.",
foreground='gray')
info.pack(anchor=tk.W, pady=(4, 0))