Files
sd_dispatcher/config/config.py
T
Denis Krivchenko 1949a461b2 feat: add department exclusion for auto-approval
- Add department attribute to LDAP search
- Add APPROVAL_EXCLUDED_DEPARTMENTS config
- Skip auto-approval if user department is excluded
2026-07-04 17:55:35 +07:00

312 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import sys
from dotenv import load_dotenv
# Автоматическое определение корневой директории проекта
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Загружаем приватные переменные окружения из вашего .env
load_dotenv(os.path.join(BASE_DIR, 'config', '.env'))
# Карта соответствия: Переменная диспетчера -> Ключ из вашего .env
# Объявлена в самом начале, чтобы скрипт знал имена карточек до обращения к API
CREDENTIALS_MAP = {
"FTP_PASS": os.getenv("PW_ID_FTP", "").strip(' "\'\r\n'), # Мягкий поиск по ключу
"API_KEY": os.getenv("PW_ID_SD", "").strip(' "\'\r\n'), # Ищет карточку по значению из .env
"AD_PASSWORD": os.getenv("PW_ID_AD", "").strip(' "\'\r\n'), # Ищет карточку по значению из .env
}
# Единственный токен, который может быть зашит в локальном .env, а не в Пассворке
EMBEDDING_API_TOKEN = os.getenv("EMBEDDING_API_TOKEN", "").strip(' "\'\r\n')
# =====================================================================
# ИНТЕГРАЦИЯ С PASSWORK (Динамическая загрузка паролей)
# =====================================================================
PASSWORK_DIR = "/opt/passwork"
if PASSWORK_DIR not in sys.path:
sys.path.insert(0, PASSWORK_DIR)
try:
from passwork import get_passwork_secrets
print("LOG: 🔐 Обращение к модулю Passwork и выгрузка сейфа для GigaAM...")
# Формируем и пробрасываем список обязательных карточек для автозащиты от коллизий
required_to_wait = [name for name in CREDENTIALS_MAP.values() if name]
passwork_pool = get_passwork_secrets(required_cards=required_to_wait)
except Exception as e:
print(f"❌ КРИТИЧЕСКАЯ ОШИБКА: Не удалось подключить модуль Passwork: {e}")
sys.exit(1)
print("LOG: 🔐 Распределение секретов и логинов по модулям диспетчера...")
for var_name, card_name in CREDENTIALS_MAP.items():
if not card_name:
print(f"⚠️ Внимание: Название карточки для {var_name} не задано в .env. Используется локальное значение.")
continue
clean_card_name = card_name.strip(' "\'\r\n')
card_data = passwork_pool.get(clean_card_name)
if card_data is None:
print(f"❌ КРИТИЧЕСКАЯ ОШИБКА: Карточка с именем '{clean_card_name}' не найдена в сейфе Passwork!")
sys.exit(1)
# Динамически заполняем пароль/токен в глобальную область видимости config.py
globals()[var_name] = card_data["password"].strip(' "\'\r\n')
# Динамически вытаскиваем сопутствующие логины из карточек
if var_name == "FTP_PASS":
globals()["FTP_USER"] = card_data.get("login", "").strip(' "\'\r\n')
elif var_name == "AD_PASSWORD":
globals()["AD_USER"] = card_data.get("login", "").strip(' "\'\r\n')
print(f" ✓ {var_name} и логин успешно синхронизированы из карточки '{clean_card_name}'")
# Интеграция с АТС (Выгрузка записей звонков по FTP)
FTP_HOST = "10.0.0.7"
FTP_DIR = "/zabbix"
FTP_ARCHIVE = "/zabbix/archive"
# =====================================================================
# 1. СИСАДМИНСКАЯ ИНФРАСТРУКТУРА, ФЛАСК И ЛОГИРОВАНИЕ
# =====================================================================
# Порт, на котором Flask-вебхук слушает входящие JSON-пакеты от ManageEngine
WEBHOOK_PORT = 5000
# Путь к файлу сквозного отладочного лога диспетчера
WEBHOOK_LOG_FILE = os.path.join(BASE_DIR, 'dispatcher_log.txt')
# Включение профилирования (замеры времени выполнения этапов обработки заявки)
ENABLE_PROFILING = True
# Ограничение длины текста исторических документов при выводе в файл лога
LOG_EXAMPLE_MAX_CHARS = 350
# Ограничение длины строки текста заявки при выводе в интерактивную CLI-консоль
CLI_LOG_MAX_CHARS = 80
# =====================================================================
# 2. КОНВЕЙЕР РАСПОЗНАВАНИЯ РЕЧИ И ПЕРВИЧНОЙ ОБРАБОТКИ (ASR PIPELINE)
# =====================================================================
# Флаг включения суммаризации текста звонка (сейчас отключен для экономии CPU)
ENABLE_TEXT_SUMMARIZATION = False
# Рабочие директории для хранения входящих аудиозаписей и результатов транскрибации
AUDIO_DIR = os.path.join(BASE_DIR, 'audio')
JSON_DIR = os.path.join(BASE_DIR, 'json')
# Длина одного чанка (куска аудио) при нарезке для модели распознавания (в секундах)
CHUNK_SECONDS = 25
# Пути к словарям терминов и золотых ИТ-токенов для исправления ошибок транскрипции
DICT_PATH = "/opt/dict/dict.json"
GOLDEN_DICT_PATH = "/opt/dict/GOLDEN_TERMS.json"
# Переключатели модулей постобработки и исправления текста после ASR
ENABLE_REGEX_CORRECTION = True # Исправление по регулярным выражениям
ENABLE_FUZZY_CORRECTION = True # Нечёткое исправление по Левенштейну/словарям
# =====================================================================
# 3. ИНТЕГРАЦИЯ С MANAGEENGINE SERVICE DESK API
# =====================================================================
# Корпоративный URL и API-эндпоинт для работы с заявками по протоколу v3
SERVER_URL = "https://servicedesk.sibcem.ru:8080"
ENDPOINT = f"{SERVER_URL}/api/v3/requests"
# Системный email-адрес учетной записи ИИ-сортировщика в Service Desk
DEFAULT_REQUESTER = "ai@sibcem.ru"
# =====================================================================
# 4. ИНТЕГРАЦИЯ С ACTIVE DIRECTORY (LDAP)
# =====================================================================
# Контроллер домена и базовая точка поиска пользователей (Base DN)
AD_SERVER = "ldap://172.16.20.20"
AD_BASE = "OU=-Пользователи,DC=sibcem,DC=ru"
# Сетевые тайм-ауты (в секундах) для защиты фоновых потоков от зависания на LDAP-запросах
AD_CONNECT_TIMEOUT = 5 # Время на установку tcp-соединения
AD_RECEIVE_TIMEOUT = 5 # Время ожидания ответа на поисковый запрос
# =====================================================================
# 5. ПОЧТОВЫЕ УВЕДОМЛЕНИЯ И АЛЕРТЫ (SMTP)
# =====================================================================
# Корпоративный почтовый релей и порт (используется стандартный 25 без SSL)
SMTP_SERVER = "srvkem-mail.sibcem.ru"
SMTP_PORT = 25
# Отправитель по умолчанию для ИИ-отчетов
DEFAULT_EMAIL_FROM = "ai@sibcem.ru"
# Списки рассылки и исключений для отправки логов принятия решений
ALERTS_DISABLED_USERS = ["ds.krivochenko@sibcem.ru"]
ALERTS_ALL_TICKETS = ["ds.krivochenko@sibcem.ru"]
# =====================================================================
# 6. ВЕКТОРНЫЙ ПОИСК И ЭМБЕДДИНГИ (QDRANT API)
# =====================================================================
# Адрес, порт и целевая коллекция локального сервера Qdrant
QDRANT_HOST = "localhost"
QDRANT_PORT = 6333
QDRANT_COLLECTION = "tickets"
# Осредненный лимит выборки документов из Qdrant под дальнейший реранкинг (оптимально для CPU)
QDRANT_SEARCH_LIMIT = 20
# Локальная служба генерации векторов (Embedding API)
EMBEDDING_API_URL = "http://127.0.0.1:8010/embed"
EMBEDDING_MODEL_NAME = "multilingual-e5-base"
# =====================================================================
# 7. ПЕРЕРАНЖИРОВАНИЕ ПРЕЦЕДЕНТОВ (CROSS-ENCODER RERANKER)
# =====================================================================
# Адрес выделенной службы реранкера (работает на порту 8081)
RERANKER_URL = "http://127.0.0.1:8081/rerank"
RERANKER_MODEL_NAME = "bge-reranker-v2-m3-Q8_0.gguf"
# Предохранитель от OOM: максимальное количество символов исторического билета, скармливаемое реранкеру
RERANKER_MAX_DOC_CHARS = 1200
# Жесткий тайм-аут сокета (в секундах) на ожидание пачки документов от реранкера
RERANKER_TIMEOUT = 60
# Коэффициент смешивания скоров (Score Blending):
# 1.0 — абсолютная власть реранкера, 0.0 — чистый Qdrant (база векторов)
RERANKER_WEIGHT = 0.7
# =====================================================================
# 8. ЛОКАЛЬНЫЙ ИНТЕЛЛЕКТ И СЕРВЕРЫ LLM / STT
# =====================================================================
# Переключатель вызова большой языковой модели
ENABLE_OLLAMA = True
# ГЛОБАЛЬНЫЙ ДИСПЕТЧЕР И АНАЛИЗАТОР: Классификация тикетов (Тяжелый квант Q8)
OLLAMA_URL = "http://127.0.0.1:8080/v1/chat/completions"
OLLAMA_MODEL = "gemma-4-12b-it-Q8_0"
# РАСПОЗНАВАНИЕ ЗВОНКОВ: Локальный роутер моделей llama.service (Порт 8080)
OLLAMA_SUBJECT_URL = "http://127.0.0.1:8080/v1/chat/completions"
OLLAMA_SUBJECT_MODEL = "gemma-4-E4B-it-Q4_K_M"
# МИКРОСЕРВИС ТРАНСКРИБАЦИИ: Точка подключения к демону GigaAM (Порт 5001)
STT_SERVICE_URL = "http://127.0.0.1:5001/transcribe"
# Размер контекстного окна для слота (динамическое выделение памяти из пула 16384)
OLLAMA_NUM_CTX = 12288
# Параметры инференса текстовой модели
OLLAMA_TEMPERATURE = 0.0 # Строгая детерминированность вывода
OLLAMA_MAX_TOKENS = 65 # Ограничение длины ответа (модели нужно выдать только имя группы)
OLLAMA_TIMEOUT = 1200 # Предельный тайм-аут генерации токенов (в секундах) под CPU-нагрузкой
# =====================================================================
# 9. МАТЕМАТИЧЕСКИЕ ФИЛЬТРЫ, ТРИГГЕРЫ МУСОРА И ПОРОГОВЫЕ ОГРАНИЧЕНИЯ
# =====================================================================
# Осредненный порог относительной уверенности Qdrant. Ниже него — принудительный вызов Qwen 2.5
CONFIDENCE_THRESHOLD = 0.85
# КРИТИЧЕСКИЙ ПРЕДОХРАНИТЕЛЬ: если абсолютный скор лучшего совпадения реранкера ниже этого веса,
# сквозной байпас ИИ запрещается, и билет отправляется на перепроверку в Ollama
FORCE_OLLAMA_SCORE_THRESHOLD = 0.75
# Сколько голосов (совпадений) максимум может забрать одна ИТ-группа в векторном пуле
QDRANT_MAX_VOTES_PER_GROUP = 10
# Абсолютный скор, выше которого заявка считается стопроцентным историческим дублем
EXACT_MATCH_SCORE_THRESHOLD = 0.9
# Фильтры детектирования аномального распределения (маркеры мусорных/непонятных заявок)
GARBAGE_CONFIDENCE_THRESHOLD = 0.01 # Предельно низкая уверенность
GARBAGE_UNIQUE_GROUPS_LIMIT = 4 # Слишком много разных групп в топ-выборке
GARBAGE_VARIANCE_THRESHOLD = 0.02 # Слишком плотный шаг весов (нет явного лидера)
GARBAGE_MIN_GROUPS_FOR_VARIANCE = 2 # Минимальное число конкурентов для оценки дисперсии
GARBAGE_BYPASS_DOMINANCE = 0.90 # Порог доминации, снимающий метку мусора
# Фильтры условий обхода вызова Ollama (Bypass)
OLLAMA_BYPASS_DOMINANCE = 0.95 # Если одна группа заняла 80% топа выборки
OLLAMA_BYPASS_MIN_CONFIDENCE = 0.10 # Минимальная базовая уверенность для байпаса
OLLAMA_ACCEPTANCE_THRESHOLD = 0.65 # Минимальная уверенность логпробов Ollama для принятия ответа
DOMINANCE_TOP_K = 10 # Глубина среза топ-результатов для расчёта коэффициента доминации
LOG_TOP_GROUPS_LIMIT = 5 # Количество позиций истории, выводимых в логи структуры decision_log
# =====================================================================
# 10. СПРАВОЧНИКИ МАРШРУТИЗАЦИИ, КАТЕГОРИИ И БИЗНЕС-ЛОГИКА АВТОМАТИЗАЦИИ
# =====================================================================
# White-list валидных ИТ-групп в системе Service Desk Plus
VALID_GROUPS = [
"CRM", "АХО", "Техподдержка", "1С", "Axapta (Microsoft Dynamics AX)",
"АСУТП", "Босс-Кадровик", "ОПС, видеонаблюдение, СКУД, СМТ",
"Программисты КТЦ", "Системное администрирование", "Телеком и сообщения",
"Битрикс", "СЭД Directum", "Администрирование систем BI", "СБИС", "Служба информационной безопасности", "НСИ"
]
# Группы, для которых открыто прямое автоматическое исполнение Put-запросов назначения через API
ALLOWED_ASSIGNMENT_GROUPS = [
"Техподдержка КЦ", "Техподдержка ХК", "Техподдержка Тимлюй",
"Техподдержка Ангарск", "Техподдержка Искитим", "Техподдержка Топки",
"Техподдержка КТЦ", "Техподдержка Волна", "Техподдержка Москва","Телеком и сообщения"
]
# Матрица ответственных менеджеров групп для отправки алертов о сбоях/назначениях билетов
GROUP_MANAGERS = {
"Техподдержка": ["e.voevodin@sibcem.ru"]
}
# Региональный справочник привязки городов к конкретным Кустовым Центрам (КЦ) и ХК
CITY_SUPPORT = {
"Ангарск": "Техподдержка Ангарск",
"Слюдянка": "Техподдержка Ангарск",
"Искитим": "Техподдержка Искитим",
"Новосибирск": "Техподдержка КТЦ",
"Топки": "Техподдержка Топки",
"Кемерово": "Техподдержка ХК",
"Москва": "Техподдержка Москва",
"Тимлюй": "Техподдержка ХК",
"Каменск": "Техподдержка ХК",
"Улан-Удэ": "Техподдержка ХК",
"Татарский Ключ": "Техподдержка ХК",
"Спас-Клепики": "Техподдержка ХК",
"Красноярск": "Техподдержка КЦ"
}
# Настройки матрицы автоматического создания уровней согласования руководителями
ENABLE_AUTO_APPROVAL = True
APPROVAL_CITIES = ["Новосибирск"]
APPROVAL_GROUPS = ["1С", "1с", "Программисты КТЦ"]
APPROVAL_CATEGORIES = {
"ИТ": ["ПО КТЦ", "Проблемы с Договорной Работой"],
"1С": ["*"],
"1с": ["*"]
}
# Отделы, исключающие пользователя из автосогласования
# Если department пользователя совпадает с любым из этих значений —
# автосогласование НЕ запускается, даже если все остальные условия выполнены.
APPROVAL_EXCLUDED_DEPARTMENTS = [
# "IT-Администраторы",
# "Системные аналитики",
]
# План «Б» маршрутизации: жесткое определение локации по телефонному префиксу внутренней АТС
PREFIX_ROUTING = {
"700": {"city": "Красноярск", "company": "ООО Комбинат Волна"},
"702": {"city": "Кемерово"},
"703": {"city": "Новосибирск"},
"704": {"city": "Красноярск"},
"705": {"city": "Каменск"},
"701": {"city": "Ангарск"},
"706": {"city": "Ангарск"},
"707": {"city": "Ангарск"},
"709": {"city": "Москва"},
"724": {"city": "Искитим"},
"71": {"city": "Топки"}
}