304 lines
18 KiB
Python
304 lines
18 KiB
Python
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с": ["*"]
|
||
}
|
||
|
||
# План «Б» маршрутизации: жесткое определение локации по телефонному префиксу внутренней АТС
|
||
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": "Топки"}
|
||
}
|