diff --git a/dokogen/threat_rules.py b/dokogen/threat_rules.py index 4cc7973..e0f67cb 100644 --- a/dokogen/threat_rules.py +++ b/dokogen/threat_rules.py @@ -456,9 +456,24 @@ def suggest_typical_object_program(isys, limit=10, sphere=None): if not obj_words: return [] + # Фильтр по сфере (важно: не подбирать ОПК-объекту сферу из здравоохранения): + # 1) сфера, переданная явно (выбрана в комбобоксе); + # 2) сфера, уже заполненная у объекта (isys.sphere); + # 3) автодетект по названию/назначению/описанию; + # 4) иначе — все сферы (подбор без фильтра). + used_sphere = sphere + if not used_sphere: + used_sphere = (getattr(isys, 'sphere', '') or '').strip() or None + if not used_sphere: + used_sphere = detect_sphere(isys) + cands = _load_all_typical() - if sphere: - cands = [c for c in cands if c['sphere'] == sphere] + if used_sphere: + cands = [c for c in cands if c['sphere'] == used_sphere] + if not cands: + # Сфера определена, но объектов нет — не расширяем на другие сферы, + # возвращаем пусто (оператор выберет сферу вручную) + return [] weights = _idf_weights(cands) @@ -474,3 +489,44 @@ def suggest_typical_object_program(isys, limit=10, sphere=None): scored.sort(key=lambda x: (-x['score'], x['name'])) return scored[:limit] + + +# --------------------------------------------------------------- +# Автоопределение сферы деятельности объекта по ключевым словам +# --------------------------------------------------------------- +SPHERE_KEYWORDS = [ + ('Здравоохранение', ['медицин', 'здрав', 'поликлиник', 'больниц', 'лечеб', 'клиник', 'фармацевт', 'аптек', 'пациент', 'врач', 'диагностик', 'лабораторн', 'медпомощ']), + ('Наука', ['научн', 'исследован', 'разработк', 'лаборатор', 'академи', 'институт', 'ниокр', 'наука']), + ('Транспорт', ['транспорт', 'перевоз', 'автомобил', 'железнодорожн', 'авиа', 'морск', 'речн', 'метрополитен', 'вокзал', 'логистик', 'движени']), + ('Связь', ['связ', 'телекоммуникац', 'оператор связи', 'интернет-провайдер', 'передач данных', 'сети связи', 'телефон']), + ('Энергетика', ['энерг', 'электро', 'теплоснабж', 'электроснабж', 'генерац', 'подстанц', 'котельн', 'энергосистем']), + ('Государственная регистрация прав', ['регистрац', 'кадастр', 'недвижим', 'реестр']), + ('Банковская сфера и финансовый рынок', ['банк', 'финанс', 'кредит', 'платеж', 'расчет', 'страхов', 'клирин', 'депозитар', 'пенсионн', 'фондов']), + ('Топливно-энергетический комплекс', ['нефт', 'газ', 'топлив', 'трубопровод', 'месторожден', 'переработк', 'уголь', 'нефте']), + ('Атомная энергетика', ['атомн', 'ядерн', 'радиацион', 'аэс', 'реактор', 'атом']), + ('Оборонная промышленность', ['оборон', 'военн', 'вооружен', 'оружи', 'оборонно', 'опк', 'госзаказ', 'госконтракт', 'боеприпас', 'ввт', 'минобороны']), + ('Ракетно-космическая промышленность', ['ракет', 'космическ', 'спутник', 'космодром', 'орбит', 'космос', 'пуск']), + ('Горнодобывающая промышленность', ['горн', 'добыч', 'шахт', 'рудник', 'карьер', 'месторожден']), + ('Металлургическая промышленность', ['металлург', 'прокат', 'стал', 'чугун', 'цветн', 'сплав']), + ('Химическая промышленность', ['химическ', 'хим', 'нефтехим', 'взрывчат', 'кислот', 'реактив', 'удобрен']), +] + + +def detect_sphere(isys): + """Определяет сферу деятельности объекта КИИ по названию/назначению/описанию. + + Возвращает название сферы или None, если определить не удалось. + """ + text = ' '.join([ + getattr(isys, 'name', '') or '', + getattr(isys, 'purpose', '') or '', + getattr(isys, 'description', '') or '', + ]).lower() + best = None + best_score = 0 + for sphere, keywords in SPHERE_KEYWORDS: + score = sum(1 for kw in keywords if kw in text) + if score > best_score: + best = sphere + best_score = score + return best if best_score > 0 else None