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)
|
||||
|
||||
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]
|
||||
|
||||
Reference in New Issue
Block a user