feat: подбор характеристик объекта КИИ — программа и ИИ
Вкладка «Основное», кнопки под полем типового объекта: - ⚙️ «Подобрать типовой объект (программа)»: скоринг по совпадению значимых слов названия/назначения объекта с перечнем 392 типовых отраслевых объектов (Распоряжение 360-р), IDF-веса (редкие слова важнее общих) → окно с вариантами, оператор выбирает и применяет (заполняет сферу + типовой объект) - 🤖 «Подобрать характеристики (ИИ)»: DeepSeek предлагает назначение, сферу, тип, архитектуру и типовой объект (из перечня 360-р) как рекомендацию → окно с полями, оператор подтверждает/правит Примеры: СКУД → «ИС, АСУ, ИТКС, обеспечивающие контроль и управление доступом на территорию»; 1С:УПП → «ИС для ведения бухгалтерского учета»
This commit is contained in:
@@ -342,3 +342,135 @@ def auto_fill_security(isys, threats=None):
|
|||||||
res['tech_measures'] = '\n'.join(tech)
|
res['tech_measures'] = '\n'.join(tech)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# Подбор типового отраслевого объекта КИИ по характеристикам объекта
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
|
# Стоп-слова: не несут смысла при сопоставлении названия объекта и типового объекта
|
||||||
|
STOPWORDS = {
|
||||||
|
'информационные', 'информационно', 'телекоммуникационные', 'автоматизированные',
|
||||||
|
'системы', 'система', 'сети', 'сеть', 'обеспечивающие', 'обеспечивающих',
|
||||||
|
'предназначенные', 'предназначенных', 'управление', 'контроль', 'мониторинг',
|
||||||
|
'объекта', 'объектов', 'объект', 'объекты', 'кии', 'рф', 'российской',
|
||||||
|
'федерации', 'исполнительной', 'власти', 'органов', 'организаций', 'организации',
|
||||||
|
'подведомственных', 'функций', 'функции', 'осуществление', 'полномочий',
|
||||||
|
'обеспечение', 'процессов', 'процесса', 'процессы', 'данных', 'информации',
|
||||||
|
'сбор', 'хранение', 'обработка', 'представление', 'использование', 'передача',
|
||||||
|
'автоматизации', 'средств', 'программных', 'программно', 'аппаратных',
|
||||||
|
'технических', 'деятельность', 'деятельности', 'осуществляющих',
|
||||||
|
'размещенные', 'размещенных', 'расположенных', 'используемых', 'используемые',
|
||||||
|
'проведении', 'проведения', 'выполнении', 'выполнения', 'реализация', 'реализации',
|
||||||
|
'электронных', 'электронного', 'информационных', 'информационного',
|
||||||
|
# Общие словоформы, встречающиеся почти у всех типовых объектов:
|
||||||
|
'контроль', 'контроля', 'контролю', 'контролем', 'контроле',
|
||||||
|
'управление', 'управления', 'управлению', 'управлением', 'управлении',
|
||||||
|
'безопасность', 'безопасности', 'безопасностью', 'безопасном',
|
||||||
|
'обеспечение', 'обеспечения', 'обеспечению', 'обеспечением',
|
||||||
|
'предназначен', 'предназначена', 'предназначено', 'предназначены',
|
||||||
|
'предоставление', 'предоставления', 'предоставлению',
|
||||||
|
'взаимодействие', 'взаимодействия', 'взаимодействию',
|
||||||
|
'функционирование', 'функционирования', 'функционированию',
|
||||||
|
'деятельность', 'деятельности', 'деятельностью',
|
||||||
|
'автоматизирован', 'автоматизированной', 'автоматизированных',
|
||||||
|
'телекоммуникацион', 'телекоммуникационной', 'телекоммуникационных',
|
||||||
|
'информационн', 'информационной', 'информационных', 'информационное',
|
||||||
|
'осуществление', 'осуществления', 'осуществлению',
|
||||||
|
'для', 'систем', 'системы', 'система', 'ресурсов', 'ресурсы',
|
||||||
|
'целью', 'цели', 'помощи', 'помощь', 'также', 'или', 'иных', 'иное',
|
||||||
|
'при', 'на', 'по', 'в', 'с', 'и', 'не', 'то', 'числе',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _tokenize(text):
|
||||||
|
"""Значимые слова текста (без стоп-слов)."""
|
||||||
|
import re as _re
|
||||||
|
words = _re.findall(r'[а-яёa-z0-9]+', (text or '').lower())
|
||||||
|
return [w for w in words if len(w) > 2 and w not in STOPWORDS]
|
||||||
|
|
||||||
|
|
||||||
|
def _load_all_typical(dict_dir=None):
|
||||||
|
"""Все типовые отраслевые объекты из typical_industry_objects.json (по сферам)."""
|
||||||
|
import os as _os
|
||||||
|
if dict_dir is None:
|
||||||
|
dict_dir = _os.path.join(_os.path.dirname(_os.path.abspath(__file__)), 'dictionaries')
|
||||||
|
path = _os.path.join(dict_dir, 'typical_industry_objects.json')
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
out = []
|
||||||
|
for sphere, items in data.items():
|
||||||
|
if sphere == 'Иная сфера деятельности':
|
||||||
|
continue
|
||||||
|
for it in items:
|
||||||
|
out.append({'sphere': sphere, 'num': it.get('num', ''),
|
||||||
|
'name': it.get('name', '')})
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
_IDF_CACHE = None
|
||||||
|
|
||||||
|
|
||||||
|
def _idf_weights(cands):
|
||||||
|
"""IDF-веса слов: чем реже слово в перечне типовых объектов, тем больше вес.
|
||||||
|
|
||||||
|
Общие слова («информационные», «управление», «контроль») встречаются почти
|
||||||
|
у всех 392 объектов и почти ничего не значат; редкие («доступом», «СКУД»,
|
||||||
|
«сигнализации») — сильно различают объекты.
|
||||||
|
"""
|
||||||
|
global _IDF_CACHE
|
||||||
|
if _IDF_CACHE is not None:
|
||||||
|
return _IDF_CACHE
|
||||||
|
import math
|
||||||
|
df = {}
|
||||||
|
for c in cands:
|
||||||
|
for w in set(_tokenize(c['name'])):
|
||||||
|
df[w] = df.get(w, 0) + 1
|
||||||
|
n = max(len(cands), 1)
|
||||||
|
weights = {w: math.log((n + 1) / (df.get(w, 0) + 1)) + 1.0 for w in df}
|
||||||
|
_IDF_CACHE = weights
|
||||||
|
return weights
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_typical_object_program(isys, limit=10, sphere=None):
|
||||||
|
"""Подбор типового отраслевого объекта КИИ по характеристикам объекта.
|
||||||
|
|
||||||
|
Логика: значимые слова из названия/назначения/описания объекта КИИ
|
||||||
|
сопоставляются со значимыми словами названий типовых объектов
|
||||||
|
(перечень Распоряжения ПРФ № 360-р, 392 объекта). Скоринг по IDF:
|
||||||
|
редкие слова (например, «доступом», «сигнализации») весят больше общих.
|
||||||
|
Пример: объект «СКУД» / «контроль и управление доступом» →
|
||||||
|
«ИС, АСУ, ИТКС, обеспечивающие контроль и управление доступом на территорию».
|
||||||
|
|
||||||
|
Возвращает список dict: {sphere, num, name, score} — по убыванию релевантности.
|
||||||
|
"""
|
||||||
|
text = ' '.join([
|
||||||
|
getattr(isys, 'name', '') or '',
|
||||||
|
getattr(isys, 'purpose', '') or '',
|
||||||
|
getattr(isys, 'description', '') or '',
|
||||||
|
])
|
||||||
|
obj_words = set(_tokenize(text))
|
||||||
|
if not obj_words:
|
||||||
|
return []
|
||||||
|
|
||||||
|
cands = _load_all_typical()
|
||||||
|
if sphere:
|
||||||
|
cands = [c for c in cands if c['sphere'] == sphere]
|
||||||
|
|
||||||
|
weights = _idf_weights(cands)
|
||||||
|
|
||||||
|
scored = []
|
||||||
|
for c in cands:
|
||||||
|
tw = set(_tokenize(c['name']))
|
||||||
|
common = tw & obj_words
|
||||||
|
if common:
|
||||||
|
score = sum(weights.get(w, 1.0) for w in common)
|
||||||
|
scored.append({'sphere': c['sphere'], 'num': c['num'],
|
||||||
|
'name': c['name'], 'score': round(score, 2),
|
||||||
|
'matched': sorted(common)})
|
||||||
|
|
||||||
|
scored.sort(key=lambda x: (-x['score'], x['name']))
|
||||||
|
return scored[:limit]
|
||||||
|
|||||||
+200
@@ -868,6 +868,16 @@ class DokoGenApp:
|
|||||||
self._typical_objects_all = ['']
|
self._typical_objects_all = ['']
|
||||||
self.is_typical_object_combo['values'] = self._typical_objects_all
|
self.is_typical_object_combo['values'] = self._typical_objects_all
|
||||||
|
|
||||||
|
# Кнопки подбора характеристик: программа (типовой объект) и ИИ (всё)
|
||||||
|
suggest_row = ttk.Frame(main_frame)
|
||||||
|
suggest_row.grid(row=5, column=0, columnspan=2, sticky=tk.W, pady=(4, 0))
|
||||||
|
ttk.Button(suggest_row, text="⚙️ Подобрать типовой объект (программа)",
|
||||||
|
command=self._suggest_typical_program_click).pack(side=tk.LEFT, padx=2)
|
||||||
|
ttk.Button(suggest_row, text="🤖 Подобрать характеристики (ИИ)",
|
||||||
|
command=self._suggest_object_params_ai_click).pack(side=tk.LEFT, padx=2)
|
||||||
|
ttk.Label(suggest_row, text="Подбор по названию/назначению объекта — как рекомендация, оператор подтверждает.",
|
||||||
|
foreground='gray').pack(side=tk.LEFT, padx=8)
|
||||||
|
|
||||||
main_frame.columnconfigure(1, weight=1)
|
main_frame.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
# ===== Вкладка «Субъект» =====
|
# ===== Вкладка «Субъект» =====
|
||||||
@@ -1554,6 +1564,196 @@ class DokoGenApp:
|
|||||||
def _set_is_edit_state(self, enabled):
|
def _set_is_edit_state(self, enabled):
|
||||||
state = 'normal' if enabled else 'disabled'
|
state = 'normal' if enabled else 'disabled'
|
||||||
|
|
||||||
|
def _suggest_typical_program_click(self):
|
||||||
|
"""⚙️ Подобрать типовой отраслевой объект программой (по названию/назначению объекта)."""
|
||||||
|
if self._current_is_idx is None:
|
||||||
|
messagebox.showinfo("Подбор", "Сначала выберите объект КИИ в списке слева")
|
||||||
|
return
|
||||||
|
self._collect_is()
|
||||||
|
isys = self.model.information_systems[self._current_is_idx]
|
||||||
|
try:
|
||||||
|
from .threat_rules import suggest_typical_object_program
|
||||||
|
sphere = self.is_sphere_combo.get() or None
|
||||||
|
results = suggest_typical_object_program(isys, limit=12, sphere=sphere)
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("Ошибка", str(e))
|
||||||
|
return
|
||||||
|
if not results:
|
||||||
|
messagebox.showinfo("Подбор",
|
||||||
|
"Не удалось подобрать типовой объект по названию/назначению.\n"
|
||||||
|
"Попробуйте кнопку «🤖 Подобрать характеристики (ИИ)».")
|
||||||
|
return
|
||||||
|
|
||||||
|
dlg = tk.Toplevel(self.root)
|
||||||
|
dlg.title("⚙️ Подбор типового отраслевого объекта")
|
||||||
|
dlg.geometry("860x520")
|
||||||
|
dlg.transient(self.root)
|
||||||
|
frm = ttk.Frame(dlg, padding=8)
|
||||||
|
frm.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
ttk.Label(frm, text=f"Объект: {isys.name}",
|
||||||
|
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
|
||||||
|
ttk.Label(frm, text="Наиболее подходящие типовые отраслевые объекты (по совпадению слов "
|
||||||
|
"с названием/назначением). Выберите и нажмите «Применить».",
|
||||||
|
foreground='gray', wraplength=820, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
|
||||||
|
|
||||||
|
lb = tk.Listbox(frm, height=16, exportselection=False)
|
||||||
|
lb.pack(fill=tk.BOTH, expand=True)
|
||||||
|
for r in results:
|
||||||
|
lb.insert(tk.END, f"[{r['score']}] ({r['sphere']}) {r['name']}")
|
||||||
|
|
||||||
|
btn_row = ttk.Frame(frm)
|
||||||
|
btn_row.pack(fill=tk.X, pady=(8, 0))
|
||||||
|
ttk.Button(btn_row, text="✔️ Применить выбранное",
|
||||||
|
command=lambda: self._apply_typical_selection(lb, results, dlg)).pack(side=tk.LEFT, padx=2)
|
||||||
|
ttk.Button(btn_row, text="Отмена", command=dlg.destroy).pack(side=tk.LEFT, padx=2)
|
||||||
|
|
||||||
|
def _apply_typical_selection(self, lb, results, dlg):
|
||||||
|
sel = lb.curselection()
|
||||||
|
if not sel:
|
||||||
|
messagebox.showinfo("Подбор", "Выберите типовой объект из списка")
|
||||||
|
return
|
||||||
|
r = results[sel[0]]
|
||||||
|
# Устанавливаем сферу и типовой объект
|
||||||
|
if hasattr(self, 'is_sphere_combo'):
|
||||||
|
self.is_sphere_combo.set(r['sphere'])
|
||||||
|
self._update_typical_objects_by_sphere()
|
||||||
|
if hasattr(self, 'is_typical_object_combo'):
|
||||||
|
self.is_typical_object_combo.set(r['name'])
|
||||||
|
self._collect_is()
|
||||||
|
self.log(f"⚙️ Типовой отраслевой объект: {r['name'][:70]}")
|
||||||
|
dlg.destroy()
|
||||||
|
|
||||||
|
def _suggest_object_params_ai_click(self):
|
||||||
|
"""🤖 Подобрать характеристики объекта через ИИ (назначение, сфера, тип, архитектура, типовой объект)."""
|
||||||
|
if self._current_is_idx is None:
|
||||||
|
messagebox.showinfo("Подбор", "Сначала выберите объект КИИ в списке слева")
|
||||||
|
return
|
||||||
|
settings = load_api_settings()
|
||||||
|
if not settings.get('ai_api_key'):
|
||||||
|
messagebox.showwarning("Настройки", "Не задан API-ключ ИИ.\nМеню «Файл → Настройки»")
|
||||||
|
return
|
||||||
|
self._collect_is()
|
||||||
|
isys = self.model.information_systems[self._current_is_idx]
|
||||||
|
# Перечень типовых объектов для выбора ИИ (всех сфер)
|
||||||
|
typical_list = []
|
||||||
|
if hasattr(self, '_typical_industry'):
|
||||||
|
for sph, items in self._typical_industry.items():
|
||||||
|
if sph == 'Иная сфера деятельности':
|
||||||
|
continue
|
||||||
|
for it in items:
|
||||||
|
typical_list.append(it.get('name', ''))
|
||||||
|
data = {
|
||||||
|
'name': isys.name or '',
|
||||||
|
'description': isys.description or '',
|
||||||
|
'purpose': isys.purpose or '',
|
||||||
|
'sphere': isys.sphere or '',
|
||||||
|
'object_type': isys.object_type or '',
|
||||||
|
}
|
||||||
|
self.log(f"🤖 Запрос к ИИ: подбор характеристик для «{isys.name}»")
|
||||||
|
self._verify_log("Подбор характеристик через ИИ…")
|
||||||
|
|
||||||
|
def _run():
|
||||||
|
try:
|
||||||
|
from .verify import suggest_object_params_ai
|
||||||
|
res, err = suggest_object_params_ai(
|
||||||
|
data, settings['ai_api_key'], settings.get('ai_model'),
|
||||||
|
settings.get('ai_base_url'), typical_objects=typical_list)
|
||||||
|
self.root.after(0, lambda: self._suggest_object_params_ai_done(res, err, isys.name))
|
||||||
|
except Exception as e:
|
||||||
|
self.root.after(0, lambda: self._suggest_object_params_ai_done(None, str(e), isys.name))
|
||||||
|
|
||||||
|
threading.Thread(target=_run, daemon=True).start()
|
||||||
|
|
||||||
|
def _suggest_object_params_ai_done(self, res, err, obj_name):
|
||||||
|
if err:
|
||||||
|
self._verify_log(f"❌ {err}")
|
||||||
|
self.log(f"❌ Подбор характеристик ИИ: {err}")
|
||||||
|
return
|
||||||
|
if not res:
|
||||||
|
self._verify_log("❌ ИИ не вернул характеристики")
|
||||||
|
return
|
||||||
|
|
||||||
|
dlg = tk.Toplevel(self.root)
|
||||||
|
dlg.title("🤖 Рекомендации ИИ по характеристикам объекта")
|
||||||
|
dlg.geometry("860x560")
|
||||||
|
dlg.transient(self.root)
|
||||||
|
frm = ttk.Frame(dlg, padding=8)
|
||||||
|
frm.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
ttk.Label(frm, text=f"Объект: {obj_name} — рекомендации ИИ (подтвердите или скорректируйте)",
|
||||||
|
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
|
||||||
|
|
||||||
|
rows = [
|
||||||
|
('назначение', 'Назначение объекта'),
|
||||||
|
('сфера', 'Сфера деятельности'),
|
||||||
|
('тип', 'Тип объекта'),
|
||||||
|
('архитектура', 'Архитектура объекта'),
|
||||||
|
('типовой_объект', 'Типовой отраслевой объект КИИ'),
|
||||||
|
]
|
||||||
|
entries = {}
|
||||||
|
for key, label in rows:
|
||||||
|
ttk.Label(frm, text=label + ":").pack(anchor=tk.W, pady=(6, 0))
|
||||||
|
e = tk.Text(frm, height=2 if key == 'типовой_объект' else 1, wrap=tk.WORD)
|
||||||
|
e.pack(fill=tk.X)
|
||||||
|
e.insert('1.0', res.get(key, '') or '')
|
||||||
|
entries[key] = e
|
||||||
|
|
||||||
|
ttk.Label(frm, text="Обоснование ИИ:").pack(anchor=tk.W, pady=(6, 0))
|
||||||
|
just = tk.Text(frm, height=2, wrap=tk.WORD)
|
||||||
|
just.pack(fill=tk.X)
|
||||||
|
just.insert('1.0', res.get('обоснование', '') or '')
|
||||||
|
|
||||||
|
btn_row = ttk.Frame(frm)
|
||||||
|
btn_row.pack(fill=tk.X, pady=(8, 0))
|
||||||
|
ttk.Button(btn_row, text="✔️ Применить",
|
||||||
|
command=lambda: self._apply_ai_params(entries, dlg)).pack(side=tk.LEFT, padx=2)
|
||||||
|
ttk.Button(btn_row, text="Отмена", command=dlg.destroy).pack(side=tk.LEFT, padx=2)
|
||||||
|
|
||||||
|
def _apply_ai_params(self, entries, dlg):
|
||||||
|
"""Применить рекомендации ИИ к полям объекта."""
|
||||||
|
def _get(e):
|
||||||
|
return e.get('1.0', 'end-1c').strip()
|
||||||
|
|
||||||
|
purpose = _get(entries['назначение'])
|
||||||
|
sphere = _get(entries['сфера'])
|
||||||
|
otype = _get(entries['тип'])
|
||||||
|
arch = _get(entries['архитектура'])
|
||||||
|
typical = _get(entries['типовой_объект'])
|
||||||
|
|
||||||
|
if purpose and hasattr(self, 'is_purpose_entry'):
|
||||||
|
self.is_purpose_entry.delete(0, tk.END)
|
||||||
|
self.is_purpose_entry.insert(0, purpose)
|
||||||
|
|
||||||
|
# Сфера — проверим, есть ли в списке
|
||||||
|
if sphere and hasattr(self, 'is_sphere_combo'):
|
||||||
|
values = list(self.is_sphere_combo['values'])
|
||||||
|
exact = next((v for v in values if v.lower() == sphere.lower()), None)
|
||||||
|
if exact:
|
||||||
|
self.is_sphere_combo.set(exact)
|
||||||
|
self._update_typical_objects_by_sphere()
|
||||||
|
else:
|
||||||
|
self.is_sphere_combo.set(sphere)
|
||||||
|
|
||||||
|
if otype and hasattr(self, 'is_object_type_combo'):
|
||||||
|
values = list(self.is_object_type_combo['values'])
|
||||||
|
exact = next((v for v in values if v.lower() == otype.lower()), None)
|
||||||
|
self.is_object_type_combo.set(exact or otype)
|
||||||
|
|
||||||
|
if arch and hasattr(self, 'is_architecture_combo'):
|
||||||
|
values = list(self.is_architecture_combo['values'])
|
||||||
|
exact = next((v for v in values if v.lower() == arch.lower()), None)
|
||||||
|
self.is_architecture_combo.set(exact or arch)
|
||||||
|
|
||||||
|
if typical and hasattr(self, 'is_typical_object_combo'):
|
||||||
|
values = list(self.is_typical_object_combo['values'])
|
||||||
|
exact = next((v for v in values if v.lower() == typical.lower()), None)
|
||||||
|
self.is_typical_object_combo.set(exact or typical)
|
||||||
|
|
||||||
|
self._collect_is()
|
||||||
|
self.log("🤖 Рекомендации ИИ применены к характеристикам объекта")
|
||||||
|
dlg.destroy()
|
||||||
|
|
||||||
def _on_sphere_changed(self, event=None):
|
def _on_sphere_changed(self, event=None):
|
||||||
"""При смене сферы объекта — подставляем типовые отраслевые объекты этой сферы (Распоряжение ПРФ № 360-р)."""
|
"""При смене сферы объекта — подставляем типовые отраслевые объекты этой сферы (Распоряжение ПРФ № 360-р)."""
|
||||||
self._update_typical_objects_by_sphere()
|
self._update_typical_objects_by_sphere()
|
||||||
|
|||||||
@@ -519,6 +519,63 @@ def suggest_threats_ai(security_data, api_key, model='deepseek-chat', base_url=N
|
|||||||
return threats_out, None
|
return threats_out, None
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_object_params_ai(object_data, api_key, model='deepseek-chat', base_url=None,
|
||||||
|
typical_objects=None):
|
||||||
|
"""ИИ предлагает характеристики объекта КИИ: назначение, сферу, тип, архитектуру,
|
||||||
|
типовой отраслевой объект — как рекомендацию оператору.
|
||||||
|
|
||||||
|
object_data — dict: name, description, purpose (что известно об объекте).
|
||||||
|
typical_objects — перечень типовых отраслевых объектов (из 360-р) для выбора.
|
||||||
|
|
||||||
|
Возвращает (dict, ошибка): dict с полями
|
||||||
|
purpose / sphere / object_type / architecture / typical_object / обоснование.
|
||||||
|
"""
|
||||||
|
if not api_key:
|
||||||
|
return None, "Не задан API-ключ ИИ (Файл → Настройки → API)"
|
||||||
|
|
||||||
|
if typical_objects:
|
||||||
|
to_text = "\n".join(f"{i+1}. {t}" for i, t in enumerate(typical_objects[:400]))
|
||||||
|
else:
|
||||||
|
to_text = "(перечень не предоставлен)"
|
||||||
|
|
||||||
|
system = (
|
||||||
|
"Ты — эксперт ФСТЭК по категорированию объектов критической информационной инфраструктуры "
|
||||||
|
"(187-ФЗ, ПП РФ № 127, Распоряжение ПРФ № 360-р, приказ ФСТЭК № 236). "
|
||||||
|
"По описанию объекта КИИ предложи его характеристики. Верни ТОЛЬКО JSON: "
|
||||||
|
'{"назначение": "короткое назначение объекта", '
|
||||||
|
'"сфера": "одна из сфер: Здравоохранение, Наука, Транспорт, Связь, Энергетика, '
|
||||||
|
'Государственная регистрация прав, Банковская сфера и финансовый рынок, '
|
||||||
|
'Топливно-энергетический комплекс, Атомная энергетика, Оборонная промышленность, '
|
||||||
|
'Ракетно-космическая промышленность, Горнодобывающая промышленность, '
|
||||||
|
'Металлургическая промышленность, Химическая промышленность, Иная сфера деятельности", '
|
||||||
|
'"тип": "Информационная система | Автоматизированные системы управления | '
|
||||||
|
'Информационно-телекоммуникационная сеть", '
|
||||||
|
'"архитектура": "одно из: клиент-серверная система, автономная (standalone), '
|
||||||
|
'распределенная система, иное", '
|
||||||
|
'"типовой_объект": "полная строка из предоставленного перечня, наиболее подходящая, '
|
||||||
|
'или пустая строка", '
|
||||||
|
'"обоснование": "почему выбраны такие характеристики (1-2 предложения)"} '
|
||||||
|
"Не выдумывай типовой объект — бери только из перечня."
|
||||||
|
)
|
||||||
|
user = (
|
||||||
|
"Информация об объекте КИИ:\n"
|
||||||
|
f"{json.dumps(object_data, ensure_ascii=False)}\n\n"
|
||||||
|
"Перечень типовых отраслевых объектов КИИ (Распоряжение ПРФ № 360-р):\n"
|
||||||
|
f"{to_text}"
|
||||||
|
)
|
||||||
|
js, err = _ai_json(api_key, model, base_url, system, user)
|
||||||
|
if err:
|
||||||
|
return None, err
|
||||||
|
return {
|
||||||
|
'назначение': str(js.get('назначение', '') or '').strip(),
|
||||||
|
'сфера': str(js.get('сфера', '') or '').strip(),
|
||||||
|
'тип': str(js.get('тип', '') or '').strip(),
|
||||||
|
'архитектура': str(js.get('архитектура', '') or '').strip(),
|
||||||
|
'типовой_объект': str(js.get('типовой_объект', '') or '').strip(),
|
||||||
|
'обоснование': str(js.get('обоснование', '') or '').strip(),
|
||||||
|
}, None
|
||||||
|
|
||||||
|
|
||||||
def check_security_ai(security_data, api_key, model='deepseek-chat', base_url=None):
|
def check_security_ai(security_data, api_key, model='deepseek-chat', base_url=None):
|
||||||
"""ИИ-проверка заполненной вкладки «Безопасность» объекта КИИ (236 приказ).
|
"""ИИ-проверка заполненной вкладки «Безопасность» объекта КИИ (236 приказ).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user