промежуточный этап. Работает.
This commit is contained in:
+35
-15
@@ -21,7 +21,7 @@ def init_db():
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 1. Таблица СКУД
|
||||
# 1. Таблица СКУД (Добавлены first_activity, anomaly_flag, snapshot_time)
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS scud_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -31,9 +31,12 @@ def init_db():
|
||||
department TEXT,
|
||||
position TEXT,
|
||||
time_in TEXT,
|
||||
first_activity TEXT DEFAULT '—',
|
||||
time_out TEXT,
|
||||
time_in_building TEXT,
|
||||
is_present INTEGER NOT NULL,
|
||||
anomaly_flag TEXT DEFAULT 'NONE',
|
||||
snapshot_time TEXT DEFAULT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
""")
|
||||
@@ -104,26 +107,32 @@ def sync_knowledge_base_to_db():
|
||||
Автоматически мигрирует правила из knowledge_base.json и системный промпт в таблицу ai_knowledge_base SQLite.
|
||||
"""
|
||||
system_ai_prompt = (
|
||||
"СИСТЕМНЫЙ ПРОМПТ ИИ (MATCHING & VERIFICATION):\n"
|
||||
"Ты — экспертный ИИ-аудитор СКУД и кадрового учета 1С. Твоя задача — проводить интеллектуальный анализ аномалий "
|
||||
"и сопоставление (Fuzzy Matching) нераспознанных ФИО из СКУД с эталонным Штатным расписанием 1С.\n\n"
|
||||
"1. ЗАЩИТА ОТ ПОЛНЫХ ТЁЗОК (FULL NAME COLLISION):\n"
|
||||
"СИСТЕМНЫЙ ПРОМПТ ИИ (MATCHING, VERIFICATION & ANOMALY DETECTION):\n"
|
||||
"Ты — экспертный ИИ-аудитор СКУД и кадрового учета 1С. Твоя задача — проводить интеллектуальный анализ аномалий, "
|
||||
"выявление массовых сбоев оборудования и сопоставление (Fuzzy Matching) нераспознанных ФИО из СКУД с эталонным Штатным расписанием 1С.\n\n"
|
||||
"1. ДЕТЕКТИРОВАНИЕ АНОМАЛИЙ И МАССОВЫХ СБОЕВ СКУД:\n"
|
||||
" - Если у сотрудника 'Начало_дня' = 'Нет входа', но заполнено поле 'Первая_активность' (например, '14:11:06') или 'Конец_дня' != 'Нет выхода', "
|
||||
"классифицируй случай как одиночную аномалию: '🚨 АНОМАЛИЯ СКУД: Присутствие/активность без утреннего входа'.\n"
|
||||
" - Если процент сотрудников с подобной аномалией превышает 5% от смены (или >10 человек), СГЕНЕРИРУЙ КРИТИЧЕСКИЙ СИСТЕМНЫЙ АЛЕРТ: "
|
||||
"'⚠️ ВНИМАНИЕ! Обнаружен массовый сбой регистраторов входа СКУД на главном КПП. Требуется проверка контроллеров.'\n\n"
|
||||
"2. ЗАЩИТА ОТ ПОЛНЫХ ТЁЗОК (FULL NAME COLLISION):\n"
|
||||
" - Если в эталонном штате 1С присутствуют два или более сотрудников с ОДИНАКОВЫМИ ФИО (полные тёзки), "
|
||||
"ты ОБЯЗАН учитывать контекст: Подразделение и Должность.\n"
|
||||
" - Ни в коем случае не объединяй записи разных людей! Если контекст не позволяет однозначно определить, кто именно из тёзок совершил проход, ПОМЕТЬ СЛУЧАЙ КАК НЕОДНОЗНАЧНЫЙ и НЕ делай автоматическую подмену.\n\n"
|
||||
"2. ПРАВИЛА СОПОСТАВЛЕНИЯ (MATCHING RULES):\n"
|
||||
"3. ПРАВИЛА СОПОСТАВЛЕНИЯ (MATCHING RULES):\n"
|
||||
" - Допускаются исправления мелких опечаток, перестановки порядка (Имя Фамилия -> Фамилия Имя), замена букв Е/Ё, И/Й.\n"
|
||||
" - Учитывай сокращения инициалов (например, 'Иванов И.В.' -> 'Иванов Иван Васильевич').\n"
|
||||
" - Если уверенность в совпадении меньше 85% — НЕ сопоставляй, оставляй запись как нераспознанную.\n\n"
|
||||
"3. ФОРМАТ ВЫХОДНЫХ ДАННЫХ:\n"
|
||||
" Верни строго JSON-объект без вводных слов и Markdown-разметки: {\"mappings\": [...], \"unmatched\": [...]}"
|
||||
"4. ФОРМАТ ВЫХОДНЫХ ДАННЫХ:\n"
|
||||
" Верни строго JSON-объект без вводных слов и Markdown-разметки: {\"mappings\": [...], \"unmatched\": [...], \"alerts\": [...]}"
|
||||
)
|
||||
|
||||
rules_to_insert = [
|
||||
system_ai_prompt,
|
||||
"ГЛОБАЛЬНОЕ ПРАВИЛО 1: Любое физическое присутствие сотрудника по СКУД при наличии в 1С документа отсутствия (отпуск, больничный, уход за ребенком и др.), КРОМЕ командировок и служебных поездок — ЯВЛЯЕТСЯ СТРОГОЙ ИСТИННОЙ АНОМАЛИЕЙ.",
|
||||
"ГЛОБАЛЬНОЕ ПРАВИЛО 2: Документы отсутствий из 1С:ЗУП имеют 100% высший приоритет над статическим реестром удалёнщиков.",
|
||||
"ГЛОБАЛЬНОЕ ПРАВИЛО 3: Удалённые сотрудники имеют право беспрепятственно работать в офисе по СКУД в любое время (это не является аномалией)."
|
||||
"ГЛОБАЛЬНОЕ ПРАВИЛО 3: Удалённые сотрудники имеют право беспрепятственно работать в офисе по СКУД в любое время (это не является аномалией).",
|
||||
"ГЛОБАЛЬНОЕ ПРАВИЛО 4: Отсутствие утренней отметки входа при наличии дневных перемещений (первая активность) является аномалией оборудования и не должно автоматически превращать запись в подтверждённое присутствие."
|
||||
]
|
||||
|
||||
kb_path = os.path.join(os.path.dirname(DATA_DIR), "knowledge_base.json")
|
||||
@@ -148,8 +157,8 @@ def sync_knowledge_base_to_db():
|
||||
conn.commit()
|
||||
|
||||
|
||||
def save_scud_to_db(df_scud, date_str):
|
||||
"""Оптимизированное сохранение логов СКУД за дату."""
|
||||
def save_scud_to_db(df_scud, date_str, snapshot_time=None):
|
||||
"""Оптимизированное сохранение логов СКУД за дату с поддержкой первой активности, флага аномалии и метки выгрузки."""
|
||||
if df_scud.empty:
|
||||
return
|
||||
|
||||
@@ -162,17 +171,28 @@ def save_scud_to_db(df_scud, date_str):
|
||||
r.get('Подразделение', ''),
|
||||
r.get('Должность', ''),
|
||||
r.get('Начало_дня', 'Нет входа'),
|
||||
r.get('Первая_активность', '—'),
|
||||
r.get('Конец_дня', 'Нет выхода'),
|
||||
r.get('Находился_в_здании', '00:00'),
|
||||
1 if r.get('Пришел', False) else 0
|
||||
1 if r.get('Пришел', False) else 0,
|
||||
r.get('anomaly_flag', 'NONE'),
|
||||
snapshot_time
|
||||
))
|
||||
|
||||
with get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM scud_logs WHERE log_date = ?", (date_str,))
|
||||
if snapshot_time:
|
||||
cursor.execute("DELETE FROM scud_logs WHERE log_date = ? AND snapshot_time = ?", (date_str, snapshot_time))
|
||||
else:
|
||||
cursor.execute("DELETE FROM scud_logs WHERE log_date = ? AND snapshot_time IS NULL", (date_str,))
|
||||
|
||||
cursor.executemany("""
|
||||
INSERT INTO scud_logs (log_date, fio, fio_clean, department, position, time_in, time_out, time_in_building, is_present)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO scud_logs (
|
||||
log_date, fio, fio_clean, department, position,
|
||||
time_in, first_activity, time_out, time_in_building,
|
||||
is_present, anomaly_flag, snapshot_time
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", data_to_insert)
|
||||
conn.commit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user