From a9680db0aa83bdfd2b7240479cd8f8bb1776558c Mon Sep 17 00:00:00 2001 From: manoraga Date: Thu, 27 Aug 2026 19:26:28 +0300 Subject: [PATCH] feat(etl): stable pipeline, exception registry in SQLite, multi-pass aggregation and db_cli --- config.py | 48 +- core/connection.py | 27 + core/database.py | 515 +- core/repositories/scud_repo.py | 227 + core/repositories/zup_repo.py | 97 + core/schema.py | 162 + data/scud_orion_ai.db | Bin 6520832 -> 9269248 bytes data/scud_orion_ai.db-shm | Bin 32768 -> 0 bytes data/scud_orion_ai.db-wal | Bin 185432 -> 0 bytes data/static_reason_workers.csv | 4 +- docs/CHANGELOG.md | 58 + docs/ROADMAP.md | 61 - docs/in_progress/ROADMAP.md | 123 + .../план_оптимизации_работы_с_контекстом.md | 72 - etl_code_snapshot.md | 3752 +++++++++++ exceptions.json | 11 +- main_etl.py | 609 +- modules/ROADMAP.md | 56 + modules/ai_engine/__init__.py | 0 modules/ai_engine/agent.py | 178 + modules/ai_engine/context_builder.py | 84 + modules/ai_engine/handlers/__init__.py | 0 modules/ai_engine/handlers/prompt_handler.py | 98 + .../ai_engine/handlers/snapshot_handler.py | 91 + modules/ai_engine/handlers/task_handler.py | 97 + modules/web_api/llm/agent.py | 572 +- modules/web_api/llm/core/context_manager.py | 64 + modules/web_api/llm/core/fast_path.py | 194 +- modules/web_api/llm/core/ollama_client.py | 10 +- modules/web_api/llm/core/prompt_merger.py | 74 - modules/web_api/llm/core/tool_injector.py | 144 +- modules/web_api/llm/db/db_snapshots.py | 49 - modules/web_api/llm/db/db_tasks.py | 82 - modules/web_api/llm/db_tools.py | 101 +- modules/web_api/llm/schemas.py | 214 +- modules/web_api/main.py | 9 +- modules/web_api/routers/auth.py | 23 +- modules/web_api/routers/chat.py | 156 +- modules/web_api/routers/exceptions.py | 31 + modules/web_api/routers/files.py | 73 + modules/web_api/routers/tasks.py | 91 +- modules/web_api/static/index.html | 391 +- modules/web_api/static/js/auth.js | 346 +- modules/web_api/static/js/chat/core.js | 540 +- modules/web_api/static/js/chat/task_widget.js | 549 +- modules/web_api/static/js/tasks.js | 215 +- project_code_snapshot.md | 5875 +++++++++++------ run_cron_etl.sh | 20 + scripts/db_cli.py | 181 +- scripts/diagnostics/make_code_snapshot.py | 46 - scripts/diagnostics/make_etl_snapshot.py | 73 + scripts/diagnostics/make_web_snapshot.py | 63 + scripts/diagnostics/web_api_code_snapshot.md | 22 + services/ai_verifier.py | 41 +- services/data_loader.py | 211 +- services/excel_exporter.py | 139 +- services/exceptions_repo.py | 84 + services/knowledge/__init__.py | 0 services/knowledge/service.py | 37 + services/prompts/__init__.py | 0 services/prompts/diff_engine.py | 79 + services/prompts/repository.py | 114 + services/prompts/service.py | 49 + services/scud_etl/__init__.py | 0 services/scud_etl/anomaly_detector.py | 60 + services/scud_etl/merger.py | 147 + services/scud_etl/pipeline.py | 59 + services/scud_etl/sql_queries.py | 116 + services/scud_export.py | 3 +- services/snapshots/__init__.py | 0 services/snapshots/service.py | 69 + services/tasks/__init__.py | 0 services/tasks/exporter.py | 101 + services/tasks/repository.py | 155 + services/tasks/service.py | 72 + services/text_reporter.py | 57 +- services/zup_extractor.py | 2 +- 77 files changed, 12548 insertions(+), 5625 deletions(-) create mode 100644 core/connection.py create mode 100644 core/repositories/scud_repo.py create mode 100644 core/repositories/zup_repo.py create mode 100644 core/schema.py delete mode 100644 data/scud_orion_ai.db-shm delete mode 100644 data/scud_orion_ai.db-wal delete mode 100644 docs/ROADMAP.md create mode 100644 docs/in_progress/ROADMAP.md delete mode 100644 docs/in_progress/план_оптимизации_работы_с_контекстом.md create mode 100644 etl_code_snapshot.md create mode 100644 modules/ROADMAP.md create mode 100644 modules/ai_engine/__init__.py create mode 100644 modules/ai_engine/agent.py create mode 100644 modules/ai_engine/context_builder.py create mode 100644 modules/ai_engine/handlers/__init__.py create mode 100644 modules/ai_engine/handlers/prompt_handler.py create mode 100644 modules/ai_engine/handlers/snapshot_handler.py create mode 100644 modules/ai_engine/handlers/task_handler.py create mode 100644 modules/web_api/llm/core/context_manager.py delete mode 100644 modules/web_api/llm/core/prompt_merger.py delete mode 100644 modules/web_api/llm/db/db_snapshots.py delete mode 100644 modules/web_api/llm/db/db_tasks.py create mode 100644 modules/web_api/routers/exceptions.py create mode 100644 modules/web_api/routers/files.py create mode 100755 run_cron_etl.sh delete mode 100644 scripts/diagnostics/make_code_snapshot.py create mode 100644 scripts/diagnostics/make_etl_snapshot.py create mode 100644 scripts/diagnostics/make_web_snapshot.py create mode 100644 scripts/diagnostics/web_api_code_snapshot.md create mode 100644 services/exceptions_repo.py create mode 100644 services/knowledge/__init__.py create mode 100644 services/knowledge/service.py create mode 100644 services/prompts/__init__.py create mode 100644 services/prompts/diff_engine.py create mode 100644 services/prompts/repository.py create mode 100644 services/prompts/service.py create mode 100644 services/scud_etl/__init__.py create mode 100644 services/scud_etl/anomaly_detector.py create mode 100644 services/scud_etl/merger.py create mode 100644 services/scud_etl/pipeline.py create mode 100644 services/scud_etl/sql_queries.py create mode 100644 services/snapshots/__init__.py create mode 100644 services/snapshots/service.py create mode 100644 services/tasks/__init__.py create mode 100644 services/tasks/exporter.py create mode 100644 services/tasks/repository.py create mode 100644 services/tasks/service.py diff --git a/config.py b/config.py index cec1cec..8c4237c 100644 --- a/config.py +++ b/config.py @@ -8,11 +8,11 @@ DATA_DIR = os.path.join(BASE_DIR, "data") SCUD_DIR = os.path.join(DATA_DIR, "scud") ZUP_1C_DIR = os.path.join(DATA_DIR, "1c") OUTPUT_DIR = os.path.join(BASE_DIR, "output") +REPORTS_DIR = os.path.join(OUTPUT_DIR, "reports") -# Путь к намонтированной сетевой шаре 1С в Linux (вместо \\storage\SCUD\Обмен\Штат) SHARE_1C_DIR = "/mnt/scud_share" -for folder in [DATA_DIR, SCUD_DIR, ZUP_1C_DIR, OUTPUT_DIR]: +for folder in [DATA_DIR, SCUD_DIR, ZUP_1C_DIR, OUTPUT_DIR, REPORTS_DIR]: os.makedirs(folder, exist_ok=True) NOW = datetime.now() @@ -23,32 +23,30 @@ if NOW.weekday() == 0: else: DATE_YESTERDAY = (NOW - timedelta(days=1)).strftime("%d.%m.%Y") -# --- Настройки LLM / Ollama --- -OLLAMA_URL = "http://192.168.11.3:11434/api/generate" -OLLAMA_MODEL = "qwen2.5:14b" +OLLAMA_URL = "http://10.121.17.227:11434/api/generate" +OLLAMA_MODEL = "qwen2.5:14b-instruct-q8_0" MODEL_NAME = OLLAMA_MODEL KNOWLEDGE_BASE_PATH = os.path.join(DATA_DIR, "knowledge_base.json") EXCEPTIONS_PATH = os.path.join(BASE_DIR, "exceptions.json") -# --- Настройки подключения к MS SQL Server (1С:ЗУП 3.1) --- ZUP_SQL_CONFIG = { - "driver": "{ODBC Driver 18 for SQL Server}", # или "{ODBC Driver 17 for SQL Server}" + "driver": "{ODBC Driver 18 for SQL Server}", "server": os.getenv("ZUP_SQL_SERVER", "ACCOUNT-01"), - "database": os.getenv("ZUP_SQL_DB", "ZUP30"), # Замените на точное имя базы ЗУП на ACCOUNT-01 - "user": os.getenv("ZUP_SQL_USER", "scud_reader"), # Логин SQL Server - "password": os.getenv("ZUP_SQL_PASS", "Rhfcysq90"), # Пароль SQL Server - "trust_server_certificate": "yes", # Доверять сертификату сервера - "encrypt": "no" # "yes", если на MS SQL включено обязательное SSL-шифрование + "database": os.getenv("ZUP_SQL_DB", "ZUP30"), + "user": os.getenv("ZUP_SQL_USER", "scud_reader"), + "password": os.getenv("ZUP_SQL_PASS", "Rhfcysq90"), + "trust_server_certificate": "yes", + "encrypt": "no" } -def find_dated_file(prefix, date_str, search_dirs=[ZUP_1C_DIR, SCUD_DIR, DATA_DIR, "."]): - """ - Ищет файлы по префиксу и дате (поддерживает и 30.07.2026, и 30_07_2026). - """ - date_dots = date_str - date_underscores = date_str.replace('.', '_') +def find_dated_file(prefix, date_str, search_dirs=None): + if search_dirs is None: + search_dirs = [ZUP_1C_DIR, SCUD_DIR, DATA_DIR, "."] + + date_dots = str(date_str).replace('_', '.') + date_underscores = date_dots.replace('.', '_') for d in search_dirs: if not os.path.exists(d): @@ -75,6 +73,18 @@ def clean_scud_fio_light(fio_str): def load_exceptions(): + """ + Приоритетно читает исключения и белый список из SQLite таблицы exceptions_registry. + При отсутствии таблицы или пустой базе выполняет fallback на exceptions.json. + """ + try: + from services.exceptions_repo import get_all_exceptions_from_db + db_exc = get_all_exceptions_from_db() + if any(db_exc.values()): + return db_exc + except Exception: + pass + import json if os.path.exists(EXCEPTIONS_PATH): try: @@ -82,4 +92,4 @@ def load_exceptions(): return json.load(f) except Exception: pass - return {"fio": [], "departments": [], "positions": [], "position_keywords": []} \ No newline at end of file + return {"fio": [], "departments": [], "positions": [], "position_keywords": [], "include_fio": []} \ No newline at end of file diff --git a/core/connection.py b/core/connection.py new file mode 100644 index 0000000..943d0b9 --- /dev/null +++ b/core/connection.py @@ -0,0 +1,27 @@ +""" +=============================================================================== +FILE: core/connection.py +PROJECT: SCUD Orion AI (Unified Architecture) +ROLE: Единый менеджер подключений к базе данных SQLite (WAL mode, timeouts). +=============================================================================== +""" + +import os +import sqlite3 +from config import DATA_DIR + +DB_PATH = os.path.join(DATA_DIR, "scud_orion_ai.db") + + +def get_connection(row_factory: bool = False) -> sqlite3.Connection: + """ + Создает оптимизированное подключение к SQLite. + row_factory=True возвращает sqlite3.Row для доступа к полям по имени. + """ + conn = sqlite3.connect(DB_PATH, timeout=30.0) + if row_factory: + conn.row_factory = sqlite3.Row + conn.execute("PRAGMA foreign_keys = ON;") + conn.execute("PRAGMA journal_mode = WAL;") + conn.execute("PRAGMA synchronous = NORMAL;") + return conn \ No newline at end of file diff --git a/core/database.py b/core/database.py index 0e0ed14..1dca47f 100644 --- a/core/database.py +++ b/core/database.py @@ -1,480 +1,35 @@ -import os -import sqlite3 -import json -import pandas as pd -from datetime import datetime -from config import DATA_DIR - -DB_PATH = os.path.join(DATA_DIR, "scud_orion_ai.db") - - -def get_connection(): - """Создает подключение к базе данных SQLite с оптимизированными настройками.""" - conn = sqlite3.connect(DB_PATH) - conn.execute("PRAGMA foreign_keys = ON;") - conn.execute("PRAGMA journal_mode = WAL;") - return conn - - -def init_db(): - """Создает структуру таблиц и индексов в базе данных.""" - with get_connection() as conn: - cursor = conn.cursor() - - cursor.execute(""" - CREATE TABLE IF NOT EXISTS scud_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - log_date TEXT NOT NULL, - fio TEXT NOT NULL, - fio_clean TEXT NOT NULL, - 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, - snapshot_id TEXT DEFAULT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - """) - - cursor.execute("PRAGMA table_info(scud_logs);") - cols = [col[1] for col in cursor.fetchall()] - if 'snapshot_id' not in cols: - cursor.execute("ALTER TABLE scud_logs ADD COLUMN snapshot_id TEXT DEFAULT NULL;") - - cursor.execute(""" - CREATE TABLE IF NOT EXISTS zup_staff ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - snapshot_date TEXT NOT NULL, - fio TEXT NOT NULL, - fio_clean TEXT NOT NULL, - department TEXT, - position TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - """) - - cursor.execute(""" - CREATE TABLE IF NOT EXISTS zup_absences ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - absence_date TEXT NOT NULL, - fio TEXT NOT NULL, - fio_clean TEXT NOT NULL, - absence_type TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - """) - - cursor.execute(""" - CREATE TABLE IF NOT EXISTS anomalies_history ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - anomaly_date TEXT NOT NULL, - fio TEXT NOT NULL, - anomaly_type TEXT NOT NULL, - details TEXT NOT NULL, - human_status TEXT DEFAULT 'Pending', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - """) - - cursor.execute(""" - CREATE TABLE IF NOT EXISTS ai_knowledge_base ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - rule_text TEXT UNIQUE NOT NULL, - added_by TEXT DEFAULT 'Human', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - """) - - cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_date ON scud_logs(log_date);") - cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_fio ON scud_logs(fio_clean);") - cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_snapshot ON scud_logs(snapshot_time);") - - conn.commit() - - sync_knowledge_base_to_db() - -def has_scud_logs_for_date(date_str): - """Проверяет, есть ли в базе данные СКУД за указанную дату.""" - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("SELECT 1 FROM scud_logs WHERE log_date = ? LIMIT 1", (date_str,)) - return cursor.fetchone() is not None - -def has_yesterday_final_snapshot(date_str): - """Проверяет, зафиксирован ли уже ИТОГОВЫЙ вчерашний снапшот с индексом Y/22:00.""" - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute( - "SELECT 1 FROM scud_logs WHERE log_date = ? AND (snapshot_id LIKE 'Y%' OR snapshot_time LIKE '%22:00:00') LIMIT 1", - (date_str,) - ) - return cursor.fetchone() is not None - - -def get_or_create_snapshot_id(snapshot_time, date_str=None, is_yesterday=False): - """ - Генерирует датированный составной ID снапшота (YYYYMMDD-NNN или YYYYMMDD-NNN). - Префикс 'Y' присваивается автоматически, если дата логов (date_str) предшествует дате снятия (snapshot_time). - """ - try: - dt_snap = datetime.strptime(snapshot_time, "%Y-%m-%d %H:%M:%S").date() - date_prefix = dt_snap.strftime("%Y%m%d") - except (ValueError, TypeError): - dt_snap = datetime.now().date() - date_prefix = dt_snap.strftime("%Y%m%d") - - # Автоматическая проверка: если дата логов раньше даты выгрузки — проставляем Y - if date_str: - try: - dt_log = datetime.strptime(date_str, "%d.%m.%Y").date() - if dt_log < dt_snap: - is_yesterday = True - except Exception: - pass - - prefix = "Y" if is_yesterday else "" - - with get_connection() as conn: - cursor = conn.cursor() - - if date_str: - cursor.execute( - "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_time = ? AND snapshot_id IS NOT NULL LIMIT 1", - (date_str, snapshot_time) - ) - else: - cursor.execute( - "SELECT snapshot_id FROM scud_logs WHERE snapshot_time = ? AND snapshot_id IS NOT NULL LIMIT 1", - (snapshot_time,) - ) - - row = cursor.fetchone() - if row and row[0]: - return row[0] - - cursor.execute(""" - SELECT snapshot_id - FROM scud_logs - WHERE snapshot_id LIKE ? OR snapshot_id LIKE ? - ORDER BY snapshot_id DESC LIMIT 1 - """, (f"{date_prefix}-%", f"Y{date_prefix}-%")) - - last_row = cursor.fetchone() - next_seq = 1 - - if last_row and last_row[0]: - parts = last_row[0].replace("Y", "").split("-") - if len(parts) > 1 and parts[1].isdigit(): - next_seq = int(parts[1]) + 1 - - return f"{prefix}{date_prefix}-{next_seq:03d}" - - -def save_scud_to_db(df_scud, date_str, snapshot_time=None, is_yesterday=False): - """Сохраняет логи СКУД с автоматическим присвоением составного snapshot_id.""" - if df_scud is None or df_scud.empty: - return - - if not snapshot_time: - snapshot_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - # Передаем date_str в генератор snapshot_id - snapshot_id = get_or_create_snapshot_id(snapshot_time, date_str=date_str, is_yesterday=is_yesterday) - - data_to_insert = [] - for _, r in df_scud.iterrows(): - data_to_insert.append(( - date_str, - r.get('Сотрудник', r.get('fio_raw', '')), - r.get('fio_clean', ''), - r.get('Подразделение', ''), - r.get('Должность', ''), - r.get('Начало_дня', 'Нет входа'), - r.get('Первая_активность', '—'), - r.get('Конец_дня', 'Нет выхода'), - r.get('Находился_в_здании', '00:00'), - 1 if r.get('Пришел', False) else 0, - r.get('anomaly_flag', 'NONE'), - snapshot_time, - snapshot_id - )) - - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM scud_logs WHERE log_date = ? AND snapshot_time = ?", (date_str, snapshot_time)) - cursor.executemany(""" - 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, snapshot_id - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, data_to_insert) - conn.commit() - - -def get_latest_snapshot_time(date_str=None): - with get_connection() as conn: - cursor = conn.cursor() - if date_str: - cursor.execute("SELECT snapshot_time FROM scud_logs WHERE log_date = ? AND snapshot_time IS NOT NULL ORDER BY snapshot_time DESC LIMIT 1", (date_str,)) - else: - cursor.execute("SELECT snapshot_time FROM scud_logs WHERE snapshot_time IS NOT NULL ORDER BY snapshot_time DESC LIMIT 1") - row = cursor.fetchone() - return row[0] if row else None - - -def load_scud_from_db_by_snapshot(date_str, snapshot_param=None): - """ - Загружает логи СКУД по ID снапшота. - Если snapshot_param не задан (или искался прошлый день), приоритетно выбирает - финальный вечерний снапшот, начинающийся с буквы 'Y' (срез на 22:00) за дату date_str. - """ - with get_connection() as conn: - df = pd.DataFrame() - - # 1. Если передан конкретный ID снапшота (например, '20260810-001') - if snapshot_param: - df = pd.read_sql_query( - "SELECT * FROM scud_logs WHERE snapshot_id = ?", - conn, params=(str(snapshot_param),) - ) - - # 2. Если по snapshot_param ничего не найдено ИЛИ snapshot_param=None (запрос за вчерашний день): - if df.empty and date_str: - cursor = conn.cursor() - - # ⭐️ ПРИОРИТЕТ 1: Ищем срез, начальный символ которого 'Y' (вечерний зафиксированный Y-снапшот) - cursor.execute( - "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_id LIKE 'Y%' ORDER BY id DESC LIMIT 1", - (date_str,) - ) - row = cursor.fetchone() - - # ⭐️ ПРИОРИТЕТ 2: Если Y-снапшот не найден, берем самый свежий обычный - if not row: - cursor.execute( - "SELECT snapshot_id FROM scud_logs WHERE log_date = ? ORDER BY id DESC LIMIT 1", - (date_str,) - ) - row = cursor.fetchone() - - if row and row[0]: - target_snap_id = row[0] - df = pd.read_sql_query( - "SELECT * FROM scud_logs WHERE snapshot_id = ?", - conn, params=(target_snap_id,) - ) - - # Приводим названия колонок к стандарту - if not df.empty: - rename_map = { - 'department': 'Подразделение', - 'position': 'Должность', - 'fio': 'Сотрудник', - 'time_in': 'Начало_дня', - 'first_activity': 'Первая_активность', - 'time_out': 'Конец_дня', - 'duration': 'Находился_в_здании', - 'is_present': 'Пришел' - } - # Переименовываем имеющиеся колонки - df = df.rename(columns={k: v for k, v in rename_map.items() if k in df.columns}) - - # Заполняем недостающие колонки значениями по умолчанию, если их не было в БД - required_cols = ['Пришел', 'Начало_дня', 'Первая_активность', 'Конец_дня', 'Находился_в_здании', 'anomaly_flag'] - for col in required_cols: - if col not in df.columns: - if col == 'Пришел': - df[col] = False - else: - df[col] = '—' - - # Приводим тип флага Пришел к bool - if 'Пришел' in df.columns: - df['Пришел'] = df['Пришел'].astype(bool) - - return df - -def get_available_snapshots(date_str=None): - """ - Возвращает список снапшотов. - Сортировка по времени snapshot_time DESC. - """ - with get_connection() as conn: - cursor = conn.cursor() - if date_str: - cursor.execute(""" - SELECT - snapshot_id, - log_date, - snapshot_time, - COUNT(*) as cnt - FROM scud_logs - WHERE log_date = ? AND snapshot_time IS NOT NULL - GROUP BY snapshot_id, log_date, snapshot_time - ORDER BY snapshot_time DESC - """, (date_str,)) - else: - cursor.execute(""" - SELECT - snapshot_id, - log_date, - snapshot_time, - COUNT(*) as cnt - FROM scud_logs - WHERE snapshot_time IS NOT NULL - GROUP BY snapshot_id, log_date, snapshot_time - ORDER BY snapshot_time DESC - """) - return cursor.fetchall() - - -def save_staff_to_db(df_staff, date_str): - if df_staff is None or df_staff.empty: - return - data_to_insert = [ - (date_str, r.get('ФИО', ''), r.get('fio_clean', ''), r.get('Подразделение', ''), r.get('Должность', '')) - for _, r in df_staff.iterrows() - ] - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM zup_staff WHERE snapshot_date = ?", (date_str,)) - cursor.executemany("INSERT INTO zup_staff (snapshot_date, fio, fio_clean, department, position) VALUES (?, ?, ?, ?, ?)", data_to_insert) - conn.commit() - - -def save_absences_to_db(df_absent, date_str): - if df_absent is None or df_absent.empty: - return - data_to_insert = [ - (date_str, r.get('ФИО', r.get('fio_clean', '')), r.get('fio_clean', ''), r.get('Вид_отсутствия', '')) - for _, r in df_absent.iterrows() - ] - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM zup_absences WHERE absence_date = ?", (date_str,)) - cursor.executemany("INSERT INTO zup_absences (absence_date, fio, fio_clean, absence_type) VALUES (?, ?, ?, ?)", data_to_insert) - conn.commit() - - -def save_anomalies_to_db(anomalies_list, date_str): - if not anomalies_list: - return - data_to_insert = [ - (date_str, a.get('fio', ''), a.get('type', ''), a.get('details', '')) - for a in anomalies_list - ] - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM anomalies_history WHERE anomaly_date = ?", (date_str,)) - cursor.executemany("INSERT INTO anomalies_history (anomaly_date, fio, anomaly_type, details) VALUES (?, ?, ?, ?)", data_to_insert) - conn.commit() - - -def get_all_rules_from_db(): - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("SELECT rule_text FROM ai_knowledge_base") - return [r[0] for r in cursor.fetchall()] - - -def add_rule_to_db(rule_text, added_by="Human"): - if not rule_text or not rule_text.strip(): - return - with get_connection() as conn: - cursor = conn.cursor() - try: - cursor.execute("INSERT OR IGNORE INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", (rule_text.strip(), added_by)) - conn.commit() - except Exception as e: - print(f"[⚠️] Ошибка записи правила в БД: {e}") - - -def sync_knowledge_base_to_db(): - pass - -def delete_snapshot_by_id(snapshot_id: str): - """Удаляет конкретный снапшот из таблицы scud_logs по его ID.""" - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM scud_logs WHERE snapshot_id = ?", (snapshot_id,)) - deleted_count = cursor.rowcount - conn.commit() - print(f"[✓] Удален снапшот [{snapshot_id}]. Удалено строк: {deleted_count}") - return deleted_count - -def delete_snapshots_by_date(date_str: str): - """Удаляет все снапшоты за указанную дату (например, '04.08.2026').""" - with get_connection() as conn: - cursor = conn.cursor() - # Удаляем по log_date или по дате внутри snapshot_id - cursor.execute("DELETE FROM scud_logs WHERE log_date = ? OR snapshot_id LIKE ?", (date_str, f"%{date_str.replace('.', '')}%")) - deleted_count = cursor.rowcount - conn.commit() - print(f"[✓] Удалены все снапшоты за дату [{date_str}]. Удалено строк: {deleted_count}") - return deleted_count -def init_department_synonyms_db(): - """Создает таблицу синонимов отделов в БД SQLite.""" - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute(""" - CREATE TABLE IF NOT EXISTS department_synonyms ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - short_name TEXT UNIQUE NOT NULL, - full_name TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - """) - # По умолчанию добавляем ОВК -> Отдел внутреннего контроля - cursor.execute(""" - INSERT OR IGNORE INTO department_synonyms (short_name, full_name) - VALUES ('овк', 'отдел внутреннего контроля') - """) - conn.commit() - - -def get_department_synonyms_dict(): - """Возвращает словарь всех изученных синонимов {short_name: full_name}.""" - init_department_synonyms_db() - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute("SELECT LOWER(short_name), LOWER(full_name) FROM department_synonyms") - return {row[0]: row[1] for row in cursor.fetchall()} - - -def add_department_synonym_to_db(short_name, full_name): - """Сохраняет новую пару синонимов отдела в базу SQLite.""" - init_department_synonyms_db() - with get_connection() as conn: - cursor = conn.cursor() - cursor.execute( - "INSERT OR REPLACE INTO department_synonyms (short_name, full_name) VALUES (?, ?)", - (short_name.strip().lower(), full_name.strip().lower()) - ) - conn.commit() - print(f"[✓] В базу SQLite добавлен новый синоним отдела: '{short_name}' ⟷ '{full_name}'") - -def load_staff_from_db(date_str): - """Загружает Штатное расписание 1С из базы SQLite за указанную дату.""" - with get_connection() as conn: - df = pd.read_sql_query( - "SELECT fio as 'ФИО', fio_clean, department as 'Подразделение', position as 'Должность' FROM zup_staff WHERE snapshot_date = ?", - conn, params=(date_str,) - ) - return df if not df.empty else None - -def load_absences_from_db(date_str): - """Загружает документальные отсутствия 1С из базы SQLite за указанную дату.""" - with get_connection() as conn: - df = pd.read_sql_query( - "SELECT fio as 'ФИО', fio_clean, absence_type as 'Вид_отсутствия' FROM zup_absences WHERE absence_date = ?", - conn, params=(date_str,) - ) - return df if not df.empty else None - \ No newline at end of file +""" +=============================================================================== +FILE: core/database.py +ROLE: Фасад ядра базы данных с полной обратной совместимостью импортов. +=============================================================================== +""" + +from core.connection import get_connection, DB_PATH +from core.schema import init_all_tables + +from core.repositories.scud_repo import ( + has_scud_logs_for_date, + has_yesterday_final_snapshot, + get_or_create_snapshot_id, + save_scud_to_db, + get_latest_snapshot_time, + load_scud_from_db_by_snapshot, + get_available_snapshots, + delete_snapshot_by_id, + delete_snapshots_by_date +) + +from core.repositories.zup_repo import ( + save_staff_to_db, + load_staff_from_db, + save_absences_to_db, + load_absences_from_db, + save_anomalies_to_db, + get_all_rules_from_db, + add_rule_to_db, + get_department_synonyms_dict, + add_department_synonym_to_db +) + +init_db = init_all_tables \ No newline at end of file diff --git a/core/repositories/scud_repo.py b/core/repositories/scud_repo.py new file mode 100644 index 0000000..c284742 --- /dev/null +++ b/core/repositories/scud_repo.py @@ -0,0 +1,227 @@ +""" +=============================================================================== +FILE: core/repositories/scud_repo.py +ROLE: Репозиторий логов СКУД, сохранение и загрузка снапшотов. +=============================================================================== +""" + +from datetime import datetime +import pandas as pd +from core.connection import get_connection + + +def has_scud_logs_for_date(date_str: str) -> bool: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT 1 FROM scud_logs WHERE log_date = ? LIMIT 1", (date_str,)) + return cursor.fetchone() is not None + + +def has_yesterday_final_snapshot(date_str: str) -> bool: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute( + "SELECT 1 FROM scud_logs WHERE log_date = ? AND (snapshot_id LIKE 'Y%' OR snapshot_time LIKE '%22:00:00') LIMIT 1", + (date_str,) + ) + return cursor.fetchone() is not None + + +def get_or_create_snapshot_id(snapshot_time: str, date_str: str = None, is_yesterday: bool = False) -> str: + try: + dt_snap = datetime.strptime(snapshot_time, "%Y-%m-%d %H:%M:%S").date() + date_prefix = dt_snap.strftime("%Y%m%d") + except (ValueError, TypeError): + dt_snap = datetime.now().date() + date_prefix = dt_snap.strftime("%Y%m%d") + + if date_str: + try: + dt_log = datetime.strptime(date_str, "%d.%m.%Y").date() + if dt_log < dt_snap: + is_yesterday = True + except Exception: + pass + + prefix = "Y" if is_yesterday else "" + + with get_connection() as conn: + cursor = conn.cursor() + if date_str: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_time = ? AND snapshot_id IS NOT NULL LIMIT 1", + (date_str, snapshot_time) + ) + else: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE snapshot_time = ? AND snapshot_id IS NOT NULL LIMIT 1", + (snapshot_time,) + ) + + row = cursor.fetchone() + if row and row[0]: + return row[0] + + cursor.execute(""" + SELECT snapshot_id FROM scud_logs + WHERE snapshot_id LIKE ? OR snapshot_id LIKE ? + ORDER BY snapshot_id DESC LIMIT 1 + """, (f"{date_prefix}-%", f"Y{date_prefix}-%")) + + last_row = cursor.fetchone() + next_seq = 1 + if last_row and last_row[0]: + parts = last_row[0].replace("Y", "").split("-") + if len(parts) > 1 and parts[1].isdigit(): + next_seq = int(parts[1]) + 1 + + return f"{prefix}{date_prefix}-{next_seq:03d}" + + +def save_scud_to_db(df_scud: pd.DataFrame, date_str: str, snapshot_time: str = None, is_yesterday: bool = False) -> None: + if df_scud is None or df_scud.empty: + return + + if not snapshot_time: + snapshot_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + snapshot_id = get_or_create_snapshot_id(snapshot_time, date_str=date_str, is_yesterday=is_yesterday) + + data_to_insert = [ + ( + date_str, + r.get('Сотрудник', r.get('fio_raw', '')), + r.get('fio_clean', ''), + r.get('Подразделение', ''), + r.get('Должность', ''), + r.get('Начало_дня', 'Нет входа'), + r.get('Первая_активность', '—'), + r.get('Конец_дня', 'Нет выхода'), + r.get('Находился_в_здании', '00:00'), + 1 if r.get('Пришел', False) else 0, + r.get('anomaly_flag', 'NONE'), + snapshot_time, + snapshot_id + ) + for _, r in df_scud.iterrows() + ] + + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE log_date = ? AND snapshot_time = ?", (date_str, snapshot_time)) + cursor.executemany(""" + 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, snapshot_id + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, data_to_insert) + conn.commit() + + +def get_latest_snapshot_time(date_str: str = None): + with get_connection() as conn: + cursor = conn.cursor() + if date_str: + cursor.execute("SELECT snapshot_time FROM scud_logs WHERE log_date = ? AND snapshot_time IS NOT NULL ORDER BY snapshot_time DESC LIMIT 1", (date_str,)) + else: + cursor.execute("SELECT snapshot_time FROM scud_logs WHERE snapshot_time IS NOT NULL ORDER BY snapshot_time DESC LIMIT 1") + row = cursor.fetchone() + return row[0] if row else None + + +def load_scud_from_db_by_snapshot(date_str: str, snapshot_param: str = None) -> pd.DataFrame: + with get_connection() as conn: + df = pd.DataFrame() + + # 1. Если передан конкретный ID снапшота (например 'Y20260820-004') + if snapshot_param: + df = pd.read_sql_query( + "SELECT * FROM scud_logs WHERE snapshot_id = ?", + conn, params=(str(snapshot_param),) + ) + + # 2. Если ищем за дату (для вчерашнего дня строго ищем Y-снапшот) + if df.empty and date_str: + cursor = conn.cursor() + + # ⭐️ Жесткий приоритет 1: Ищем снапшот с префиксом 'Y' + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_id LIKE 'Y%' ORDER BY snapshot_time DESC, id DESC LIMIT 1", + (date_str,) + ) + row = cursor.fetchone() + + # Приоритет 2: Если Y нет (например, за сегодня), берем самый свежий по времени + if not row: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? ORDER BY snapshot_time DESC, id DESC LIMIT 1", + (date_str,) + ) + row = cursor.fetchone() + + if row and row[0]: + target_id = row[0] + df = pd.read_sql_query( + "SELECT * FROM scud_logs WHERE snapshot_id = ?", + conn, params=(target_id,) + ) + + if not df.empty: + rename_map = { + 'department': 'department_scud', + 'position': 'Должность', + 'fio': 'Сотрудник', + 'time_in': 'Начало_дня', + 'first_activity': 'Первая_активность', + 'time_out': 'Конец_дня', + 'time_in_building': 'Находился_в_здании', + 'is_present': 'Пришел' + } + df = df.rename(columns={k: v for k, v in rename_map.items() if k in df.columns}) + if 'department_scud' in df.columns and 'Подразделение' not in df.columns: + df['Подразделение'] = df['department_scud'] + + for col in ['Пришел', 'Начало_дня', 'Первая_активность', 'Конец_дня', 'Находился_в_здании', 'anomaly_flag']: + if col not in df.columns: + df[col] = False if col == 'Пришел' else '—' + if 'Пришел' in df.columns: + df['Пришел'] = df['Пришел'].astype(bool) + + return df + + +def get_available_snapshots(date_str: str = None): + with get_connection() as conn: + cursor = conn.cursor() + query = """ + SELECT snapshot_id, log_date, snapshot_time, COUNT(*) as cnt + FROM scud_logs + WHERE snapshot_time IS NOT NULL + """ + params = [] + if date_str: + query += " AND log_date = ?" + params.append(date_str) + query += " GROUP BY snapshot_id, log_date, snapshot_time ORDER BY snapshot_time DESC" + cursor.execute(query, params) + return cursor.fetchall() + + +def delete_snapshot_by_id(snapshot_id: str) -> int: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE snapshot_id = ?", (snapshot_id,)) + cnt = cursor.rowcount + conn.commit() + return cnt + + +def delete_snapshots_by_date(date_str: str) -> int: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE log_date = ? OR snapshot_id LIKE ?", (date_str, f"%{date_str.replace('.', '')}%")) + cnt = cursor.rowcount + conn.commit() + return cnt \ No newline at end of file diff --git a/core/repositories/zup_repo.py b/core/repositories/zup_repo.py new file mode 100644 index 0000000..9d52b6e --- /dev/null +++ b/core/repositories/zup_repo.py @@ -0,0 +1,97 @@ +""" +=============================================================================== +FILE: core/repositories/zup_repo.py +ROLE: Репозиторий кадровых данных 1С:ЗУП, аномалий и базы знаний. +=============================================================================== +""" + +import pandas as pd +from typing import List, Dict, Any +from core.connection import get_connection + + +def save_staff_to_db(df_staff: pd.DataFrame, date_str: str) -> None: + if df_staff is None or df_staff.empty: + return + data = [ + (date_str, r.get('ФИО', ''), r.get('fio_clean', ''), r.get('Подразделение', ''), r.get('Должность', '')) + for _, r in df_staff.iterrows() + ] + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM zup_staff WHERE snapshot_date = ?", (date_str,)) + cursor.executemany("INSERT INTO zup_staff (snapshot_date, fio, fio_clean, department, position) VALUES (?, ?, ?, ?, ?)", data) + conn.commit() + + +def load_staff_from_db(date_str: str) -> pd.DataFrame: + with get_connection() as conn: + df = pd.read_sql_query( + "SELECT fio as 'ФИО', fio_clean, department as 'Подразделение', position as 'Должность' FROM zup_staff WHERE snapshot_date = ?", + conn, params=(date_str,) + ) + return df if not df.empty else None + + +def save_absences_to_db(df_absent: pd.DataFrame, date_str: str) -> None: + if df_absent is None or df_absent.empty: + return + data = [ + (date_str, r.get('ФИО', r.get('fio_clean', '')), r.get('fio_clean', ''), r.get('Вид_отсутствия', '')) + for _, r in df_absent.iterrows() + ] + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM zup_absences WHERE absence_date = ?", (date_str,)) + cursor.executemany("INSERT INTO zup_absences (absence_date, fio, fio_clean, absence_type) VALUES (?, ?, ?, ?)", data) + conn.commit() + + +def load_absences_from_db(date_str: str) -> pd.DataFrame: + with get_connection() as conn: + df = pd.read_sql_query( + "SELECT fio as 'ФИО', fio_clean, absence_type as 'Вид_отсутствия' FROM zup_absences WHERE absence_date = ?", + conn, params=(date_str,) + ) + return df if not df.empty else None + + +def save_anomalies_to_db(anomalies_list: List[Dict[str, Any]], date_str: str) -> None: + if not anomalies_list: + return + data = [(date_str, a.get('fio', ''), a.get('type', ''), a.get('details', '')) for a in anomalies_list] + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM anomalies_history WHERE anomaly_date = ?", (date_str,)) + cursor.executemany("INSERT INTO anomalies_history (anomaly_date, fio, anomaly_type, details) VALUES (?, ?, ?, ?)", data) + conn.commit() + + +def get_all_rules_from_db() -> List[str]: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT rule_text FROM ai_knowledge_base") + return [r[0] for r in cursor.fetchall()] + + +def add_rule_to_db(rule_text: str, added_by: str = "Human") -> None: + if not rule_text or not rule_text.strip(): + return + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("INSERT OR IGNORE INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", (rule_text.strip(), added_by)) + conn.commit() + + +def get_department_synonyms_dict() -> Dict[str, str]: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT LOWER(short_name), LOWER(full_name) FROM department_synonyms") + return {row[0]: row[1] for row in cursor.fetchall()} + + +def add_department_synonym_to_db(short_name: str, full_name: str) -> None: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("INSERT OR REPLACE INTO department_synonyms (short_name, full_name) VALUES (?, ?)", (short_name.strip().lower(), full_name.strip().lower())) + conn.commit() \ No newline at end of file diff --git a/core/schema.py b/core/schema.py new file mode 100644 index 0000000..c623dc5 --- /dev/null +++ b/core/schema.py @@ -0,0 +1,162 @@ +""" +=============================================================================== +FILE: core/schema.py +PROJECT: SCUD Orion AI (Unified Architecture) +ROLE: DDL-схемы таблиц, создание индексов и инициализация базы данных. +=============================================================================== +""" + +import logging +from core.connection import get_connection + +logger = logging.getLogger("DB_SCHEMA") + + +def init_all_tables() -> None: + """Инициализирует все таблицы и индексы системы.""" + with get_connection() as conn: + cursor = conn.cursor() + + # 1. Логи СКУД + cursor.execute(""" + CREATE TABLE IF NOT EXISTS scud_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + log_date TEXT NOT NULL, + fio TEXT NOT NULL, + fio_clean TEXT NOT NULL, + 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, + snapshot_id TEXT DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 2. Кадровые реестры 1С + cursor.execute(""" + CREATE TABLE IF NOT EXISTS zup_staff ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + snapshot_date TEXT NOT NULL, + fio TEXT NOT NULL, + fio_clean TEXT NOT NULL, + department TEXT, + position TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS zup_absences ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + absence_date TEXT NOT NULL, + fio TEXT NOT NULL, + fio_clean TEXT NOT NULL, + absence_type TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 3. Аномалии и база знаний + cursor.execute(""" + CREATE TABLE IF NOT EXISTS anomalies_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + anomaly_date TEXT NOT NULL, + fio TEXT NOT NULL, + anomaly_type TEXT NOT NULL, + details TEXT NOT NULL, + human_status TEXT DEFAULT 'Pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS ai_knowledge_base ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + rule_text TEXT UNIQUE NOT NULL, + added_by TEXT DEFAULT 'Human', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS department_synonyms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + short_name TEXT UNIQUE NOT NULL, + full_name TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 4. Узлы системного промпта и сессии + cursor.execute(""" + CREATE TABLE IF NOT EXISTS system_prompt_nodes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + prompt_name TEXT DEFAULT 'main_agent', + section_id INTEGER NOT NULL, + item_id INTEGER NOT NULL, + content TEXT NOT NULL, + is_active INTEGER DEFAULT 1, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(prompt_name, section_id, item_id) + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS session_states ( + session_id TEXT PRIMARY KEY, + state_type TEXT NOT NULL, + pending_data TEXT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS chat_messages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL, + role TEXT NOT NULL, + content TEXT NOT NULL, + is_ephemeral INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS exceptions_registry ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + category TEXT NOT NULL, -- 'department', 'position', 'fio', 'position_keyword', 'include_fio', 'remote_worker' + value TEXT NOT NULL, + comment TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(category, value) + ); + """) + + # 5. Задачи + cursor.execute(""" + CREATE TABLE IF NOT EXISTS tasks ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + task_id TEXT, + module TEXT DEFAULT 'general', + title TEXT NOT NULL, + priority TEXT DEFAULT 'MEDIUM', + status TEXT DEFAULT 'BACKLOG', + due_date TEXT, + user_id INTEGER DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 6. Индексы + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_date ON scud_logs(log_date);") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_fio ON scud_logs(fio_clean);") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_snapshot ON scud_logs(snapshot_time);") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_prompt_nodes ON system_prompt_nodes(prompt_name, section_id, item_id);") + + conn.commit() \ No newline at end of file diff --git a/data/scud_orion_ai.db b/data/scud_orion_ai.db index 7900e5b67b1cf5d637d56bf6727b0afa5a603e01..af9d01ea099cdcffe86fd921c27c9e589fbc6545 100644 GIT binary patch delta 1355356 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 z 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%0A`s$e=$YE04Sc| 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%0D=F6 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

C$bVBll?DSJZ2T}3x>Y1bC+dJ%Jo&!|Y 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�gO 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 T*pO(PUC18a>4}uaty=g0{x3KD delta 309057 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 ypQu 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 KU&)LA;P^LNTGg@u diff --git a/data/scud_orion_ai.db-shm b/data/scud_orion_ai.db-shm deleted file mode 100644 index ed9a00585a0606b9b5949d75c416215769a91573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 PD2(-9CVzqR;xF+3*=`p2 diff --git a/data/static_reason_workers.csv b/data/static_reason_workers.csv index 49f9ef7..f7d96f6 100644 --- a/data/static_reason_workers.csv +++ b/data/static_reason_workers.csv @@ -11,4 +11,6 @@ fio,reason,note Ковалев Владимир Владимирович,Удаленная работа,Постоянная удаленка Кожокарь Татьяна Юрьевна,Удаленная работа,Постоянная удаленка Субетто Юлия Викторовна,Удаленная работа,Постоянная удаленка -Ароян Станислав Месропович,Удаленная работа,Временная удаленка \ No newline at end of file +Чуркина Елена Геннадьевна,Удаленная работа,Постоянная удаленка +Пушков Александр Александрович,Удаленная работа,Временная удаленка с 26.08.2026 по 04.09.2026 +Сысоев Алексей Валерьевич,Удаленная работа,Временная удаленка с 25.08.2026 по 27.08.2026 \ No newline at end of file diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e1ef71a..0301c1e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,64 @@ Все ключевые изменения архитектуры, инструментов и модулей проекта SCUD Orion AI фиксируются в данном файле[cite: 6]. +## [3.0.0] — 2026-08-21 +### 🚀 Глубокий архитектурный рефакторинг (Unified Clean Architecture) + +#### Добавлено: +- **Пакет ядра `core/`:** + - `core/connection.py`: централизованный менеджер SQLite-подключений с поддержкой WAL-режима и row_factory. + - `core/schema.py`: единая точка инициализации схемы данных и индексов. + - `core/repositories/`: низкоуровневые репозитории `scud_repo.py` и `zup_repo.py`. +- **Доменные сервисы `services/`:** + - `services/tasks/`: полная изоляция логики задач (CRUD, Markdown-экспорт, генерация `ROADMAP.md`). + - `services/prompts/`: доменный сервис системного промпта, поддержка превью, генерация HTML-Diff и пакетное удаление узлов (`BATCH_DELETE`). + - `services/snapshots/`: бизнес-логика срезов СКУД с защитой финишных Y-снапшотов. + - `services/knowledge/`: сервис базы знаний правил и синонимов отделов. + - `services/scud_etl/`: модульный ETL-конвейер (`pipeline.py`, `anomaly_detector.py`, `merger.py`, `sql_queries.py`). +- **ИИ-оркестратор `modules/ai_engine/`:** + - Декомпозиция монолитного `agent.py` на узкие обработчики `handlers/` и динамический контекст-билдер `context_builder.py`. + - Двухконтурная обработка: нативный Function Calling + семантический страхующий инжектор (`tool_injector.py`). + - Интеллектуальный Topic Drift менеджер с вежливым напоминанием на 3-й шаг и автоочисткой эфемерных сообщений на 4-й. +- **Интерфейс и UI:** + - Кнопка «✏️ Редактировать» прямо в карточке просмотра системного промпта с инлайн-редактором. + +#### Исправлено: +- Устранена утечка системного промпта в постоянный контекст (`chat_messages`). +- Исправлены ошибки несоответствия сигнатур (`TypeError: create_prompt_preview`, `save_full_prompt_draft`, `get_snapshots_registry`) в Fast-Path. +- Устранена галлюцинация слов-паразитов («Почемучка», «Почемучто») на уровне валидации ответа. +- Исправлено устаревшее противоречивое правило 2.3 в базе данных, блокировавшее интерактивное удаление задач. + +#### Удалено: +- Устаревшие файлы-дубли: `modules/web_api/llm/db/db_tasks.py`, `db_snapshots.py`, `prompt_merger.py`. + +--- + +## [2026-08-19] — Инлайн-редактор задач, интеллектуальный ContextManager и стабилизация Function Calling + +### ✨ Добавлено +* **Инлайн-редактирование задач (`task_widget.js` / `tasks.py`)**: + - Добавлена кнопка редактирования (`✏️`) на каждой карточке задачи. + - Карточка трансформируется в инлайн-форму с тремя полями: текст задачи, HTML5-пикер календаря планируемого срока и выпадающий список важности (`LOW`, `MEDIUM`, `HIGH`, `CRITICAL`). + - Добавлен REST API эндпоинт `PATCH /api/v1/tasks/{task_id}` с поддержкой комплексного обновления полей в SQLite. + - В карточки выведено отображение даты создания задачи. +* **Интеллектуальный ContextManager (`context_manager.py`)**: + - Служебные запросы и карточки инструментов сохраняются синхронными парами (`is_ephemeral = 1`) и атомарно удаляются при завершении операций. + - Свободные диалоги оператора (включая темы Topic Drift) сохраняются в постоянную историю (`is_ephemeral = 0`) и не стираются при закрытии сессий промпта/задач. +* **Поддержка Y-снапшотов (`db_snapshots.py`)**: + - Исправлен SQL-запрос `db_get_snapshots` для точного извлечения ночных и фоновых срезов с префиксом `Y` (например, `Y20260817-003`). + +### 🔧 Изменено +* **`modules/web_api/llm/agent.py`**: + - Полностью удалены эвристические текстовые фильтры и принудительные сортировки инструментов. + - Настроен нативный возврат и исполнение инструментов без зацикливания модели. + - Устранена ошибка `UnboundLocalError` при вызове справочных инструментов. +* **`modules/web_api/llm/schemas.py`**: + - Очищены описания инструментов от агрессивных директив и капса, стабилизирована селективность Function Calling для Qwen 2.5. +* **`modules/web_api/llm/core/ollama_client.py`**: + - Оптимизированы параметры генерации для Function Calling (`repeat_penalty: 1.0`, `presence_penalty: 0.0`, `temperature: 0.0`), что исключило спам несколькими вызовами инструментов на один запрос. +* **`modules/web_api/static/js/chat/task_widget.js`**: + - Фильтр по умолчанию переведен на вкладку **«В работе»** (`IN_PROGRESS`). + --- ## [2026-08-18] — Двухфазный жизненный цикл сессий, двусторонний Diff и Topic Drift Guard diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md deleted file mode 100644 index 780cc22..0000000 --- a/docs/ROADMAP.md +++ /dev/null @@ -1,61 +0,0 @@ -# 🗺️ ДОРОЖНАЯ КАРТА И АРХИТЕКТУРНЫЙ РОАДМАП ПРОЕКТА SCUD ORION AI - -## 📌 Зафиксированные вехи и концептуальные архитектурные решения - -Схема веток Gitea для развития проекта: - -main (100% стабильный релиз) - │ - ├──► feature/prompt-relational-nodes ──┐ (Перевод системного промпта на реляционные узлы в SQLite) - │ ▼ - ├──────────────────────────────────► merge to main - │ - ├──► feature/native-function-calling ──┐ (Отказ от регулярных выражений tool_injector.py в пользу нативного FC) - │ ▼ - ├──────────────────────────────────► merge to main - │ - └──► feature/ephemeral-context ────────┐ (Интеллектуальный жизненный цикл эфемерных сообщений) - ▼ - merge to main - ---- - -## 🎯 Текущий активный спринт: Нативный Function Calling и реляционный редактор промпта - -### 1. Архитектура чистого диалогового агента без регулярных выражений -* **Концепция:** Полный отказ от жестких эвристик и регулярных выражений в `tool_injector.py`. Все решения о намерениях оператора, вызове инструментов и переключении тем принимает языковая модель через семантический контекст. -* **Ключевые этапы реализации:** - * **Этап 1 (Санитарная очистка):** Превращение `tool_injector.py` в простой фильтр мусорных тегов без инжекции и перехватов команд. - * **Этап 2 (Семантическое управление сессией):** Инструктаж модели в `role: system` о поведении в состоянии `PROMPT_PREVIEW` (оценка подтверждения, отмены, правок или смены темы диалога). - * **Этап 3 (Жизненный цикл контекста):** Модель видит временные сообщения (`is_ephemeral = 1`) только во время активной ветки; при фиксации решения (`fast_path.py`) контекст очищается через `db_purge_ephemeral_messages`. - * **Этап 4 (Гибридный UI):** Поддержка как диалоговых правок, так и прямого инлайн-редактирования через форму `[✏️ Редактировать]` в окне чата. - ---- - -## 🚀 Масштабирование эфемерного контекста и сервисные инструменты - -### 2. Модуль инспекции контекста и базы данных (`db_cli.py`) -* **Статус:** `Реализовано`. -* Добавлена команда `context [session_id] [--limit N]` для просмотра сырой таблицы сообщений `chat_messages` с пометками об эфемерности. - -### 3. Модуль задач и бэклога (`tasks`) -* **Целевые инструменты:** `db_get_tasks`, `db_add_task`, `db_update_task_status`, `db_delete_task`. -* Вывод интерактивных карточек задач с фильтрами без засорения постоянной истории диалога. - -### 4. Модуль срезов и архива СКУД (`snapshots`) -* **Целевые инструменты:** `db_get_snapshots`, `db_delete_snapshots`. -* Интерактивное подтверждение удаления срезов и автоматическая очистка таблиц срезов из контекста. - -### 5. Модуль базы знаний, правил и аномалий (`kb & anomalies`) -* **Целевые инструменты:** `db_get_rules`, `db_get_anomalies`, `db_get_reference`. -* Изоляция нормативных справочников от постоянной истории диалога для предотвращения залипания LLM. - ---- - -## 🔮 Долгосрочный бэклог (Future Modules) - -### 6. Интерактивный модуль планирования (Checklist & Task Planner Engine) -* Динамические проектные чек-листы с синхронизацией в таблицу `tasks`. - -### 7. Изолированная песочница кода (Code Execution Sandbox Engine) -* Запуск динамических Python/Pandas вычислений в изолированном Docker/gVisor контуре. \ No newline at end of file diff --git a/docs/in_progress/ROADMAP.md b/docs/in_progress/ROADMAP.md new file mode 100644 index 0000000..1ec6ff1 --- /dev/null +++ b/docs/in_progress/ROADMAP.md @@ -0,0 +1,123 @@ +# План реализации (ROADMAP) + +## 1. Очистка от регулярок и костылей (`tool_injector.py`) +- [x] Полностью удалить принудительные перехваты текста регулярными выражениями для команд добавления, редактирования и удаления пунктов[cite: 4]. +- [x] Оставить в модуле только базовую санитарную очистку сырых тегов (``)[cite: 4]. + +--- + +## 2. Настройка контекста и инструкций сессии (`agent.py`) +- [x] Передать управление диалогом языковой модели через системный блок `role: "system"`[cite: 4]. +- [x] При активном состоянии `PROMPT_PREVIEW` передавать модели инструкцию: + - **Подтверждение / отмена / корректировка:** продолжать работу с превью и вызывать соответствующие инструменты[cite: 4]. + - **Смена темы:** вежливо напомнить об открытом изменении и запросить решение[cite: 4]. +- [x] Обеспечить видимость эфемерных сообщений (`is_ephemeral = 1`) для модели во время активной работы с превью[cite: 4]. +- [x] Внедрить семантический Topic Drift Guard (`idle_turns` = 3) с вопросами и кнопками из `tool_action_registry`[cite: 4]. +- [x] Реализовать детерминированный мгновенный сброс сессии и зачистку эфемерного контекста при вызове сторонних инструментов[cite: 4]. + +--- + +## 3. Очистка эфемерных сообщений при завершении (`fast_path.py` / `context_manager.py`) +- [x] Настроить удаление временных сообщений превью (`db_purge_ephemeral_messages`) строго в момент нажатия кнопок **«Подтвердить»** или **«Отменить»**[cite: 4]. +- [x] Сбрасывать состояние сессии в базе данных после фиксации решения[cite: 4]. +- [x] Внедрить прямое точечное применение изменений через `db_apply_prompt_node_action`[cite: 4]. +- [x] Добавить обработку фазы `PROMPT_FOLLOWUP` с кнопками завершения и очистки контекста[cite: 4]. +- [x] Создать `context_manager.py` для строгого разграничения служебных tool-пар (`is_ephemeral=1`) и содержательного диалога (`is_ephemeral=0`), сохраняя беседы Topic Drift в истории[cite: 4]. + +--- + +## 4. Инлайн-редактор в окне диалога (`core.js`) +- [x] Проверить работу блока ручного редактирования (`inline-prompt-editor-container`) с кнопками **«Сохранить правки»** и **«Свернуть»**[cite: 4]. +- [x] Обеспечить сохранение черновика через API (`/api/v1/chat/draft`) и отображение обновленного текста перед подтверждением[cite: 4]. +- [x] Реализовать двусторонний клиентский Diff-рендерер (одновременная подсветка добавленных строк и зачеркивание удаленных `[УДАЛЕНИЕ]`)[cite: 4]. +- [x] Добавить авто-форматирование и отступы подпунктов (`X.Y.`) при ручном сохранении черновика[cite: 4]. + +--- + +## 5. Тестирование и валидация системного промпта +- [x] **Нативные вызовы:** проверить добавление, редактирование и удаление пунктов через нативные вызовы модели (`db_prompt_node_edit`)[cite: 4]. +- [x] **Контекстные сценарии:** проверить поведение модели при смене темы диалога оператором (Guardrail)[cite: 4]. +- [x] **UI и очистка:** проверить ручное редактирование через кнопку в окне чата и последующую очистку контекста (`db_purge_ephemeral_messages`)[cite: 4]. + +--- + +## 6. Распространение архитектурного паттерна на модуль задач (`tasks`) +- [x] **Масштабирование UI задач:** + - Увеличена ширина карточки до `max-w-4xl` и динамическая высота скролла до `70vh`[cite: 4]. + - Реализованы переключатели фильтрации: «В работе» (по умолчанию), «В планах», «Готово», «Все»[cite: 4]. + - Разделены кнопки действия: «В работу» (для плановых) и «Готово» (для текущих)[cite: 4]. +- [x] **Инлайн-редактирование карточки задачи:** + - Плавная трансформация карточки в 3-строчную форму (текст, дата со встроенным пикером, выпадающий список важности)[cite: 4]. + - Отображение даты создания задачи[cite: 4]. + - Сохранение через REST API эндпоинт `PATCH /api/v1/tasks/{id}`[cite: 4]. +- [x] **Детерминированный Fast-Path и двухфазное удаление:** + - Мгновенная смена статусов без задержек LLM[cite: 4]. + - Карточка подтверждения удаления с автоочисткой контекста[cite: 4]. +- [x] **Генерация отчетов задач в Markdown:** + - Добавлен инструмент `db_export_tasks_markdown` для формирования Markdown-файла с группировкой по модулям и чекбоксами `[x]` / `[ ]`[cite: 3]. + - Реализован роутер безопасной отдачи файлов с сохранением имени (`/api/v1/files/download/...`)[cite: 3]. +- [x] **Доменная консолидация задач:** + - Реализован консолидированный инструмент `db_tasks_edit(action: ["ADD", "UPDATE", "DELETE", "EXPORT"], ...)`[cite: 3]. + +--- + +## 7. Распространение на модуль снапшотов (`snapshots`) +- [x] **Поддержка Y-снапшотов:** универсальный парсинг и поиск по `snapshot_id LIKE 'Y%'` и срезам за 22:00:00[cite: 4]. +- [x] **Single Active Snapshot View:** сохранение активного среза в контексте для аналитики с автоматической ротацией и зачисткой при запросе новых дат[cite: 4]. +- [x] **Интерактивный UI с чекбоксами и защитой срезов:** + - Чекбоксы в строках дневных срезов и кнопка «Выбрать все» в шапке[cite: 3]. + - Защита итогового вечернего среза Y (иконка замочка `🔒`, блокировка выбора)[cite: 3]. + - Динамическая кнопка «Удалить выбранные (N)» в подвале карточки[cite: 3]. +- [x] **Детерминированный Fast-Path удаления срезов:** + - Двухфазное подтверждение удаления (одиночное и пакетное) с корректным счётчиком количества удаляемых элементов[cite: 3]. + - Защита от сброса фильтра даты (`query_date`) при обновлении карточки после удаления[cite: 3]. + +--- + +## 🏗️ Раздел 8. Глубокий архитектурный рефакторинг ядра и сервисов `[ЗАВЕРШЕНО]` + +- [x] **Шаг 1. Выделение общего слоя ядра (`core/`)** + - [x] Изолированный пул соединений SQLite (`core/connection.py`) с поддержкой WAL и таймаутов. + - [x] DDL-схемы таблиц и индексов (`core/schema.py`). + - [x] Репозитории СКУД и 1С (`core/repositories/scud_repo.py`, `core/repositories/zup_repo.py`). + - [x] Фасад обратной совместимости (`core/database.py`). +- [x] **Шаг 2. Декомпозиция предметных доменов (`services/`)** + - [x] Сервис задач (`services/tasks/`): CRUD, валидация, markdown-экспорт (`exporter.py`). + - [x] Сервис системного промпта (`services/prompts/`): сборка узлов, вычисление diff (`diff_engine.py`), пакетное удаление (`BATCH_DELETE`). + - [x] Сервис снапшотов СКУД (`services/snapshots/`): безопасное удаление с защитой Y-снапшотов. + - [x] Сервис базы знаний (`services/knowledge/`): правила арбитража и синонимы отделов. +- [x] **Шаг 3. Рефакторинг ETL-конвейера (`services/scud_etl/`)** + - [x] Оркестратор этапов контроллинга (`pipeline.py`). + - [x] Детектор аномалий и конфликтов реестров (`anomaly_detector.py`). + - [x] Агрегация проходов и наложение исключений (`merger.py`). + - [x] Информативное консольное логирование этапов в `main_etl.py`. +- [x] **Шаг 4. Модульный ИИ-оркестратор (`modules/ai_engine/`)** + - [x] Динамический строитель системного контекста (`context_builder.py`). + - [x] Изолированные обработчики инструментов (`handlers/task_handler.py`, `handlers/prompt_handler.py`, `handlers/snapshot_handler.py`). + - [x] Компактный диспетчер диалога (`agent.py`). + - [x] Двухконтурный семантический анализатор намерений (`tool_injector.py`). +- [x] **Шаг 5. Зачистка рудиментов и стабилизация** + - [x] Устранение дубликатов в `web_api/llm/db/`. + - [x] Очистка роутеров от прямых манипуляций с базой данных. + - [x] Исправление сигнатур Fast-Path перехватчиков. + +--- + +## 📊 Раздел 9. Диалоговая генерация и контроль отчетов СКУД (Conversational Reporting Engine) `[В ПЛАНАХ]` + +- [ ] **Интерактивный запуск отчетов из чата** + - [ ] Инструмент `db_generate_report(date_str, report_type)` для генерации сводки или детального отчета по требованию оператора. + - [ ] Автоматическая отдача карточки скачивания сформированного Excel-файла прямо в диалоге (`FILE_DOWNLOAD_CARD`). +- [ ] **Диалоговый аудит расхождений** + - [ ] Инструмент точечной выборки: «Кто сегодня не пришел из отдела ОВК?», «Покажи опоздавших за вчера». + - [ ] Быстрое внесение исключений и синонимов подразделений через диалог. + +--- + +## 10. Изолированная песочница кода (Code Execution Sandbox Engine) +- [ ] **Docker/gVisor контур:** + - Создание изолированного контейнера без доступа к внешней сети (network: none) с ограниченными лимитами по памяти и CPU (cgroups)[cite: 4]. + - Настройка безопасного монтирования только необходимых CSV/Parquet-файлов данных в режиме Read-Only[cite: 4]. +- [ ] **Динамические Python/Pandas вычисления:** + - Инструмент генерации и безопасного выполнения скриптов агрегации и аналитики данных СКУД / 1С на лету[cite: 4]. + - Перехват stdout/stderr, сбор результатов расчетов и графиков с передачей в UI-чата[cite: 4]. \ No newline at end of file diff --git a/docs/in_progress/план_оптимизации_работы_с_контекстом.md b/docs/in_progress/план_оптимизации_работы_с_контекстом.md deleted file mode 100644 index 4587843..0000000 --- a/docs/in_progress/план_оптимизации_работы_с_контекстом.md +++ /dev/null @@ -1,72 +0,0 @@ -# План реализации - -## 1. Очистка от регулярок и костылей (`tool_injector.py`) -- [x] Полностью удалить принудительные перехваты текста регулярными выражениями для команд добавления, редактирования и удаления пунктов[cite: 4]. -- [x] Оставить в модуле только базовую санитарную очистку сырых тегов (``)[cite: 4]. - ---- - -## 2. Настройка контекста и инструкций сессии (`agent.py`) -- [x] Передать управление диалогом языковой модели через системный блок `role: "system"`[cite: 4]. -- [x] При активном состоянии `PROMPT_PREVIEW` передавать модели инструкцию: - - **Подтверждение / отмена / корректировка:** продолжать работу с превью и вызывать соответствующие инструменты[cite: 4]. - - **Смена темы:** вежливо напомнить об открытом изменении и запросить решение[cite: 4]. -- [x] Обеспечить видимость эфемерных сообщений (`is_ephemeral = 1`) для модели во время активной работы с превью[cite: 4]. -- [x] Внедрить семантический Topic Drift Guard (`idle_turns` = 3) с вопросами и кнопками из `tool_action_registry`. -- [x] Реализовать детерминированный мгновенный сброс сессии и зачистку эфемерного контекста при вызове сторонних инструментов. - ---- - -## 3. Очистка эфемерных сообщений при завершении (`fast_path.py`) -- [x] Настроить удаление временных сообщений превью (`db_purge_ephemeral_messages`) строго в момент нажатия кнопок **«Подтвердить»** или **«Отменить»**[cite: 4]. -- [x] Сбрасывать состояние сессии в базе данных после фиксации решения[cite: 4]. -- [x] Внедрить прямое точечное применение изменений через `db_apply_prompt_node_action`[cite: 4]. -- [x] Добавить обработку фазы `PROMPT_FOLLOWUP` с кнопками завершения и очистки контекста. - ---- - -## 4. Инлайн-редактор в окне диалога (`core.js`) -- [x] Проверить работу блока ручного редактирования (`inline-prompt-editor-container`) с кнопками **«Сохранить правки»** и **«Свернуть»**[cite: 4]. -- [x] Обеспечить сохранение черновика через API (`/api/v1/chat/draft`) и отображение обновленного текста перед подтверждением[cite: 4]. -- [x] Реализовать двусторонний клиентский Diff-рендерер (одновременная подсветка добавленных строк и зачеркивание удаленных `[УДАЛЕНИЕ]`). -- [x] Добавить авто-форматирование и отступы подпунктов (`X.Y.`) при ручном сохранении черновика. - ---- - -## 5. Тестирование и валидация системного промпта -- [x] **Нативные вызовы:** проверить добавление, редактирование и удаление пунктов через нативные вызовы модели (`db_prompt_node_edit`)[cite: 4]. -- [x] **Контекстные сценарии:** проверить поведение модели при смене темы диалога оператором (Guardrail)[cite: 4]. -- [x] **UI и очистка:** проверить ручное редактирование через кнопку в окне чата и последующую очистку контекста (`db_purge_ephemeral_messages`)[cite: 4]. - ---- - -## 6. Распространение архитектурного паттерна на модуль задач (`tasks`) -- [ ] **Масштабирование UI задач:** - - Увеличить размер окна/виджета просмотра и управления задачами (`TASK_INTERACTIVE_CARD`) по аналогии с окном редактирования системного промпта для удобного управления большим списком. -- [ ] **Интерактивное управление и превью:** - - Карточка предпросмотра параметров создаваемой задачи (`db_add_task`) с кнопками `[Подтвердить]`, `[Отменить]`, `[✏️ Редактировать]`. - - Подтверждение опасных операций (удаление задачи `db_delete_task`) с кнопками валидации. - - Follow-up фаза с выводом актуализированного списка задач из `tool_action_registry`. -- [ ] **Доменная консолидация:** - - Объединить `db_add_task`, `db_update_task_status`, `db_delete_task` в единый диспетчер `db_tasks_edit(action: ["ADD", "UPDATE", "DELETE"], ...)`[cite: 4]. - - Обновить `TOOLS_SCHEMA` в `schemas.py`[cite: 4]. - ---- - -## 7. Распространение на модуль снапшотов (`snapshots`) и правил (`rules`) -- [ ] **Консолидация модуля `snapshots`:** - - Интерактивное подтверждение массового удаления снапшотов за дату (`db_delete_snapshots`). - - Объединить операции удаления и управления срезами в единый `db_snapshots_edit(action: ["DELETE"], ...)`[cite: 4]. - - Авто-зачистка тяжелых таблиц снапшотов из контекста при переходе к другим темам. -- [ ] **Модуль правил арбитража (`rules`):** - - Редактирование правил базы знаний через единый паттерн узлов с подсветкой diff. - ---- - -## 8. Изолированная песочница кода (Code Execution Sandbox Engine) -- [ ] **Docker/gVisor контур:** - - Создание изолированного контейнера без доступа к внешней сети (network: none) с ограниченными лимитами по памяти и CPU (cgroups). - - Настройка безопасного монтирования только необходимых CSV/Parquet-файлов данных в режиме Read-Only. -- [ ] **Динамические Python/Pandas вычисления:** - - Инструмент генерации и безопасного выполнения скриптов агрегации и аналитики данных СКУД / 1С на лету. - - Перехват stdout/stderr, сбор результатов расчетов и графиков с передачей в UI-чата. \ No newline at end of file diff --git a/etl_code_snapshot.md b/etl_code_snapshot.md new file mode 100644 index 0000000..002af36 --- /dev/null +++ b/etl_code_snapshot.md @@ -0,0 +1,3752 @@ +# 📦 ETL-СЛЕПОК ИСХОДНОГО КОДА (СКУД ⟷ 1С & DB CORE) + +## File: `./config.py` +```py +import os +import re +from datetime import datetime, timedelta + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +DATA_DIR = os.path.join(BASE_DIR, "data") + +SCUD_DIR = os.path.join(DATA_DIR, "scud") +ZUP_1C_DIR = os.path.join(DATA_DIR, "1c") +OUTPUT_DIR = os.path.join(BASE_DIR, "output") +REPORTS_DIR = os.path.join(OUTPUT_DIR, "reports") + +# Путь к намонтированной сетевой шаре 1С в Linux (вместо \\storage\SCUD\Обмен\Штат) +SHARE_1C_DIR = "/mnt/scud_share" + +for folder in [DATA_DIR, SCUD_DIR, ZUP_1C_DIR, OUTPUT_DIR, REPORTS_DIR]: + os.makedirs(folder, exist_ok=True) + +NOW = datetime.now() +DATE_TODAY = NOW.strftime("%d.%m.%Y") + +if NOW.weekday() == 0: + DATE_YESTERDAY = (NOW - timedelta(days=3)).strftime("%d.%m.%Y") +else: + DATE_YESTERDAY = (NOW - timedelta(days=1)).strftime("%d.%m.%Y") + +# --- Настройки LLM / Ollama --- +OLLAMA_URL = "http://10.121.17.227:11434/api/generate" +OLLAMA_MODEL = "qwen2.5:14b-instruct-q8_0" +MODEL_NAME = OLLAMA_MODEL + +KNOWLEDGE_BASE_PATH = os.path.join(DATA_DIR, "knowledge_base.json") +EXCEPTIONS_PATH = os.path.join(BASE_DIR, "exceptions.json") + +# --- Настройки подключения к MS SQL Server (1С:ЗУП 3.1) --- +ZUP_SQL_CONFIG = { + "driver": "{ODBC Driver 18 for SQL Server}", # или "{ODBC Driver 17 for SQL Server}" + "server": os.getenv("ZUP_SQL_SERVER", "ACCOUNT-01"), + "database": os.getenv("ZUP_SQL_DB", "ZUP30"), # Замените на точное имя базы ЗУП на ACCOUNT-01 + "user": os.getenv("ZUP_SQL_USER", "scud_reader"), # Логин SQL Server + "password": os.getenv("ZUP_SQL_PASS", "Rhfcysq90"), # Пароль SQL Server + "trust_server_certificate": "yes", # Доверять сертификату сервера + "encrypt": "no" # "yes", если на MS SQL включено обязательное SSL-шифрование +} + + +def find_dated_file(prefix, date_str, search_dirs=[ZUP_1C_DIR, SCUD_DIR, DATA_DIR, "."]): + """ + Ищет файлы по префиксу и дате (поддерживает и 30.07.2026, и 30_07_2026). + """ + date_dots = date_str + date_underscores = date_str.replace('.', '_') + + for d in search_dirs: + if not os.path.exists(d): + continue + for f in os.listdir(d): + if f.endswith('.xlsx') or f.endswith('.csv'): + if f.lower().startswith(prefix.lower()): + if date_dots in f or date_underscores in f: + return os.path.join(d, f) + return None + + +def normalize_fio(fio): + if not fio or not isinstance(fio, str): + return "" + fio_clean = re.sub(r'\(.*?\)', '', fio) + fio_clean = fio_clean.replace('\xa0', ' ') + parts = fio_clean.strip().split() + return " ".join(parts).title() + + +def clean_scud_fio_light(fio_str): + return normalize_fio(fio_str) + + +def load_exceptions(): + import json + if os.path.exists(EXCEPTIONS_PATH): + try: + with open(EXCEPTIONS_PATH, "r", encoding="utf-8") as f: + return json.load(f) + except Exception: + pass + return {"fio": [], "departments": [], "positions": [], "position_keywords": []} +``` + +## File: `./exceptions.json` +```json +{ + "departments": [ + "ОВК" + ], + "positions": [ + "Уборщик производственных помещений", + "Уборщик служебных помещений" + ], + "fio": [ + "Таткало Валерий Валерьевич", + "Петренюк Андрей Германович", + "Михалев Сергей Геннадьевич" + ], + "position_keywords": [ + "уборщик", + "клинер", + "дворник", + "гардероб", + "рабочий по обслуживанию" + ], + "include_fio": [ + "Тарасенко Александр Александрович", + "Журиков Михаил Николаевич" + ] +} +``` + +## File: `./main_etl.py` +```py +""" +=============================================================================== +FILE: main_etl.py +PROJECT: SCUD Orion AI (Unified Architecture) +ROLE: Главная точка входа ETL-конвейера СКУД ⟷ 1С:ЗУП. +=============================================================================== +""" + +import os +import sys +import argparse +import logging +import pandas as pd +from datetime import datetime, timedelta + +from services.scud_etl.pipeline import load_best_snapshot_for_date, load_1c_files_for_date +from services.scud_etl.merger import merge_scud_and_1c, calculate_summary_metrics +from services.scud_etl.anomaly_detector import detect_registry_anomalies +from services.text_reporter import generate_markdown_report + +from services.scud_export import run_export +from services.share_copier import copy_1c_files_from_share +from services.excel_exporter import generate_summary_excel, generate_detailed_excel + +logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] %(message)s") + + +def main(): + parser = argparse.ArgumentParser(description="Модульный контроллинг СКУД ⟷ 1С") + parser.add_argument("-d", "--debug", action="store_true", help="Режим отладки") + parser.add_argument("--skip-export", action="store_true", help="Пропустить выгрузку СКУД из MS SQL") + parser.add_argument("--snapshot", type=str, default=None, help="ID снапшота для расчета") + args = parser.parse_args() + + print("=" * 60) + print(f"ЗАПУСК СИСТЕМЫ МОДУЛЬНОГО КОНТРОЛЛИНГА СКУД ⟷ 1С {'[DEBUG]' if args.debug else ''}") + print("=" * 60) + + now = datetime.now() + today_str = now.strftime("%d.%m.%Y") + # ⭐️ По понедельникам (weekday == 0) отчетом накануне является пятница (-3 дня) + if now.weekday() == 0: + yesterday_str = (now - timedelta(days=3)).strftime("%d.%m.%Y") + else: + yesterday_str = (now - timedelta(days=1)).strftime("%d.%m.%Y") + + # [Этап 0] Выгрузка свежих данных СКУД + if not args.skip_export and not args.snapshot: + print(f"\n[0/5] Экспорт данных СКУД за {today_str} и {yesterday_str}...") + run_export(debug=args.debug) + else: + print("\n[0/5] Пропуск прямого экспорта СКУД из MS SQL (--skip-export)...") + + # [Этап 0.5] Синхронизация файлов с шары 1С + if not args.snapshot and not args.skip_export: + print(f"\n[0.5/5] Проверка и копирование файлов 1С с шары...") + copy_1c_files_from_share() + else: + print("\n[0.5/5] Пропуск синхронизации с шары (чтение локальных данных)...") + + # [Этап 1-2] Загрузка данных + print(f"\n[1-2/5] Загрузка срезов: Сегодня = {today_str}, Накануне = {yesterday_str}...") + df_scud_yesterday = load_best_snapshot_for_date(yesterday_str, prefer_final_y=True) + df_scud_today = load_best_snapshot_for_date(today_str, prefer_final_y=False) + + df_staff_yesterday, df_abs_yesterday = load_1c_files_for_date(yesterday_str) + df_staff_today, df_abs_today = load_1c_files_for_date(today_str) + + # [Этап 3] Детальный отчет за вчера + print(f"\n[3/5] Обработка и построение детального отчета за ВЧЕРА ({yesterday_str})...") + df_merged_yesterday = merge_scud_and_1c(df_scud_yesterday, df_staff_yesterday, df_abs_yesterday) + generate_detailed_excel(df_merged_yesterday, date_str=yesterday_str) + + # [Этап 4] Сводка за сегодня + print(f"\n[4/5] Обработка и построение Ежедневной сводки за {today_str}...") + df_merged_today = merge_scud_and_1c(df_scud_today, df_staff_today, df_abs_today) + metrics_today = calculate_summary_metrics(df_merged_today) + anomalies_today = detect_registry_anomalies(df_merged_today) + generate_summary_excel(df_merged_today, date_str=today_str) + + # [Этап 5] Формирование Markdown-сводки через ИИ-аудитора + print(f"\n[5/5] Формирование Markdown-сводки через ИИ-аудитора (Ollama)...") + + absent_explained = df_merged_today[ + (df_merged_today['Пришел'] == False) & + (df_merged_today['Вид_отсутствия'].notna()) & + (~df_merged_today['Вид_отсутствия'].astype(str).str.startswith('Исключение')) + ] + absent_unexplained = df_merged_today[ + (df_merged_today['Пришел'] == False) & + (df_merged_today['Вид_отсутствия'].isna() | (df_merged_today['Вид_отсутствия'].astype(str).str.strip() == '')) & + (df_merged_today.get('is_excluded', False) == False) + ] + + summary_md = generate_markdown_report( + merged_df=df_merged_today[df_merged_today.get('is_excluded', False) == False], + absent_explained=absent_explained, + absent_unexplained=absent_unexplained, + scud_present_but_absent_in_1c=pd.DataFrame(), + anomalies_list=anomalies_today, + date_str=today_str + ) + + os.makedirs("output", exist_ok=True) + md_file_path = f"output/Сводка_контроллинга_{today_str}.md" + with open(md_file_path, "w", encoding="utf-8") as f: + f.write(summary_md) + print(f"[✓] Текстовый отчет сохранен в: {md_file_path}") + + print("\n" + "=" * 60) + print("ГОТОВАЯ ТЕКСТОВАЯ СВОДКА ИИ-АУДИТОРА:") + print("=" * 60) + print(summary_md) + + +if __name__ == "__main__": + main() +``` + +## File: `./run_cron_etl.sh` +```bash +#!/bin/bash +set -e + +# Переход в папку проекта +cd /home/puh/projects/scud_ai + +# Создание папки для логов +mkdir -p /home/puh/projects/scud_ai/logs + +# Фиксация старта +echo "==================================================" >> /home/puh/projects/scud_ai/logs/cron_etl.log +echo "[CRON START] $(date '+%Y-%m-%d %H:%M:%S')" >> /home/puh/projects/scud_ai/logs/cron_etl.log +echo "==================================================" >> /home/puh/projects/scud_ai/logs/cron_etl.log + +# Запуск main_etl.py через интерпретатор окружения +/home/puh/scud_orion_ai_v2/venv/bin/python /home/puh/projects/scud_ai/main_etl.py >> /home/puh/projects/scud_ai/logs/cron_etl.log 2>&1 + +# Фиксация окончания +echo "[CRON FINISH] $(date '+%Y-%m-%d %H:%M:%S')" >> /home/puh/projects/scud_ai/logs/cron_etl.log +echo "" >> /home/puh/projects/scud_ai/logs/cron_etl.log +``` + +## File: `./scripts/db_cli.py` +```py +import os +import sys +import argparse +import sqlite3 +import pandas as pd +from datetime import datetime + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from config import DATA_DIR, DATE_TODAY, OUTPUT_DIR, EXCEPTIONS_PATH, normalize_fio +from core.database import ( + get_connection, + get_available_snapshots, + get_all_rules_from_db, + load_scud_from_db_by_snapshot, + get_latest_snapshot_time +) +from services.exceptions_repo import ( + get_all_exceptions_from_db, + add_exception_to_db, + remove_exception_from_db, + sync_json_to_db +) + +DB_PATH = os.path.join(DATA_DIR, "scud_orion_ai.db") + + +def print_tool_actions(): + """Выводит реестр декларативных действий инструментов и шаблоны кнопок.""" + print("\n" + "=" * 110) + print("🧰 ДЕКЛАРАТИВНЫЙ РЕЕСТР ДЕЙСТВИЙ ИНСТРУМЕНТОВ (tool_action_registry):") + print("=" * 110) + with get_connection() as conn: + cursor = conn.cursor() + try: + cursor.execute(""" + SELECT id, tool_name, category, bypass_llm, success_template, follow_up_question, buttons_json + FROM tool_action_registry + WHERE is_active = 1 + ORDER BY id ASC + """) + rows = cursor.fetchall() + if not rows: + print("Таблица tool_action_registry пуста.") + else: + for r in rows: + print(f"ID: {r[0]} | Tool: [{r[1]}] | Категория: {r[2]} | Bypass LLM: {'ДА (0.05с)' if r[3] else 'НЕТ'}") + print(f" • Сообщение: {r[4]}") + if r[5]: + print(f" • Вопрос: {r[5]}") + print(f" • Кнопки: {r[6]}") + print("-" * 110) + except Exception as e: + print(f"Таблица tool_action_registry недоступна: {e}") + print("=" * 110 + "\n") + + +def print_stats(): + """Выводит общую статистику по записям в таблицах БД.""" + print("\n" + "=" * 60) + print("📊 СТАТИСТИКА БАЗЫ ДАННЫХ SQLITE (scud_orion_ai.db):") + print("=" * 60) + with get_connection() as conn: + cursor = conn.cursor() + tables = [ + 'scud_logs', 'zup_staff', 'zup_absences', 'anomalies_history', + 'ai_knowledge_base', 'chat_messages', 'session_states', + 'system_prompt_nodes', 'tasks', 'exceptions_registry' + ] + for t in tables: + try: + cursor.execute(f"SELECT COUNT(*) FROM {t}") + cnt = cursor.fetchone()[0] + print(f" • Таблица [{t:<22}]: {cnt:>6} записей") + except Exception: + pass + print("=" * 60 + "\n") + + +def print_snapshots_list(date_str=None): + """Выводит реестр снапшотов с отображением даты и точного времени среза.""" + rows = get_available_snapshots(date_str) + + print("\n" + "=" * 105) + print(f"📸 РЕЕСТР СОХРАНЕННЫХ СНАПШОТОВ (СВЕРХУ СВЕЖИЕ) {'ЗА ЛОГИ ' + date_str if date_str else ''}:") + print("=" * 105) + + header = f"{'ID снапшота':<16} | {'Дата снапшота (создания)':<24} | {'Дата и время среза':<20} | {'Записей':<8}" + print(header) + print("-" * 105) + + if not rows: + print("Снапшотов пока нет.") + print("=" * 105 + "\n") + return + + def snapshot_sort_key(row): + snap_id = row[0] or "" + snap_time = row[2] or "" + seq_num = 0 + if "-" in snap_id: + parts = snap_id.replace("Y", "").split("-") + if len(parts) > 1 and parts[1].isdigit(): + seq_num = int(parts[1]) + return (snap_time, seq_num) + + sorted_rows = sorted(rows, key=snapshot_sort_key, reverse=True) + + for r in sorted_rows: + snap_id = r[0] if r[0] else '----------' + log_date = r[1] if r[1] else '—' + snap_time = r[2] if r[2] else '—' + count = r[3] + + time_part = "—" + if snap_time and " " in snap_time: + time_part = snap_time.split(" ")[1] + + slice_datetime_str = f"{log_date} {time_part}" if time_part != "—" else log_date + formatted_snap_id = f" {snap_id}" if not snap_id.startswith("Y") else snap_id + + print(f"{formatted_snap_id:<16} | {snap_time:<24} | {slice_datetime_str:<20} | {count:<8}") + + print("=" * 105 + "\n") + + +def delete_snapshot_by_id(snapshot_id: str): + """Удаляет конкретный снапшот из таблицы scud_logs по его ID.""" + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE snapshot_id = ?", (snapshot_id,)) + deleted_count = cursor.rowcount + conn.commit() + print(f"\n[✓] Успешно удален снапшот [{snapshot_id}]. Удалено строк: {deleted_count}\n") + return deleted_count + + +def delete_snapshots_by_date(date_str: str): + """Удаляет все снапшоты за указанную дату (например, '04.08.2026').""" + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE log_date = ? OR snapshot_id LIKE ?", (date_str, f"%{date_str.replace('.', '')}%")) + deleted_count = cursor.rowcount + conn.commit() + print(f"\n[✓] Успешно удалены все снапшоты за дату [{date_str}]. Удалено строк: {deleted_count}\n") + return deleted_count + + +def inspect_scud(snapshot_id=None, date_str=None, export_xlsx=None): + """Инспектирует логи СКУД за выбранный снапшот или дату и опционально сохраняет XLSX.""" + target_date = date_str if date_str else DATE_TODAY + + print("\n" + "=" * 115) + if snapshot_id: + print(f"🔍 ИНСПЕКЦИЯ СКУД ПО СНАПШОТУ [{snapshot_id}] (Дата среза: {target_date}):") + else: + print(f"🔍 ИНСПЕКЦИЯ СКУД ЗА ТЕКУЩУЮ ДАТУ [{target_date}] (ПОСЛЕДНИЙ СРЕЗ):") + print("=" * 115) + + df = load_scud_from_db_by_snapshot(target_date, snapshot_param=snapshot_id) + + if df is None or df.empty: + print("Записи СКУД не найдены.") + print("=" * 115 + "\n") + return + + fio_col = next((c for c in ['Сотрудник', 'fio', 'fio_clean'] if c in df.columns), None) + dept_col = next((c for c in ['Подразделение', 'department_scud', 'department'] if c in df.columns), None) + pos_col = next((c for c in ['Должность', 'position'] if c in df.columns), None) + in_col = next((c for c in ['Начало_дня', 'time_in'] if c in df.columns), None) + first_act_col = next((c for c in ['Первая_активность', 'first_activity'] if c in df.columns), None) + out_col = next((c for c in ['Конец_дня', 'time_out'] if c in df.columns), None) + dur_col = next((c for c in ['Находился_в_здании', 'time_in_building', 'duration'] if c in df.columns), None) + present_col = next((c for c in ['Пришел', 'is_present'] if c in df.columns), None) + anom_col = 'anomaly_flag' if 'anomaly_flag' in df.columns else None + snap_col = 'snapshot_id' if 'snapshot_id' in df.columns else None + + total = len(df) + if present_col: + present_cnt = len(df[df[present_col].astype(str).str.lower().isin(['true', '1'])]) + else: + present_cnt = 0 + absent_cnt = total - present_cnt + + print(f"Всего записей: {total} | Присутствовали: {present_cnt} | Отсутствовали: {absent_cnt}") + print("-" * 115) + + display_cols = [c for c in [fio_col, dept_col, in_col, first_act_col, out_col, dur_col, present_col, anom_col, snap_col] if c] + print(df[display_cols].head(30).to_string(index=False)) + + if len(df) > 30: + print(f"\n... и ещё {len(df) - 30} строк.") + + if export_xlsx: + out_path = export_xlsx if export_xlsx.endswith('.xlsx') else f"{export_xlsx}.xlsx" + if not os.path.isabs(out_path): + out_path = os.path.join(OUTPUT_DIR, out_path) + + df.to_excel(out_path, index=False) + print("\n" + "*" * 115) + print(f"[✓] УСПЕШНЫЙ ЭКСПОРТ ДЕБАГ-ФАЙЛА В EXCEL: {out_path}") + print("*" * 115) + + print("=" * 115 + "\n") + + +def print_absences(date_str=None): + """Выводит список официально отсутствующих сотрудников из 1С:ЗУП за выбранный день.""" + target_date = date_str if date_str else DATE_TODAY + print("\n" + "=" * 90) + print(f"📋 ОФИЦИАЛЬНЫЕ ОТСУТСТВИЯ ИЗ 1С:ЗУП ЗА ДАТУ [{target_date}]:") + print("=" * 90) + + with get_connection() as conn: + df = pd.read_sql_query( + "SELECT fio as 'ФИО', absence_type as 'Причина отсутствия 1С' FROM zup_absences WHERE absence_date = ? ORDER BY absence_type, fio", + conn, + params=(target_date,) + ) + + if df.empty: + print(f"Записи об отсутствиях 1С за {target_date} в базе не найдены.") + else: + print(f"Всего зафиксировано документов 1С: {len(df)}") + print("-" * 90) + print(df.to_string(index=False)) + + print("=" * 90 + "\n") + + +def print_anomalies(): + """Выводит список аномалий СКУД из БД.""" + print("\n" + "=" * 80) + print("🚨 ИСТОРИЯ НАЙДЕННЫХ АНОМАЛИЙ СКУД ⟷ 1С:") + print("=" * 80) + with get_connection() as conn: + df = pd.read_sql_query("SELECT anomaly_date, fio, anomaly_type, details FROM anomalies_history ORDER BY id DESC LIMIT 50", conn) + if df.empty: + print("Аномалии не найдены.") + else: + print(df.to_string(index=False)) + print("=" * 80 + "\n") + + +def print_rules(): + """Выводит правила базы знаний ИИ.""" + rules = get_all_rules_from_db() + print("\n" + "=" * 80) + print("🧠 ПРАВИЛА БАЗЫ ЗНАНИЙ ИИ:") + print("=" * 80) + if not rules: + print("База знаний пуста.") + else: + for idx, r in enumerate(rules, 1): + print(f" {idx}. {r}") + print("=" * 80 + "\n") + + +def dump_all_to_excel(out_filename="db_dump_full.xlsx"): + """Дампит всю базу SQLite во многостраничный Excel.""" + out_path = os.path.join(OUTPUT_DIR, out_filename) + print(f"\n[🔄] Создание полного дампа БД в файл: {out_path} ...") + with get_connection() as conn, pd.ExcelWriter(out_path, engine='openpyxl') as writer: + for table in ['scud_logs', 'zup_staff', 'zup_absences', 'anomalies_history', 'ai_knowledge_base', 'chat_messages', 'session_states', 'system_prompt_nodes', 'tasks', 'exceptions_registry']: + try: + df = pd.read_sql_query(f"SELECT * FROM {table}", conn) + df.to_excel(writer, sheet_name=table[:31], index=False) + except Exception: + pass + print(f"[✓] Дамп успешно сохранен: {out_path}\n") + + +def print_system_prompts(): + """Выводит все системные промпты из базы данных.""" + print("\n" + "=" * 80) + print("📝 СИСТЕМНЫЕ ПРОМПТЫ (system_prompt_nodes):") + print("=" * 80) + with get_connection() as conn: + cursor = conn.cursor() + try: + cursor.execute("SELECT section_id, item_id, content, is_active, updated_at FROM system_prompt_nodes ORDER BY section_id ASC, item_id ASC") + rows = cursor.fetchall() + except Exception: + rows = [] + + if not rows: + print("Таблица system_prompt_nodes пуста.") + else: + for r in rows: + print(f"Раздел {r[0]}.{r[1]} | Active: {r[3]} | Updated: {r[4]}") + print(f" {r[2]}") + print("-" * 80) + print("=" * 80 + "\n") + + +def print_session_states(): + """Выводит текущие активные сессии и превью (session_states).""" + print("\n" + "=" * 80) + print("🔄 АКТИВНЫЕ СЕССИИ И ПРЕВЬЮ (session_states):") + print("=" * 80) + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT session_id, state_type, updated_at, pending_data FROM session_states") + rows = cursor.fetchall() + if not rows: + print("Таблица session_states пуста (нет активных превью).") + else: + for r in rows: + print(f"Session: {r[0]} | Type: {r[1]} | Updated: {r[2]}") + print("-" * 80) + print(f"Pending Data:\n{r[3]}\n") + print("=" * 80 + "\n") + + +def print_chat_messages(session_id=None, limit=50): + """Выводит таблицу истории сообщений чата (контекст).""" + print("\n" + "=" * 105) + print(f"💬 ИСТОРИЯ СООБЩЕНИЙ ЧАТА (chat_messages) {f'для сессии: {session_id}' if session_id else 'все сессии'}:") + print("=" * 105) + + with get_connection() as conn: + cursor = conn.cursor() + if session_id: + cursor.execute(""" + SELECT id, session_id, role, content, is_ephemeral, created_at + FROM chat_messages + WHERE session_id = ? + ORDER BY id ASC + LIMIT ? + """, (session_id, limit)) + else: + cursor.execute(""" + SELECT id, session_id, role, content, is_ephemeral, created_at + FROM chat_messages + ORDER BY id DESC + LIMIT ? + """, (limit,)) + + rows = cursor.fetchall() + if not rows: + print("Таблица chat_messages пуста.") + else: + if not session_id: + rows = list(reversed(rows)) + + for r in rows: + msg_id, sess, role, content, ephemeral, created = r + eph_marker = " [ЭФЕМЕРНОЕ]" if ephemeral else "" + print(f"[{msg_id}] {created} | Сессия: {sess} | Роль: {role.upper()}{eph_marker}") + print("-" * 105) + content_preview = content if content else "" + print(f"{content_preview}") + print("=" * 105) + print("\n") + + +def purge_chat_context(session_id=None, purge_all=False): + """ + Очистка контекста сообщений: + - По умолчанию: удаляет эфемерные сообщения, осиротевшие превью и сбрасывает стейты сессий. + - purge_all=True (--all): полностью очищает всю таблицу chat_messages и сбрасывает сессии. + """ + with get_connection() as conn: + cursor = conn.cursor() + + if purge_all: + if session_id: + cursor.execute("DELETE FROM chat_messages WHERE session_id = ?", (session_id,)) + cursor.execute("DELETE FROM session_states WHERE session_id = ?", (session_id,)) + else: + cursor.execute("DELETE FROM chat_messages") + cursor.execute("DELETE FROM session_states") + deleted_msgs = cursor.rowcount + conn.commit() + print(f"\n[✓] Полная очистка истории выполнена! Удалено сообщений: {deleted_msgs}\n") + return + + query = """ + DELETE FROM chat_messages + WHERE is_ephemeral = 1 + OR content LIKE '%Предпросмотр изменений%' + OR content LIKE '%Удален пункт:%' + OR content LIKE '%добавлен пункт:%' + """ + if session_id: + cursor.execute(query + " AND session_id = ?", (session_id,)) + cursor.execute("DELETE FROM session_states WHERE session_id = ?", (session_id,)) + else: + cursor.execute(query) + cursor.execute("DELETE FROM session_states") + + deleted_msgs = cursor.rowcount + conn.commit() + + print(f"\n[✓] Умная зачистка контекста выполнена! Удалено сообщений: {deleted_msgs}\n") + + +# ⭐️ Новые функции управления исключениями (Exceptions & Whitelist) +def print_exceptions(): + """Выводит реестр исключений и белый список сотрудников из базы SQLite.""" + exc = get_all_exceptions_from_db() + print("\n" + "=" * 80) + print("📋 РЕЕСТР ИСКЛЮЧЕНИЙ И БЕЛЫЙ СПИСОК (exceptions_registry):") + print("=" * 80) + for cat, items in exc.items(): + print(f"[{cat.upper()}] ({len(items)} шт.):") + if items: + for it in items: + print(f" • {it}") + else: + print(" — пусто") + print("-" * 80) + print("=" * 80 + "\n") + + +HELP_TEXT = """ +CLI-утилита инспекции и управления SQLite базой данных СКУД (scud_orion_ai.db) + +ДОСТУПНЫЕ КОМАНДЫ: + stats -- Общая статистика строк по всем таблицам БД + snapshots [ДД.ММ.ГГГГ] -- Посмотреть реестр снапшотов (опционально за конкретную дату) + scud [ДД.ММ.ГГГГ] [--snapshot ID] [--export-xlsx NAME] -- Инспекция логов СКУД по дате/снапшоту и экспорт в Excel + absences [ДД.ММ.ГГГГ] -- Посмотреть список официально отсутствующих из 1С:ЗУП + anomalies -- Посмотреть историю найденных аномалий СКУД ⟷ 1С + rules -- Посмотреть правила Базы Знаний ИИ из SQLite + prompts -- Посмотреть узлы системного промпта (system_prompt_nodes) + tools -- Посмотреть реестр действий инструментов и кнопок (tool_action_registry) + sessions -- Посмотреть активные сессии и превью (session_states) + context [session_id] [--limit N] -- Посмотреть таблицу контекста сообщений чата (chat_messages) + context purge [session_id] [--all] -- Очистить контекст (умная зачистка или полная с флагом --all) + dump [output.xlsx] -- Полный дамп всех таблиц БД в многостраничный Excel + snapshot del [ID] или [--day ДД.ММ.ГГГГ] -- Удаление снапшота по ID или всех за выбранный день + + exceptions [list] -- Посмотреть реестр исключений и белый список (SQLite) + exceptions add -c CATEGORY -v VALUE [-m COMMENT] -- Добавить исключение (fio, include_fio, departments, positions, position_keywords) + exceptions del -c CATEGORY -v VALUE -- Удалить исключение из БД + exceptions sync -- Синхронизировать exceptions.json -> SQLite + +ПРИМЕРЫ ЗАПУСКА: + python scripts/db_cli.py stats + python scripts/db_cli.py snapshots 06.08.2026 + python scripts/db_cli.py scud 06.08.2026 --export-xlsx срез_четверг + python scripts/db_cli.py absences 07.08.2026 + python scripts/db_cli.py prompts + python scripts/db_cli.py tools + python scripts/db_cli.py sessions + python scripts/db_cli.py context web_session_main --limit 20 + python scripts/db_cli.py context purge + python scripts/db_cli.py context purge --all + python scripts/db_cli.py context purge web_session_main --all + python scripts/db_cli.py snapshot del Y20260805-007 + python scripts/db_cli.py dump my_dump.xlsx + python scripts/db_cli.py exceptions + python scripts/db_cli.py exceptions add -c include_fio -v "Тарасенко Александр Александрович" + python scripts/db_cli.py exceptions add -c fio -v "Михалев Сергей Геннадьевич" -m "Уборщик" + python scripts/db_cli.py exceptions del -c fio -v "Михалев Сергей Геннадьевич" + python scripts/db_cli.py exceptions sync +""" + + +def main(): + if any(arg in sys.argv for arg in ['-h', '--help']): + print(HELP_TEXT) + sys.exit(0) + + parser = argparse.ArgumentParser( + description=HELP_TEXT, + formatter_class=argparse.RawDescriptionHelpFormatter, + add_help=False + ) + parser.add_argument('command', nargs='?', default=None, choices=[ + 'stats', 'snapshots', 'scud', 'absences', 'anomalies', + 'rules', 'prompts', 'sessions', 'dump', 'snapshot', + 'tools', 'context', 'exceptions' + ], help="Основная команда") + parser.add_argument('action', nargs='?', default=None, help="Действие ('del', 'purge', 'add', 'sync') или дата/сессия") + parser.add_argument('param', nargs='?', default=None, help="Параметр (дата, ID снапшота, session_id, имя файла)") + parser.add_argument('-c', '--category', type=str, default=None, choices=['departments', 'positions', 'fio', 'position_keywords', 'include_fio'], help="Категория исключения") + parser.add_argument('-v', '--value', type=str, default=None, help="Значение исключения (ФИО, отдел, должность)") + parser.add_argument('-m', '--comment', type=str, default="", help="Комментарий к исключению") + parser.add_argument('--snapshot', type=str, default=None, help="ID конкретного снапшота для инспекции") + parser.add_argument('--export-xlsx', type=str, default=None, help="Экспорт среза СКУД в Excel-файл") + parser.add_argument('--day', type=str, default=None, help="Удалить снапшоты за конкретный день (ДД.ММ.ГГГГ)") + parser.add_argument('--limit', type=int, default=50, help="Лимит выводимых сообщений чата (для команды context)") + parser.add_argument('--all', action='store_true', help="Полная очистка всех сообщений (для команды context purge)") + + if len(sys.argv) == 1: + print_stats() + return + + args = parser.parse_args() + + if args.command == 'stats': + print_stats() + elif args.command == 'snapshots': + date_val = args.action or args.param + print_snapshots_list(date_str=date_val) + elif args.command == 'scud': + date_val = args.action or args.param + inspect_scud(snapshot_id=args.snapshot, date_str=date_val, export_xlsx=args.export_xlsx) + elif args.command == 'absences': + date_val = args.action or args.param + print_absences(date_str=date_val) + elif args.command == 'anomalies': + print_anomalies() + elif args.command == 'rules': + print_rules() + elif args.command == 'prompts': + print_system_prompts() + elif args.command == 'sessions': + print_session_states() + elif args.command == 'tools': + print_tool_actions() + elif args.command == 'context': + if args.action in ['purge', 'clear']: + is_all = args.all or (args.param == '--all') + sess_id = None if (args.param == '--all' or not args.param) else args.param + purge_chat_context(session_id=sess_id, purge_all=is_all) + else: + sess_id = args.action if args.action else None + print_chat_messages(session_id=sess_id, limit=args.limit) + elif args.command == 'dump': + filename = args.action or args.param or "db_dump_full.xlsx" + dump_all_to_excel(filename) + elif args.command == 'snapshot': + if args.action == 'del': + if args.day: + delete_snapshots_by_date(args.day) + elif args.param: + delete_snapshot_by_id(args.param) + else: + print("\n[❌] Ошибка: Не указан ID снапшота или параметр --day для удаления.") + print("Пример: python scripts/db_cli.py snapshot del Y20260805-007\n") + else: + print(f"\n[❌] Ошибка: Неизвестное действие '{args.action}' для команды snapshot.") + print("Используйте: python scripts/db_cli.py snapshot del [ID или --day 'ДД.ММ.ГГГГ']\n") + elif args.command == 'exceptions': + if args.action == 'add': + if not args.category or not args.value: + print("\n[❌] Ошибка: Для добавления исключения укажите флаги -c/--category и -v/--value") + print("Пример: python scripts/db_cli.py exceptions add -c include_fio -v \"Тарасенко Александр Александрович\"\n") + return + if add_exception_to_db(args.category, args.value, args.comment): + print(f"\n[✓] Успешно добавлено исключение: [{args.category}] {args.value}\n") + else: + print(f"\n[❌] Ошибка добавления исключения [{args.category}] {args.value}\n") + elif args.action in ['del', 'delete', 'remove']: + if not args.category or not args.value: + print("\n[❌] Ошибка: Для удаления исключения укажите флаги -c/--category и -v/--value") + print("Пример: python scripts/db_cli.py exceptions del -c fio -v \"Михалев Сергей Геннадьевич\"\n") + return + if remove_exception_from_db(args.category, args.value): + print(f"\n[✓] Успешно удалено исключение: [{args.category}] {args.value}\n") + else: + print(f"\n[⚠️] Запись не найдена в базе: [{args.category}] {args.value}\n") + elif args.action == 'sync': + sync_json_to_db() + print("\n[✓] Синхронизация exceptions.json -> SQLite успешно завершена.\n") + else: + print_exceptions() + else: + print("\n[❌] Ошибка: Неизвестная команда.") + print(HELP_TEXT) + + +if __name__ == "__main__": + main() +``` + +## File: `./core/connection.py` +```py +""" +=============================================================================== +FILE: core/connection.py +PROJECT: SCUD Orion AI (Unified Architecture) +ROLE: Единый менеджер подключений к базе данных SQLite (WAL mode, timeouts). +=============================================================================== +""" + +import os +import sqlite3 +from config import DATA_DIR + +DB_PATH = os.path.join(DATA_DIR, "scud_orion_ai.db") + + +def get_connection(row_factory: bool = False) -> sqlite3.Connection: + """ + Создает оптимизированное подключение к SQLite. + row_factory=True возвращает sqlite3.Row для доступа к полям по имени. + """ + conn = sqlite3.connect(DB_PATH, timeout=30.0) + if row_factory: + conn.row_factory = sqlite3.Row + conn.execute("PRAGMA foreign_keys = ON;") + conn.execute("PRAGMA journal_mode = WAL;") + conn.execute("PRAGMA synchronous = NORMAL;") + return conn +``` + +## File: `./core/database.py` +```py +""" +=============================================================================== +FILE: core/database.py +ROLE: Фасад ядра базы данных с полной обратной совместимостью импортов. +=============================================================================== +""" + +from core.connection import get_connection, DB_PATH +from core.schema import init_all_tables + +from core.repositories.scud_repo import ( + has_scud_logs_for_date, + has_yesterday_final_snapshot, + get_or_create_snapshot_id, + save_scud_to_db, + get_latest_snapshot_time, + load_scud_from_db_by_snapshot, + get_available_snapshots, + delete_snapshot_by_id, + delete_snapshots_by_date +) + +from core.repositories.zup_repo import ( + save_staff_to_db, + load_staff_from_db, + save_absences_to_db, + load_absences_from_db, + save_anomalies_to_db, + get_all_rules_from_db, + add_rule_to_db, + get_department_synonyms_dict, + add_department_synonym_to_db +) + +init_db = init_all_tables +``` + +## File: `./core/schema.py` +```py +""" +=============================================================================== +FILE: core/schema.py +PROJECT: SCUD Orion AI (Unified Architecture) +ROLE: DDL-схемы таблиц, создание индексов и инициализация базы данных. +=============================================================================== +""" + +import logging +from core.connection import get_connection + +logger = logging.getLogger("DB_SCHEMA") + + +def init_all_tables() -> None: + """Инициализирует все таблицы и индексы системы.""" + with get_connection() as conn: + cursor = conn.cursor() + + # 1. Логи СКУД + cursor.execute(""" + CREATE TABLE IF NOT EXISTS scud_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + log_date TEXT NOT NULL, + fio TEXT NOT NULL, + fio_clean TEXT NOT NULL, + 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, + snapshot_id TEXT DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 2. Кадровые реестры 1С + cursor.execute(""" + CREATE TABLE IF NOT EXISTS zup_staff ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + snapshot_date TEXT NOT NULL, + fio TEXT NOT NULL, + fio_clean TEXT NOT NULL, + department TEXT, + position TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS zup_absences ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + absence_date TEXT NOT NULL, + fio TEXT NOT NULL, + fio_clean TEXT NOT NULL, + absence_type TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 3. Аномалии и база знаний + cursor.execute(""" + CREATE TABLE IF NOT EXISTS anomalies_history ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + anomaly_date TEXT NOT NULL, + fio TEXT NOT NULL, + anomaly_type TEXT NOT NULL, + details TEXT NOT NULL, + human_status TEXT DEFAULT 'Pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS ai_knowledge_base ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + rule_text TEXT UNIQUE NOT NULL, + added_by TEXT DEFAULT 'Human', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS department_synonyms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + short_name TEXT UNIQUE NOT NULL, + full_name TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 4. Узлы системного промпта и сессии + cursor.execute(""" + CREATE TABLE IF NOT EXISTS system_prompt_nodes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + prompt_name TEXT DEFAULT 'main_agent', + section_id INTEGER NOT NULL, + item_id INTEGER NOT NULL, + content TEXT NOT NULL, + is_active INTEGER DEFAULT 1, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(prompt_name, section_id, item_id) + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS session_states ( + session_id TEXT PRIMARY KEY, + state_type TEXT NOT NULL, + pending_data TEXT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS chat_messages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL, + role TEXT NOT NULL, + content TEXT NOT NULL, + is_ephemeral INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS exceptions_registry ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + category TEXT NOT NULL, -- 'department', 'position', 'fio', 'position_keyword', 'include_fio', 'remote_worker' + value TEXT NOT NULL, + comment TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(category, value) + ); + """) + + # 5. Задачи + cursor.execute(""" + CREATE TABLE IF NOT EXISTS tasks ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + task_id TEXT, + module TEXT DEFAULT 'general', + title TEXT NOT NULL, + priority TEXT DEFAULT 'MEDIUM', + status TEXT DEFAULT 'BACKLOG', + due_date TEXT, + user_id INTEGER DEFAULT 1, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + """) + + # 6. Индексы + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_date ON scud_logs(log_date);") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_fio ON scud_logs(fio_clean);") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scud_snapshot ON scud_logs(snapshot_time);") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_prompt_nodes ON system_prompt_nodes(prompt_name, section_id, item_id);") + + conn.commit() +``` + +## File: `./core/repositories/scud_repo.py` +```py +""" +=============================================================================== +FILE: core/repositories/scud_repo.py +ROLE: Репозиторий логов СКУД, сохранение и загрузка снапшотов. +=============================================================================== +""" + +from datetime import datetime +import pandas as pd +from core.connection import get_connection + + +def has_scud_logs_for_date(date_str: str) -> bool: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT 1 FROM scud_logs WHERE log_date = ? LIMIT 1", (date_str,)) + return cursor.fetchone() is not None + + +def has_yesterday_final_snapshot(date_str: str) -> bool: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute( + "SELECT 1 FROM scud_logs WHERE log_date = ? AND (snapshot_id LIKE 'Y%' OR snapshot_time LIKE '%22:00:00') LIMIT 1", + (date_str,) + ) + return cursor.fetchone() is not None + + +def get_or_create_snapshot_id(snapshot_time: str, date_str: str = None, is_yesterday: bool = False) -> str: + try: + dt_snap = datetime.strptime(snapshot_time, "%Y-%m-%d %H:%M:%S").date() + date_prefix = dt_snap.strftime("%Y%m%d") + except (ValueError, TypeError): + dt_snap = datetime.now().date() + date_prefix = dt_snap.strftime("%Y%m%d") + + if date_str: + try: + dt_log = datetime.strptime(date_str, "%d.%m.%Y").date() + if dt_log < dt_snap: + is_yesterday = True + except Exception: + pass + + prefix = "Y" if is_yesterday else "" + + with get_connection() as conn: + cursor = conn.cursor() + if date_str: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_time = ? AND snapshot_id IS NOT NULL LIMIT 1", + (date_str, snapshot_time) + ) + else: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE snapshot_time = ? AND snapshot_id IS NOT NULL LIMIT 1", + (snapshot_time,) + ) + + row = cursor.fetchone() + if row and row[0]: + return row[0] + + cursor.execute(""" + SELECT snapshot_id FROM scud_logs + WHERE snapshot_id LIKE ? OR snapshot_id LIKE ? + ORDER BY snapshot_id DESC LIMIT 1 + """, (f"{date_prefix}-%", f"Y{date_prefix}-%")) + + last_row = cursor.fetchone() + next_seq = 1 + if last_row and last_row[0]: + parts = last_row[0].replace("Y", "").split("-") + if len(parts) > 1 and parts[1].isdigit(): + next_seq = int(parts[1]) + 1 + + return f"{prefix}{date_prefix}-{next_seq:03d}" + + +def save_scud_to_db(df_scud: pd.DataFrame, date_str: str, snapshot_time: str = None, is_yesterday: bool = False) -> None: + if df_scud is None or df_scud.empty: + return + + if not snapshot_time: + snapshot_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + snapshot_id = get_or_create_snapshot_id(snapshot_time, date_str=date_str, is_yesterday=is_yesterday) + + data_to_insert = [ + ( + date_str, + r.get('Сотрудник', r.get('fio_raw', '')), + r.get('fio_clean', ''), + r.get('Подразделение', ''), + r.get('Должность', ''), + r.get('Начало_дня', 'Нет входа'), + r.get('Первая_активность', '—'), + r.get('Конец_дня', 'Нет выхода'), + r.get('Находился_в_здании', '00:00'), + 1 if r.get('Пришел', False) else 0, + r.get('anomaly_flag', 'NONE'), + snapshot_time, + snapshot_id + ) + for _, r in df_scud.iterrows() + ] + + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE log_date = ? AND snapshot_time = ?", (date_str, snapshot_time)) + cursor.executemany(""" + 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, snapshot_id + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, data_to_insert) + conn.commit() + + +def get_latest_snapshot_time(date_str: str = None): + with get_connection() as conn: + cursor = conn.cursor() + if date_str: + cursor.execute("SELECT snapshot_time FROM scud_logs WHERE log_date = ? AND snapshot_time IS NOT NULL ORDER BY snapshot_time DESC LIMIT 1", (date_str,)) + else: + cursor.execute("SELECT snapshot_time FROM scud_logs WHERE snapshot_time IS NOT NULL ORDER BY snapshot_time DESC LIMIT 1") + row = cursor.fetchone() + return row[0] if row else None + + +def load_scud_from_db_by_snapshot(date_str: str, snapshot_param: str = None) -> pd.DataFrame: + with get_connection() as conn: + df = pd.DataFrame() + + # 1. Если передан конкретный ID снапшота (например 'Y20260820-004') + if snapshot_param: + df = pd.read_sql_query( + "SELECT * FROM scud_logs WHERE snapshot_id = ?", + conn, params=(str(snapshot_param),) + ) + + # 2. Если ищем за дату (для вчерашнего дня строго ищем Y-снапшот) + if df.empty and date_str: + cursor = conn.cursor() + + # ⭐️ Жесткий приоритет 1: Ищем снапшот с префиксом 'Y' + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_id LIKE 'Y%' ORDER BY snapshot_time DESC, id DESC LIMIT 1", + (date_str,) + ) + row = cursor.fetchone() + + # Приоритет 2: Если Y нет (например, за сегодня), берем самый свежий по времени + if not row: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? ORDER BY snapshot_time DESC, id DESC LIMIT 1", + (date_str,) + ) + row = cursor.fetchone() + + if row and row[0]: + target_id = row[0] + df = pd.read_sql_query( + "SELECT * FROM scud_logs WHERE snapshot_id = ?", + conn, params=(target_id,) + ) + + if not df.empty: + rename_map = { + 'department': 'department_scud', + 'position': 'Должность', + 'fio': 'Сотрудник', + 'time_in': 'Начало_дня', + 'first_activity': 'Первая_активность', + 'time_out': 'Конец_дня', + 'time_in_building': 'Находился_в_здании', + 'is_present': 'Пришел' + } + df = df.rename(columns={k: v for k, v in rename_map.items() if k in df.columns}) + if 'department_scud' in df.columns and 'Подразделение' not in df.columns: + df['Подразделение'] = df['department_scud'] + + for col in ['Пришел', 'Начало_дня', 'Первая_активность', 'Конец_дня', 'Находился_в_здании', 'anomaly_flag']: + if col not in df.columns: + df[col] = False if col == 'Пришел' else '—' + if 'Пришел' in df.columns: + df['Пришел'] = df['Пришел'].astype(bool) + + return df + + +def get_available_snapshots(date_str: str = None): + with get_connection() as conn: + cursor = conn.cursor() + query = """ + SELECT snapshot_id, log_date, snapshot_time, COUNT(*) as cnt + FROM scud_logs + WHERE snapshot_time IS NOT NULL + """ + params = [] + if date_str: + query += " AND log_date = ?" + params.append(date_str) + query += " GROUP BY snapshot_id, log_date, snapshot_time ORDER BY snapshot_time DESC" + cursor.execute(query, params) + return cursor.fetchall() + + +def delete_snapshot_by_id(snapshot_id: str) -> int: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE snapshot_id = ?", (snapshot_id,)) + cnt = cursor.rowcount + conn.commit() + return cnt + + +def delete_snapshots_by_date(date_str: str) -> int: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM scud_logs WHERE log_date = ? OR snapshot_id LIKE ?", (date_str, f"%{date_str.replace('.', '')}%")) + cnt = cursor.rowcount + conn.commit() + return cnt +``` + +## File: `./core/repositories/zup_repo.py` +```py +""" +=============================================================================== +FILE: core/repositories/zup_repo.py +ROLE: Репозиторий кадровых данных 1С:ЗУП, аномалий и базы знаний. +=============================================================================== +""" + +import pandas as pd +from typing import List, Dict, Any +from core.connection import get_connection + + +def save_staff_to_db(df_staff: pd.DataFrame, date_str: str) -> None: + if df_staff is None or df_staff.empty: + return + data = [ + (date_str, r.get('ФИО', ''), r.get('fio_clean', ''), r.get('Подразделение', ''), r.get('Должность', '')) + for _, r in df_staff.iterrows() + ] + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM zup_staff WHERE snapshot_date = ?", (date_str,)) + cursor.executemany("INSERT INTO zup_staff (snapshot_date, fio, fio_clean, department, position) VALUES (?, ?, ?, ?, ?)", data) + conn.commit() + + +def load_staff_from_db(date_str: str) -> pd.DataFrame: + with get_connection() as conn: + df = pd.read_sql_query( + "SELECT fio as 'ФИО', fio_clean, department as 'Подразделение', position as 'Должность' FROM zup_staff WHERE snapshot_date = ?", + conn, params=(date_str,) + ) + return df if not df.empty else None + + +def save_absences_to_db(df_absent: pd.DataFrame, date_str: str) -> None: + if df_absent is None or df_absent.empty: + return + data = [ + (date_str, r.get('ФИО', r.get('fio_clean', '')), r.get('fio_clean', ''), r.get('Вид_отсутствия', '')) + for _, r in df_absent.iterrows() + ] + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM zup_absences WHERE absence_date = ?", (date_str,)) + cursor.executemany("INSERT INTO zup_absences (absence_date, fio, fio_clean, absence_type) VALUES (?, ?, ?, ?)", data) + conn.commit() + + +def load_absences_from_db(date_str: str) -> pd.DataFrame: + with get_connection() as conn: + df = pd.read_sql_query( + "SELECT fio as 'ФИО', fio_clean, absence_type as 'Вид_отсутствия' FROM zup_absences WHERE absence_date = ?", + conn, params=(date_str,) + ) + return df if not df.empty else None + + +def save_anomalies_to_db(anomalies_list: List[Dict[str, Any]], date_str: str) -> None: + if not anomalies_list: + return + data = [(date_str, a.get('fio', ''), a.get('type', ''), a.get('details', '')) for a in anomalies_list] + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM anomalies_history WHERE anomaly_date = ?", (date_str,)) + cursor.executemany("INSERT INTO anomalies_history (anomaly_date, fio, anomaly_type, details) VALUES (?, ?, ?, ?)", data) + conn.commit() + + +def get_all_rules_from_db() -> List[str]: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT rule_text FROM ai_knowledge_base") + return [r[0] for r in cursor.fetchall()] + + +def add_rule_to_db(rule_text: str, added_by: str = "Human") -> None: + if not rule_text or not rule_text.strip(): + return + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("INSERT OR IGNORE INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", (rule_text.strip(), added_by)) + conn.commit() + + +def get_department_synonyms_dict() -> Dict[str, str]: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT LOWER(short_name), LOWER(full_name) FROM department_synonyms") + return {row[0]: row[1] for row in cursor.fetchall()} + + +def add_department_synonym_to_db(short_name: str, full_name: str) -> None: + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("INSERT OR REPLACE INTO department_synonyms (short_name, full_name) VALUES (?, ?)", (short_name.strip().lower(), full_name.strip().lower())) + conn.commit() +``` + +## File: `./services/data_loader.py` +```py +""" +=============================================================================== +FILE: services/data_loader.py +ROLE: Надежная загрузка штата и отсутствий (MS SQL ЗУП -> Резервный Excel). +=============================================================================== +""" + +import os +import warnings +import pandas as pd +from config import ( + normalize_fio, clean_scud_fio_light, load_exceptions, + DATE_TODAY, DATE_YESTERDAY, find_dated_file, ZUP_1C_DIR, SCUD_DIR, DATA_DIR +) +from services.zup_extractor import fetch_zup_absences_from_sql +from core.database import ( + load_scud_from_db_by_snapshot, + load_staff_from_db, + load_absences_from_db +) + +warnings.filterwarnings('ignore', category=UserWarning, module='pandas') + + +def load_staff_data(date_str): + """Загружает файл Штатного расписания 1С.""" + filepath = find_dated_file("Штат", date_str) + if not filepath: + fallback_path = os.path.join(ZUP_1C_DIR, "штат.xlsx") + if os.path.exists(fallback_path): + filepath = fallback_path + else: + return None + + try: + df_raw = pd.read_excel(filepath, skiprows=8) + df_staff = df_raw.iloc[:, [1, 5, 12]].copy() + df_staff.columns = ['ФИО', 'Подразделение', 'Должность'] + + df_staff = df_staff.dropna(subset=['ФИО']).reset_index(drop=True) + df_staff = df_staff[~df_staff['ФИО'].astype(str).str.contains('Всего|Организация|Сотрудник|ФИО', case=False, na=False)] + df_staff['fio_clean'] = df_staff['ФИО'].apply(normalize_fio) + return df_staff + except Exception as e: + print(f"[❌] Ошибка загрузки штата из {filepath}: {e}") + return None + + +def load_absent_from_excel(date_str): + """Резервное чтение файла Отсутствия_ДД_ММ_ГГГГ.xlsx.""" + filepath = find_dated_file("Отсутствия", date_str) + if not filepath: + return None + + try: + for skip in [0, 1, 2, 3, 4, 5, 8]: + df_try = pd.read_excel(filepath, skiprows=skip) + fio_col = None + reason_col = None + for col in df_try.columns: + c_str = str(col).lower() + if ('фио' in c_str or 'сотрудник' in c_str) and fio_col is None: + fio_col = col + if ('вид' in c_str or 'причина' in c_str or 'отсутств' in c_str) and reason_col is None: + reason_col = col + + if fio_col and reason_col: + df_res = df_try[[fio_col, reason_col]].copy() + df_res.columns = ['ФИО', 'Вид_отсутствия'] + df_res = df_res.dropna(subset=['ФИО', 'Вид_отсутствия']) + df_res = df_res[~df_res['ФИО'].astype(str).str.contains('Всего|Организация|Сотрудник|ФИО|ЛЕНМОРНИИПРОЕКТ', case=False, na=False)] + df_res['fio_clean'] = df_res['ФИО'].apply(normalize_fio) + print(f" [✓] Резервный Excel: загружено {len(df_res)} записей отсутствий из {os.path.basename(filepath)}") + return df_res[['fio_clean', 'Вид_отсутствия']].dropna(subset=['fio_clean']) + except Exception as e: + print(f" [⚠️] Ошибка чтения резервного Excel отсутствий {filepath}: {e}") + + return None + + +def load_absent_data(date_str): + """ + Загружает отсутствия из MS SQL 1С:ЗУП, а при сбое — из локального Excel. + """ + df_absent = None + try: + df_absent = fetch_zup_absences_from_sql(date_str) + if df_absent is not None and not df_absent.empty: + print(f" [✓] MS SQL ЗУП: получено {len(df_absent)} записей отсутствий за {date_str}") + df_absent = df_absent.dropna(subset=['ФИО', 'Вид_отсутствия']) + df_absent = df_absent[~df_absent['ФИО'].astype(str).str.contains('АО "ЛЕНМОРНИИПРОЕКТ"|Сотрудник', case=False, na=False)] + df_absent['fio_clean'] = df_absent['ФИО'].apply(normalize_fio) + df_absent = df_absent[['fio_clean', 'Вид_отсутствия']].dropna(subset=['fio_clean']) + except Exception as e: + print(f" [⚠️] Ошибка подключения к MS SQL ЗУП за {date_str}: {e}") + + # Резервный источник: Excel файл из 1С с сетевой шары + if df_absent is None or df_absent.empty: + df_absent = load_absent_from_excel(date_str) + + if df_absent is None: + df_absent = pd.DataFrame(columns=['fio_clean', 'Вид_отсутствия']) + + # Обогащение удаленщиками из static_reason_workers.csv + try: + static_path = os.path.join(DATA_DIR, "static_reason_workers.csv") + if os.path.exists(static_path): + df_static = pd.read_csv(static_path, encoding='utf-8') + if 'fio' in df_static.columns and 'reason' in df_static.columns: + df_static['fio_clean'] = df_static['fio'].apply(normalize_fio) + existing_fios = set(df_absent['fio_clean'].dropna().tolist()) if not df_absent.empty else set() + + new_rows = [] + for _, s_row in df_static.iterrows(): + if s_row['fio_clean'] not in existing_fios: + new_rows.append({ + 'fio_clean': s_row['fio_clean'], + 'Вид_отсутствия': s_row['reason'] + }) + if new_rows: + df_absent = pd.concat([df_absent, pd.DataFrame(new_rows)], ignore_index=True) + print(f" [✓] Реестр удаленщиков: добавлено {len(new_rows)} чел. из static_reason_workers.csv") + except Exception as e: + print(f" [⚠️] Ошибка чтения static_reason_workers.csv: {e}") + + return df_absent if not df_absent.empty else None + + +def load_1c_data_smart(date_str, use_db=False): + df_staff = None + df_absent = None + + if use_db: + df_staff = load_staff_from_db(date_str) + df_absent = load_absences_from_db(date_str) + + if df_staff is None: + df_staff = load_staff_data(date_str) + if df_absent is None: + df_absent = load_absent_data(date_str) + + return df_staff, df_absent +``` + +## File: `./services/scud_export.py` +```py +""" +Модуль автоматического экспорта данных СКУД (Orion) из MS SQL Server в SQLite и Excel. +Добавлена фиксация Первой Активности (без учета направления) и среза по времени. +""" + +import argparse +import logging +import os +import sys +import warnings +from datetime import datetime, timedelta + +import pandas as pd +import pyodbc +from openpyxl.utils import get_column_letter + +from config import SCUD_DIR, clean_scud_fio_light, load_exceptions +from core.database import save_scud_to_db, has_scud_logs_for_date, has_yesterday_final_snapshot + +warnings.filterwarnings("ignore", message="pandas only supports SQLAlchemy connectable") + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +LOG_DIR = os.path.join(SCRIPT_DIR, "..", "logs") +os.makedirs(LOG_DIR, exist_ok=True) + +TODAY_DATE_STR = datetime.now().strftime("%d.%m.%Y") +LOG_FILE = os.path.join(LOG_DIR, f"export_{TODAY_DATE_STR}.log") + +logger = logging.getLogger("scud_export") +logger.setLevel(logging.INFO) +logger.propagate = False + +if not logger.handlers: + _file_handler = logging.FileHandler(LOG_FILE, encoding="utf-8") + _console_handler = logging.StreamHandler(sys.stdout) + _formatter = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") + _file_handler.setFormatter(_formatter) + _console_handler.setFormatter(_formatter) + logger.addHandler(_file_handler) + logger.addHandler(_console_handler) + + +def log(message: str, level: str = "INFO"): + level_map = { + "INFO": logging.INFO, + "ERROR": logging.ERROR, + "WARNING": logging.WARNING, + "SUCCESS": logging.INFO, + } + if level == "SUCCESS": + logger.info(f"[SUCCESS] {message}") + else: + logger.log(level_map.get(level, logging.INFO), message) + + +SERVER_NAME = r"172.16.200.147\SQL" +DATABASE_NAME = "Orion-14.01.21-1" +SQL_USER = "sa" +SQL_PASSWORD = "123456" +ODBC_DRIVER = "ODBC Driver 18 for SQL Server" + +SQL_QUERY_TEMPLATE = r""" +DECLARE @InputDate DATE = '{target_date}'; +DECLARE @TargetDate DATE = @InputDate; + +DECLARE @StartDate DATETIME = CAST(@TargetDate AS DATETIME); +DECLARE @EndDate DATETIME = DATEADD(SECOND, -1, DATEADD(DAY, 1, @StartDate)); + +WITH DailyLogs AS ( + SELECT + log.HozOrgan AS EmployeeID, + log.TimeVal, + log.Event, + log.Mode, + CASE + WHEN log.Mode = 2 OR log.Event IN (29, 27, 33) THEN 'OUT' + WHEN log.Mode = 1 OR log.Event IN (28, 26, 32) THEN 'IN' + ELSE 'OTHER' + END AS Direction, + ROW_NUMBER() OVER (PARTITION BY log.HozOrgan ORDER BY log.TimeVal DESC) AS RowNumDesc + FROM pLogData log WITH (NOLOCK) + WHERE log.TimeVal BETWEEN @StartDate AND @EndDate + AND log.HozOrgan IS NOT NULL + AND log.HozOrgan > 0 + AND log.Event IN (26, 27, 28, 29, 32, 33, 54, 55, 64, 65) +), +Passages AS ( + SELECT + EmployeeID, + MIN(TimeVal) AS FirstRawEvent, + MAX(TimeVal) AS LastRawEvent, + MIN(CASE WHEN Direction = 'IN' THEN TimeVal END) AS FirstIn, + MAX(CASE WHEN Direction = 'OUT' THEN TimeVal END) AS LastOut, + MAX(CASE WHEN RowNumDesc = 1 THEN Direction END) AS LastEventType + FROM DailyLogs + GROUP BY EmployeeID +) +SELECT + N'ЛЕНМОРНИИПРОЕКТ' AS [Фирма], + ISNULL(CAST(div.Name AS NVARCHAR(255)), N'Без подразделения') AS [Подразделение], + LTRIM(RTRIM( + ISNULL(CAST(p.Name AS NVARCHAR(255)), N'') + + CASE WHEN p.FirstName IS NOT NULL AND CAST(p.FirstName AS NVARCHAR(255)) <> '' + THEN N' ' + CAST(p.FirstName AS NVARCHAR(255)) ELSE N'' END + + CASE WHEN p.MidName IS NOT NULL AND CAST(p.MidName AS NVARCHAR(255)) <> '' + THEN N' ' + CAST(p.MidName AS NVARCHAR(255)) ELSE N'' END + )) AS [Сотрудник], + ISNULL(CAST(post.Name AS NVARCHAR(255)), N'—') AS [Должность], + ISNULL(CAST(p.TabNumber AS NVARCHAR(50)), N'—') AS [Таб_№], + CONVERT(VARCHAR(10), @TargetDate, 104) AS [Дата], + ISNULL(CAST(CONVERT(VARCHAR(8), pass.FirstIn, 108) AS NVARCHAR(20)), N'Нет входа') AS [Начало_дня], + CASE + WHEN pass.FirstIn IS NULL AND pass.FirstRawEvent IS NOT NULL + THEN CAST(CONVERT(VARCHAR(8), pass.FirstRawEvent, 108) AS NVARCHAR(20)) + ELSE N'—' + END AS [Первая_активность], + CASE + WHEN @TargetDate = CAST(GETDATE() AS DATE) AND (pass.LastEventType = 'IN' OR pass.LastOut IS NULL OR pass.LastOut <= pass.FirstIn) + THEN N'Нет выхода' + WHEN pass.LastOut IS NOT NULL AND pass.LastOut > pass.FirstIn + THEN CAST(CONVERT(VARCHAR(8), pass.LastOut, 108) AS NVARCHAR(20)) + WHEN @TargetDate < CAST(GETDATE() AS DATE) AND pass.LastRawEvent IS NOT NULL AND pass.LastRawEvent > ISNULL(pass.FirstIn, pass.FirstRawEvent) + THEN CAST(CONVERT(VARCHAR(8), pass.LastRawEvent, 108) AS NVARCHAR(20)) + ELSE N'Нет выхода' + END AS [Конец_дня], + CASE + WHEN pass.EmployeeID IS NOT NULL AND (pass.FirstIn IS NOT NULL OR pass.FirstRawEvent IS NOT NULL) THEN + RIGHT('0' + CAST(DATEDIFF(MINUTE, + ISNULL(pass.FirstIn, pass.FirstRawEvent), + CASE + WHEN @TargetDate = CAST(GETDATE() AS DATE) AND (pass.LastEventType = 'IN' OR pass.LastOut IS NULL OR pass.LastOut <= pass.FirstIn) THEN GETDATE() + ELSE ISNULL(pass.LastOut, pass.LastRawEvent) + END) / 60 AS VARCHAR), 2) + ':' + + RIGHT('0' + CAST(DATEDIFF(MINUTE, + ISNULL(pass.FirstIn, pass.FirstRawEvent), + CASE + WHEN @TargetDate = CAST(GETDATE() AS DATE) AND (pass.LastEventType = 'IN' OR pass.LastOut IS NULL OR pass.LastOut <= pass.FirstIn) THEN GETDATE() + ELSE ISNULL(pass.LastOut, pass.LastRawEvent) + END) % 60 AS VARCHAR), 2) + ELSE N'00:00' + END AS [Находился_в_здании], + CASE + WHEN pass.EmployeeID IS NOT NULL THEN N'Присутствовал' + ELSE N'Отсутствовал (Нет событий)' + END AS [Статус] +FROM pList p WITH (NOLOCK) +LEFT JOIN PDivision div WITH (NOLOCK) ON p.Section = div.ID +LEFT JOIN PPost post WITH (NOLOCK) ON p.Post = post.ID +LEFT JOIN Passages pass ON p.ID = pass.EmployeeID +WHERE + ISNULL(p.StatusRecord, 0) = 0 + AND p.DateTimeInArchive IS NULL + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Аренд%' + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT IN (N'Без подразделения', N'') + AND p.Name NOT LIKE N'бр.%' + AND p.Name NOT LIKE N'Гость%' + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT IN (N'БГИ', N'КНР') + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Рабоч%' + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Врем%' + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'Практика%' + AND ISNULL(CAST(div.Name AS NVARCHAR(255)), N'') NOT LIKE N'тест%' + AND ISNULL(CAST(post.Name AS NVARCHAR(255)), N'') NOT LIKE N'Практикант%' +ORDER BY p.Name ASC; +""" + + +def auto_fit_columns(file_path: str, sheet_name: str, padding: float = 2.0, min_width: float = 8.0, max_width: float = 60.0): + from openpyxl import load_workbook + + wb = load_workbook(file_path) + ws = wb[sheet_name] + + for col_cells in ws.columns: + max_len = 0 + col_letter = get_column_letter(col_cells[0].column) + for cell in col_cells: + if cell.value is not None: + cell_len = len(str(cell.value)) + if cell_len > max_len: + max_len = cell_len + width = max(min_width, min(max_len + padding, max_width)) + ws.column_dimensions[col_letter].width = width + + wb.save(file_path) + + +def get_targets(input_date: str | None): + targets = [] + if input_date: + try: + parsed = datetime.strptime(input_date, "%d.%m.%Y").date() + targets.append({"name": "Указанная дата", "date": parsed}) + except ValueError: + log(f"ОШИБКА: Неверный формат даты '{input_date}'. Используйте ДД.ММ.ГГГГ", "ERROR") + sys.exit(1) + else: + now = datetime.now() + yesterday = (now - timedelta(days=3 if now.weekday() == 0 else 1)).date() + today = now.date() + + targets.append({"name": "Вчера", "date": yesterday}) + targets.append({"name": "Сегодня", "date": today}) + + return targets + + +def run_export(input_date: str | None = None, save_xlsx: bool = True, debug: bool = False): + if debug: + logger.setLevel(logging.DEBUG) + log("=== ВКЛЮЧЕН РЕЖИМ ОТЛАДКИ (DEBUG MODE) ===", "WARNING") + + log("=== [ЭТАП 0] Выгрузка свежих данных СКУД напрямую из БД Орион ===") + os.makedirs(SCUD_DIR, exist_ok=True) + + targets = get_targets(input_date) + conn_str = ( + f"DRIVER={{{ODBC_DRIVER}}};" + f"SERVER={SERVER_NAME};" + f"DATABASE={DATABASE_NAME};" + f"UID={SQL_USER};" + f"PWD={SQL_PASSWORD};" + f"TrustServerCertificate=yes;" + f"Encrypt=no;" + ) + + success = True + for target in targets: + processing_date = target["date"] + processing_date_str = processing_date.strftime("%d.%m.%Y") + period_label = target["name"] + is_yesterday = (period_label == "Вчера") + + # ⚡️ ПРОВЕРКА НАЛИЧИЯ ВЧЕРАШНЕГО ДНЯ В SQLITE: + # Если это вчерашний день и его снапшот уже зафиксирован в SQLite — пропускаем тяжелый запрос к MS SQL + if is_yesterday and has_yesterday_final_snapshot(processing_date_str): + log(f"[ℹ️] Вчерашний день ({processing_date_str}) уже зафиксирован финишным снапшотом Y. Пропускаем запрос к MS SQL.") + continue + + if is_yesterday: + snapshot_time = f"{processing_date.strftime('%Y-%m-%d')} 22:00:00" + else: + snapshot_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + log(f"--- Обработка периода: {period_label} ({processing_date_str}) --- [Снапшот: {snapshot_time}]") + sql_query = SQL_QUERY_TEMPLATE.format(target_date=processing_date.strftime("%Y-%m-%d")) + + connection = None + try: + connection = pyodbc.connect(conn_str, timeout=120) + df = pd.read_sql(sql_query, connection) + + log(f"База вернула {len(df)} строк за {processing_date_str}") + + if len(df) > 0: + df['fio_clean'] = df['Сотрудник'].apply(clean_scud_fio_light) + + df['anomaly_flag'] = 'NONE' + mask_anomaly = (df['Начало_дня'] == 'Нет входа') & (df['Первая_активность'] != '—') + df.loc[mask_anomaly, 'anomaly_flag'] = 'ANOMALY_NO_IN_HAS_ACTIVITY' + + df['Пришел'] = df['Статус'].str.contains('Присутствовал', case=False, na=False) & (~mask_anomaly) + + save_scud_to_db(df, processing_date_str, snapshot_time=snapshot_time, is_yesterday=is_yesterday) + log(f"[✓] Записи за {processing_date_str} успешно сохранены в SQLite!", "SUCCESS") + + if save_xlsx: + file_name = f"Сотрудники_{processing_date_str}.xlsx" + file_path = os.path.join(SCUD_DIR, file_name) + + if os.path.exists(file_path): + try: + os.remove(file_path) + except OSError as e: + log(f"ОШИБКА при удалении старого файла {file_name}: {e}", "ERROR") + + df.to_excel(file_path, sheet_name="Отчет", index=False, engine="openpyxl") + auto_fit_columns(file_path, sheet_name="Отчет") + log(f"[✓] Успешно экспортирован файл: data/scud/{file_name}", "SUCCESS") + else: + log(f"Запрос за {processing_date_str} вернул 0 строк.", "WARNING") + + except Exception as e: + log(f"🛑 ОШИБКА выгрузки СКУД за {processing_date_str}: {e}", "ERROR") + success = False + finally: + if connection is not None: + connection.close() + + log("=== Выгрузка СКУД завершена ===\n") + return success + + +if __name__ == "__main__": + help_text = """ +Модуль прямого экспорта данных СКУД Орион Pro (MS SQL Server) в SQLite и Excel. + +ПРИМЕРЫ ЗАПУСКА: + python services/scud_export.py -- Автоматическая выгрузка за Сегодня и Вчера + python services/scud_export.py --date 05.08.2026 -- Точечная выгрузка СКУД за конкретную дату + python services/scud_export.py --no-xlsx -- Сохранение логов СКУД ТОЛЬКО в SQLite без дублирования в XLSX + python services/scud_export.py -d -- Запуск в режиме отладки MS SQL запросов (DEBUG) +""" + parser = argparse.ArgumentParser( + description=help_text, + formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument("--date", dest="input_date", default=None, help="Дата выгрузки в формате ДД.ММ.ГГГГ (по умолчанию выгружаются Вчера и Сегодня)") + parser.add_argument("-d", "--debug", action="store_true", help="Включить подробные логи отладки подключения и запросов к MS SQL") + parser.add_argument("--no-xlsx", dest="save_xlsx", action="store_false", default=True, help="Отключить генерирование промежуточных XLSX-файлов в папке data/scud/") + args = parser.parse_args() + + run_export(args.input_date, save_xlsx=args.save_xlsx, debug=args.debug) +``` + +## File: `./services/share_copier.py` +```py +import os +import shutil +from config import DATE_TODAY, DATE_YESTERDAY, ZUP_1C_DIR, SHARE_1C_DIR + + +def find_file_strictly_on_share(prefix, date_str): + """ + Ищет файл со строгой привязкой ТОЛЬКО к сетевой шаре SHARE_1C_DIR, + не обращаясь к локальным папкам. + """ + if not os.path.exists(SHARE_1C_DIR): + return None + + date_dots = date_str + date_underscores = date_str.replace('.', '_') + + try: + for f in os.listdir(SHARE_1C_DIR): + if f.endswith('.xlsx') or f.endswith('.csv'): + if f.lower().startswith(prefix.lower()): + if date_dots in f or date_underscores in f: + return os.path.join(SHARE_1C_DIR, f) + except Exception as e: + print(f" [⚠️] Ошибка чтения сетевой шары: {e}") + return None + + +def copy_1c_files_from_share(): + r""" + Копирует свежие файлы 1С (Штат и Отсутствия) за Сегодня и Вчера + из сетевой шары \\storage\SCUD\Обмен\Штат в локальную папку data/1c/ + """ + print(f"[0.5/5] Проверка и копирование файлов 1С с шары: {SHARE_1C_DIR}...") + + if not os.path.exists(SHARE_1C_DIR): + print(f"[⚠️] Сетевой шар недоступен или путь не найден: {SHARE_1C_DIR}") + print(" Используем ранее сохраненные локальные файлы из data/1c/\n") + return False + + dates_to_copy = [DATE_TODAY, DATE_YESTERDAY] + prefixes = ["Штат", "Отсутствия"] + copied_count = 0 + + os.makedirs(ZUP_1C_DIR, exist_ok=True) + + for d_str in dates_to_copy: + for prefix in prefixes: + remote_file = find_file_strictly_on_share(prefix, d_str) + + if remote_file and os.path.exists(remote_file): + filename = os.path.basename(remote_file) + local_target_path = os.path.join(ZUP_1C_DIR, filename) + + try: + shutil.copy2(remote_file, local_target_path) + print(f" [✓] Успешно скопирован с шары: {filename} -> data/1c/") + copied_count += 1 + except Exception as e: + print(f" [⚠️] Ошибка копирования {filename}: {e}") + else: + d_fmt = d_str.replace('.', '_') + print(f" [ℹ️] На сетевой шаре отсутствует {prefix} за {d_str} ({prefix}_{d_fmt}.xlsx)") + + if copied_count > 0: + print(f"[✓] Успешно скопировано файлов с сетевой шары: {copied_count} шт.\n") + else: + print("[ℹ️] Новых файлов за указанные даты на сетевой шаре не обнаружено.\n") + + return True +``` + +## File: `./services/excel_exporter.py` +```py +import math +import os +import time +import openpyxl +import pandas as pd +from datetime import datetime +from openpyxl import Workbook +from openpyxl.styles import Font, Alignment, PatternFill, Border, Side +from openpyxl.utils import get_column_letter +from config import REPORTS_DIR + +MONTHS_RU_GENITIVE = { + 1: "января", 2: "февраля", 3: "марта", 4: "апреля", + 5: "мая", 6: "июня", 7: "июля", 8: "августа", + 9: "сентября", 10: "октября", 11: "ноября", 12: "декабря" +} + +MONTHS_RU_NOMINATIVE = { + 1: "январь", 2: "февраль", 3: "март", 4: "апрель", + 5: "май", 6: "июнь", 7: "июль", 8: "август", + 9: "сентябрь", 10: "октябрь", 11: "ноябрь", 12: "декабрь" +} + + +def format_date_ru(date_str): + try: + dt = datetime.strptime(date_str, "%d.%m.%Y") + return f"{dt.day} {MONTHS_RU_GENITIVE[dt.month]} {dt.year}" + except Exception: + return date_str + + +def get_dated_reports_dir(date_str): + try: + dt = datetime.strptime(date_str, "%d.%m.%Y") + year_str = str(dt.year) + month_name = MONTHS_RU_NOMINATIVE[dt.month] + except Exception: + now = datetime.now() + year_str = str(now.year) + month_name = MONTHS_RU_NOMINATIVE[now.month] + + target_dir = os.path.join(REPORTS_DIR, year_str, month_name) + os.makedirs(target_dir, exist_ok=True) + return target_dir + + +THIN_SIDE = Side(border_style="thin", color="D3D3D3") +THIN_BORDER = Border(left=THIN_SIDE, right=THIN_SIDE, top=THIN_SIDE, bottom=THIN_SIDE) + +FILL_HEADER = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid") +FILL_TOTAL_LIST = PatternFill(start_color="F2F2F2", end_color="F2F2F2", fill_type="solid") +FILL_UNEXPLAINED = PatternFill(start_color="FCE4D6", end_color="FCE4D6", fill_type="solid") +FILL_PRESENT = PatternFill(start_color="E2EFDA", end_color="E2EFDA", fill_type="solid") +FILL_REMOTE = PatternFill(start_color="E8F8F5", end_color="E8F8F5", fill_type="solid") +FILL_ANOMALY = PatternFill(start_color="FCE4D6", end_color="FCE4D6", fill_type="solid") +FILL_NO_PASS = PatternFill(start_color="E1F5FE", end_color="E1F5FE", fill_type="solid") +FILL_EXCEPTIONS = PatternFill(start_color="EFEBE9", end_color="EFEBE9", fill_type="solid") # Мягкий бежево-серый для исключений + +CATEGORY_PASTEL_COLORS = ["FFF2CC", "E1D5E7", "E1F5FE", "FFF0F5", "FCF3CF"] + +YELLOW_FILL = PatternFill(start_color="FFF2CC", end_color="FFF2CC", fill_type="solid") +LIGHT_RED_FILL = PatternFill(start_color="FCE4D6", end_color="FCE4D6", fill_type="solid") +GREEN_FILL = PatternFill(start_color="E2EFDA", end_color="E2EFDA", fill_type="solid") +LIGHT_BLUE_FILL = PatternFill(start_color="E1F5FE", end_color="E1F5FE", fill_type="solid") + + +def calculate_deviation(time_in_building_str, reason="", norm_hours=8, lunch_minutes=30): + if pd.notna(reason) and isinstance(reason, str) and reason.strip() != "": + return "0:00" + + if not isinstance(time_in_building_str, str) or time_in_building_str in ['00:00', '0', '', 'None', 'nan', 'NaN']: + return f"-{norm_hours}:00" + + try: + parts = time_in_building_str.strip().split(':') + hh = int(parts[0]) + mm = int(parts[1]) if len(parts) > 1 else 0 + total_in_building_minutes = hh * 60 + mm + + if total_in_building_minutes == 0: + return f"-{norm_hours}:00" + + work_minutes = max(0, total_in_building_minutes - lunch_minutes) + norm_minutes = norm_hours * 60 + diff = work_minutes - norm_minutes + + if diff == 0: + return "0:00" + + sign = "-" if diff < 0 else "" + abs_diff = abs(diff) + res_hh = abs_diff // 60 + res_mm = abs_diff % 60 + + return f"{sign}{res_hh}:{res_mm:02d}" + except Exception: + return f"-{norm_hours}:00" + + +def apply_borders_to_cell(cell, border=THIN_BORDER): + cell.border = border + + +def format_row_cells(ws, r_num, fill_obj, is_bold=False, align_b="right", bold_font=None, wrap_b=False): + cell_a = ws.cell(row=r_num, column=1) + cell_b = ws.cell(row=r_num, column=2) + if fill_obj: + cell_a.fill = fill_obj + cell_b.fill = fill_obj + apply_borders_to_cell(cell_a) + apply_borders_to_cell(cell_b) + if is_bold and bold_font: + cell_a.font = bold_font + cell_b.font = bold_font + if align_b: + cell_b.alignment = Alignment(horizontal=align_b, vertical="center", wrap_text=wrap_b) + + +# --- 1. СВОДКА НА СЕГОДНЯ --- +def generate_summary_excel(merged_df, date_str="21.08.2026", filename=None): + if not filename: + filename = f"{format_date_ru(date_str)} сводка.xlsx" + + target_dir = get_dated_reports_dir(date_str) + output_path = os.path.join(target_dir, filename) + wb = Workbook() + ws = wb.active + ws.title = "Лист_1" + + ws.sheet_properties.outlinePr.summaryBelow = False + ws.sheet_properties.outlinePr.summaryRight = False + ws.sheet_properties.outlinePr.showOutlineSymbols = True + ws.sheet_view.showOutlineSymbols = True + + bold_font = Font(name="Calibri", size=11, bold=True) + + # 1. Шапка + ws.cell(row=1, column=1, value="Сводка на") + ws.cell(row=1, column=2, value=date_str) + format_row_cells(ws, 1, FILL_HEADER, is_bold=True, bold_font=bold_font) + + apply_borders_to_cell(ws.cell(row=2, column=1)) + apply_borders_to_cell(ws.cell(row=2, column=2)) + + # 2. По списку + ws.cell(row=3, column=1, value="По списку") + ws.cell(row=3, column=2, value=len(merged_df)) + format_row_cells(ws, 3, FILL_TOTAL_LIST, is_bold=True, bold_font=bold_font) + + current_row = 4 + + is_no_pass = merged_df['no_scud_pass'] == True if 'no_scud_pass' in merged_df.columns else False + is_exc = merged_df.get('is_excluded', False) == True + + # 3. НЕИЗВЕСТНО + unexplained = merged_df[ + (merged_df['Пришел'] == False) & + (merged_df['Вид_отсутствия'].isna() | (merged_df['Вид_отсутствия'].astype(str).str.strip() == '')) & + (~is_no_pass) & + (~is_exc) + ] + ws.cell(row=current_row, column=1, value="неизвестно") + ws.cell(row=current_row, column=2, value=len(unexplained)) + format_row_cells(ws, current_row, FILL_UNEXPLAINED, is_bold=True, bold_font=bold_font) + current_row += 1 + + for fio in sorted(unexplained['Сотрудник'].dropna().unique()): + ws.cell(row=current_row, column=1, value=fio) + format_row_cells(ws, current_row, FILL_UNEXPLAINED, is_bold=False) + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = False + current_row += 1 + + # 4. РАЗДЕЛ: НЕТ ПРОПУСКА + no_pass_df = merged_df[is_no_pass] if 'no_scud_pass' in merged_df.columns else pd.DataFrame() + + ws.cell(row=current_row, column=1, value="Нет пропуска") + ws.cell(row=current_row, column=2, value=len(no_pass_df)) + format_row_cells(ws, current_row, FILL_NO_PASS, is_bold=True, bold_font=bold_font) + current_row += 1 + + if not no_pass_df.empty: + for fio in sorted(no_pass_df['Сотрудник'].dropna().unique()): + ws.cell(row=current_row, column=1, value=fio) + format_row_cells(ws, current_row, FILL_NO_PASS, is_bold=False) + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = False + current_row += 1 + + # 5. КАТЕГОРИИ ОТСУТСТВИЙ (без удаленки и исключений) + reason_clean = merged_df['Вид_отсутствия'].astype(str).str.lower() + is_remote_reason = reason_clean.str.contains('удален|дистанцион', regex=True, na=False) + + absent_only = merged_df[ + (merged_df['Пришел'] == False) & + (merged_df['Вид_отсутствия'].notna()) & + (~merged_df['Вид_отсутствия'].astype(str).str.startswith('Исключение')) & + (~is_remote_reason) & + (~is_exc) + ] + absent_groups = absent_only.groupby('Вид_отсутствия') + + for idx_cat, (cat_name, group) in enumerate(absent_groups): + hex_color = CATEGORY_PASTEL_COLORS[idx_cat % len(CATEGORY_PASTEL_COLORS)] + cat_fill = PatternFill(start_color=hex_color, end_color=hex_color, fill_type="solid") + + ws.cell(row=current_row, column=1, value=cat_name) + ws.cell(row=current_row, column=2, value=len(group)) + format_row_cells(ws, current_row, cat_fill, is_bold=True, bold_font=bold_font) + current_row += 1 + + for fio in sorted(group['Сотрудник'].dropna().unique()): + ws.cell(row=current_row, column=1, value=fio) + format_row_cells(ws, current_row, cat_fill, is_bold=False) + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = True + current_row += 1 + + # 6. ИТОГО НА РАБОТЕ (Строго физически пришедшие в офис по СКУД) + present = merged_df[(merged_df['Пришел'] == True) & (~is_exc)] + + ws.cell(row=current_row, column=1, value="Итого на работе") + ws.cell(row=current_row, column=2, value=len(present)) + format_row_cells(ws, current_row, FILL_PRESENT, is_bold=True, bold_font=bold_font) + current_row += 1 + + if not present.empty: + for fio in sorted(present['Сотрудник'].dropna().unique()): + ws.cell(row=current_row, column=1, value=fio) + format_row_cells(ws, current_row, FILL_PRESENT, is_bold=False) + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = True + current_row += 1 + + # 6.1. В ТОМ ЧИСЛЕ НА УДАЛЕННОЙ РАБОТЕ (Удаленщики из дома, которых нет в офисе) + remote_home = merged_df[(merged_df['Пришел'] == False) & is_remote_reason & (~is_exc)] + + ws.cell(row=current_row, column=1, value="В том числе на удаленной работе") + ws.cell(row=current_row, column=2, value=len(remote_home)) + format_row_cells(ws, current_row, FILL_REMOTE, is_bold=True, bold_font=bold_font) + current_row += 1 + + if not remote_home.empty: + for fio in sorted(remote_home['Сотрудник'].dropna().unique()): + ws.cell(row=current_row, column=1, value=fio) + format_row_cells(ws, current_row, FILL_REMOTE, is_bold=False) + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = True + current_row += 1 + + # 7. АНОМАЛИИ СКУД И 1С + anomalies = merged_df[ + (~is_exc) & ( + ((merged_df['Пришел'] == True) & (merged_df['Вид_отсутствия'].notna()) & + (~merged_df['Вид_отсутствия'].astype(str).str.startswith('Исключение')) & + (~is_remote_reason) & + (~reason_clean.str.contains('командировк', na=False))) | + (merged_df.get('anomaly_flag', 'NONE') == 'ANOMALY_NO_IN_HAS_ACTIVITY') + ) + ] + + ws.cell(row=current_row, column=1, value="Аномалии СКУД и 1С") + ws.cell(row=current_row, column=2, value=len(anomalies)) + format_row_cells(ws, current_row, FILL_ANOMALY, is_bold=True, bold_font=bold_font) + current_row += 1 + + chars_per_line_b = 30 + + if not anomalies.empty: + for _, row in anomalies.iterrows(): + fio = row.get('Сотрудник', '') + reason = row.get('Вид_отсутствия', '') + anom_flag = row.get('anomaly_flag', 'NONE') + + if anom_flag == 'ANOMALY_NO_IN_HAS_ACTIVITY': + first_act = row.get('Первая_активность', '—') + reason_text = f"🚨 АНОМАЛИЯ СКУД: Нет входа (первая активность: {first_act})" + else: + reason_text = f"В 1С: {reason}" + + cell_a = ws.cell(row=current_row, column=1, value=f"{fio}") + cell_b = ws.cell(row=current_row, column=2, value=reason_text) + + cell_a.fill = FILL_ANOMALY + cell_b.fill = FILL_ANOMALY + apply_borders_to_cell(cell_a) + apply_borders_to_cell(cell_b) + + cell_b.alignment = Alignment(horizontal="left", vertical="center", wrap_text=True) + cell_a.alignment = Alignment(horizontal="left", vertical="center") + + if len(reason_text) > chars_per_line_b: + lines_count = math.ceil(len(reason_text) / chars_per_line_b) + ws.row_dimensions[current_row].height = max(lines_count * 18, 22) + else: + ws.row_dimensions[current_row].height = 20 + + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = True + current_row += 1 + + # ⭐️ 8. РАЗДЕЛ: ИСКЛЮЧЕНИЯ (В самом низу, раскрывающийся список) + exceptions_df = merged_df[is_exc] + + ws.cell(row=current_row, column=1, value="Исключения") + ws.cell(row=current_row, column=2, value=len(exceptions_df)) + format_row_cells(ws, current_row, FILL_EXCEPTIONS, is_bold=True, bold_font=bold_font) + current_row += 1 + + if not exceptions_df.empty: + for fio in sorted(exceptions_df['Сотрудник'].dropna().unique()): + ws.cell(row=current_row, column=1, value=fio) + format_row_cells(ws, current_row, FILL_EXCEPTIONS, is_bold=False) + ws.row_dimensions[current_row].outlineLevel = 1 + ws.row_dimensions[current_row].hidden = True + current_row += 1 + + ws.column_dimensions['A'].width = 45.0 + ws.column_dimensions['B'].width = 38.0 + + try: + wb.save(output_path) + print(f"[✓] Ежедневная сводка сохранена: {output_path}") + except PermissionError: + alt_filename = filename.replace(".xlsx", f"_{int(time.time())}.xlsx") + alt_path = os.path.join(target_dir, alt_filename) + wb.save(alt_path) + print(f"[⚠️] Файл открыт в Excel! Сохранено как: {alt_path}") + + +# --- 2. ДЕТАЛЬНЫЙ ОТЧЕТ ЗА ВЧЕРА --- +def generate_detailed_excel(merged_df, date_str="20.08.2026", filename=None): + if not filename: + filename = f"{format_date_ru(date_str)} отчет.xlsx" + + if merged_df is not None and not merged_df.empty: + df_export = merged_df[merged_df.get('is_excluded', False) == False].copy() + else: + df_export = pd.DataFrame() + + target_dir = get_dated_reports_dir(date_str) + output_path = os.path.join(target_dir, filename) + wb = Workbook() + ws = wb.active + ws.title = "Детальный_отчет" + + ws["B2"] = "Дата:" + ws["D2"] = date_str + ws["B2"].font = Font(name="Arial", size=10, bold=True) + ws["D2"].font = Font(name="Arial", size=10, bold=True) + + headers = [ + "№", "ФИО", "Подразделение", "время входа", "первая активность", "время выхода", + "находился в здании", "причина отсутствия", "норма", "отклонение от нормы" + ] + ws.append([]) + ws.append(headers) + + header_fill = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid") + for col_idx in range(1, len(headers) + 1): + cell = ws.cell(row=4, column=col_idx) + cell.fill = header_fill + cell.font = Font(name="Arial", size=10, bold=True) + cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True) + apply_borders_to_cell(cell) + + start_col = 'Начало дня' if 'Начало дня' in df_export.columns else 'Начало_дня' + end_col = 'Конец дня' if 'Конец дня' in df_export.columns else 'Конец_дня' + hours_col = 'Часы' if 'Часы' in df_export.columns else 'Находился_в_здании' + + chars_per_line_h = 24 + + for idx, row in df_export.reset_index(drop=True).iterrows(): + is_present = row.get('Пришел', False) + absence_reason = row.get('Вид_отсутствия', '') + has_reason = pd.notna(absence_reason) and str(absence_reason).strip() != '' + anom_flag = row.get('anomaly_flag', 'NONE') + + in_building_str = str(row.get(hours_col, '00:00')) + first_act_val = str(row.get('Первая_активность', '—')).strip() + has_first_act = first_act_val not in ['—', '', 'None', 'nan'] + + dept_scud_val = row.get('department_scud', row.get('department', row.get('Подразделение', ''))) + deviation_val = calculate_deviation(in_building_str, reason=absence_reason if has_reason else "", norm_hours=8, lunch_minutes=30) + + ws.append([ + idx + 1, + row.get('Сотрудник', ''), + dept_scud_val, + row.get(start_col, 'Нет входа'), + first_act_val, + row.get(end_col, 'Нет выхода'), + in_building_str, + absence_reason if has_reason else '', + 8, + deviation_val + ]) + + row_num = 5 + idx + + if is_present and has_reason: + row_fill = GREEN_FILL + elif not is_present and has_reason: + row_fill = YELLOW_FILL + elif not is_present and not has_reason and not has_first_act: + row_fill = LIGHT_RED_FILL + else: + row_fill = None + + val_h_str = str(absence_reason) if has_reason else "" + if len(val_h_str) > chars_per_line_h: + needed_lines = math.ceil(len(val_h_str) / chars_per_line_h) + ws.row_dimensions[row_num].height = max(needed_lines * 18, 22) + else: + ws.row_dimensions[row_num].height = 20 + + for col_idx in range(1, len(headers) + 1): + cell = ws.cell(row=row_num, column=col_idx) + apply_borders_to_cell(cell) + if row_fill: + cell.fill = row_fill + + if col_idx == 8: + cell.alignment = Alignment(horizontal="left", vertical="center", wrap_text=True) + elif col_idx in [1, 4, 5, 6, 7, 9, 10]: + cell.alignment = Alignment(horizontal="center", vertical="center") + else: + cell.alignment = Alignment(horizontal="left", vertical="center") + + for col in ws.columns: + col_letter = get_column_letter(col[0].column) + max_len = 0 + for cell in col: + if cell.value is not None: + cell_lines = str(cell.value).split("\n") + line_max = max(len(line) for line in cell_lines) + if line_max > max_len: + max_len = line_max + + optimal_width = max(max_len + 2, 8) + if optimal_width > 35: + optimal_width = 35 + ws.column_dimensions[col_letter].width = optimal_width + + try: + wb.save(output_path) + print(f"[✓] Детальный отчет сохранен: {output_path}") + except PermissionError: + alt_filename = filename.replace(".xlsx", f"_{int(time.time())}.xlsx") + alt_path = os.path.join(target_dir, alt_filename) + wb.save(alt_path) + print(f"[⚠️] Файл открыт в Excel! Сохранено как: {alt_path}") + + +def export_raw_scud(df_scud, filename="СКУД_Сырые_данные.xlsx"): + output_path = os.path.join(REPORTS_DIR, filename) + df_scud.to_excel(output_path, index=False) +``` + +## File: `./services/text_reporter.py` +```py +import json +import difflib +import re +from services.ai_verifier import ask_ollama +from services.knowledge_base import load_knowledge_base + + +def find_python_fuzzy_matches(unexplained_df, raw_absent_df): + if unexplained_df.empty or raw_absent_df is None or raw_absent_df.empty: + return [] + + absent_dict = {} + for idx, r in raw_absent_df.iterrows(): + raw_fio = str(r.get('ФИО', '')) + clean_fio = str(r.get('fio_clean', '')) + reason = str(r.get('Вид_отсутствия', '')) + if clean_fio and clean_fio not in ['Ао "Ленморниипроект"', 'Сотрудник', 'Nan', 'None']: + absent_dict[clean_fio] = {'raw_fio': raw_fio, 'reason': reason} + + matches = [] + unexplained_fios = unexplained_df['fio_clean'].unique() if 'fio_clean' in unexplained_df.columns else [] + + for fio in unexplained_fios: + fio_parts = fio.split() + if not fio_parts: + continue + surname = fio_parts[0].lower() + + for abs_clean, abs_info in absent_dict.items(): + abs_parts = abs_clean.split() + if not abs_parts: + continue + abs_surname = abs_parts[0].lower() + + if surname == abs_surname: + ratio = difflib.SequenceMatcher(None, fio.lower(), abs_clean.lower()).ratio() + if ratio >= 0.75: + matches.append({ + "target_fio": fio, + "found_in_1c_raw": abs_info['raw_fio'], + "reason_1c": abs_info['reason'] + }) + break + + return matches + + +def generate_markdown_report(merged_df, absent_explained, absent_unexplained, scud_present_but_absent_in_1c, anomalies_list=None, raw_scud_df=None, raw_staff_df=None, raw_absent_df=None, date_str="05.08.2026"): + kb = load_knowledge_base() + custom_rules = kb.get("rules", []) + custom_rules_str = "\n".join([f"- {r}" for r in custom_rules]) if custom_rules else "Специфических правил компании пока нет." + + total_staff = len(merged_df) + + # 1. Пришедшие в офис + present_office_cnt = len(merged_df[merged_df['Пришел'] == True]) + + # 2. Не пришедшие удаленщики + reason_series = merged_df['Вид_отсутствия'].astype(str).str.lower() + is_remote_reason = reason_series.str.contains('удален|дистанцион', regex=True, na=False) + remote_home_cnt = len(merged_df[(merged_df['Пришел'] == False) & is_remote_reason]) + + # 3. Официально отсутствующие (без удаленки) + explained_cnt = len(merged_df[(merged_df['Пришел'] == False) & (merged_df['Вид_отсутствия'].notna()) & (~is_remote_reason) & (~merged_df['Вид_отсутствия'].astype(str).str.startswith('Исключение'))]) + + unexplained_cnt = len(absent_unexplained) + anomalies_cnt = len(anomalies_list) if anomalies_list else 0 + + fio_mismatches_python = find_python_fuzzy_matches(absent_unexplained, raw_absent_df) + + anomalies_formatted = [] + if anomalies_list: + for idx, a in enumerate(anomalies_list, 1): + anomalies_formatted.append(f"{idx}. {a.get('fio', 'Сотрудник')}: {a.get('description', '')}") + anomalies_text_block = "\n".join(anomalies_formatted) if anomalies_formatted else "Аномалий не обнаружено." + + unexplained_list = [] + if not absent_unexplained.empty: + for idx, r in absent_unexplained.iterrows(): + fio = r.get('Сотрудник', r.get('fio_clean', '')) + dept_scud = str(r.get('department_scud', '')).strip() + dept_1c = str(r.get('Подразделение', '')).strip() + dept = dept_scud if (dept_scud and dept_scud.lower() != 'nan' and dept_scud != '—') else dept_1c + if not dept: + dept = '—' + pos = r.get('Должность', '—') + unexplained_list.append(f"{fio} — {dept}, {pos}") + + prompt = f""" +Ты — старший аудитор кадровой безопасности и контроллинга СКУД. +Сформируй итоговую сводку кадрового контроля на {date_str}. + +📌 БАЗА ЗНАНИЙ И ПРАВИЛА ПРЕДПРИЯТИЯ: +{custom_rules_str} + +🚨 ВХОДНЫЕ МЕТРИКИ: +- Всего сотрудников: {total_staff} +- Итого на работе (в офисе): {present_office_cnt} +- В том числе на удаленной работе: {remote_home_cnt} +- Официально отсутствуют: {explained_cnt} +- Неизвестно (истинно неотмеченные): {unexplained_cnt} +- Выявлено аномалий/конфликтов реестров: {anomalies_cnt} + +--- +🚨 ПОДТВЕРЖДЁННЫЕ АНОМАЛИИ ({anomalies_cnt} шт): +{anomalies_text_block} + +--- +⚠️ ПОДТВЕРЖДЁННЫЕ PYTHON ОШИБКИ СОПОСТАВЛЕНИЯ ФИО В 1С ({len(fio_mismatches_python)} шт): +{json.dumps(fio_mismatches_python, ensure_ascii=False, indent=2)} + +--- +📊 СПИСОК НЕИЗВЕСТНЫХ СЛУЧАЕВ ({unexplained_cnt} чел): +{json.dumps(unexplained_list, ensure_ascii=False, indent=2)} + +СТРОГИЕ ИНСТРУКЦИИ ДЛЯ ИИ: +1. КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО выводить JSON! В блоке "Выявленные ИИ аномалии" выведи читаемый нумерованный список строк ровно так, как передано в разделе "ПОДТВЕРЖДЁННЫЕ АНОМАЛИИ". Если аномалий нет, напиши: "Аномалий не обнаружено." +2. В разделе "Подозрения на ошибки сопоставления ФИО" используй ТОЛЬКО массив `ПОДТВЕРЖДЁННЫЕ PYTHON ОШИБКИ СОПОСТАВЛЕНИЯ ФИО`. Если он пуст, напиши: "Ошибок сопоставления ФИО и неточностей в 1С не обнаружено." +3. В разделе "Неизвестные случаи" выведи НУМЕРОВАННЫЙ СПИСОК всех {unexplained_cnt} человек ровно в том виде, в котором они переданы выше. +4. В разделе "Рекомендации" дай 2-3 конкретные системные рекомендации для кадровой службы без перечисления конкретных ФИО. + +СТРОГИЙ ШАБЛОН ОТВЕТА: + +**Сводка контроллинга СКУД и 1С:ЗУП на {date_str}** + +- Всего офисных сотрудников: **{total_staff}** +- Итого на работе (в офисе): **{present_office_cnt}** +- В том числе на удаленной работе: **{remote_home_cnt}** +- Официально отсутствуют: **{explained_cnt}** +- Неизвестно (истинно неотмеченные): **{unexplained_cnt}** чел. +- Выявлено аномалий/конфликтов реестров: **{anomalies_cnt}** шт. + +#### 🚨 Выявленные ИИ аномалии и конфликты источников ({anomalies_cnt}): +(Выведи нумерованный текстовый список аномалий или 'Аномалий не обнаружено.') + +#### ⚠️ Подозрения на ошибки сопоставления ФИО и несоответствия 1С: +(Выведи данные ИСКЛЮЧИТЕЛЬНО из массива ошибок ФИО. Если пуст — 'Ошибок сопоставления ФИО и неточностей в 1С не обнаружено.') + +#### Неизвестные случаи: {unexplained_cnt} +(Выведи нумерованный список всех {unexplained_cnt} человек) + +### Точечные рекомендации: +(2-3 системные рекомендации) +""" + + sys_prompt = "Ты — русскоязычный кадровый аудитор. Пиши СТРОГО на русском языке обычным форматированным текстом. Категорически запрещено выводить фигурные скобки JSON или технический код." + return ask_ollama(prompt, system_prompt=sys_prompt) +``` + +## File: `./services/exceptions_repo.py` +```py +""" +=============================================================================== +FILE: services/exceptions_repo.py +ROLE: Управление исключениями в SQLite с синхронизацией с exceptions.json. +=============================================================================== +""" + +from typing import Dict, List, Any +import json +import os +from config import EXCEPTIONS_PATH, normalize_fio +from core.connection import get_connection + + +def init_exceptions_table(): + with get_connection() as conn: + conn.execute(""" + CREATE TABLE IF NOT EXISTS exceptions_registry ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + category TEXT NOT NULL, + value TEXT NOT NULL, + comment TEXT DEFAULT '', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(category, value) + ); + """) + conn.commit() + + +def get_all_exceptions_from_db() -> Dict[str, List[str]]: + init_exceptions_table() + cfg = {"departments": [], "positions": [], "fio": [], "position_keywords": [], "include_fio": []} + + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("SELECT category, value FROM exceptions_registry") + rows = cursor.fetchall() + + if not rows and os.path.exists(EXCEPTIONS_PATH): + # Первичная миграция из JSON в SQLite + sync_json_to_db() + return get_all_exceptions_from_db() + + for cat, val in rows: + if cat in cfg: + cfg[cat].append(val) + return cfg + + +def add_exception_to_db(category: str, value: str, comment: str = "") -> bool: + init_exceptions_table() + val_clean = normalize_fio(value) if category in ["fio", "include_fio"] else value.strip() + if not val_clean: + return False + with get_connection() as conn: + conn.execute( + "INSERT OR REPLACE INTO exceptions_registry (category, value, comment) VALUES (?, ?, ?)", + (category, val_clean, comment) + ) + conn.commit() + return True + + +def remove_exception_from_db(category: str, value: str) -> bool: + init_exceptions_table() + with get_connection() as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM exceptions_registry WHERE category = ? AND value = ?", (category, value.strip())) + conn.commit() + return cursor.rowcount > 0 + + +def sync_json_to_db(): + """Переносит данные из exceptions.json в SQLite.""" + if not os.path.exists(EXCEPTIONS_PATH): + return + try: + with open(EXCEPTIONS_PATH, "r", encoding="utf-8") as f: + data = json.load(f) + for cat, items in data.items(): + for item in items: + add_exception_to_db(cat, item, comment="Импорт из JSON") + except Exception as e: + print(f"[⚠️] Ошибка синхронизации JSON -> DB: {e}") +``` + +## File: `./services/zup_extractor.py` +```py +import os +import logging +from datetime import date, datetime +import pyodbc +import pandas as pd +from config import DATA_DIR, normalize_fio, ZUP_SQL_CONFIG + +logger = logging.getLogger(__name__) + + +def get_zup_connection_string() -> str: + """Формирует строку подключения pyodbc к MS SQL Server из config.py.""" + return ( + f"DRIVER={ZUP_SQL_CONFIG['driver']};" + f"SERVER={ZUP_SQL_CONFIG['server']};" + f"DATABASE={ZUP_SQL_CONFIG['database']};" + f"UID={ZUP_SQL_CONFIG['user']};" + f"PWD={ZUP_SQL_CONFIG['password']};" + f"TrustServerCertificate={ZUP_SQL_CONFIG.get('trust_server_certificate', 'yes')};" + f"Encrypt={ZUP_SQL_CONFIG.get('encrypt', 'no')};" + ) + + +def fetch_zup_absences_from_sql(target_date) -> pd.DataFrame: + """ + Извлекает оперативные отсутствия и действующие декреты из MS SQL 1С:ЗУП 3.1 + на указанную дату (принимает как datetime.date, так и строку 'DD.MM.YYYY' / 'DD_MM_YYYY'). + """ + if isinstance(target_date, str): + clean_date_str = target_date.replace('_', '.') + try: + target_date = datetime.strptime(clean_date_str, "%d.%m.%Y").date() + except ValueError: + logger.error(f"[❌] Неверный формат даты для SQL-запроса: {target_date}. Ожидался DD.MM.YYYY") + return pd.DataFrame() + + query = """ + DECLARE @TargetDate DATE = ?; + + -- 1. Оперативные отсутствия (Отпуска, Командировки, Больничные, Отгулы) + SELECT + LTRIM(RTRIM(ref_emp._Description)) AS [ФИО], + CASE state._Fld16925RRef + WHEN 0x9C10B2452D414FDF4A90E2B2AB81D3F7 THEN N'Отпуск основной' + WHEN 0xBA63FCF94B4AD0664ED369D2E6505D67 THEN N'Командировка' + WHEN 0x8C3B61F23954155A40EB0108FC0932DB THEN N'Болезнь' + WHEN 0x853001C18D0965EE4B2702405C94054A THEN N'Отпуск неоплачиваемый по разрешению работодателя' + WHEN 0xB7335AEFD8708C3E462861FC59489A38 THEN N'Отпуск по беременности и родам' + ELSE N'Другое отсутствие' + END AS [Вид_отсутствия] + + FROM dbo._InfoRg16921 state WITH (NOLOCK) + INNER JOIN dbo._Reference299 ref_emp WITH (NOLOCK) + ON state._Fld16922RRef = ref_emp._IDRRef + + WHERE @TargetDate BETWEEN CAST(CASE WHEN YEAR(state._Fld16926) > 3000 THEN DATEADD(YEAR, -2000, state._Fld16926) ELSE state._Fld16926 END AS DATE) + AND CAST(CASE WHEN YEAR(state._Fld16927) > 3000 THEN DATEADD(YEAR, -2000, state._Fld16927) ELSE state._Fld16927 END AS DATE) + + UNION ALL + + -- 2. Динамический выбор ДЕЙСТВУЮЩИХ декретниц по уходу за ребенком + SELECT + active_state.fio AS [ФИО], + N'Отпуск по уходу за ребенком' AS [Вид_отсутствия] + + FROM ( + SELECT + LTRIM(RTRIM(ref_emp._Description)) AS fio, + all_states._Fld16925RRef AS state_guid, + CAST(CASE WHEN YEAR(all_states._Fld16926) > 3000 THEN DATEADD(YEAR, -2000, all_states._Fld16926) ELSE all_states._Fld16926 END AS DATE) AS date_start, + ROW_NUMBER() OVER ( + PARTITION BY all_states._Fld16922RRef + ORDER BY all_states._Fld16926 DESC + ) AS rn + FROM dbo._InfoRg16921 all_states WITH (NOLOCK) + INNER JOIN dbo._Reference299 ref_emp WITH (NOLOCK) + ON all_states._Fld16922RRef = ref_emp._IDRRef + WHERE CAST(CASE WHEN YEAR(all_states._Fld16926) > 3000 THEN DATEADD(YEAR, -2000, all_states._Fld16926) ELSE all_states._Fld16926 END AS DATE) <= @TargetDate + ) active_state + + WHERE active_state.rn = 1 + AND active_state.state_guid = 0xA4FBA038663B3C2A48DA151C262855E1 + AND active_state.date_start >= DATEADD(YEAR, -3, @TargetDate) + + ORDER BY [ФИО] ASC; + """ + + try: + conn_str = get_zup_connection_string() + with pyodbc.connect(conn_str, timeout=30) as conn: + df = pd.read_sql(query, conn, params=[target_date]) + + if not df.empty: + df['fio_clean'] = df['ФИО'].apply(normalize_fio) + return df + except Exception as e: + logger.error(f"[❌] Ошибка SQL-выгрузки отсутствий за {target_date}: {e}") + return pd.DataFrame() + + +def fetch_zup_staff_from_sql() -> pd.DataFrame: + """Резервная выгрузка штата из MS SQL.""" + query = """ + SELECT DISTINCT + LTRIM(RTRIM(ref_emp._Description)) AS [ФИО], + N'Организация' AS [Подразделение], + N'Сотрудник' AS [Должность] + FROM dbo._Reference299 ref_emp WITH (NOLOCK) + WHERE ref_emp._Description <> '' + AND ref_emp._Marked = 0x00 + ORDER BY [ФИО] ASC; + """ + try: + conn_str = get_zup_connection_string() + with pyodbc.connect(conn_str, timeout=5) as conn: + df = pd.read_sql(query, conn) + + if not df.empty: + df['fio_clean'] = df['ФИО'].apply(normalize_fio) + return df + except Exception as e: + logger.error(f"[❌] Ошибка выгрузки штата из MS SQL: {e}") + return pd.DataFrame() + + +def sync_zup_to_excel(target_date) -> bool: + """Создает дамп в Excel при необходимости.""" + try: + if isinstance(target_date, str): + clean_date_str = target_date.replace('_', '.') + target_date_obj = datetime.strptime(clean_date_str, "%d.%m.%Y").date() + else: + target_date_obj = target_date + + date_str_file = target_date_obj.strftime("%d_%m_%Y") + c_1c_dir = os.path.join(DATA_DIR, "1c") + os.makedirs(c_1c_dir, exist_ok=True) + + df_staff = fetch_zup_staff_from_sql() + df_absences = fetch_zup_absences_from_sql(target_date_obj) + + staff_excel_path = os.path.join(c_1c_dir, f"Штат_{date_str_file}.xlsx") + absences_excel_path = os.path.join(c_1c_dir, f"Отсутствия_{date_str_file}.xlsx") + + with pd.ExcelWriter(staff_excel_path, engine='openpyxl') as writer: + dummy_headers = pd.DataFrame([[""] * 13] * 8) + dummy_headers.to_excel(writer, index=False, header=False) + df_staff[['ФИО', 'Подразделение', 'Должность']].to_excel(writer, startrow=8, index=False) + + with pd.ExcelWriter(absences_excel_path, engine='openpyxl') as writer: + dummy_headers = pd.DataFrame([[""] * 3] * 3) + dummy_headers.to_excel(writer, index=False, header=False) + df_absences[['ФИО', 'Вид_отсутствия']].to_excel(writer, startrow=3, index=False) + + return True + + except Exception as e: + logger.error(f"[❌] Ошибка прямого импорта из MS SQL 1С: {e}") + return False +``` + +## File: `./services/ai_verifier.py` +```py +import json +import re +import requests +import pandas as pd +from config import OLLAMA_URL, OLLAMA_MODEL +from core.database import get_all_rules_from_db +from core.database import get_department_synonyms_dict, add_department_synonym_to_db + +def resolve_department_exception_ai(dept_1c, dept_scud, exception_departments): + """ + Универсальный сопоставитель отделов. + Проверяет 1С, СКУД, локальную базу синонимов SQLite и задействует ИИ для сложных случайных аббревиатур. + """ + if not exception_departments: + return False + + d_1c = str(dept_1c).strip().lower() if dept_1c else "" + d_scud = str(dept_scud).strip().lower() if dept_scud else "" + exc_list = [d.strip().lower() for d in exception_departments] + + # 1. Прямая проверка: если точное имя или подстрока уже совпали в 1С или СКУД + for exc in exc_list: + if exc and (exc in d_1c or exc in d_scud or d_1c in exc or d_scud in exc): + return True + + # 2. Проверка по сохраненной Базе Знаний синонимов из SQLite + synonyms = get_department_synonyms_dict() + for exc in exc_list: + # Если в БД зафиксировано: 'овк' -> 'отдел внутреннего контроля' + full_from_db = synonyms.get(exc, "") + if full_from_db and (full_from_db in d_1c or full_from_db in d_scud): + return True + + # 3. Умный ИИ-арбитраж (если отдел спорный и еще не сохранен в БД) + if d_1c or d_scud: + dept_to_check = d_1c if d_1c else d_scud + prompt = f""" +Ты — кадровый аналитик. +Проверь, является ли отдел сотрудника "{dept_to_check}" тем же самым подразделением, что и один из отделов-исключений: {exception_departments}? + +Примеры: +- "Отдел внутреннего контроля" — это "ОВК" (Да) +- "Отдел технического обеспечения" — это "ОТО" (Да) + +Ответь СТРОГО в формате JSON: +{{ + "is_match": true/false, + "matched_exception": "Название из списка исключений", + "explanation": "краткое объяснение" +}} +""" + try: + raw_res = ask_ollama(prompt, system_prompt="Отвечай только валидным JSON.") + match = re.search(r'\{.*\}', raw_res, re.DOTALL) + if match: + data = json.loads(match.group(0)) + if data.get("is_match"): + matched_exc = data.get("matched_exception", "").lower() + # Запоминаем открытую ИИ связь в SQLite навсегда! + add_department_synonym_to_db(matched_exc, dept_to_check) + return True + except Exception as e: + print(f"[⚠️] Ошибка ИИ-арбитража отделов: {e}") + + return False + +def ask_ollama(prompt, system_prompt=None): + """ + Универсальная функция отправки запросов к локальной модели Ollama (Qwen 2.5). + """ + payload = { + "model": OLLAMA_MODEL, + "prompt": f"{system_prompt}\n\n{prompt}" if system_prompt else prompt, + "stream": False + } + + try: + response = requests.post(OLLAMA_URL, json=payload, timeout=120) + if response.status_code == 200: + data = response.json() + if "response" in data: + return data["response"].strip() + elif "message" in data and "content" in data["message"]: + return data["message"]["content"].strip() + else: + return f"⚠️ Неизвестная структура ответа Ollama: {data}" + else: + return f"⚠️ Ошибка Ollama (Код {response.status_code}): {response.text}" + except requests.exceptions.ConnectionError: + return "⚠️ Не удалось подключиться к Ollama. Проверьте, запущен ли сервис (ollama run qwen2.5:14b)." + except Exception as e: + return f"⚠️ Ошибка при обращении к Ollama: {e}" + + +def get_system_rules_context(): + """ + Загружает динамические системные правила компании напрямую из Базы Данных SQLite. + """ + rules = get_all_rules_from_db() + if not rules: + return "" + rules_text = "\n".join([f"- {r}" for r in rules]) + return f"\nОБЯЗАТЕЛЬНЫЕ ГЛОБАЛЬНЫЕ ПРАВИЛА И ПРИОРИТЕТЫ КОМПАНИИ (ИЗ SQLITE БД):\n{rules_text}\n" + + +def analyze_scud_mass_failure_ai(df_scud): + """ + Оценивает процент аномалий 'ANOMALY_NO_IN_HAS_ACTIVITY' в выгрузке. + Если процент аномалий превышает 5% от смены или 10 человек, вызывает ИИ для генерации критического алерта. + """ + if df_scud is None or df_scud.empty: + return None + + total_records = len(df_scud) + anomaly_rows = df_scud[df_scud.get('anomaly_flag', 'NONE') == 'ANOMALY_NO_IN_HAS_ACTIVITY'] + anomaly_count = len(anomaly_rows) + + if total_records == 0: + return None + + anomaly_percent = round((anomaly_count / total_records) * 100, 1) + + if anomaly_percent > 5.0 or anomaly_count >= 10: + rules_context = get_system_rules_context() + prompt = f""" +{rules_context} +ВНИМАНИЕ! Проведён анализ смены СКУД: +- Всего записей за смену: {total_records} +- Выявлено сотрудников без утреннего входа, но с зафиксированной дневной активностью: {anomaly_count} ({anomaly_percent}% от смены) + +Сформируй понятное предупреждение для Администратора СКУД и Руководителя. +Объясни, что это критический массовый сбой турникетов/контроллеров входа на КПП, и порекомендуй действия. +""" + alert_text = ask_ollama(prompt, system_prompt="Ты — ИИ-аналитик контроллинга СКУД. Отвечай кратко и строго по делу.") + return { + "is_mass_failure": True, + "anomaly_count": anomaly_count, + "anomaly_percent": anomaly_percent, + "alert_text": alert_text + } + + return { + "is_mass_failure": False, + "anomaly_count": anomaly_count, + "anomaly_percent": anomaly_percent, + "alert_text": "Массовых сбоев оборудования не зафиксировано." + } + + +def ai_verify_scud_against_staff(unrecognized_scud_fios, staff_fios): + if not unrecognized_scud_fios or not staff_fios: + return {} + + # Исключаем точные совпадения + staff_fios_set = set(staff_fios) + real_unrecognized = [f for f in unrecognized_scud_fios if f not in staff_fios_set] + + if not real_unrecognized: + return {} + + rules_context = get_system_rules_context() + + prompt = f""" +Ты — кадровый аудитор безопасности СКУД. +{rules_context} +В СКУД записаны неопознанные ФИО: {json.dumps(real_unrecognized, ensure_ascii=False)} +В официальном Штатном расписании 1С записаны ЭТАЛОНЫ: {json.dumps(staff_fios, ensure_ascii=False)} + +СТРОГИЕ ПРАВИЛА: +1. Запись из Штат 1С — это 100% ПРАВИЛЬНЫЙ эталон. +2. В СКУД допущена опечатка. +3. Любое присутствие сотрудника по СКУД при наличии в 1С документа отсутствия (кроме командировок) является гарантированной аномалией. +4. В поле "warning" опиши обнаруженную опечатку. +5. Запрещено выдумывать опечатки и объединять разных людей/однофамильцев! + +ОТВЕЧАЙ ТОЛЬКО ИСКЛЮЧИТЕЛЬНО В ФОРМАТЕ ВАЛИДНОГО JSON: +{{ + "verified_matches": [ + {{ + "scud_fio": "ФИО из СКУД", + "staff_fio": "эталон ФИО из Штат 1С", + "warning": "Описание опечатки в СКУД" + }} + ] +}} +""" + raw_response = ask_ollama( + prompt, + system_prompt="Ты — строгий JSON API генератор. Отвечай только валидным JSON объектом без пояснительного текста." + ) + + mapping = {} + if not raw_response: + return mapping + + # Фаза 1: Попытка прямого разбора с санитарной очисткой + try: + match = re.search(r'\{.*\}', raw_response, re.DOTALL) + if match: + json_str = match.group(0) + # Убираем висячие запятые: {"a": 1,} -> {"a": 1} + json_str = re.sub(r',\s*([\}\]])', r'\1', json_str) + # Заменяем одинарные кавычки в ключах/значениях на двойные при необходимости + json_str = re.sub(r"(?<=\{|\,)\s*'([^']+)'\s*:", r'"\1":', json_str) + + data = json.loads(json_str) + for item in data.get("verified_matches", []): + scud_f = item.get("scud_fio") + staff_f = item.get("staff_fio") + warn = item.get("warning", "Точное совпадение (без опечаток)") + if scud_f and staff_f and staff_f in staff_fios_set: + mapping[scud_f] = {"staff_fio": staff_f, "warning": warn} + return mapping + except Exception: + pass + + # Фаза 2: Резервный Regex-парсер (если JSON синтаксически сломан, но пары ключ-значение есть) + try: + pattern = r'["\']scud_fio["\']\s*:\s*["\']([^"\']+)["\'].*?["\']staff_fio["\']\s*:\s*["\']([^"\']+)["\']' + matches = re.findall(pattern, raw_response, re.DOTALL) + for scud_f, staff_f in matches: + scud_clean = scud_f.strip() + staff_clean = staff_f.strip() + if staff_clean in staff_fios_set: + mapping[scud_clean] = {"staff_fio": staff_clean, "warning": "Восстановлено парсером опечаток"} + except Exception as e: + print(f"[!] Ошибка резервного парсинга опечаток: {e}") + + return mapping + + +def ai_verify_department_exceptions(unexplained_df, exception_departments): + """ + Локальный ИИ проверяет, не являются ли неотмеченные отделы синонимами отделов-исключений. + """ + if unexplained_df.empty or not exception_departments: + return [] + + dept_list = unexplained_df['Подразделение'].dropna().unique().tolist() + rules_context = get_system_rules_context() + + prompt = f""" +{rules_context} +Ты — кадровый аудитор. +Список отделов-исключений компании: {json.dumps(exception_departments, ensure_ascii=False)} +Список отделов сотрудников, попавших в неизвестные: {json.dumps(dept_list, ensure_ascii=False)} + +Определи, какие из отделов сотрудников являются ПОЛНЫМИ НАЗВАНИЯМИ или СИНУНИМАМИ отделов-исключений (например: 'Отдел внутреннего контроля' — это 'ОВК'). + +Выдай ответ строго в формате JSON: +{{ + "matched_departments": ["Название отдела 1", "Название отдела 2"] +}} +""" + raw_response = ask_ollama(prompt, system_prompt="Выдавай только валидный JSON.") + + try: + match = re.search(r'\{.*\}', raw_response, re.DOTALL) + if match: + data = json.loads(match.group(0)) + return data.get("matched_departments", []) + except Exception as e: + print(f"[⚠️] Ошибка ИИ-арбитража отделов: {e}") + + return [] +``` + +## File: `./services/knowledge_base.py` +```py +import os +from core.database import get_all_rules_from_db, add_rule_to_db + + +def load_knowledge_base(): + """ + Загружает актуальные правила Базы Знаний компании напрямую из базы данных SQLite. + """ + rules = get_all_rules_from_db() + return { + "rules": rules if rules else [], + "fio_corrections": {} + } + + +def add_rule_to_kb(new_rule): + """ + Добавляет новое принятое человеком правило в SQLite таблицу ai_knowledge_base. + """ + if not new_rule or not new_rule.strip(): + return + add_rule_to_db(new_rule.strip(), added_by="Human") + print(f"[✓] База знаний SQLite успешно обновлена! Новое правило: {new_rule.strip()}") +``` + +## File: `./services/knowledge/service.py` +```py +""" +=============================================================================== +FILE: services/knowledge/service.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: services / knowledge +ROLE: Доменный сервис базы знаний, правил компании и синонимов подразделений. +=============================================================================== +""" + +from typing import List, Dict, Any +from core.repositories.zup_repo import ( + get_all_rules_from_db, + add_rule_to_db, + get_department_synonyms_dict, + add_department_synonym_to_db +) + + +def get_rules() -> List[Dict[str, Any]]: + """Получить все правила базы знаний в виде списка словарей.""" + raw_rules = get_all_rules_from_db() + return [{"id": idx, "rule_text": r} for idx, r in enumerate(raw_rules, 1)] + + +def add_rule(rule_text: str, added_by: str = "Human") -> None: + """Добавить новое правило в базу знаний.""" + add_rule_to_db(rule_text, added_by=added_by) + + +def get_synonyms() -> Dict[str, str]: + """Получить словарь синонимов отделов.""" + return get_department_synonyms_dict() + + +def register_department_synonym(short_name: str, full_name: str) -> None: + """Сохранить новую пару синонимов подразделения.""" + add_department_synonym_to_db(short_name, full_name) +``` + +## File: `./services/scud_etl/pipeline.py` +```py +""" +=============================================================================== +FILE: services/scud_etl/pipeline.py +ROLE: Выборка данных СКУД из SQLite (scud_logs) с жестким приоритетом Y-снапшотов. +=============================================================================== +""" + +import os +import logging +import pandas as pd +from core.connection import get_connection +from services.data_loader import load_1c_data_smart + +logger = logging.getLogger("SCUD_PIPELINE") + + +def load_best_snapshot_for_date(date_str: str, prefer_final_y: bool = True) -> pd.DataFrame: + """Извлекает срез СКУД. Для вчерашнего дня строго берет финальный вечерний срез Y.""" + with get_connection() as conn: + df = pd.DataFrame() + cursor = conn.cursor() + + if prefer_final_y: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? AND snapshot_id LIKE 'Y%' ORDER BY id DESC LIMIT 1", + (date_str,) + ) + row = cursor.fetchone() + if row and row[0]: + df = pd.read_sql_query("SELECT * FROM scud_logs WHERE snapshot_id = ?", conn, params=(row[0],)) + + if df.empty: + cursor.execute( + "SELECT snapshot_id FROM scud_logs WHERE log_date = ? ORDER BY id DESC LIMIT 1", + (date_str,) + ) + row = cursor.fetchone() + if row and row[0]: + df = pd.read_sql_query("SELECT * FROM scud_logs WHERE snapshot_id = ?", conn, params=(row[0],)) + + if not df.empty: + rename_map = { + 'department': 'Подразделение', 'position': 'Должность', 'fio': 'Сотрудник', + 'time_in': 'Начало_дня', 'first_activity': 'Первая_активность', 'time_out': 'Конец_дня', + 'time_in_building': 'Находился_в_здании', 'is_present': 'Пришел' + } + df = df.rename(columns={k: v for k, v in rename_map.items() if k in df.columns}) + if 'fio_clean' not in df.columns and 'Сотрудник' in df.columns: + df['fio_clean'] = df['Сотрудник'].astype(str).str.strip() + if 'Пришел' in df.columns: + df['Пришел'] = df['Пришел'].astype(bool) + + return df + + +def load_1c_files_for_date(date_str: str) -> tuple[pd.DataFrame, pd.DataFrame]: + df_staff, df_absences = load_1c_data_smart(date_str, use_db=False) + return (df_staff if df_staff is not None else pd.DataFrame(), + df_absences if df_absences is not None else pd.DataFrame()) +``` + +## File: `./services/scud_etl/merger.py` +```py +""" +=============================================================================== +FILE: services/scud_etl/merger.py +=============================================================================== +""" + +import logging +from typing import Dict, Any +import pandas as pd + +from services.knowledge.service import get_department_synonyms_dict +from config import normalize_fio, load_exceptions + +logger = logging.getLogger("SCUD_MERGER") + + +def merge_scud_and_1c( + df_scud: pd.DataFrame, + df_staff_1c: pd.DataFrame, + df_absences_1c: pd.DataFrame +) -> pd.DataFrame: + if (df_scud is None or df_scud.empty) and (df_staff_1c is None or df_staff_1c.empty): + return pd.DataFrame(columns=[ + 'Сотрудник', 'fio_clean', 'Подразделение', 'Должность', + 'Начало_дня', 'Первая_активность', 'Конец_дня', 'Находился_в_здании', + 'Пришел', 'anomaly_flag', 'причина отсутствия', 'Вид_отсутствия', 'is_excluded' + ]) + + synonyms = get_department_synonyms_dict() + exceptions_cfg = load_exceptions() + + df_res = df_scud.copy() if df_scud is not None and not df_scud.empty else df_staff_1c.copy() + + if "Сотрудник" in df_res.columns: + df_res["fio_clean"] = df_res["Сотрудник"].apply(normalize_fio) + elif "ФИО" in df_res.columns: + df_res["Сотрудник"] = df_res["ФИО"] + df_res["fio_clean"] = df_res["ФИО"].apply(normalize_fio) + elif "fio_clean" not in df_res.columns: + df_res["fio_clean"] = "" + + for col, default_val in [ + ('Начало_дня', 'Нет входа'), + ('Первая_активность', '—'), + ('Конец_дня', 'Нет выхода'), + ('Находился_в_здании', '00:00'), + ('Пришел', False), + ('anomaly_flag', 'NONE') + ]: + if col not in df_res.columns: + df_res[col] = default_val + + # 1. Приведение отделов к аббревиатурам + reverse_synonyms = {v.lower(): k.upper() for k, v in synonyms.items()} + direct_synonyms = {k.lower(): k.upper() for k in synonyms.keys()} + all_dept_map = {**reverse_synonyms, **direct_synonyms, "отдел внутреннего контроля": "ОВК", "отдел вневедомственного контроля": "ОВК"} + + if "Подразделение" in df_res.columns: + df_res["Подразделение"] = df_res["Подразделение"].apply( + lambda d: all_dept_map.get(str(d).strip().lower(), str(d).strip()) + ) + + # 2. Привязка документов отсутствий из 1С ПЕРЕД разметкой исключений + absences_map = {} + if not df_absences_1c.empty: + fio_col = next((c for c in ["fio_clean", "ФИО", "Сотрудник"] if c in df_absences_1c.columns), None) + reason_col = next((c for c in ["Вид_отсутствия", "Причина", "причина отсутствия"] if c in df_absences_1c.columns), None) + + if fio_col and reason_col: + for _, row in df_absences_1c.iterrows(): + fio = normalize_fio(str(row[fio_col])) + reason = str(row[reason_col]).strip() + if reason and reason.lower() != "nan": + absences_map[fio] = reason + + df_res["причина отсутствия"] = df_res["fio_clean"].map(absences_map) + df_res["Вид_отсутствия"] = df_res["причина отсутствия"] + + # 3. Разметка исключений + exc_fios = [normalize_fio(f) for f in exceptions_cfg.get("fio", []) if f] + exc_depts = [d.strip().upper() for d in exceptions_cfg.get("departments", []) if d] + exc_pos = [p.strip().lower() for p in exceptions_cfg.get("positions", []) if p] + pos_kw = [k.strip().lower() for k in exceptions_cfg.get("position_keywords", []) if k] + whitelist_fios = [normalize_fio(f) for f in exceptions_cfg.get("include_fio", []) if f] + + df_res["is_excluded"] = False + for idx, row in df_res.iterrows(): + fio = row.get("fio_clean", "") + has_official_absence = pd.notna(row.get("Вид_отсутствия")) and str(row.get("Вид_отсутствия")).strip() != "" + + # ⭐️ Если сотрудник в белом списке ИЛИ у него есть официальное отсутствие — он НЕ исключается + if fio in whitelist_fios or has_official_absence: + df_res.at[idx, "is_excluded"] = False + continue + + dep = str(row.get("Подразделение", "")).upper() + pos = str(row.get("Должность", "")).lower() + + if fio in exc_fios or dep in exc_depts or any(d in dep for d in exc_depts) or pos in exc_pos or any(k in pos for k in pos_kw): + df_res.at[idx, "is_excluded"] = True + + # Чистое "Исключение" только для истинно исключенных без документов 1С + mask_exc = (df_res["is_excluded"] == True) & (df_res["Вид_отсутствия"].isna() | (df_res["Вид_отсутствия"] == "")) + df_res.loc[mask_exc, "Вид_отсутствия"] = "Исключение" + df_res.loc[mask_exc, "причина отсутствия"] = "Исключение" + + return df_res + + +def calculate_summary_metrics(df_merged: pd.DataFrame) -> Dict[str, Any]: + active_df = df_merged[df_merged.get("is_excluded", False) == False].copy() + total_staff = len(active_df) + + # 1. Строго физически пришедшие в офис + came_to_office_mask = active_df["Начало_дня"].astype(str).str.strip().ne("Нет входа") + working_in_office = active_df[came_to_office_mask] + working_in_office_count = len(working_in_office) + + # 2. Не пришедшие в офис + df_not_came = active_df[~came_to_office_mask] + + # 3. Из не пришедших — удаленщики (работают из дома) + reason_series = df_not_came["причина отсутствия"].astype(str).str.lower() + is_remote_mask = reason_series.str.contains("удален|дистанцион", regex=True, na=False) + remote_home = df_not_came[is_remote_mask] + remote_home_count = len(remote_home) + + # 4. Из оставшихся — официальные отсутствия (отпуск, больничный, командировка) + df_remaining_absent = df_not_came[~is_remote_mask] + has_doc_mask = df_remaining_absent["причина отсутствия"].notna() & \ + df_remaining_absent["причина отсутствия"].ne("") & \ + df_remaining_absent["причина отсутствия"].ne("nan") & \ + (~df_remaining_absent["причина отсутствия"].astype(str).str.startswith("Исключение")) + official_absent_count = len(df_remaining_absent[has_doc_mask]) + + # 5. Неизвестные + unknown = df_remaining_absent[~has_doc_mask] + unknown_count = len(unknown) + + return { + "total_staff": total_staff, + "working_in_office_count": working_in_office_count, + "remote_home_count": remote_home_count, + "official_absent_count": official_absent_count, + "unknown_count": unknown_count, + "unknown_list": unknown[["fio_clean", "Подразделение", "Должность"]].to_dict(orient="records") if not unknown.empty else [] + } +``` + +## File: `./services/scud_etl/anomaly_detector.py` +```py +""" +=============================================================================== +FILE: services/scud_etl/anomaly_detector.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: services / scud_etl +ROLE: Детектирование истинных аномалий и конфликтов реестров. + (Сотрудники из exceptions.json, удаленка и командировки исключены). +=============================================================================== +""" + +import logging +from typing import List, Dict, Any +import pandas as pd + +logger = logging.getLogger("SCUD_ANOMALY") + + +def detect_registry_anomalies(df_merged: pd.DataFrame) -> List[Dict[str, Any]]: + """ + Выявляет реальные аномалии: + - Приход в офис во время отпуска или больничного листа. + - Ошибки считывателей СКУД (наличие выхода при отсутствии отметки входа). + """ + anomalies = [] + if df_merged is None or df_merged.empty: + return anomalies + + for _, row in df_merged.iterrows(): + # Пропускаем системные исключения + if row.get("is_excluded", False): + continue + + fio = row.get("fio_clean") or row.get("Сотрудник", "") + start_day = str(row.get("Начало_дня", "")).strip() + end_day = str(row.get("Конец_дня", "")).strip() + reason = str(row.get("причина отсутствия", row.get("Вид_отсутствия", ""))).strip() + reason_lower = reason.lower() + + # Пропускаем технические метки + if "исключен" in reason_lower or "овк" in reason_lower: + continue + + # ⭐️ Физический приход в офис: удаленка и командировки разрешены и НЕ являются аномалией + if start_day not in ["Нет входа", "—", "", "nan", "None"] and reason and reason != "nan": + if not ("удален" in reason_lower or "дистанцион" in reason_lower or "командировк" in reason_lower or "поездк" in reason_lower): + anomalies.append({ + "fio": fio, + "type": "PHYSICAL_PRESENCE_DURING_ABSENCE", + "description": f"Сотрудник пришел по СКУД ({start_day}), но в 1С оформлен документ: '{reason}'." + }) + + # Аномалия оборудования (есть выход без утреннего входа) + if start_day in ["Нет входа", "—", ""] and end_day not in ["Нет выхода", "—", "", "nan", "None"]: + anomalies.append({ + "fio": fio, + "type": "SCUD_EQUIPMENT_ANOMALY", + "description": f"Отсутствует отметка утреннего входа при наличии выхода ({end_day})." + }) + + return anomalies +``` + +## File: `./services/snapshots/service.py` +```py +""" +=============================================================================== +FILE: services/snapshots/service.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: services / snapshots +ROLE: Бизнес-логика срезов СКУД (выборка, валидация Y-срезов, удаление). + +AI-CONTEXT-ANCHORS: + - ANCHOR[SNAPSHOT_GET_REGISTRY]: Выборка срезов с разметкой защищенных Y-снапшотов. + - ANCHOR[SNAPSHOT_DELETE_SAFE]: Безопасное удаление дневных срезов с защитой итоговых. +=============================================================================== +""" + +from typing import Dict, Any, Optional, List +from core.connection import get_connection +from core.repositories.scud_repo import get_available_snapshots, delete_snapshot_by_id + + +# ANCHOR[SNAPSHOT_GET_REGISTRY] +def get_snapshots_registry(date_str: Optional[str] = None) -> Dict[str, Any]: + """Возвращает реестр снапшотов за дату или за все доступные дни.""" + clean_date = date_str.strip() if date_str else "" + rows = get_available_snapshots(date_str=clean_date if clean_date else None) + + snapshots = [ + { + "snapshot_id": r[0], + "log_date": r[1], + "snapshot_time": r[2], + "record_count": r[3], + "is_final": str(r[0]).startswith("Y") + } + for r in rows + ] + + return { + "query_date": clean_date or "все", + "snapshots_count": len(snapshots), + "snapshots": snapshots + } + + +# ANCHOR[SNAPSHOT_DELETE_SAFE] +def delete_snapshots_safely(snapshot_ids: List[str]) -> Dict[str, Any]: + """ + Удаляет выбранные дневные снапшоты. + Итоговые вечерние срезы с префиксом 'Y' гарантированно защищены от удаления. + """ + if not snapshot_ids: + return {"status": "error", "message": "Не указаны ID снапшотов для удаления."} + + safe_ids = [str(s).strip() for s in snapshot_ids if s and not str(s).strip().startswith("Y")] + + if not safe_ids: + return {"status": "error", "message": "⚠️ Итоговый срез Y защищен от удаления. Выберите дневные снапшоты."} + + with get_connection() as conn: + cursor = conn.cursor() + placeholders = ",".join(["?"] * len(safe_ids)) + cursor.execute(f"DELETE FROM scud_logs WHERE snapshot_id IN ({placeholders})", safe_ids) + deleted_count = cursor.rowcount + conn.commit() + + return { + "status": "success", + "deleted_count": deleted_count, + "deleted_ids": safe_ids, + "message": f"Успешно удалено снапшотов: {len(safe_ids)} шт." + } +``` + +## File: `./services/tasks/repository.py` +```py +""" +=============================================================================== +FILE: services/tasks/repository.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: services / tasks +ROLE: Низкоуровневые операции к таблице tasks в SQLite (CRUD). + +AI-CONTEXT-ANCHORS: + - ANCHOR[TASK_REPO_GET]: Выборка задач с фильтрацией по статусу и пользователю. + - ANCHOR[TASK_REPO_ADD]: Вставка новой задачи со сквозным ID. + - ANCHOR[TASK_REPO_UPDATE]: Обновление реквизитов и статуса задачи. + - ANCHOR[TASK_REPO_DELETE]: Удаление задачи по числовому или строковому ID. +=============================================================================== +""" + +import re +from typing import List, Dict, Any, Optional +from core.connection import get_connection + + +def normalize_task_id(task_id_input: str) -> str: + """Нормализует идентификатор задачи к формату TASK-XX.""" + if not task_id_input: + return "" + clean_id = str(task_id_input).strip().upper().replace("TASK-", "").replace("TASK", "").replace("#", "") + if clean_id.isdigit(): + num = int(clean_id) + return f"TASK-{num:02d}" if num < 100 else f"TASK-{num:03d}" + return f"TASK-{clean_id}" + + +# ANCHOR[TASK_REPO_GET] +def repo_get_tasks(user_id: int, status: Optional[str] = None) -> List[Dict[str, Any]]: + """Получает список задач пользователя с опциональной фильтрацией по статусу.""" + conn = get_connection(row_factory=True) + cursor = conn.cursor() + + if status and status.upper() != "ALL": + target_status = status.upper() + if target_status in ["PROGRESS", "В РАБОТЕ"]: + target_status = "IN_PROGRESS" + elif target_status in ["DONE", "ГОТОВО"]: + target_status = "COMPLETED" + elif target_status in ["PLANNED", "ПЛАНЫ"]: + target_status = "BACKLOG" + + cursor.execute(""" + SELECT id, task_id, module, title, priority, status, due_date, created_at + FROM tasks + WHERE user_id = ? AND (status = ? OR (status = 'BACKLOG' AND ? = 'PLANNED')) + ORDER BY id DESC + """, (user_id, target_status, target_status)) + else: + cursor.execute(""" + SELECT id, task_id, module, title, priority, status, due_date, created_at + FROM tasks + WHERE user_id = ? + ORDER BY id DESC + """, (user_id,)) + + rows = cursor.fetchall() + conn.close() + return [dict(r) for r in rows] + + +# ANCHOR[TASK_REPO_ADD] +def repo_add_task( + user_id: int, + module: str, + title: str, + priority: str = "MEDIUM", + due_date: Optional[str] = None, + status: str = "BACKLOG" +) -> Dict[str, Any]: + """Добавляет новую задачу в SQLite с автогенерацией порядкового TASK-ID.""" + conn = get_connection() + cursor = conn.cursor() + cursor.execute("SELECT MAX(id) FROM tasks") + max_id = cursor.fetchone()[0] or 0 + new_task_id = f"TASK-{(max_id + 1):02d}" + + target_status = status.upper() if status else "BACKLOG" + if target_status in ["PROGRESS", "В РАБОТЕ"]: + target_status = "IN_PROGRESS" + elif target_status in ["DONE", "ГОТОВО"]: + target_status = "COMPLETED" + elif target_status in ["PLANNED", "ПЛАНЫ", "BACKLOG"]: + target_status = "BACKLOG" + + cursor.execute(""" + INSERT INTO tasks (task_id, module, title, priority, status, due_date, user_id) + VALUES (?, ?, ?, ?, ?, ?, ?) + """, (new_task_id, module or "general", title.strip(), priority.upper(), target_status, due_date, user_id)) + conn.commit() + conn.close() + return {"status": "success", "task_id": new_task_id, "id": max_id + 1} + + +# ANCHOR[TASK_REPO_UPDATE] +def repo_update_task( + user_id: int, + task_id: str, + title: Optional[str] = None, + priority: Optional[str] = None, + status: Optional[str] = None, + due_date: Optional[str] = None +) -> Dict[str, Any]: + """Комплексное обновление атрибутов задачи.""" + conn = get_connection() + cursor = conn.cursor() + + clean_num = re.sub(r'\D', '', str(task_id)) + formatted_id = normalize_task_id(task_id) + + updates = [] + params = [] + + if title is not None and title.strip(): + updates.append("title = ?") + params.append(title.strip()) + + if priority is not None and priority.strip(): + updates.append("priority = ?") + params.append(priority.strip().upper()) + + if status is not None and status.strip(): + target_status = status.strip().upper() + if target_status in ["PROGRESS", "В РАБОТЕ"]: + target_status = "IN_PROGRESS" + elif target_status in ["DONE", "ГОТОВО"]: + target_status = "COMPLETED" + elif target_status in ["PLANNED", "ПЛАНЫ"]: + target_status = "BACKLOG" + updates.append("status = ?") + params.append(target_status) + + if due_date is not None: + updates.append("due_date = ?") + params.append(due_date.strip() if due_date.strip() else None) + + if not updates: + conn.close() + return {"status": "success", "message": "Нет данных для обновления"} + + params.extend([clean_num, formatted_id, f"%{task_id.strip()}", user_id]) + sql = f""" + UPDATE tasks + SET {', '.join(updates)} + WHERE (id = ? OR UPPER(task_id) = ? OR task_id LIKE ?) AND user_id = ? + """ + cursor.execute(sql, params) + rows_affected = cursor.rowcount + conn.commit() + conn.close() + + if rows_affected == 0: + return {"error": f"Задача {task_id} не найдена или принадлежит другому пользователю"} + + return {"status": "success", "message": f"Задача #{task_id} успешно обновлена"} + + +# ANCHOR[TASK_REPO_DELETE] +def repo_delete_task(user_id: int, task_id: str) -> Dict[str, Any]: + """Удаляет задачу по номеру ID.""" + conn = get_connection() + cursor = conn.cursor() + clean_num = re.sub(r'\D', '', str(task_id)) + formatted_id = normalize_task_id(task_id) + + cursor.execute(""" + DELETE FROM tasks + WHERE (id = ? OR UPPER(task_id) = ? OR task_id LIKE ?) AND user_id = ? + """, (clean_num, formatted_id, f"%{task_id.strip()}", user_id)) + + deleted = cursor.rowcount + conn.commit() + conn.close() + + if deleted == 0: + return {"error": f"Задача {task_id} не найдена"} + return {"status": "success", "message": f"Задача #{task_id} удалена"} +``` + +## File: `./services/tasks/service.py` +```py +""" +=============================================================================== +FILE: services/tasks/service.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: services / tasks +ROLE: Единый доменный сервис задач (бизнес-логика и диспетчер операций). + +AI-CONTEXT-ANCHORS: + - ANCHOR[TASK_SERVICE_DISPATCHER]: Маршрутизация действий ADD/UPDATE/DELETE/EXPORT. +=============================================================================== +""" + +from typing import Dict, Any, Optional, List +from .repository import repo_get_tasks, repo_add_task, repo_update_task, repo_delete_task +from .exporter import export_tasks_to_markdown + + +def get_tasks(user_id: int, status: Optional[str] = None) -> List[Dict[str, Any]]: + """Получить список задач.""" + return repo_get_tasks(user_id, status) + + +def add_task(user_id: int, module: str, title: str, priority: str = "MEDIUM", due_date: Optional[str] = None, status: str = "BACKLOG") -> Dict[str, Any]: + """Создать задачу.""" + res = repo_add_task(user_id, module, title, priority, due_date, status) + return {"status": "success", "task_id": res["task_id"], "message": f"Задача #{res['id']} создана и добавлена в планы"} + + +def update_task_details(user_id: int, task_id: str, title: Optional[str] = None, priority: Optional[str] = None, status: Optional[str] = None, due_date: Optional[str] = None) -> Dict[str, Any]: + """Обновить задачу.""" + return repo_update_task(user_id, task_id, title, priority, status, due_date) + + +def delete_task(user_id: int, task_id: str) -> Dict[str, Any]: + """Удалить задачу.""" + return repo_delete_task(user_id, task_id) + + +# ANCHOR[TASK_SERVICE_DISPATCHER] +def execute_task_action( + user_id: int, + action: str, + task_id: Optional[str] = None, + title: Optional[str] = None, + priority: Optional[str] = "MEDIUM", + status: Optional[str] = None, + module: Optional[str] = "general", + due_date: Optional[str] = None, + filename: Optional[str] = "ROADMAP.md" +) -> Dict[str, Any]: + """Консолидированный диспетчер операций над задачами.""" + act = (action or "").strip().upper() + + if act == "ADD": + if not title: + return {"status": "error", "message": "Для создания задачи требуется указать title"} + return add_task(user_id, module or "general", title, priority or "MEDIUM", due_date, status or "BACKLOG") + + elif act == "UPDATE": + if not task_id: + return {"status": "error", "message": "Для обновления требуется указать task_id"} + return update_task_details(user_id, str(task_id), title, priority, status, due_date) + + elif act == "DELETE": + if not task_id: + return {"status": "error", "message": "Для удаления требуется указать task_id"} + return delete_task(user_id, str(task_id)) + + elif act == "EXPORT": + return export_tasks_to_markdown(user_id, filename=filename or "ROADMAP.md", status_filter=status) + + return {"status": "error", "message": f"Неизвестное действие action='{action}'"} +``` diff --git a/exceptions.json b/exceptions.json index 742ba5f..ab43c66 100644 --- a/exceptions.json +++ b/exceptions.json @@ -7,10 +7,9 @@ "Уборщик служебных помещений" ], "fio": [ - "Таткало Валерий Валерьевич", - "Петренюк Андрей Германович", - "Чуркина Елена Геннадьевна", - "Михалев Сергей Геннадьевич" + "Таткало Валерий Валерьевич", + "Петренюк Андрей Германович", + "Михалев Сергей Геннадьевич" ], "position_keywords": [ "уборщик", @@ -18,5 +17,9 @@ "дворник", "гардероб", "рабочий по обслуживанию" + ], + "include_fio": [ + "Тарасенко Александр Александрович", + "Журиков Михаил Николаевич" ] } \ No newline at end of file diff --git a/main_etl.py b/main_etl.py index 3a1b6f5..3b6e194 100644 --- a/main_etl.py +++ b/main_etl.py @@ -1,571 +1,116 @@ +""" +=============================================================================== +FILE: main_etl.py +PROJECT: SCUD Orion AI (Unified Architecture) +ROLE: Главная точка входа ETL-конвейера СКУД ⟷ 1С:ЗУП. +=============================================================================== +""" + import os import sys -import json import argparse +import logging import pandas as pd from datetime import datetime, timedelta -sys.path.append(os.path.dirname(os.path.abspath(__file__))) +from services.scud_etl.pipeline import load_best_snapshot_for_date, load_1c_files_for_date +from services.scud_etl.merger import merge_scud_and_1c, calculate_summary_metrics +from services.scud_etl.anomaly_detector import detect_registry_anomalies +from services.text_reporter import generate_markdown_report -from config import DATE_TODAY, DATE_YESTERDAY, OUTPUT_DIR, DATA_DIR, normalize_fio from services.scud_export import run_export from services.share_copier import copy_1c_files_from_share -from services.data_validator import check_file_freshness -from services.data_loader import load_1c_data_smart, load_scud_data from services.excel_exporter import generate_summary_excel, generate_detailed_excel -from services.ai_verifier import ai_verify_scud_against_staff, analyze_scud_mass_failure_ai -from services.text_reporter import generate_markdown_report -from services.feedback_loop import review_ai_decisions -from services.knowledge_base import load_knowledge_base -from core.database import ( - init_db, - save_scud_to_db, - save_staff_to_db, - save_absences_to_db, - save_anomalies_to_db, - load_scud_from_db_by_snapshot, - load_staff_from_db, - load_absences_from_db, - get_latest_snapshot_time, - has_scud_logs_for_date -) - -def load_exceptions_config(): - """Загружает файл exceptions.json из корня проекта.""" - root_dir = os.path.dirname(os.path.abspath(__file__)) - json_path = os.path.join(root_dir, "exceptions.json") - if not os.path.exists(json_path): - return {} - try: - with open(json_path, 'r', encoding='utf-8') as f: - return json.load(f) - except Exception as e: - print(f"[⚠️] Ошибка чтения exceptions.json: {e}") - return {} - - -def apply_exceptions_from_json(df, exceptions_cfg): - """ - Быстрая и эффективная разметка флага is_excluded=True на основе exceptions.json. - Выполняется мгновенно без цикличных HTTP-запросов к ИИ. - """ - if df is None or df.empty or not exceptions_cfg: - if df is not None: - df['is_excluded'] = False - return df - - deps = [d.strip().lower() for d in exceptions_cfg.get("departments", []) if d] - exact_pos = [p.strip().lower() for p in exceptions_cfg.get("positions", []) if p] - pos_kw = [k.strip().lower() for k in exceptions_cfg.get("position_keywords", []) if k] - exc_fios = [normalize_fio(f) for f in exceptions_cfg.get("fio", []) if f] - - df['is_excluded'] = False - - for idx, row in df.iterrows(): - fio_clean = row.get('fio_clean', '') - dep_1c = str(row.get('Подразделение', '')).lower() - dep_scud = str(row.get('department_scud', row.get('department', ''))).lower() - pos = str(row.get('Должность', '')).lower() - - is_fio_exc = fio_clean in exc_fios - is_pos_exc = (pos in exact_pos) or any(k in pos for k in pos_kw if k) if pos else False - - # Быстрая проверка отделов по подстрокам - is_dep_exc = False - if deps: - is_dep_exc = any(d in dep_1c or d in dep_scud for d in deps) - - if is_fio_exc or is_dep_exc or is_pos_exc: - df.at[idx, 'is_excluded'] = True - - return df - - -def filter_report_dataframe(merged_df): - """ - Исключает сотрудников из списка исключений и сотрудников без пропуска из детального отчета, - ЕСЛИ у них нет официального документа отсутствия из 1С:ЗУП. - """ - if merged_df is None or merged_df.empty: - return merged_df - - has_1c_reason = ( - merged_df['Вид_отсутствия'].notna() & - (merged_df['Вид_отсутствия'].astype(str).str.strip() != '') & - (~merged_df['Вид_отсутствия'].astype(str).str.startswith('Исключение')) - ) - is_not_excluded = merged_df.get('is_excluded', False) == False - is_not_no_pass = merged_df.get('no_scud_pass', False) == False - - filtered_df = merged_df[(is_not_excluded & is_not_no_pass) | has_1c_reason].copy() - return filtered_df - - -def load_static_reason_workers(): - """Загружает реестр удалёнщиков и статических причин из CSV.""" - static_path = os.path.join(DATA_DIR, "static_reason_workers.csv") - if not os.path.exists(static_path): - return {} - try: - df_static = pd.read_csv(static_path, encoding='utf-8') - if 'fio' in df_static.columns and 'reason' in df_static.columns: - df_static['fio_clean'] = df_static['fio'].apply(normalize_fio) - return dict(zip(df_static['fio_clean'], df_static['reason'])) - except Exception as e: - print(f"[⚠️] Ошибка чтения static_reason_workers.csv: {e}") - return {} - - -def detect_all_anomalies(merged_df, static_reasons_dict, kb_rules, scud_fios_set=None): - """ - Автоматически выявляет истинные аномалии СКУД ⟷ 1С. - """ - anomalies = [] - kb_rules_text = " ".join(kb_rules).lower() if kb_rules else "" - - ALLOWED_WORK_TRIP_KEYWORDS = ['командировк', 'разъездн', 'поездк'] - - for idx, row in merged_df.iterrows(): - fio = row.get('Сотрудник', row.get('fio_clean', '')) - fio_clean = row.get('fio_clean', '') - is_present = row.get('Пришел', False) - is_exc = row.get('is_excluded', False) - reason_1c = str(row.get('Вид_отсутствия', '')).strip() - has_1c_reason = pd.notna(row.get('Вид_отсутствия')) and reason_1c != '' and not reason_1c.startswith('Исключение') - anom_flag = row.get('anomaly_flag', 'NONE') - - is_fio_whitelisted_in_kb = fio_clean.lower() in kb_rules_text - - if is_present and has_1c_reason: - reason_lower = reason_1c.lower() - is_allowed_trip = any(kw in reason_lower for kw in ALLOWED_WORK_TRIP_KEYWORDS) - - if not is_allowed_trip and not is_fio_whitelisted_in_kb: - anomalies.append({ - "type": "ФИЗИЧЕСКОЕ ПРИСУТСТВИЕ ПРИ ОФИЦИАЛЬНОМ ОТСУТСТВИИ", - "fio": fio, - "details": f"Сотрудник пришел по СКУД, но в 1С оформлен документ: '{reason_1c}'" - }) - - if is_exc and not has_1c_reason: - continue - - if anom_flag == 'ANOMALY_NO_IN_HAS_ACTIVITY': - first_act = row.get('Первая_активность', '—') - anomalies.append({ - "type": "АНОМАЛИЯ СКУД: ПЕРЕМЕЩЕНИЕ БЕЗ ВХОДА", - "fio": fio, - "details": f"Отсутствует регистрация входа на КПП при зафиксированной первой активности в {first_act}" - }) - - if scud_fios_set is not None: - if fio_clean not in scud_fios_set and not has_1c_reason: - anomalies.append({ - "type": "АНОМАЛИЯ УЧЕТА: СОТРУДНИК ОТСУТСТВУЕТ В СКУД ОРИОН PRO", - "fio": fio, - "details": f"Сотрудник числится в Штатном расписании 1С ({row.get('Подразделение', '—')}), но полностью отсутствует в базе СКУД Орион Pro (профиль не создан или карта не выдана)" - }) - - return anomalies - - -def aggregate_scud_by_employee(df, debug=False): - """Агрегирует проходы СКУД по уникальным сотрудникам.""" - if df is None or df.empty or 'fio_clean' not in df.columns: - return df - - aggregated = [] - for fio_clean, group in df.groupby('fio_clean', sort=False): - is_present = group['Пришел'].any() if 'Пришел' in group.columns else False - - if is_present and 'Пришел' in group.columns: - present_rows = group[group['Пришел'] == True] - best_row = present_rows.iloc[0].to_dict() if not present_rows.empty else group.iloc[0].to_dict() - else: - best_row = group.iloc[0].to_dict() - - best_row['Пришел'] = is_present - aggregated.append(best_row) - - return pd.DataFrame(aggregated) +logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] %(message)s") def main(): - help_text = """ -Система автоматизированного контроллинга СКУД ⟷ 1С:ЗУП (scud_orion_ai_v2) - -ПРИМЕРЫ ЗАПУСКА: - python main.py -- Обычный дневной запуск - python main.py --skip-export -- Расчет отчета по ПОСЛЕДНЕМУ имеющемуся снапшоту из SQLite - python main.py --snapshot 20260805-001 -- Расчет отчета строго по ID снапшота - python main.py -d -- Запуск в режиме расширенной отладки (DEBUG) -""" - parser = argparse.ArgumentParser( - description=help_text, - formatter_class=argparse.RawDescriptionHelpFormatter - ) - parser.add_argument('-d', '--debug', action='store_true', help="Запуск в режиме отладки с выводом подробных логов") - parser.add_argument('--skip-export', action='store_true', help="Пропустить выгрузку СКУД из MS SQL и построить отчет по последнему снапшоту") - parser.add_argument('--snapshot', type=str, default=None, help="Составной ID снапшота или время создания") - + parser = argparse.ArgumentParser(description="Модульный контроллинг СКУД ⟷ 1С") + parser.add_argument("-d", "--debug", action="store_true", help="Режим отладки") + parser.add_argument("--skip-export", action="store_true", help="Пропустить выгрузку СКУД из MS SQL") + parser.add_argument("--snapshot", type=str, default=None, help="ID снапшота для расчета") args = parser.parse_args() - DEBUG = args.debug print("=" * 60) - print(f"ЗАПУСК СИСТЕМЫ МОДУЛЬНОГО КОНТРОЛЛИНГА СКУД ⟷ 1С {'[DEBUG MODE]' if DEBUG else ''}") + print(f"ЗАПУСК СИСТЕМЫ МОДУЛЬНОГО КОНТРОЛЛИНГА СКУД ⟷ 1С {'[DEBUG]' if args.debug else ''}") print("=" * 60) - init_db() - kb_data = load_knowledge_base() - kb_rules = kb_data.get("rules", []) - exceptions_cfg = load_exceptions_config() - - if args.snapshot: - snapshot_param = args.snapshot - print(f"[📸] РЕЖИМ СНАПШОТА: Расчет отчета строго по срезу '{snapshot_param}'") - elif args.skip_export: - snapshot_param = get_latest_snapshot_time() - print(f"[📸] РЕЖИМ --skip-export: Используем последний снапшот из SQLite ('{snapshot_param}')") + now = datetime.now() + today_str = now.strftime("%d.%m.%Y") + # ⭐️ По понедельникам (weekday == 0) отчетом накануне является пятница (-3 дня) + if now.weekday() == 0: + yesterday_str = (now - timedelta(days=3)).strftime("%d.%m.%Y") else: - snapshot_param = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print(f"[📸] СФОРМИРОВАН НОВЫЙ СНАПШОТ: '{snapshot_param}'") + yesterday_str = (now - timedelta(days=1)).strftime("%d.%m.%Y") + # [Этап 0] Выгрузка свежих данных СКУД if not args.skip_export and not args.snapshot: - try: - run_export(save_xlsx=True, debug=DEBUG) - except Exception as e: - print(f"[⚠️] Ошибка автоэкспорта из БД: {e}. Переходим к записям в SQLite.") + print(f"\n[0/5] Экспорт данных СКУД за {today_str} и {yesterday_str}...") + run_export(debug=args.debug) else: - print("[0/5] Пропуск прямого экспорта из MS SQL (чтение из базы SQLite)...") + print("\n[0/5] Пропуск прямого экспорта СКУД из MS SQL (--skip-export)...") - # ⚡️ ПРОВЕРКА ШАРЫ ТОЛЬКО ДЛЯ ОБЫЧНОГО ДНЕВНОГО ЗАПУСКА + # [Этап 0.5] Синхронизация файлов с шары 1С if not args.snapshot and not args.skip_export: + print(f"\n[0.5/5] Проверка и копирование файлов 1С с шары...") copy_1c_files_from_share() - - print("[1/5] Проверка актуальности и свежести входных данных...") - is_valid, warnings, errors, has_today_1c = check_file_freshness() - - if warnings: - print("\n--- ⚠️ ПРЕДУПРЕЖДЕНИЯ ОБ АКТУАЛЬНОСТИ ---") - for w in warnings: - print(f" • {w}") - print("-" * 45) - - if not is_valid: - print("\n" + "!" * 60) - print("🛑 ОСТАНОВКА ВЫПОЛНЕНИЯ: Отсутствуют критически важные файлы за вчерашний день!") - for e in errors: - print(f" {e}") - print("!" * 60) - sys.exit(1) - - print("[✓] Проверка доступности данных успешно пройдена!\n") else: - print("[1/5] Пропуск проверки сетевой шары (все данные читаются из SQLite)...") - has_today_1c = True + print("\n[0.5/5] Пропуск синхронизации с шары (чтение локальных данных)...") - print("[2/5] Загрузка данных из СКУД, 1С:ЗУП, реестра причин и исключений...") - - # 🎯 ВЫЧИСЛЕНИЕ ДАТ СНАПШОТА И ДАТ НАКАНУНЕ - if args.snapshot or args.skip_export: - raw_scud_today_df = load_scud_from_db_by_snapshot(None, snapshot_param=snapshot_param) - - if not raw_scud_today_df.empty and 'log_date' in raw_scud_today_df.columns: - target_date_str = str(raw_scud_today_df['log_date'].iloc[0]) - else: - target_date_str = DATE_TODAY + # [Этап 1-2] Загрузка данных + print(f"\n[1-2/5] Загрузка срезов: Сегодня = {today_str}, Накануне = {yesterday_str}...") + df_scud_yesterday = load_best_snapshot_for_date(yesterday_str, prefer_final_y=True) + df_scud_today = load_best_snapshot_for_date(today_str, prefer_final_y=False) - dt_target = datetime.strptime(target_date_str, "%d.%m.%Y") - if dt_target.weekday() == 0: # Понедельник -> Пятница - dt_yesterday = dt_target - timedelta(days=3) - else: - dt_yesterday = dt_target - timedelta(days=1) - yesterday_date_str = dt_yesterday.strftime("%d.%m.%Y") + df_staff_yesterday, df_abs_yesterday = load_1c_files_for_date(yesterday_str) + df_staff_today, df_abs_today = load_1c_files_for_date(today_str) - print(f"[📸] СНАПШОТ ОПРЕДЕЛЕН: Целевая дата = {target_date_str}, Накануне = {yesterday_date_str}") + # [Этап 3] Детальный отчет за вчера + print(f"\n[3/5] Обработка и построение детального отчета за ВЧЕРА ({yesterday_str})...") + df_merged_yesterday = merge_scud_and_1c(df_scud_yesterday, df_staff_yesterday, df_abs_yesterday) + generate_detailed_excel(df_merged_yesterday, date_str=yesterday_str) - raw_scud_yesterday_df = load_scud_from_db_by_snapshot(yesterday_date_str, snapshot_param=None) + # [Этап 4] Сводка за сегодня + print(f"\n[4/5] Обработка и построение Ежедневной сводки за {today_str}...") + df_merged_today = merge_scud_and_1c(df_scud_today, df_staff_today, df_abs_today) + metrics_today = calculate_summary_metrics(df_merged_today) + anomalies_today = detect_registry_anomalies(df_merged_today) + generate_summary_excel(df_merged_today, date_str=today_str) - # Гарантированная загрузка кадров 1С за обе даты (БД + локальный фолбэк) - df_staff_today, df_absent_today = load_1c_data_smart(target_date_str, use_db=True) - df_staff_yesterday, df_absent_yesterday = load_1c_data_smart(yesterday_date_str, use_db=True) - else: - target_date_str = DATE_TODAY - yesterday_date_str = DATE_YESTERDAY + # [Этап 5] Формирование Markdown-сводки через ИИ-аудитора + print(f"\n[5/5] Формирование Markdown-сводки через ИИ-аудитора (Ollama)...") - raw_scud_today_df = load_scud_from_db_by_snapshot(target_date_str, snapshot_param=snapshot_param) - raw_scud_yesterday_df = load_scud_from_db_by_snapshot(yesterday_date_str, snapshot_param=None) + absent_explained = df_merged_today[ + (df_merged_today['Пришел'] == False) & + (df_merged_today['Вид_отсутствия'].notna()) & + (~df_merged_today['Вид_отсутствия'].astype(str).str.startswith('Исключение')) + ] + absent_unexplained = df_merged_today[ + (df_merged_today['Пришел'] == False) & + (df_merged_today['Вид_отсутствия'].isna() | (df_merged_today['Вид_отсутствия'].astype(str).str.strip() == '')) & + (df_merged_today.get('is_excluded', False) == False) + ] - df_staff_today, df_absent_today = load_1c_data_smart(DATE_TODAY, use_db=False) - df_staff_yesterday, df_absent_yesterday = load_1c_data_smart(DATE_YESTERDAY, use_db=False) - - if df_staff_yesterday is not None: - save_staff_to_db(df_staff_yesterday, yesterday_date_str) - if df_absent_yesterday is not None: - save_absences_to_db(df_absent_yesterday, yesterday_date_str) - - if df_staff_today is not None: - save_staff_to_db(df_staff_today, target_date_str) - if df_absent_today is not None: - save_absences_to_db(df_absent_today, target_date_str) - - staff_fios_yesterday_clean = df_staff_yesterday['fio_clean'].dropna().tolist() if df_staff_yesterday is not None else [] - static_reasons_dict = load_static_reason_workers() - - # ============================================================ - # 🎯 ЧАСТЬ 1: ДЕТАЛЬНЫЙ ОТЧЕТ ЗА ВЧЕРА (ДЕНЬ НАКАНУНЕ) - # ============================================================ - print(f"\n[3/5] Обработка и построение детального отчета за ВЧЕРА ({yesterday_date_str})...") - - if not raw_scud_yesterday_df.empty and 'Пришел' not in raw_scud_yesterday_df.columns: - raw_scud_yesterday_df['Пришел'] = raw_scud_yesterday_df['is_present'].astype(int) == 1 if 'is_present' in raw_scud_yesterday_df.columns else False - - scud_yesterday_unrecognized = raw_scud_yesterday_df[~raw_scud_yesterday_df['fio_clean'].isin(staff_fios_yesterday_clean)]['fio_clean'].tolist() if not raw_scud_yesterday_df.empty else [] - - fio_mapping_scud_y = ai_verify_scud_against_staff(scud_yesterday_unrecognized, staff_fios_yesterday_clean) - if fio_mapping_scud_y: - raw_scud_yesterday_df['fio_clean'] = raw_scud_yesterday_df['fio_clean'].apply( - lambda x: fio_mapping_scud_y[x]['staff_fio'] if x in fio_mapping_scud_y else x - ) - - if df_absent_yesterday is not None and not df_absent_yesterday.empty: - absent_unrecognized_yesterday = df_absent_yesterday[~df_absent_yesterday['fio_clean'].isin(staff_fios_yesterday_clean)]['fio_clean'].tolist() - if absent_unrecognized_yesterday: - fio_mapping_absent_y = ai_verify_scud_against_staff(absent_unrecognized_yesterday, staff_fios_yesterday_clean) - if fio_mapping_absent_y: - df_absent_yesterday['fio_clean'] = df_absent_yesterday['fio_clean'].apply( - lambda x: fio_mapping_absent_y[x]['staff_fio'] if x in fio_mapping_absent_y else x - ) - - raw_scud_yesterday_df = aggregate_scud_by_employee(raw_scud_yesterday_df, debug=DEBUG) - - # ⭐️ ФОРМИРУЕМ МЕРДЖ ИСКЛЮЧИТЕЛЬНО НА БАЗЕ ШТАТА ЗА ПРОШЛЫЙ ДЕНЬ - merged_yesterday = df_staff_yesterday.copy() if (df_staff_yesterday is not None and not df_staff_yesterday.empty) else (df_staff_today.copy() if df_staff_today is not None else pd.DataFrame()) - - if not merged_yesterday.empty: - if not raw_scud_yesterday_df.empty: - if 'Подразделение' in raw_scud_yesterday_df.columns: - raw_scud_yesterday_df['department_scud'] = raw_scud_yesterday_df['Подразделение'] - elif 'department' in raw_scud_yesterday_df.columns: - raw_scud_yesterday_df['department_scud'] = raw_scud_yesterday_df['department'] - else: - raw_scud_yesterday_df['department_scud'] = '' - - merged_yesterday = merged_yesterday.merge( - raw_scud_yesterday_df[['fio_clean', 'Пришел', 'Начало_дня', 'Первая_активность', 'Конец_дня', 'Находился_в_здании', 'anomaly_flag', 'department_scud']], - on='fio_clean', how='left' - ) - - if 'Вид_отсутствия' in merged_yesterday.columns: - merged_yesterday = merged_yesterday.drop(columns=['Вид_отсутствия']) - - # Присоединяем отсутствия СТРОГО за дату yesterday_date_str - if df_absent_yesterday is not None and not df_absent_yesterday.empty: - merged_yesterday = merged_yesterday.merge( - df_absent_yesterday[['fio_clean', 'Вид_отсутствия']], - on='fio_clean', - how='left' - ) - - if 'Пришел' not in merged_yesterday.columns: - merged_yesterday['Пришел'] = False - else: - merged_yesterday['Пришел'] = merged_yesterday['Пришел'].fillna(False) - - if 'Сотрудник' not in merged_yesterday.columns: - merged_yesterday['Сотрудник'] = merged_yesterday.get('ФИО', merged_yesterday['fio_clean']) - - if static_reasons_dict: - for fio_clean, reason_val in static_reasons_dict.items(): - mask_yesterday = ( - (merged_yesterday['Пришел'] == False) & - (merged_yesterday['Вид_отсутствия'].isna() | (merged_yesterday['Вид_отсутствия'].astype(str).str.strip() == '')) & - (merged_yesterday['fio_clean'] == fio_clean) - ) - merged_yesterday.loc[mask_yesterday, 'Вид_отсутствия'] = reason_val - - merged_yesterday = apply_exceptions_from_json(merged_yesterday, exceptions_cfg) - mask_exc_yesterday = ( - (merged_yesterday['Пришел'] == False) & - (merged_yesterday['Вид_отсутствия'].isna() | (merged_yesterday['Вид_отсутствия'].astype(str).str.strip() == '')) & - (merged_yesterday.get('is_excluded', False) == True) + summary_md = generate_markdown_report( + merged_df=df_merged_today[df_merged_today.get('is_excluded', False) == False], + absent_explained=absent_explained, + absent_unexplained=absent_unexplained, + scud_present_but_absent_in_1c=pd.DataFrame(), + anomalies_list=anomalies_today, + date_str=today_str ) - merged_yesterday.loc[mask_exc_yesterday, 'Вид_отсутствия'] = 'Исключение (ОВК/Подрядчики)' + + os.makedirs("output", exist_ok=True) + md_file_path = f"output/Сводка_контроллинга_{today_str}.md" + with open(md_file_path, "w", encoding="utf-8") as f: + f.write(summary_md) + print(f"[✓] Текстовый отчет сохранен в: {md_file_path}") - scud_fios_yesterday_set = set(raw_scud_yesterday_df['fio_clean'].dropna().tolist()) if not raw_scud_yesterday_df.empty else set() - merged_yesterday['no_scud_pass'] = ( - (~merged_yesterday['fio_clean'].isin(scud_fios_yesterday_set)) & - (merged_yesterday['Вид_отсутствия'].isna() | (merged_yesterday['Вид_отсутствия'].astype(str).str.strip() == '')) & - (merged_yesterday.get('is_excluded', False) == False) - ) - - anomalies_yesterday_list = detect_all_anomalies(merged_yesterday, static_reasons_dict, kb_rules, scud_fios_set=scud_fios_yesterday_set) - save_anomalies_to_db(anomalies_yesterday_list, yesterday_date_str) - - filtered_yesterday = filter_report_dataframe(merged_yesterday) - generate_detailed_excel(merged_df=filtered_yesterday, date_str=yesterday_date_str) - - yesterday_dt_obj = datetime.strptime(yesterday_date_str, "%d.%m.%Y") - yesterday_22_str = yesterday_dt_obj.strftime("%Y-%m-%d 22:00:00") - save_scud_to_db(merged_yesterday, yesterday_date_str, snapshot_time=yesterday_22_str, is_yesterday=True) - print(f"[✓] Детальный отчет за вчера сформирован и зафиксирован в SQLite за {yesterday_date_str}") - - # ============================================================ - # 🎯 ЧАСТЬ 2: ЕЖЕДНЕВНАЯ СВОДКА (ЗА ЦЕЛЕВОЙ ДЕНЬ СНАПШОТА) - # ============================================================ - if not args.snapshot and not args.skip_export: - save_scud_to_db(raw_scud_today_df, target_date_str, snapshot_time=snapshot_param, is_yesterday=False) - - if has_today_1c and df_staff_today is not None and df_absent_today is not None: - print(f"\n[4/5] Обработка и построение Ежедневной сводки за {target_date_str}...") - staff_fios_today_clean = df_staff_today['fio_clean'].dropna().tolist() - - if not raw_scud_today_df.empty and 'Пришел' not in raw_scud_today_df.columns: - raw_scud_today_df['Пришел'] = raw_scud_today_df['is_present'].astype(int) == 1 if 'is_present' in raw_scud_today_df.columns else False - - scud_unrecognized = raw_scud_today_df[~raw_scud_today_df['fio_clean'].isin(staff_fios_today_clean)]['fio_clean'].tolist() if not raw_scud_today_df.empty else [] - fio_mapping_scud = ai_verify_scud_against_staff(scud_unrecognized, staff_fios_today_clean) - if fio_mapping_scud: - raw_scud_today_df['fio_clean'] = raw_scud_today_df['fio_clean'].apply( - lambda x: fio_mapping_scud[x]['staff_fio'] if x in fio_mapping_scud else x - ) - - absent_unrecognized_today = df_absent_today[~df_absent_today['fio_clean'].isin(staff_fios_today_clean)]['fio_clean'].tolist() - if absent_unrecognized_today: - fio_mapping_absent = ai_verify_scud_against_staff(absent_unrecognized_today, staff_fios_today_clean) - if fio_mapping_absent: - df_absent_today['fio_clean'] = df_absent_today['fio_clean'].apply( - lambda x: fio_mapping_absent[x]['staff_fio'] if x in fio_mapping_absent else x - ) - - raw_scud_today_df = aggregate_scud_by_employee(raw_scud_today_df, debug=DEBUG) - - merged_today = df_staff_today.copy() - if not raw_scud_today_df.empty: - if 'Подразделение' in raw_scud_today_df.columns: - raw_scud_today_df['department_scud'] = raw_scud_today_df['Подразделение'] - elif 'department' in raw_scud_today_df.columns: - raw_scud_today_df['department_scud'] = raw_scud_today_df['department'] - else: - raw_scud_today_df['department_scud'] = '' - - merged_today = merged_today.merge( - raw_scud_today_df[['fio_clean', 'Пришел', 'Начало_дня', 'Первая_активность', 'Конец_дня', 'Находился_в_здании', 'anomaly_flag', 'department_scud']], - on='fio_clean', how='left' - ) - - if df_absent_today is not None and not df_absent_today.empty: - merged_today = merged_today.merge(df_absent_today[['fio_clean', 'Вид_отсутствия']], on='fio_clean', how='left') - - if 'Пришел' not in merged_today.columns: - merged_today['Пришел'] = False - else: - merged_today['Пришел'] = merged_today['Пришел'].fillna(False) - - if 'Сотрудник' not in merged_today.columns: - merged_today['Сотрудник'] = merged_today.get('ФИО', merged_today['fio_clean']) - - if static_reasons_dict: - for fio_clean, reason_val in static_reasons_dict.items(): - mask_today = ( - (merged_today['Пришел'] == False) & - (merged_today['Вид_отсутствия'].isna() | (merged_today['Вид_отсутствия'].astype(str).str.strip() == '')) & - (merged_today['fio_clean'] == fio_clean) - ) - merged_today.loc[mask_today, 'Вид_отсутствия'] = reason_val - - merged_today = apply_exceptions_from_json(merged_today, exceptions_cfg) - mask_exc_today = ( - (merged_today['Пришел'] == False) & - (merged_today['Вид_отсутствия'].isna() | (merged_today['Вид_отсутствия'].astype(str).str.strip() == '')) & - (merged_today.get('is_excluded', False) == True) - ) - merged_today.loc[mask_exc_today, 'Вид_отсутствия'] = 'Исключение (ОВК/Подрядчики)' - - scud_fios_today_set = set(raw_scud_today_df['fio_clean'].dropna().tolist()) if not raw_scud_today_df.empty else set() - merged_today['no_scud_pass'] = ( - (~merged_today['fio_clean'].isin(scud_fios_today_set)) & - (merged_today['Вид_отсутствия'].isna() | (merged_today['Вид_отсутствия'].astype(str).str.strip() == '')) & - (merged_today.get('is_excluded', False) == False) - ) - - scud_fios_set = set(raw_scud_today_df['fio_clean'].dropna().tolist()) if not raw_scud_today_df.empty else set() - anomalies_list = detect_all_anomalies(merged_today, static_reasons_dict, kb_rules, scud_fios_set=scud_fios_set) - - mass_failure_today = analyze_scud_mass_failure_ai(raw_scud_today_df) - if mass_failure_today and mass_failure_today.get("is_mass_failure"): - print("\n" + "!" * 60) - print(f"🚨 ВНИМАНИЕ! ИИ ОБНАРУЖИЛ ОПЕРАТИВНЫЙ СБОЙ ТУРНИКЕТОВ ВХОДА СЕГОДНЯ ({mass_failure_today['anomaly_percent']}% СМЕНЫ)") - print(mass_failure_today["alert_text"]) - print("!" * 60 + "\n") - - save_anomalies_to_db(anomalies_list, target_date_str) - - is_no_pass_today = merged_today['no_scud_pass'] == True if 'no_scud_pass' in merged_today.columns else False - is_exc_today = merged_today.get('is_excluded', False) == True - - absent_explained = merged_today[ - (merged_today['Пришел'] == False) & - (merged_today['Вид_отсутствия'].notna()) & - (~merged_today['Вид_отсутствия'].astype(str).str.startswith('Исключение')) - ] - - absent_unexplained = merged_today[ - (merged_today['Пришел'] == False) & - (merged_today['Вид_отсутствия'].isna() | (merged_today['Вид_отсутствия'].astype(str).str.strip() == '')) & - (~is_no_pass_today) & - (~is_exc_today) - ] - - scud_present_but_absent_in_1c = merged_today[ - (~is_exc_today) & - (merged_today['Пришел'] == True) & - (merged_today['Вид_отсутствия'].notna()) & - (~merged_today['Вид_отсутствия'].astype(str).str.startswith('Исключение')) - ] - - print("[5/5] Запуск ИИ-аудитора и построение Ежедневной сводки...") - filtered_anomalies_list = [ - a for a in anomalies_list - if "ОТСУТСТВУЕТ В СКУД" not in a.get('type', '') - ] - - report_text = generate_markdown_report( - merged_df=merged_today, - absent_explained=absent_explained, - absent_unexplained=absent_unexplained, - scud_present_but_absent_in_1c=scud_present_but_absent_in_1c, - anomalies_list=filtered_anomalies_list, - raw_scud_df=raw_scud_today_df, - raw_absent_df=df_absent_today, - date_str=target_date_str - ) - - generate_summary_excel(merged_df=merged_today, date_str=target_date_str) - - md_report_path = os.path.join(OUTPUT_DIR, f"Сводка_контроллинга_{target_date_str}.md") - with open(md_report_path, "w", encoding="utf-8") as f: - f.write(report_text) - print(f"\n[✓] Текстовый отчет сохранен в: {md_report_path}") - - suspicious_cases = [] - for a in anomalies_list: - if "ОФИЦИАЛЬНОМ ОТСУТСТВИИ" not in a.get('type', ''): - suspicious_cases.append({ - 'fio_target': a['fio'], - 'reason': f"{a['type']}: {a['details']}" - }) - - if suspicious_cases: - review_ai_decisions(report_text, suspicious_cases) - - print("\n" + "=" * 60) - print("ГОТОВАЯ ТЕКСТОВАЯ СВОДКА ИИ-АУДИТОРА:") - print("=" * 60) - print(report_text) - else: - print(f"\n[ℹ️] Формирование Ежедневной сводки за {target_date_str} ПРОПУЩЕНО.") + print("\n" + "=" * 60) + print("ГОТОВАЯ ТЕКСТОВАЯ СВОДКА ИИ-АУДИТОРА:") + print("=" * 60) + print(summary_md) if __name__ == "__main__": diff --git a/modules/ROADMAP.md b/modules/ROADMAP.md new file mode 100644 index 0000000..65cbe6d --- /dev/null +++ b/modules/ROADMAP.md @@ -0,0 +1,56 @@ +# 🗺️ Дорожная карта задач проекта (ROADMAP) + +> **Сформировано:** 2026-08-19 18:40 | **Всего задач:** 16 + +--- + +## Модуль `api` + +- [x] **#35** [HIGH] `[ЗАВЕРШЕНО]` Создание REST API на FastAPI (/api/v1/snapshots, /api/v1/scud/logs, /api/v1/anomalies) + +--- + +## Модуль `core/database` + +- [x] **#22** [HIGH] `[ЗАВЕРШЕНО]` Перевод подключения 1С:ЗУП на продакшн MS SQL сервер ACCOUNT-01 + гибридный фоллбэк +- [x] **#37** [MEDIUM] `[ЗАВЕРШЕНО]` Создание модуля персистентной памяти проекта в SQLite и CLI-инструмента для фиксации архитектурных решений + +--- + +## Модуль `general` + +- [x] **#38** [HIGH] `[ЗАВЕРШЕНО]` По запросу, вывести возможности системы, которые уже настроены. Например на запрос о возможностях по СКУД. И изменить стартовую плашку. +- [ ] **#41** [MEDIUM] Полностью отказаться от tool_injector.py и перевести все вызовы на нативный Function Calling языковой модели. LLM будет основным арбитром *(срок: 2026-08-21)* +- [ ] **#44** [LOW] Тестовая-3 *(срок: 2026-08-20)* + +--- + +## Модуль `scripts` + +- [x] **#26** [MEDIUM] `[ЗАВЕРШЕНО]` Создание и выполнение скрипта сквозной переиндексации снапшотов с префиксом Y +- [x] **#27** [MEDIUM] `[ЗАВЕРШЕНО]` Реализация CLI-инспектора БД и выравнивание номеров срезов для идеальной верстки в терминале +- [ ] **#33** [MEDIUM] Автоматизация сбора срезов по расписанию (Cron / Systemd Timers на 12:00, 17:00, 19:00) + +--- + +## Модуль `services/ai_verifier` + +- [x] **#28** [HIGH] `[ЗАВЕРШЕНО]` Двойная проверка исключений по department_scud и 1С, удержание 100% приоритета кадровых документов + +--- + +## Модуль `services/scud_export` + +- [x] **#23** [HIGH] `[ЗАВЕРШЕНО]` Инцидент Равина В.Э.: Фиксация 100% приоритета сырых логов pLogData СКУД над расчетом УРВ Ориона +- [x] **#25** [HIGH] `[ЗАВЕРШЕНО]` Исправление бага дублирования номеров снапшотов (переход на вычисление MAX() по суффиксу) +- [x] **#29** [LOW] `[ЗАВЕРШЕНО]` Лаконичный вывод неразмеченных сотрудников с короткими аббревиатурами отделов СКУД (РУК, ОИЗ, ПУ и др.) +- [ ] **#30** [HIGH] `[В РАБОТЕ]` Внутридневной контроль: Извлечение полных цепочек проходов pLogData (входы/выходы за смену) +- [ ] **#31** [HIGH] `[В РАБОТЕ]` Внутридневной контроль: Расчет количества и суммарной длительности отлучек/перекуров сверх обеда + +--- + +## Модуль `services/text_reporter` + +- [ ] **#32** [MEDIUM] `[В РАБОТЕ]` Внутридневной контроль: Вывод списка системных нарушителей внутреннего распорядка в Markdown-отчет + +--- diff --git a/modules/ai_engine/__init__.py b/modules/ai_engine/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/ai_engine/agent.py b/modules/ai_engine/agent.py new file mode 100644 index 0000000..16f55fb --- /dev/null +++ b/modules/ai_engine/agent.py @@ -0,0 +1,178 @@ +""" +=============================================================================== +FILE: modules/ai_engine/agent.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: modules / ai_engine +ROLE: Лаконичный нативный оркестратор Function Calling, диспетчер handlers + и менеджер свободных диалогов (Topic Drift). + +AI-CONTEXT-ANCHORS: + - ANCHOR[AGENT_PIPELINE_ENTRY]: Главная точка входа process_chat_message. +=============================================================================== +""" + +import sys +import json +import logging +from typing import List, Dict, Any, Tuple, Optional + +from modules.web_api.llm.schemas import TOOLS_SCHEMA +from modules.web_api.llm.core.ollama_client import call_ollama_chat +from modules.web_api.llm.core.fast_path import handle_fast_path_intercept +from modules.web_api.llm.core.tool_injector import clean_raw_tool_tags, clean_output, inject_tools_if_needed +from modules.web_api.llm.core.context_manager import mark_last_user_message_ephemeral, close_tool_session_and_cleanup +from modules.web_api.llm.db.db_chat import db_save_chat_message, db_get_chat_history, db_purge_ephemeral_messages +from modules.web_api.llm.db.db_prompts import ( + db_get_session_state, db_clear_session_state, db_set_session_state, + db_get_stats, db_get_anomalies, db_get_reference +) +from services.knowledge.service import get_rules + +from .context_builder import build_agent_system_context +from .handlers.task_handler import handle_tasks_call +from .handlers.prompt_handler import handle_prompt_call +from .handlers.snapshot_handler import handle_snapshots_call + +logger = logging.getLogger("AI_AGENT") +logger.setLevel(logging.INFO) + + +# ANCHOR[AGENT_PIPELINE_ENTRY] +def process_chat_message( + user_id: int, + user_message: str, + file_context: str = "", + image_b64: Optional[str] = None, + chat_history: List[Dict[str, Any]] = None, + session_id: str = "web_session_main" +) -> Tuple[str, List[Dict[str, Any]], Optional[Dict[str, Any]]]: + """Главный конвейер обработки сообщений чата.""" + logger.info(f"Сообщение от user_id={user_id}, session_id={session_id}: {user_message}") + + session_state = db_get_session_state(session_id) + if not session_state: + db_purge_ephemeral_messages(session_id) + + full_user_content = f"{user_message}\n\n[СОДЕРЖИМОЕ ПРИКРЕПЛЕННОГО ФАЙЛА]:\n{file_context}" if file_context else user_message + + # 1. Быстрый Fast-Path перехват кнопок подтверждения + fast_path_res = handle_fast_path_intercept(session_id, user_message, full_user_content, session_state) + if fast_path_res: + return fast_path_res + + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=0) + db_history = db_get_chat_history(session_id, limit=20) + system_prompt = build_agent_system_context(user_id, session_state) + + user_msg_obj = {"role": "user", "content": full_user_content} + + try: + if image_b64: + user_msg_obj["images"] = [image_b64] + messages = [{"role": "system", "content": "Строгий модуль OCR. Перепиши весь текст буква в букву."}, user_msg_obj] + msg = call_ollama_chat(messages, is_vision=True) + else: + clean_history = [dict(m) for m in db_history] + for m in clean_history: m.pop("images", None) + messages = [{"role": "system", "content": system_prompt}] + clean_history + [user_msg_obj] + msg = call_ollama_chat(messages, tools=TOOLS_SCHEMA, is_vision=False) + + raw_reply = msg.get("content", "") + tool_calls = msg.get("tool_calls", []) + + # 2. Гибридный семантический классификатор намерений (Fallback Safety Net) + tool_calls = inject_tools_if_needed(user_message, raw_reply, tool_calls) + + # 3. Исполнение инструментов через изолированные handlers + if tool_calls: + tool = tool_calls[0] + fn_name = tool["function"]["name"] + fn_args = tool["function"].get("arguments", {}) + if isinstance(fn_args, str): + try: fn_args = json.loads(fn_args) + except Exception: fn_args = {} + + logger.info(f"Вызов инструмента: {fn_name} с аргументами: {fn_args}") + close_tool_session_and_cleanup(session_id, close_reason=f"ACTIVATE_{fn_name}") + mark_last_user_message_ephemeral(session_id) + + state_data = session_state.get("data_json") or {} if session_state else {} + + if fn_name in ["db_get_tasks", "db_tasks_edit", "db_add_task", "db_update_task_status", "db_delete_task"]: + return handle_tasks_call(fn_name, fn_args, user_id, session_id) + + elif fn_name in ["db_get_system_prompt", "db_prompt_node_edit"]: + return handle_prompt_call(fn_name, fn_args, session_id) + + elif fn_name in ["db_get_snapshots", "db_delete_snapshots"]: + return handle_snapshots_call(fn_name, fn_args, session_id, user_message, state_data) + + elif fn_name == "db_get_rules": + res_str = json.dumps(get_rules(), ensure_ascii=False) + elif fn_name == "db_get_stats": + res_str = json.dumps(db_get_stats(), ensure_ascii=False) + elif fn_name == "db_get_anomalies": + res_str = json.dumps(db_get_anomalies(limit=fn_args.get("limit", 100), date_str=fn_args.get("date_str")), ensure_ascii=False) + elif fn_name == "db_get_reference": + res_str = json.dumps(db_get_reference(category=fn_args.get("category")), ensure_ascii=False) + else: + res_str = "{}" + + messages.append(msg) + messages.append({"role": "tool", "content": res_str}) + sec_msg = call_ollama_chat(messages, is_vision=False) + final_content = clean_raw_tool_tags(clean_output(sec_msg.get("content", ""))) or "Запрос выполнен." + db_save_chat_message(session_id, "assistant", final_content, is_ephemeral=0) + return final_content, db_get_chat_history(session_id), None + + # 4. Обычный содержательный диалог и управление Topic Drift + final_reply = clean_raw_tool_tags(clean_output(raw_reply)) or "Запрос обработан." + for artifact in ["почемучка,", "почемучка!", "почемучка?", "почемучка", "почемучто,", "почемучто", "почему-то"]: + if final_reply.lower().startswith(artifact): + final_reply = final_reply[len(artifact):].lstrip(",.!?:; -") + + action_payload = None + + # Обработка ответа "нет / спасибо" в режиме открытого инструмента + if session_state and any(kw in user_message.lower() for kw in ["нет", "спасибо", "не надо", "готово", "хватит"]): + close_tool_session_and_cleanup(session_id, close_reason="USER_DISMISSED_TOOL") + db_save_chat_message(session_id, "assistant", final_reply, is_ephemeral=0) + return final_reply, db_get_chat_history(session_id), None + + # Инкремент счётчика шагов в сторону от инструмента (Topic Drift) + if session_state and session_state.get("state_type") in ["PROMPT_FOLLOWUP", "PROMPT_PREVIEW", "SNAPSHOTS_VIEW"]: + state_type = session_state.get("state_type") + state_data = session_state.get("data_json") or {} + if not isinstance(state_data, dict): + state_data = {} + + idle_turns = state_data.get("idle_turns", 0) + 1 + state_data["idle_turns"] = idle_turns + + if idle_turns >= 4: + # 4-й шаг не по теме: бесшумно закрываем сессию и вычищаем эфемерные карточки + close_tool_session_and_cleanup(session_id, close_reason="TOPIC_DRIFT_TIMEOUT") + elif idle_turns == 3: + # 3-й шаг: выводим вежливое напоминание с кнопками + tool_label = "системным промптом" if "PROMPT" in state_type else "снапшотами СКУД" + guard_question = f"Желаете продолжить работу с {tool_label}?" + final_reply += f"\n\n💡 *Напоминание:* {guard_question}" + action_payload = { + "type": "FOLLOW_UP_ACTION", + "buttons": [ + {"label": "Показать снова", "value": "покажи системный промпт" if "PROMPT" in state_type else "покажи снапшоты", "style": "primary"}, + {"label": "Завершить", "value": "нет, спасибо", "style": "secondary"} + ] + } + db_set_session_state(session_id, state_type, state_data) + else: + # 1-й и 2-й шаг: фиксируем обновленный счётчик + db_set_session_state(session_id, state_type, state_data) + + is_ephem_reply = 1 if "актуальный системный промпт:" in final_reply.lower() else 0 + db_save_chat_message(session_id, "assistant", final_reply, is_ephemeral=is_ephem_reply) + return final_reply, db_get_chat_history(session_id), action_payload + + except Exception as ex: + logger.exception(f"Ошибка в агенте: {ex}") + return f"Внутренняя ошибка сервера: {ex}", db_get_chat_history(session_id), None \ No newline at end of file diff --git a/modules/ai_engine/context_builder.py b/modules/ai_engine/context_builder.py new file mode 100644 index 0000000..5b0fd48 --- /dev/null +++ b/modules/ai_engine/context_builder.py @@ -0,0 +1,84 @@ +""" +=============================================================================== +FILE: modules/ai_engine/context_builder.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: modules / ai_engine +ROLE: Динамическая сборка системного промпта из БД, календаря и контекста сессий. + +AI-CONTEXT-ANCHORS: + - ANCHOR[CONTEXT_BUILDER_MAIN]: Формирование полного системного контекста для LLM. +=============================================================================== +""" + +from typing import Dict, Any, Optional +from services.prompts.service import get_active_system_prompt +from modules.web_api.llm.core.calendar_utils import get_dynamic_calendar_context + + +# ANCHOR[CONTEXT_BUILDER_MAIN] +def build_agent_system_context( + user_id: int, + session_state: Optional[Dict[str, Any]] +) -> str: + """Формирует полный динамический системный контекст агента с правилами из БД.""" + + # 1. Загружаем актуальный базовый системный промпт из SQLite БД + base_system_prompt = get_active_system_prompt() + + # 2. Серверный календарь и контекст дат + calendar_context = get_dynamic_calendar_context() + user_info = f"Пользователь ID={user_id}" if user_id != 0 else "Гость" + + # 3. Контекст текущего активного стейта сессии + current_state_type = session_state.get("state_type") if session_state else None + state_data = session_state.get("data_json") or {} if session_state else {} + if not isinstance(state_data, dict): + state_data = {} + + active_state_context = "" + if current_state_type == "PROMPT_PREVIEW": + active_state_context = ( + "\n[ТЕКУЩИЙ РЕЖИМ: ПРЕДПРОСМОТР СИСТЕМНОГО ПРОМПТА]\n" + "- Открыт предпросмотр изменений промпта. Для любых правок вызывай db_prompt_node_edit.\n" + ) + elif current_state_type == "PROMPT_FOLLOWUP": + active_state_context = ( + "\n[ТЕКУЩИЙ РЕЖИМ: СЕССИЯ РЕДАКТИРОВАНИЯ ПРОМПТА]\n" + "- Оператор просматривает или редактирует системный промпт.\n" + "- На любые команды вида 'удали пункт X.Y' или 'удали X.Y' ТЫ ОБЯЗАН ВЫЗВАТЬ db_prompt_node_edit с action='DELETE', section_id=X, item_id=Y.\n" + "- На любые команды 'добавь пункт X.Y ...' вызывай action='ADD'.\n" + "- Запрещено путать ADD и DELETE.\n" + ) + elif current_state_type == "SNAPSHOTS_VIEW": + active_date = state_data.get("query_date", "выбранную дату") + active_state_context = ( + f"\n[ТЕКУЩИЙ РЕЖИМ: ПРОСМОТР СНАПШОТОВ СКУД]\n" + f"- Сейчас на экране отображаются снапшоты за {active_date}.\n" + f"- Ты можешь форматировать, фильтровать или анализировать этот текущий срез.\n" + f"- Если оператор запрашивает ДРУГУЮ дату или день недели (например: 'за вчера', 'а за 13.08') — " + f"ТЫ ОБЯЗАН СРАЗУ ВЫЗВАТЬ db_get_snapshots(date_str=...).\n" + f"- Запрещено генерировать текст за другую дату по памяти.\n" + ) + elif current_state_type == "SNAPSHOT_DELETE_CONFIRM": + active_state_context = "\n[ВНИМАНИЕ: ОЖИДАЕТСЯ ПОДТВЕРЖДЕНИЕ УДАЛЕНИЯ СНАПШОТОВ]\n" + elif current_state_type == "TASK_DELETE_CONFIRM": + active_state_context = "\n[ВНИМАНИЕ: ОЖИДАЕТСЯ ПОДТВЕРЖДЕНИЕ УДАЛЕНИЯ ЗАДАЧИ]\n" + + # 4. Сборка полного системного сообщения + return ( + f"{base_system_prompt}\n\n" + f"СТРОГИЕ ПРАВИЛА ВЫЗОВА ИНСТРУМЕНТОВ:\n" + f"1. Для системного промпта:\n" + f" - 'добавь X.Y Текст' -> СРАЗУ вызывай db_prompt_node_edit(action='ADD', section_id=X, item_id=Y, content='Текст').\n" + f" - 'удали X.Y' -> СРАЗУ вызывай db_prompt_node_edit(action='DELETE', section_id=X, item_id=Y, content='').\n" + f" - 'покажи системный промпт' -> СРАЗУ вызывай db_get_system_prompt().\n" + f"2. Для задач:\n" + f" - 'удали задачу N' -> СРАЗУ вызывай db_tasks_edit(action='DELETE', task_id='N').\n" + f" - 'возьми в работу N' -> СРАЗУ вызывай db_tasks_edit(action='UPDATE', task_id='N', status='IN_PROGRESS').\n" + f" - 'заверши N' / 'готово N' -> СРАЗУ вызывай db_tasks_edit(action='UPDATE', task_id='N', status='COMPLETED').\n" + f"3. Запрещено задавать вопросы и писать подтверждения текстом — СРАЗУ вызывай соответствующий инструмент!\n\n" + f"[СИСТЕМНЫЙ КАЛЕНДАРЬ СЕРВЕРА]\n" + f"- Пользователь: {user_info}\n" + f"- {calendar_context}\n" + f"{active_state_context}" + ) \ No newline at end of file diff --git a/modules/ai_engine/handlers/__init__.py b/modules/ai_engine/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/ai_engine/handlers/prompt_handler.py b/modules/ai_engine/handlers/prompt_handler.py new file mode 100644 index 0000000..02ca6a8 --- /dev/null +++ b/modules/ai_engine/handlers/prompt_handler.py @@ -0,0 +1,98 @@ +""" +=============================================================================== +FILE: modules/ai_engine/handlers/prompt_handler.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: modules / ai_engine / handlers +ROLE: Изолированная обработка команд управления системным промптом. +=============================================================================== +""" + +from typing import Dict, Any, Tuple, Optional +from services.prompts.service import get_active_system_prompt, create_prompt_preview +from modules.web_api.llm.db.db_chat import db_save_chat_message, db_get_chat_history +from modules.web_api.llm.db.db_prompts import db_set_session_state + + +# ANCHOR[PROMPT_HANDLER_DISPATCH] +def handle_prompt_call( + fn_name: str, + fn_args: Dict[str, Any], + session_id: str +) -> Tuple[str, list, Optional[Dict[str, Any]]]: + """Обрабатывает вызовы просмотра и изменения системного промпта.""" + + # 1. Просмотр промпта с кнопкой быстрого перехода в редактор + if fn_name == "db_get_system_prompt": + active_prompt = get_active_system_prompt() + reply_text = f"Актуальный системный промпт:\n\n{active_prompt}" + + # Сохраняем состояние сессии для возможности мгновенного редактирования и подтверждения + db_set_session_state(session_id, "PROMPT_PREVIEW", { + "draft_text": active_prompt, + "action": "MANUAL_EDIT", + "idle_turns": 0 + }) + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + + return reply_text, db_get_chat_history(session_id), { + "type": "PROMPT_PREVIEW", + "raw_draft": active_prompt, + "baseline_prompt": active_prompt, + "buttons": [ + {"label": "✏️ Редактировать", "value": "action:open_editor", "style": "secondary"}, + {"label": "Готово", "value": "нет, спасибо", "style": "secondary"} + ] + } + + # 2. Предпросмотр точечных или пакетных изменений (ADD / EDIT / DELETE / BATCH_DELETE) + action = str(fn_args.get("action", "ADD")).upper() + nodes_list = fn_args.get("nodes_list", []) + delete_nodes_tuples = [] + + if nodes_list: + for n_str in nodes_list: + parts = str(n_str).strip().split(".") + if len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit(): + delete_nodes_tuples.append((int(parts[0]), int(parts[1]))) + + sec_id = None + itm_id = None + try: + if fn_args.get("section_id") is not None: + sec_id = int(str(fn_args.get("section_id")).strip()) + if fn_args.get("item_id") is not None: + itm_id = int(str(fn_args.get("item_id")).strip()) + except Exception: + pass + + content = str(fn_args.get("content", "")).strip() + + merged_prompt, diff_html, baseline_prompt = create_prompt_preview( + action=action, + section_id=sec_id, + item_id=itm_id, + content=content, + delete_nodes=delete_nodes_tuples if delete_nodes_tuples else None + ) + + db_set_session_state(session_id, "PROMPT_PREVIEW", { + "draft_text": merged_prompt, + "action": "MANUAL_EDIT", + "section_id": sec_id, + "item_id": itm_id, + "content": content, + "idle_turns": 0 + }) + + preview_reply = f"Предпросмотр изменений системного промпта:\n\n{diff_html}\n\nДля применения подтвердите действие, отредактируйте или отмените." + db_save_chat_message(session_id, "assistant", preview_reply, is_ephemeral=1) + return preview_reply, db_get_chat_history(session_id), { + "type": "PROMPT_PREVIEW", + "raw_draft": merged_prompt, + "baseline_prompt": baseline_prompt, + "buttons": [ + {"label": "Подтвердить", "value": "подтверждаю", "style": "primary"}, + {"label": "Отменить", "value": "отмена", "style": "danger"}, + {"label": "✏️ Редактировать", "value": "action:open_editor", "style": "secondary"} + ] + } \ No newline at end of file diff --git a/modules/ai_engine/handlers/snapshot_handler.py b/modules/ai_engine/handlers/snapshot_handler.py new file mode 100644 index 0000000..3b7b425 --- /dev/null +++ b/modules/ai_engine/handlers/snapshot_handler.py @@ -0,0 +1,91 @@ +""" +=============================================================================== +FILE: modules/ai_engine/handlers/snapshot_handler.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: modules / ai_engine / handlers +ROLE: Изолированная обработка запросов просмотра и удаления срезов СКУД. + +AI-CONTEXT-ANCHORS: + - ANCHOR[SNAPSHOT_HANDLER_DISPATCH]: Обработка db_get_snapshots и db_delete_snapshots. +=============================================================================== +""" + +from typing import Dict, Any, Tuple, Optional, List +from services.snapshots.service import get_snapshots_registry, delete_snapshots_safely +from modules.web_api.llm.core.calendar_utils import parse_relative_date_ru +from modules.web_api.llm.db.db_chat import db_save_chat_message, db_get_chat_history +from modules.web_api.llm.db.db_prompts import db_set_session_state + + +# ANCHOR[SNAPSHOT_HANDLER_DISPATCH] +def handle_snapshots_call( + fn_name: str, + fn_args: Dict[str, Any], + session_id: str, + user_message: str, + state_data: Dict[str, Any] +) -> Tuple[str, list, Optional[Dict[str, Any]]]: + """Обрабатывает запросы реестра и безопасного удаления срезов.""" + + # 1. Получение срезов + if fn_name == "db_get_snapshots": + date_param = fn_args.get("date_str") + if not date_param and user_message: + date_param = parse_relative_date_ru(user_message) + + snapshots_res = get_snapshots_registry(date_str=date_param) + query_date = snapshots_res.get("query_date", "выбранную дату") + + db_set_session_state(session_id, "SNAPSHOTS_VIEW", snapshots_res) + reply_text = f"Реестр срезов СКУД за {query_date}:" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOTS_CARD", + "data": snapshots_res + } + + # 2. Удаление срезов (двухфазное подтверждение) + raw_id = fn_args.get("snapshot_id") or fn_args.get("day_str") + raw_ids = fn_args.get("snapshot_ids") or [] + is_confirmed = fn_args.get("confirmed", False) + + if raw_id and not raw_ids: + if isinstance(raw_id, str) and "," in raw_id: + raw_ids = [s.strip() for s in raw_id.split(",")] + else: + raw_ids = [raw_id] + + safe_ids = [s.strip() for s in raw_ids if s and not str(s).strip().startswith("Y")] + if not safe_ids: + reply_text = "⚠️ Итоговый срез Y защищен от удаления. Выберите дневные снапшоты." + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), None + + if not is_confirmed: + query_date = state_data.get("query_date", "") + db_set_session_state(session_id, "SNAPSHOT_DELETE_CONFIRM", { + "snapshot_ids": safe_ids, + "query_date": query_date, + "idle_turns": 0 + }) + ids_str = ", ".join(safe_ids) + reply_text = f"Вы действительно хотите удалить дневные снапшоты: {ids_str}?" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOT_DELETE_CONFIRM", + "buttons": [ + {"label": f"Удалить ({len(safe_ids)} шт.)", "value": f"подтверждаю удаление снапшотов {ids_str}", "style": "danger"}, + {"label": "Отмена", "value": "отмена", "style": "secondary"} + ] + } + else: + delete_snapshots_safely(snapshot_ids=safe_ids) + query_date = state_data.get("query_date", "") + updated_data = get_snapshots_registry(date_str=query_date) + + reply_text = f"✅ Успешно удалено снапшотов: {len(safe_ids)} шт." + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOTS_CARD", + "data": updated_data + } \ No newline at end of file diff --git a/modules/ai_engine/handlers/task_handler.py b/modules/ai_engine/handlers/task_handler.py new file mode 100644 index 0000000..f5d7e39 --- /dev/null +++ b/modules/ai_engine/handlers/task_handler.py @@ -0,0 +1,97 @@ +""" +=============================================================================== +FILE: modules/ai_engine/handlers/task_handler.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: modules / ai_engine / handlers +ROLE: Изолированная обработка вызовов инструментов задач (get, edit, delete, export). + +AI-CONTEXT-ANCHORS: + - ANCHOR[TASK_HANDLER_DISPATCH]: Обработка вызовов db_get_tasks и db_tasks_edit. +=============================================================================== +""" + +from typing import Dict, Any, Tuple, Optional +from services.tasks.service import get_tasks, execute_task_action +from modules.web_api.llm.db.db_chat import db_save_chat_message, db_get_chat_history +from modules.web_api.llm.db.db_prompts import db_set_session_state + + +# ANCHOR[TASK_HANDLER_DISPATCH] +def handle_tasks_call( + fn_name: str, + fn_args: Dict[str, Any], + user_id: int, + session_id: str +) -> Tuple[str, list, Optional[Dict[str, Any]]]: + """Обрабатывает нативные tool-вызовы по задачам.""" + + # 1. Просмотр задач + if fn_name == "db_get_tasks": + raw_tasks = get_tasks(user_id, status=fn_args.get("status")) + reply_text = "Вот интерактивный список ваших текущих задач:" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "TASK_INTERACTIVE_CARD", + "tasks": raw_tasks + } + + # 2. Модификация / Удаление / Экспорт + action = (fn_args.get("action") or "UPDATE").upper() + if fn_name == "db_add_task": action = "ADD" + elif fn_name == "db_delete_task": action = "DELETE" + elif fn_name == "db_update_task_status": action = "UPDATE" + + # Двухфазное подтверждение удаления + if action == "DELETE": + task_id_raw = str(fn_args.get("task_id", "")).replace("#", "").replace("TASK-", "").strip() + db_set_session_state(session_id, "TASK_DELETE_CONFIRM", {"task_id": task_id_raw, "idle_turns": 0}) + reply_text = f"Вы действительно хотите удалить задачу #{task_id_raw}?" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "TASK_DELETE_CONFIRM", + "buttons": [ + {"label": f"Удалить #{task_id_raw}", "value": f"подтверждаю удаление задачи {task_id_raw}", "style": "danger"}, + {"label": "Отмена", "value": "отмена", "style": "secondary"} + ] + } + + # Экспорт в Markdown + elif action == "EXPORT": + export_res = execute_task_action( + user_id=user_id, + action="EXPORT", + filename=fn_args.get("filename"), + status=fn_args.get("status") + ) + reply_text = export_res.get("message", "Отчет по задачам успешно экспортирован.") + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=0) + + action_payload = None + if export_res.get("status") == "success": + action_payload = { + "type": "FILE_DOWNLOAD_CARD", + "filename": export_res.get("filename"), + "download_url": export_res.get("download_url"), + "tasks_count": export_res.get("tasks_count") + } + return reply_text, db_get_chat_history(session_id), action_payload + + # Создание и обновление + else: + res = execute_task_action( + user_id=user_id, + action=action, + task_id=fn_args.get("task_id"), + title=fn_args.get("title"), + priority=fn_args.get("priority", "MEDIUM"), + status=fn_args.get("status"), + module=fn_args.get("module", "general"), + due_date=fn_args.get("due_date") + ) + raw_tasks = get_tasks(user_id) + reply_text = res.get("message", "Операция над задачами выполнена.") + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "TASK_INTERACTIVE_CARD", + "tasks": raw_tasks + } \ No newline at end of file diff --git a/modules/web_api/llm/agent.py b/modules/web_api/llm/agent.py index a341b8b..575b4c1 100644 --- a/modules/web_api/llm/agent.py +++ b/modules/web_api/llm/agent.py @@ -3,18 +3,22 @@ FILE: modules/web_api/llm/agent.py PROJECT: SCUD Orion AI (Unified Architecture) MODULE: web_api / llm (Core Agent Coordinator) -ROLE: Оркестратор диалога, диспетчер реляционных узлов промпта, - управление сессионными стейтами, Topic Drift Guard и очистка контекста. +ROLE: Нативный оркестратор диалога, диспетчер инструментов (Function Calling) + и управление сессионными стейтами через ContextManager. + +AI-CONTEXT-ANCHORS: + - ANCHOR[AGENT_IMPORTS]: Системные и доменные импорты. + - ANCHOR[AGENT_MAIN_PIPELINE]: Основная точка входа process_chat_message. + - ANCHOR[AGENT_SYSTEM_PROMPT]: Формирование динамического контекста. + - ANCHOR[AGENT_TOOL_DISPATCHER]: Исполнение нативных вызовов инструментов. + - ANCHOR[AGENT_TOPIC_DRIFT]: Защита контекста и обработка свободных тем. =============================================================================== """ -# ============================================================================= -# БЛОК 1: ИМПОРТЫ И ИНИЦИАЛИЗАЦИЯ СИСТЕМНЫХ МОДУЛЕЙ -# ============================================================================= +# ANCHOR[AGENT_IMPORTS] import sys import json import logging -import re from typing import List, Dict, Any, Tuple, Optional from .db.connection import get_db_connection @@ -26,6 +30,8 @@ from .db_tools import ( db_update_task_status, db_delete_task, db_add_task, + db_tasks_edit, + db_export_tasks_markdown, db_get_rules, db_set_session_state, db_get_session_state, @@ -46,6 +52,12 @@ from .core.calendar_utils import get_dynamic_calendar_context from .core.tool_injector import clean_raw_tool_tags, clean_output, inject_tools_if_needed from .core.ollama_client import call_ollama_chat from .core.fast_path import handle_fast_path_intercept +from .core.context_manager import ( + save_tool_interaction, + save_dialog_interaction, + mark_last_user_message_ephemeral, + close_tool_session_and_cleanup +) logger = logging.getLogger("SCUD_AGENT") logger.setLevel(logging.INFO) @@ -58,9 +70,7 @@ if not logger.handlers: logger.addHandler(handler) -# ============================================================================= -# БЛОК 2: ГЛАВНЫЙ КОНВЕЙЕР ОБРАБОТКИ СООБЩЕНИЙ ЧАТА -# ============================================================================= +# ANCHOR[AGENT_MAIN_PIPELINE] def process_chat_message( user_id: int, user_message: str, @@ -70,40 +80,29 @@ def process_chat_message( session_id: str = "web_session_main" ) -> Tuple[str, List[Dict[str, Any]], Optional[Dict[str, Any]]]: """ - Главная функция обработки сообщения: - 1. Очищает осиротевшие эфемерные сообщения. - 2. Перехватывает быстрые кнопки (Fast-Path). - 3. Собирает контекст и передает управление Ollama. - 4. Выполняет Tool Calls и управляет счетчиком Topic Drift. + Главный конвейер обработки входящего сообщения чата на базе нативного Function Calling. """ logger.info(f"Получено сообщение от user_id={user_id}, session_id={session_id}: {user_message}") - # 🧹 ГАРБАДЖ-КОЛЛЕКТОР: Если стейт сессии пуст, удаляем висящие эфемерные сообщения session_state = db_get_session_state(session_id) if not session_state: db_purge_ephemeral_messages(session_id) full_user_content = f"{user_message}\n\n[СОДЕРЖИМОЕ ПРИКРЕПЛЕННОГО ФАЙЛА]:\n{file_context}" if file_context else user_message - # Перехват нажатия кнопок («Подтвердить», «Отменить», «Завершить») без вызова LLM + # 1. Быстрый перехват строго системных кнопок UI (подтверждение превью промпта) fast_path_res = handle_fast_path_intercept(session_id, user_message, full_user_content, session_state) if fast_path_res: return fast_path_res - # Сохранение входящего сообщения оператора - is_user_ephemeral = 1 if session_state else 0 - db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=is_user_ephemeral) + # 2. Фиксация сообщения пользователя + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=0) db_history = db_get_chat_history(session_id, limit=20) - - # ========================================================================= - # БЛОК 3: ДИНАМИЧЕСКАЯ СБОРКА СИСТЕМНОГО ИНСТРУКТАЖА - # ========================================================================= - dynamic_prompt_text = db_get_active_system_prompt() + # ANCHOR[AGENT_SYSTEM_PROMPT] calendar_context = get_dynamic_calendar_context() user_info = f"Пользователь ID={user_id}" if user_id != 0 else "Гость" - # Извлечение текущего состояния и счетчика отвлечений (idle_turns) current_state_type = session_state.get("state_type") if session_state else None state_data = session_state.get("data_json") or {} if session_state else {} if not isinstance(state_data, dict): @@ -113,47 +112,61 @@ def process_chat_message( active_state_context = "" if current_state_type == "PROMPT_PREVIEW": active_state_context = ( - "\n[ВНИМАНИЕ: АКТИВНЫЙ РЕЖИМ ПРЕДПРОСМОТРА ПРОМПТА]\n" - "- Сейчас открыт предпросмотр изменения системного промпта.\n" - "- Если пользователь просит изменить, скорректировать формулировку или удалить пункт — вызови инструмент db_prompt_node_edit.\n" - "- Если пользователь переключился на другую тему — ответь на его вопрос кратко и по делу.\n" + "\n[ТЕКУЩИЙ РЕЖИМ: ПРЕДПРОСМОТР СИСТЕМНОГО ПРОМПТА]\n" + "- Открыт предпросмотр изменений промпта. Для любых правок вызывай db_prompt_node_edit.\n" ) elif current_state_type == "PROMPT_FOLLOWUP": active_state_context = ( - "\n[ВНИМАНИЕ: АКТИВНА СЕССИЯ РЕДАКТИРОВАНИЯ СИСТЕМНОГО ПРОМПТА]\n" - "- Оператор только что применил предыдущее изменение или запросил просмотр промпта.\n" - "- Любые команды вида 'добавь X.Y', 'удали X.Y', 'измени X.Y' ОЗНАЧАЮТ ПРОДОЛЖЕНИЕ РАБОТЫ С СИСТЕМНЫМ ПРОМПТОМ -> ВЫЗЫВАЙ db_prompt_node_edit.\n" - "- Если запрос оператора не ясен или относится к другой теме — ответь на него естественно.\n" + "\n[ТЕКУЩИЙ РЕЖИМ: СЕССИЯ РЕДАКТИРОВАНИЯ ПРОМПТА]\n" + "- Оператор просматривает или редактирует системный промпт.\n" + "- На любые команды вида 'удали пункт X.Y' или 'удали X.Y' ТЫ ОБЯЗАН ВЫЗВАТЬ db_prompt_node_edit с action='DELETE', section_id=X, item_id=Y.\n" + "- На любые команды 'добавь пункт X.Y ...' вызывай action='ADD'.\n" + "- Запрещено путать ADD и DELETE.\n" + ) + elif current_state_type == "SNAPSHOTS_VIEW": + active_date = state_data.get("query_date", "выбранную дату") + active_state_context = ( + f"\n[ТЕКУЩИЙ РЕЖИМ: ПРОСМОТР СНАПШОТОВ СКУД]\n" + f"- Сейчас на экране отображаются снапшоты за {active_date}.\n" + f"- Ты можешь форматировать, фильтровать или анализировать этот текущий срез.\n" + f"- Если оператор запрашивает ДРУГУЮ дату или день недели, отличную от {active_date} (например: 'за вчера', 'а за 13.08', 'покажи за сегодня') — " + f"ТЫ ОБЯЗАН СРАЗУ ВЫЗВАТЬ db_get_snapshots(date_str=...).\n" + f"- Запрещено генерировать текст за другую дату по памяти.\n" + ) + elif current_state_type == "SNAPSHOT_DELETE_CONFIRM": + active_state_context = ( + "\n[ВНИМАНИЕ: ОЖИДАЕТСЯ ПОДТВЕРЖДЕНИЕ УДАЛЕНИЯ СНАПШОТОВ]\n" + ) + elif current_state_type == "TASK_DELETE_CONFIRM": + active_state_context = ( + "\n[ВНИМАНИЕ: ОЖИДАЕТСЯ ПОДТВЕРЖДЕНИЕ УДАЛЕНИЯ ЗАДАЧИ]\n" ) system_prompt_content = ( - f"Ты — интеллектуальный ассистент SCUD Orion AI. " - f"Ты управляешь задачами, аналитикой СКУД и системными настройками с помощью инструментов (tools).\n\n" - f"СТРОГИЕ ПРАВИЛА СТИЛЯ:\n" - f"- Запрещено использовать панибратские или шутливые обращения. Отвечай профессионально и строго по существу.\n\n" - f"[ОКРУЖЕНИЕ]\n" + f"Ты — интеллектуальный ассистент SCUD Orion AI.\n" + f"Ты управляешь задачами, аналитикой СКУД и системными настройками исключительно через инструменты (tools).\n\n" + f"СТРОГИЕ ПРАВИЛА:\n" + f"1. К оператору всегда обращайся на Вы.\n" + f"2. Для получения данных всегда вызывай соответствующий инструмент:\n" + f" - Снапшоты и срезы логов СКУД за любые даты и дни недели -> db_get_snapshots\n" + f" - Удаление снапшотов -> db_delete_snapshots\n" + f" - Задачи и бэклог (просмотр, создание, смена статуса, удаление, экспорт) -> db_get_tasks, db_tasks_edit\n" + f" - Системный промпт -> db_get_system_prompt, db_prompt_node_edit\n" + f" - Аномалии СКУД/1С -> db_get_anomalies\n" + f" - База знаний -> db_get_rules\n" + f" - Статистика БД -> db_get_stats\n" + f" - Справка -> db_get_reference\n" + f"3. Запрещено сочинять данные от себя без вызова инструментов.\n\n" + f"[СИСТЕМНЫЙ КАЛЕНДАРЬ СЕРВЕРА]\n" f"- Пользователь: {user_info}\n" f"- {calendar_context}\n" - f"{active_state_context}\n" - f"[ПРАВИЛА ИСПОЛЬЗОВАНИЯ ИНСТРУМЕНТОВ]\n" - f"1. Для ЛЮБЫХ операций с системным промптом ТЫ ОБЯЗАН СРАЗУ ВЫЗВАТЬ db_prompt_node_edit:\n" - f" - 'удали 2.9' / 'удалить пункт 2.9' -> ВЫЗОВ db_prompt_node_edit(action='DELETE', section_id=2, item_id=9, content='')\n" - f" - 'добавь 3.4 Текст' / 'добавить пункт 3.4' -> ВЫЗОВ db_prompt_node_edit(action='ADD', section_id=3, item_id=4, content='Текст')\n" - f" - 'измени 1.2 Текст' -> ВЫЗОВ db_prompt_node_edit(action='UPDATE', section_id=1, item_id=2, content='Текст')\n" - f" КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО отвечать текстом вроде 'Удален пункт... Напишите подтверждаю'. Только Function Call!\n" - f"2. Для просмотра системного промпта ВСЕГДА вызывай db_get_system_prompt().\n" - f"3. Для просмотра задач ВСЕГДА вызывай db_get_tasks().\n\n" - f"[ТЕКУЩИЙ АКТИВНЫЙ СИСТЕМНЫЙ ПРОМПТ]:\n{dynamic_prompt_text}" + f"{active_state_context}" ) user_msg_object = {"role": "user", "content": full_user_content} - - # ========================================================================= - # БЛОК 4: ВЫЗОВ НЕЙРОСЕТИ И МАРШРУТИЗАЦИЯ FUNCTION CALLING - # ========================================================================= + # ANCHOR[AGENT_TOOL_DISPATCHER] try: - # Режим Vision (OCR) if image_b64: user_msg_object["images"] = [image_b64] messages = [ @@ -162,7 +175,6 @@ def process_chat_message( ] msg = call_ollama_chat(messages, is_vision=True) else: - # Текстовый диалог clean_db_history = [dict(m) for m in db_history] for m in clean_db_history: m.pop("images", None) @@ -171,241 +183,329 @@ def process_chat_message( raw_text_reply = msg.get("content", "") tool_calls = msg.get("tool_calls", []) - tool_calls = inject_tools_if_needed(user_message, raw_text_reply, tool_calls) - # Исполнение вызванных моделью инструментов + if not tool_calls: + tool_calls = inject_tools_if_needed(user_message, raw_text_reply, tool_calls) + if tool_calls: logger.info(f"Ответ от Ollama получен. Tool calls: True (кол-во: {len(tool_calls)})") - messages.append(msg) - tool_names_called = [] + + tool = tool_calls[0] + fn_name = tool["function"]["name"] + fn_args = tool["function"].get("arguments", {}) + if isinstance(fn_args, str): + try: + fn_args = json.loads(fn_args) + except Exception: + fn_args = {} - # ----------------------------------------------------------------- - # TOPIC DRIFT GUARD ДЛЯ ИНСТРУМЕНТОВ: - # Если вызваны сторонние инструменты (снапшоты, задачи, статы) - # — мгновенно закрываем сессию и вычищаем эфемерный контекст - # ----------------------------------------------------------------- - is_prompt_tool = any(t["function"]["name"] in ["db_prompt_node_edit", "db_get_system_prompt", "db_get_system_prompts"] for t in tool_calls) - if not is_prompt_tool and session_state: - logger.info(f"Смена темы на инструмент {tool_calls[0]['function']['name']}. Закрываем сессию и очищаем эфемерный контекст.") - db_clear_session_state(session_id) - db_purge_ephemeral_messages(session_id) - session_state = None + logger.info(f"Вызов функции (Tool): {fn_name} с аргументами: {fn_args}") - for tool in tool_calls: - fn_name = tool["function"]["name"] - fn_args = tool["function"].get("arguments", {}) - tool_names_called.append(fn_name) - logger.info(f"Вызов функции (Tool): {fn_name} с аргументами: {fn_args}") - tool_result_content = "" + # Ротация контекста: закрываем старую сессию инструмента + close_tool_session_and_cleanup(session_id, close_reason=f"ACTIVATE_{fn_name}") + session_state = None + mark_last_user_message_ephemeral(session_id) - # --- 4.1. Модуль задач --- - if fn_name == "db_get_tasks": + # 1. Задачи (Просмотр) + if fn_name == "db_get_tasks": + raw_tasks = db_get_tasks(user_id, status=fn_args.get("status")) + reply_text = "Вот интерактивный список ваших текущих задач:" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "TASK_INTERACTIVE_CARD", + "tasks": raw_tasks + } + + # 2. Единый диспетчер задач + elif fn_name in ["db_tasks_edit", "db_add_task", "db_update_task_status", "db_delete_task"]: + action = fn_args.get("action", "UPDATE").upper() + if fn_name == "db_add_task": action = "ADD" + elif fn_name == "db_delete_task": action = "DELETE" + elif fn_name == "db_update_task_status": action = "UPDATE" + + if action == "DELETE": + task_id_raw = str(fn_args.get("task_id", "")).replace("#", "").replace("TASK-", "").strip() + db_set_session_state(session_id, "TASK_DELETE_CONFIRM", {"task_id": task_id_raw, "idle_turns": 0}) + reply_text = f"Вы действительно хотите удалить задачу #{task_id_raw}?" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "TASK_DELETE_CONFIRM", + "buttons": [ + {"label": f"Удалить #{task_id_raw}", "value": f"подтверждаю удаление задачи {task_id_raw}", "style": "danger"}, + {"label": "Отмена", "value": "отмена", "style": "secondary"} + ] + } + + elif action == "EXPORT": + export_res = db_export_tasks_markdown( + user_id=user_id, + filename=fn_args.get("filename"), + status_filter=fn_args.get("status") + ) + reply_text = export_res.get("message", "Отчет по задачам успешно экспортирован.") + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=0) + + action_payload = None + if export_res.get("status") == "success": + action_payload = { + "type": "FILE_DOWNLOAD_CARD", + "filename": export_res.get("filename"), + "download_url": export_res.get("download_url"), + "tasks_count": export_res.get("tasks_count") + } + return reply_text, db_get_chat_history(session_id), action_payload + + else: + res = db_tasks_edit( + user_id=user_id, + action=action, + task_id=fn_args.get("task_id"), + title=fn_args.get("title"), + priority=fn_args.get("priority", "MEDIUM"), + status=fn_args.get("status"), + module=fn_args.get("module", "general"), + due_date=fn_args.get("due_date") + ) raw_tasks = db_get_tasks(user_id) - reply_text = "Вот интерактивный список ваших текущих задач:" + reply_text = res.get("message", "Операция над задачами выполнена.") db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) return reply_text, db_get_chat_history(session_id), { "type": "TASK_INTERACTIVE_CARD", "tasks": raw_tasks } - # --- 4.2. Прямой просмотр системного промпта из SQLite --- - elif fn_name in ["db_get_system_prompt", "db_get_system_prompts"]: - active_prompt = db_get_active_system_prompt() - reply_text = f"Актуальный системный промпт:\n\n{active_prompt}" - - # Переводим сессию в PROMPT_FOLLOWUP для отслеживания Topic Drift - db_set_session_state(session_id, "PROMPT_FOLLOWUP", {"idle_turns": 0}) + # 3. Системный промпт + elif fn_name == "db_get_system_prompt": + active_prompt = db_get_active_system_prompt() + reply_text = f"Актуальный системный промпт:\n\n{active_prompt}" + db_set_session_state(session_id, "PROMPT_FOLLOWUP", {"idle_turns": 0}) + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), None + + elif fn_name == "db_prompt_node_edit": + action = str(fn_args.get("action", "ADD")).upper() + + try: + sec_id = int(str(fn_args.get("section_id", 3)).strip()) + except Exception: + sec_id = 3 + + try: + itm_id = int(str(fn_args.get("item_id", 1)).strip()) + except Exception: + itm_id = 1 + + content = str(fn_args.get("content", "")).strip() + baseline_prompt = db_get_active_system_prompt() + + with get_db_connection() as temp_conn: + temp_cursor = temp_conn.cursor() + temp_cursor.execute(""" + SELECT section_id, item_id, content + FROM system_prompt_nodes + WHERE prompt_name = 'main_agent' AND is_active = 1 + ORDER BY section_id, item_id + """) + existing_nodes = temp_cursor.fetchall() + + nodes_dict = {(sec, itm): txt for sec, itm, txt in existing_nodes} + nodes_dict_for_draft = {k: v for k, v in nodes_dict.items() if k != (sec_id, itm_id)} if action == "DELETE" else dict(nodes_dict) + if action != "DELETE": + nodes_dict_for_draft[(sec_id, itm_id)] = content + + draft_lines = [] + curr_sec = None + for (s_id, i_id), txt in sorted(nodes_dict_for_draft.items()): + if i_id == 0: + if curr_sec is not None: draft_lines.append("") + draft_lines.append(f"{s_id}. {txt}") + curr_sec = s_id + else: + draft_lines.append(f" {s_id}.{i_id}. {txt}") + merged_prompt = "\n".join(draft_lines) + + diff_lines = [] + curr_sec = None + display_nodes = dict(nodes_dict) + if action != "DELETE": + display_nodes[(sec_id, itm_id)] = content + + for (s_id, i_id), txt in sorted(display_nodes.items()): + if i_id == 0: + if curr_sec is not None: diff_lines.append("") + diff_lines.append(f"{s_id}. {txt}") + curr_sec = s_id + else: + if s_id == sec_id and i_id == itm_id: + line_str = f' {s_id}.{i_id}. {txt} [УДАЛЕНИЕ]' if action == "DELETE" else f' {s_id}.{i_id}. {txt}' + else: + line_str = f" {s_id}.{i_id}. {txt}" + diff_lines.append(line_str) + + diff_html = "\n".join(diff_lines) + + db_set_session_state(session_id, "PROMPT_PREVIEW", { + "draft_text": merged_prompt, + "action": action, + "section_id": sec_id, + "item_id": itm_id, + "content": content, + "idle_turns": 0 + }) + + preview_reply = f"Предпросмотр изменений системного промпта:\n\n{diff_html}\n\nДля применения подтвердите действие, отредактируйте или отмените." + db_save_chat_message(session_id, "assistant", preview_reply, is_ephemeral=1) + return preview_reply, db_get_chat_history(session_id), { + "type": "PROMPT_PREVIEW", + "raw_draft": merged_prompt, + "baseline_prompt": baseline_prompt, + "buttons": [ + {"label": "Подтвердить", "value": "подтверждаю", "style": "primary"}, + {"label": "Отменить", "value": "отмена", "style": "danger"}, + {"label": "✏️ Редактировать", "value": "action:open_editor", "style": "secondary"} + ] + } + + # 4. Снапшоты СКУД + elif fn_name == "db_get_snapshots": + snapshots_res = db_get_snapshots(session_id=session_id, date_str=fn_args.get("date_str"), original_user_message=user_message) + query_date = snapshots_res.get("query_date", "выбранную дату") + reply_text = f"Реестр срезов СКУД за {query_date}:" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOTS_CARD", + "data": snapshots_res + } + + elif fn_name == "db_delete_snapshots": + raw_id = fn_args.get("snapshot_id") or fn_args.get("day_str") + raw_ids = fn_args.get("snapshot_ids") or [] + is_confirmed = fn_args.get("confirmed", False) + + if raw_id and not raw_ids: + if isinstance(raw_id, str) and "," in raw_id: + raw_ids = [s.strip() for s in raw_id.split(",")] + else: + raw_ids = [raw_id] + + safe_ids = [s.strip() for s in raw_ids if s and not str(s).strip().startswith("Y")] + if not safe_ids: + reply_text = "⚠️ Итоговый срез Y защищен от удаления. Выберите дневные снапшоты." db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) return reply_text, db_get_chat_history(session_id), None - # --- 4.3. Реляционное изменение промпта (ADD / UPDATE / DELETE) --- - elif fn_name == "db_prompt_node_edit": - action = fn_args.get("action", "ADD").upper() - sec_id = int(fn_args.get("section_id", 2)) - itm_id = int(fn_args.get("item_id", 1)) - content = fn_args.get("content", "").strip() - baseline_prompt = db_get_active_system_prompt() - - with get_db_connection() as temp_conn: - temp_cursor = temp_conn.cursor() - temp_cursor.execute(""" - SELECT section_id, item_id, content - FROM system_prompt_nodes - WHERE prompt_name = 'main_agent' AND is_active = 1 - ORDER BY section_id, item_id - """) - existing_nodes = temp_cursor.fetchall() - - nodes_dict = {(sec, itm): txt for sec, itm, txt in existing_nodes} - - if action == "DELETE": - nodes_dict_for_draft = {k: v for k, v in nodes_dict.items() if k != (sec_id, itm_id)} - else: - nodes_dict_for_draft = dict(nodes_dict) - nodes_dict_for_draft[(sec_id, itm_id)] = content - - # Формирование чистого текста для редактора - draft_lines = [] - curr_sec = None - for (s_id, i_id), txt in sorted(nodes_dict_for_draft.items()): - if i_id == 0: - if curr_sec is not None: - draft_lines.append("") - draft_lines.append(f"{s_id}. {txt}") - curr_sec = s_id - else: - draft_lines.append(f" {s_id}.{i_id}. {txt}") - merged_prompt = "\n".join(draft_lines) - - # Формирование HTML Diff с подсветкой - diff_lines = [] - curr_sec = None - display_nodes = dict(nodes_dict) - if action != "DELETE": - display_nodes[(sec_id, itm_id)] = content - - for (s_id, i_id), txt in sorted(display_nodes.items()): - if i_id == 0: - if curr_sec is not None: - diff_lines.append("") - diff_lines.append(f"{s_id}. {txt}") - curr_sec = s_id - else: - if s_id == sec_id and i_id == itm_id: - if action == "DELETE": - line_str = f' {s_id}.{i_id}. {txt} [УДАЛЕНИЕ]' - else: - line_str = f' {s_id}.{i_id}. {txt}' - else: - line_str = f" {s_id}.{i_id}. {txt}" - diff_lines.append(line_str) - - diff_html = "\n".join(diff_lines) - - # Фиксация предпросмотра в session_states - db_set_session_state(session_id, "PROMPT_PREVIEW", { - "draft_text": merged_prompt, - "action": action, - "section_id": sec_id, - "item_id": itm_id, - "content": content, + if not is_confirmed: + query_date = state_data.get("query_date", "") + db_set_session_state(session_id, "SNAPSHOT_DELETE_CONFIRM", { + "snapshot_ids": safe_ids, + "query_date": query_date, "idle_turns": 0 }) - - with get_db_connection() as conn_fix: - conn_fix.cursor().execute(""" - UPDATE chat_messages - SET is_ephemeral = 1 - WHERE id = (SELECT MAX(id) FROM chat_messages WHERE session_id = ? AND role = 'user') - """, (session_id,)) - conn_fix.commit() - - preview_reply = ( - f"Предпросмотр изменений системного промпта:\n\n" - f"{diff_html}\n\n" - f"Для применения подтвердите действие, отредактируйте или отмените." - ) - - db_save_chat_message(session_id, "assistant", preview_reply, is_ephemeral=1) - return preview_reply, db_get_chat_history(session_id), { - "type": "PROMPT_PREVIEW", - "raw_draft": merged_prompt, - "baseline_prompt": baseline_prompt, + ids_str = ", ".join(safe_ids) + reply_text = f"Вы действительно хотите удалить дневные снапшоты: {ids_str}?" + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOT_DELETE_CONFIRM", "buttons": [ - {"label": "Подтвердить", "value": "подтверждаю", "style": "primary"}, - {"label": "Отменить", "value": "отмена", "style": "danger"}, - {"label": "✏️ Редактировать", "value": "action:open_editor", "style": "secondary"} + {"label": f"Удалить ({len(safe_ids)} шт.)", "value": f"подтверждаю удаление снапшотов {ids_str}", "style": "danger"}, + {"label": "Отмена", "value": "отмена", "style": "secondary"} ] } + else: + db_delete_snapshots(snapshot_ids=safe_ids) + query_date = state_data.get("query_date", "") + updated_snapshots_res = db_get_snapshots(session_id=session_id, date_str=query_date) - # --- 4.4. Сервисные инструменты --- - elif fn_name == "db_get_snapshots": - snapshots_res = db_get_snapshots(session_id=session_id, date_str=fn_args.get("date_str"), original_user_message=user_message) - tool_result_content = json.dumps(snapshots_res, ensure_ascii=False) + reply_text = f"✅ Успешно удалено снапшотов: {len(safe_ids)} шт." + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOTS_CARD", + "data": updated_snapshots_res + } + + elif fn_name == "db_delete_snapshots": + raw_id = fn_args.get("snapshot_id") or fn_args.get("day_str") + raw_ids = fn_args.get("snapshot_ids") or ([raw_id] if raw_id else []) + + # Защита: итоговые Y-срезы удалять запрещено + safe_ids = [s for s in raw_ids if not str(s).startswith("Y")] + if not safe_ids: + reply_text = "⚠️ Итоговый срез Y защищен от удаления. Выберите дневные снапшоты." + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), None - elif fn_name == "db_get_current_server_time": - tool_result_content = json.dumps(db_get_current_server_time(), ensure_ascii=False) + # Прямое выполнение удаления в SQLite без лишних текстовых подтверждений + del_res = db_delete_snapshots(snapshot_ids=safe_ids) + + # Получаем свежий реестр за ту же дату + query_date = fn_args.get("day_str", "") + updated_snapshots_res = db_get_snapshots(session_id=session_id, date_str=query_date) - elif fn_name == "db_get_stats": - tool_result_content = json.dumps(db_get_stats(), ensure_ascii=False) + reply_text = f"✅ Успешно удалено снапшотов: {len(safe_ids)} шт." + db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + return reply_text, db_get_chat_history(session_id), { + "type": "SNAPSHOTS_CARD", + "data": updated_snapshots_res + } - elif fn_name == "db_get_anomalies": - tool_result_content = json.dumps(db_get_anomalies(limit=fn_args.get("limit", 100), date_str=fn_args.get("date_str")), ensure_ascii=False) + # 5. Сервисные запросы + elif fn_name == "db_get_current_server_time": + tool_result_content = json.dumps(db_get_current_server_time(), ensure_ascii=False) + elif fn_name == "db_get_stats": + tool_result_content = json.dumps(db_get_stats(), ensure_ascii=False) + elif fn_name == "db_get_anomalies": + tool_result_content = json.dumps(db_get_anomalies(limit=fn_args.get("limit", 100), date_str=fn_args.get("date_str")), ensure_ascii=False) + elif fn_name == "db_get_rules": + tool_result_content = json.dumps(db_get_rules(), ensure_ascii=False) + elif fn_name == "db_get_reference": + tool_result_content = json.dumps(db_get_reference(category=fn_args.get("category")), ensure_ascii=False) + else: + tool_result_content = "{}" - elif fn_name == "db_get_rules": - tool_result_content = json.dumps(db_get_rules(), ensure_ascii=False) - - elif fn_name == "db_get_reference": - tool_result_content = json.dumps(db_get_reference(category=fn_args.get("category")), ensure_ascii=False) - - elif fn_name == "db_add_task": - res = db_add_task(user_id=user_id, module=fn_args.get("module", "general"), title=fn_args.get("title"), priority=fn_args.get("priority", "MEDIUM"), due_date=fn_args.get("due_date")) - tool_result_content = json.dumps(res, ensure_ascii=False) - - elif fn_name == "db_update_task_status": - res = db_update_task_status(user_id=user_id, task_id=str(fn_args.get("task_id")), status=fn_args.get("status", "COMPLETED"), due_date=fn_args.get("due_date")) - tool_result_content = json.dumps(res, ensure_ascii=False) - - elif fn_name == "db_delete_task": - res = db_delete_task(user_id=user_id, task_id=str(fn_args.get("task_id", "")).upper()) - tool_result_content = json.dumps(res, ensure_ascii=False) - - elif fn_name == "db_delete_snapshots": - res = db_delete_snapshots(snapshot_id=fn_args.get("snapshot_id"), day_str=fn_args.get("day_str")) - tool_result_content = json.dumps(res, ensure_ascii=False) - - messages.append({"role": "tool", "content": tool_result_content}) - - # Интерпретация результатов вызова инструментов + messages.append(msg) + messages.append({"role": "tool", "content": tool_result_content}) sec_msg = call_ollama_chat(messages, is_vision=False) raw_content = sec_msg.get("content", "").strip().replace("**", "").replace("*", "") - final_content = clean_raw_tool_tags(clean_output(raw_content)) + final_content = clean_raw_tool_tags(clean_output(raw_content)) or "Запрос выполнен." - is_output_ephemeral = 1 if any(name in ["db_get_system_prompt", "db_get_system_prompts", "db_prompt_node_edit"] for name in tool_names_called) else 0 + for artifact in ["почемучка,", "почемучка!", "почемучка?", "почемучка", "почемучто", "почему-то"]: + if final_content.lower().startswith(artifact): + final_content = final_content[len(artifact):].lstrip(",.!?:; -") - db_save_chat_message(session_id, "assistant", final_content, is_ephemeral=is_output_ephemeral) + is_ephem = 1 if fn_name in ["db_get_snapshots", "db_get_system_prompt", "db_prompt_node_edit"] else 0 + db_save_chat_message(session_id, "assistant", final_content, is_ephemeral=is_ephem) return final_content, db_get_chat_history(session_id), None - - # ===================================================================== - # БЛОК 5: ОБЫЧНЫЙ ТЕКСТОВЫЙ ОТВЕТ И СЕМАНТИЧЕСКИЙ TOPIC DRIFT GUARD - # ===================================================================== + # ANCHOR[AGENT_TOPIC_DRIFT] raw_str = msg.get("content", "").strip().replace("**", "").replace("*", "") final_reply = clean_raw_tool_tags(clean_output(raw_str)) or "Запрос обработан." + + for artifact in ["почемучка,", "почемучка!", "почемучка?", "почемучка", "почемучто", "почему-то"]: + if final_reply.lower().startswith(artifact): + final_reply = final_reply[len(artifact):].lstrip(",.!?:; -") + action_payload = None - # Обработка отвлечений оператора при активной сессии настройки/просмотра if session_state and session_state.get("state_type") in ["PROMPT_FOLLOWUP", "PROMPT_PREVIEW"]: idle_turns += 1 - logger.info(f"Topic Drift: активна сессия {session_state.get('state_type')}, шагов отвлечения: {idle_turns}/3") - - # Порог отвлечений превышен (> 2 шагов после напоминания) -> Полная зачистка if idle_turns > 3: db_clear_session_state(session_id) - deleted_count = db_purge_ephemeral_messages(session_id) - logger.info(f"Topic Drift Guard TTL: сессия закрыта по таймауту, очищено {deleted_count} сообщений.") + db_purge_ephemeral_messages(session_id) action_payload = None session_state = None elif idle_turns == 3: - # На 3-м сообщении стороннего диалога вежливо спрашиваем оператора tool_action = db_get_tool_action("db_confirm_prompt_preview") guard_question = tool_action.get("follow_up_question", "Желаете продолжить работу с системным промптом?") if tool_action else "Желаете продолжить работу с системным промптом?" buttons = tool_action.get("buttons", []) if tool_action else [] - final_reply += f"\n\n💡 *Напоминание:* {guard_question}" - action_payload = { - "type": "PROMPT_FOLLOWUP", - "buttons": buttons - } + action_payload = {"type": "PROMPT_FOLLOWUP", "buttons": buttons} db_set_session_state(session_id, "PROMPT_FOLLOWUP", {"idle_turns": idle_turns}) else: - # Шаги 1 и 2: продолжаем обычный диалог, инкрементируя счетчик db_set_session_state(session_id, session_state.get("state_type"), {"idle_turns": idle_turns}) - db_save_chat_message(session_id, "assistant", final_reply, is_ephemeral=(1 if session_state else 0)) + db_save_chat_message(session_id, "assistant", final_reply, is_ephemeral=0) return final_reply, db_get_chat_history(session_id), action_payload - # Обработка исключений except Exception as ex: logger.exception(f"Непредвиденная ошибка агента: {ex}") error_reply = f"Внутренняя ошибка сервера: {ex}" diff --git a/modules/web_api/llm/core/context_manager.py b/modules/web_api/llm/core/context_manager.py new file mode 100644 index 0000000..fd0dcb6 --- /dev/null +++ b/modules/web_api/llm/core/context_manager.py @@ -0,0 +1,64 @@ +""" +=============================================================================== +FILE: modules/web_api/llm/core/context_manager.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: web_api / llm / core +ROLE: Интеллектуальный менеджер контекста: разделение служебных транзакций + инструментов и содержательного диалога с сохранением Topic Drift. +=============================================================================== +""" + +import logging +from typing import Dict, Any, Optional, List + +from ..db.connection import get_db_connection +from ..db_tools import ( + db_save_chat_message, + db_get_chat_history, + db_purge_ephemeral_messages, + db_clear_session_state, + db_set_session_state +) + +logger = logging.getLogger("CONTEXT_MANAGER") + + +def save_tool_interaction(session_id: str, user_content: str, assistant_reply: str) -> None: + """ + Сохраняет синхронную служебную пару инструмента (и вопрос, и ответ = 1). + При очистке удалятся оба сообщения, не оставляя сирот. + """ + db_save_chat_message(session_id, "user", user_content, is_ephemeral=1) + db_save_chat_message(session_id, "assistant", assistant_reply, is_ephemeral=1) + + +def save_dialog_interaction(session_id: str, user_content: str, assistant_reply: str) -> None: + """ + Сохраняет содержательный диалог пользователя и ассистента (и вопрос, и ответ = 0). + Эти сообщения остаются в истории навсегда (включая Topic Drift). + """ + db_save_chat_message(session_id, "user", user_content, is_ephemeral=0) + db_save_chat_message(session_id, "assistant", assistant_reply, is_ephemeral=0) + + +def mark_last_user_message_ephemeral(session_id: str) -> None: + """Помечает последнее сообщение пользователя как эфемерное при активации инструмента.""" + with get_db_connection() as conn: + cursor = conn.cursor() + cursor.execute(""" + UPDATE chat_messages + SET is_ephemeral = 1 + WHERE id = (SELECT MAX(id) FROM chat_messages WHERE session_id = ? AND role = 'user') + """, (session_id,)) + conn.commit() + + +def close_tool_session_and_cleanup(session_id: str, close_reason: str = "COMPLETED") -> int: + """ + Закрывает сессию инструмента и удаляет ТОЛЬКО служебные карточки/команды. + Весь содержательный диалог сохраняется. + """ + db_clear_session_state(session_id) + deleted_count = db_purge_ephemeral_messages(session_id) + logger.info(f"[ContextManager] Сессия инструмента закрыта ({close_reason}). Очищено служебных сообщений: {deleted_count}") + return deleted_count \ No newline at end of file diff --git a/modules/web_api/llm/core/fast_path.py b/modules/web_api/llm/core/fast_path.py index 69b6d7f..b33e1c8 100644 --- a/modules/web_api/llm/core/fast_path.py +++ b/modules/web_api/llm/core/fast_path.py @@ -3,104 +3,166 @@ FILE: modules/web_api/llm/core/fast_path.py PROJECT: SCUD Orion AI (Unified Architecture) MODULE: web_api / llm / core -ROLE: Двухфазный жизненный цикл сессии (PROMPT_PREVIEW -> PROMPT_FOLLOWUP), - атомарная фиксация узлов и мягкая зачистка эфемерного контекста. +ROLE: Детерминированный мгновенный перехват нажатий кнопок подтверждения + (без задержек LLM и обращения к Ollama). + +AI-CONTEXT-ANCHORS: + - ANCHOR[FAST_PATH_MAIN]: Точка входа handle_fast_path_intercept. =============================================================================== """ +import json import logging from typing import Dict, Any, Tuple, Optional -from llm.db_tools import ( - db_apply_prompt_node_action, - db_add_system_prompt, - db_set_session_state, - db_clear_session_state, - db_purge_ephemeral_messages, - db_save_chat_message, - db_get_chat_history -) +# Прямые вызовы чистых доменных сервисов +from services.prompts.service import save_full_prompt_draft, apply_prompt_action, get_active_system_prompt +from services.tasks.service import get_tasks, delete_task +from services.snapshots.service import get_snapshots_registry, delete_snapshots_safely + +# Чат и сессии +from modules.web_api.llm.db.db_chat import db_save_chat_message, db_get_chat_history, db_purge_ephemeral_messages +from modules.web_api.llm.db.db_prompts import db_set_session_state, db_clear_session_state, db_get_tool_action +from modules.web_api.llm.core.context_manager import close_tool_session_and_cleanup logger = logging.getLogger("FAST_PATH") +# ANCHOR[FAST_PATH_MAIN] def handle_fast_path_intercept( - session_id: str, - user_message: str, - full_user_content: str, + session_id: str, + user_message: str, + full_user_content: str, session_state: Optional[Dict[str, Any]] ) -> Optional[Tuple[str, list, Optional[Dict[str, Any]]]]: - """Обрабатывает команды подтверждения, отмены и завершения сессии.""" + """ + Мгновенный перехват нажатий кнопок подтверждения (Fast-Path). + Возвращает (reply, history, action_type) или None, если требуется передать управление LLM. + """ if not session_state: return None state_type = session_state.get("state_type") - user_msg_clean = user_message.lower().strip(" .!?:;") + state_data = session_state.get("data_json") or {} + if not isinstance(state_data, dict): + state_data = {} - # ========================================================================= - # ФАЗА 1: ОБРАБОТКА В СОСТОЯНИИ PROMPT_PREVIEW - # ========================================================================= + msg_lower = user_message.strip().lower() + + # ------------------------------------------------------------------------- + # 1. ПОДТВЕРЖДЕНИЕ ПРЕВЬЮ СИСТЕМНОГО ПРОМПТА + # ------------------------------------------------------------------------- if state_type == "PROMPT_PREVIEW": - state_data = session_state.get("data_json") or {} - if not isinstance(state_data, dict): - state_data = {} + is_confirm = msg_lower in ["подтверждаю", "да", "сохраняй", "применить", "ок", "подтвердить"] + is_cancel = msg_lower in ["отмена", "отменить", "нет", "отклонить"] - draft_text = state_data.get("draft_text", "") - action = state_data.get("action") - sec_id = state_data.get("section_id") - itm_id = state_data.get("item_id") - content = state_data.get("content", "") + if is_confirm: + action = state_data.get("action", "MANUAL_EDIT") + draft_text = state_data.get("draft_text", "") - # 1. ПОДТВЕРДИТЬ ИЗМЕНЕНИЯ -> ПЕРЕХОД В PROMPT_FOLLOWUP - if user_msg_clean in ["подтверждаю", "подтвердить", "да", "сохранить", "применить", "ок", "хорошо"]: - if action == "MANUAL_EDIT" or not action or sec_id is None: - if draft_text: - db_add_system_prompt("main_agent", draft_text) + # Применение изменений + if action == "MANUAL_EDIT" and draft_text: + save_full_prompt_draft(draft_text, prompt_name="main_agent") else: - db_apply_prompt_node_action(action=action, section_id=sec_id, item_id=itm_id, content=content) + sec_id = state_data.get("section_id") + itm_id = state_data.get("item_id") + content = state_data.get("content", "") + if sec_id is not None and itm_id is not None: + apply_prompt_action(action=action, section_id=sec_id, item_id=itm_id, content=content) + elif draft_text: + save_full_prompt_draft(draft_text, prompt_name="main_agent") - logger.info("Системный промпт применен в БД. Переход в PROMPT_FOLLOWUP.") + # Закрытие сессии и зачистка + close_tool_session_and_cleanup(session_id, close_reason="PROMPT_APPLIED_SUCCESSFULLY") + db_clear_session_state(session_id) + + tool_action = db_get_tool_action("db_confirm_prompt_preview") + reply = tool_action.get("success_template", "✅ Системный промпт успешно сохранен и применен в базе данных.") if tool_action else "✅ Системный промпт успешно сохранен и применен в базе данных." - # Переводим сессию в режим ожидания продолжения/завершения - db_set_session_state(session_id, "PROMPT_FOLLOWUP", {}) + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=0) + db_save_chat_message(session_id, "assistant", reply, is_ephemeral=0) + return reply, db_get_chat_history(session_id), None - reply_text = "Системный промпт успешно сохранен и применен в базе данных. Желаете продолжить работу с системным промптом или завершить?" - db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=1) + elif is_cancel: + close_tool_session_and_cleanup(session_id, close_reason="PROMPT_EDIT_CANCELLED") + db_clear_session_state(session_id) - action_payload = { - "type": "PROMPT_FOLLOWUP", - "buttons": [ - {"label": "✨ Показать обновленный промпт", "value": "покажи системный промпт", "style": "secondary"}, - {"label": "🏁 Завершить работу", "value": "завершить работу", "style": "primary"} - ] + tool_action = db_get_tool_action("db_cancel_prompt_preview") + reply = tool_action.get("success_template", "❌ Изменения системного промпта отменены.") if tool_action else "❌ Изменения системного промпта отменены." + + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=0) + db_save_chat_message(session_id, "assistant", reply, is_ephemeral=0) + return reply, db_get_chat_history(session_id), None + + # ------------------------------------------------------------------------- + # 2. ПОДТВЕРЖДЕНИЕ УДАЛЕНИЯ СНАПШОТОВ СКУД + # ------------------------------------------------------------------------- + elif state_type == "SNAPSHOT_DELETE_CONFIRM": + is_confirm = "подтверждаю удаление снапшот" in msg_lower or msg_lower in ["подтверждаю", "да", "удалить"] + is_cancel = msg_lower in ["отмена", "отменить", "нет"] + + if is_confirm: + snap_ids = state_data.get("snapshot_ids", []) + query_date = state_data.get("query_date", "") + + # Безопасное удаление через сервис + del_res = delete_snapshots_safely(snapshot_ids=snap_ids) + + close_tool_session_and_cleanup(session_id, close_reason="SNAPSHOTS_DELETED") + + # Получаем свежий список за ту же дату + updated_data = get_snapshots_registry(date_str=query_date if query_date else None) + db_set_session_state(session_id, "SNAPSHOTS_VIEW", updated_data) + + reply = f"✅ Успешно удалено снапшотов: {len(snap_ids)} шт." + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=1) + db_save_chat_message(session_id, "assistant", reply, is_ephemeral=1) + + return reply, db_get_chat_history(session_id), { + "type": "SNAPSHOTS_CARD", + "data": updated_data } - return reply_text, db_get_chat_history(session_id), action_payload - # 2. ОТМЕНА В МОМЕНТ ПРЕВЬЮ -> ПОЛНАЯ ЗАЧИСТКА - elif user_msg_clean in ["отмена", "отменить", "отклонить", "назад", "стоп"]: + elif is_cancel: + close_tool_session_and_cleanup(session_id, close_reason="SNAPSHOT_DELETE_CANCELLED") db_clear_session_state(session_id) - deleted_count = db_purge_ephemeral_messages(session_id) - logger.info(f"Изменения промпта отменены. Удалено эфемерных сообщений: {deleted_count}") + + reply = "❌ Удаление снапшотов отменено." + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=0) + db_save_chat_message(session_id, "assistant", reply, is_ephemeral=0) + return reply, db_get_chat_history(session_id), None - reply_text = "Изменения системного промпта отменены. Контекст диалога чист." - db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=0) - return reply_text, db_get_chat_history(session_id), None + # ------------------------------------------------------------------------- + # 3. ПОДТВЕРЖДЕНИЕ УДАЛЕНИЯ ЗАДАЧИ + # ------------------------------------------------------------------------- + elif state_type == "TASK_DELETE_CONFIRM": + is_confirm = "подтверждаю удаление задачи" in msg_lower or msg_lower in ["подтверждаю", "да", "удалить"] + is_cancel = msg_lower in ["отмена", "отменить", "нет"] - # ========================================================================= - # ФАЗА 2: ОБРАБОТКА В СОСТОЯНИИ PROMPT_FOLLOWUP - # ========================================================================= - elif state_type == "PROMPT_FOLLOWUP": - # Явный сигнал завершения работы - if user_msg_clean in [ - "завершить работу", "завершить", "закончить", "готово", "всё", - "все", "нет", "нет, спасибо", "спасибо", "хватит", "выйти" - ]: + if is_confirm: + task_id = state_data.get("task_id") + delete_task(user_id=1, task_id=str(task_id)) + + close_tool_session_and_cleanup(session_id, close_reason="TASK_DELETED") db_clear_session_state(session_id) - deleted_count = db_purge_ephemeral_messages(session_id) - logger.info(f"Сессия работы с промптом закрыта. Очищено эфемерных сообщений: {deleted_count}") - reply_text = "Работа с системным промптом завершена. Чем могу помочь?" - db_save_chat_message(session_id, "assistant", reply_text, is_ephemeral=0) - return reply_text, db_get_chat_history(session_id), None + raw_tasks = get_tasks(user_id=1) + reply = f"🗑 Задача #{task_id} удалена." + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=1) + db_save_chat_message(session_id, "assistant", reply, is_ephemeral=1) + + return reply, db_get_chat_history(session_id), { + "type": "TASK_INTERACTIVE_CARD", + "tasks": raw_tasks + } + + elif is_cancel: + close_tool_session_and_cleanup(session_id, close_reason="TASK_DELETE_CANCELLED") + db_clear_session_state(session_id) + + reply = "❌ Удаление задачи отменено." + db_save_chat_message(session_id, "user", full_user_content, is_ephemeral=0) + db_save_chat_message(session_id, "assistant", reply, is_ephemeral=0) + return reply, db_get_chat_history(session_id), None return None \ No newline at end of file diff --git a/modules/web_api/llm/core/ollama_client.py b/modules/web_api/llm/core/ollama_client.py index a6fd772..83dd592 100644 --- a/modules/web_api/llm/core/ollama_client.py +++ b/modules/web_api/llm/core/ollama_client.py @@ -14,16 +14,16 @@ from typing import Dict, Any, Optional logger = logging.getLogger("OLLAMA_CLIENT") -OLLAMA_URL = "http://192.168.11.3:11434/api/chat" -TEXT_MODEL = "qwen2.5:14b" +OLLAMA_URL = "http://10.121.17.227:11434/api/chat" +TEXT_MODEL = "qwen2.5:14b-instruct-q8_0" VISION_MODEL = "qwen2.5vl:7b-q8_0" LLM_OPTIONS = { "num_predict": 8192, "num_ctx": 8192, - "temperature": 0.1, - "repeat_penalty": 1.1, - "presence_penalty": 0.5, + "temperature": 0.0, + "repeat_penalty": 1.0, + "presence_penalty": 0.0, "top_p": 0.9 } diff --git a/modules/web_api/llm/core/prompt_merger.py b/modules/web_api/llm/core/prompt_merger.py deleted file mode 100644 index 5407901..0000000 --- a/modules/web_api/llm/core/prompt_merger.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -=============================================================================== -FILE: modules/web_api/llm/core/prompt_merger.py -PROJECT: SCUD Orion AI (Unified Architecture) -MODULE: web_api / llm / core -ROLE: Алгоритмы парсинга, предпросмотра, слияния и визуального выделения правок. -=============================================================================== -""" - -# ANCHOR[PROMPT_MERGER_IMPORTS] -import re -import logging - -logger = logging.getLogger("PROMPT_MERGER") - - -# ANCHOR[PROMPT_MERGE_ENGINE] -def build_prompt_preview_merge(current_prompt: str, user_message: str, proposed_text: str) -> str: - """ - Вычисляет результирующий чистый текст промпта для записи в БД. - """ - user_msg_lower = user_message.lower() - - # 1. Сценарий удаления пункта - if any(w in user_msg_lower for w in ["удали", "стереть", "убрать", "вырежи", "удалить"]): - target_num_match = re.search(r'\d+(\.\d+)*', user_message) - target_num = target_num_match.group(0) if target_num_match else "" - - lines = current_prompt.splitlines() - if target_num: - new_lines = [line for line in lines if not line.strip().startswith(f"{target_num}.")] - else: - new_lines = lines - return "\n".join(new_lines) - - # 2. Сценарий добавления или замены пункта - if proposed_text: - if len(proposed_text) < 500: - clean_item = proposed_text.strip() - for prefix in ["добавь пункт", "добавить пункт", "вставь пункт", "добавь"]: - if prefix in clean_item.lower(): - clean_item = re.sub(prefix, "", clean_item, flags=re.IGNORECASE).strip(" .:") - - lines = current_prompt.splitlines() - new_lines = [] - inserted = False - for line in lines: - new_lines.append(line) - if "3.3." in line and not inserted: - item_str = clean_item if re.match(r'^\d+\.\d+\.', clean_item) else f"3.4. {clean_item}" - new_lines.append(f" {item_str}") - inserted = True - if not inserted: - new_lines.append(f" {clean_item}") - return "\n".join(new_lines) - - return proposed_text or current_prompt - - -def highlight_prompt_diff(old_prompt: str, new_prompt: str) -> str: - """ - Генерирует текст с подсветкой добавленных/измененных строк HTML-классами Tailwind. - """ - old_lines_set = {line.strip() for line in old_prompt.splitlines() if line.strip()} - diff_lines = [] - - for line in new_prompt.splitlines(): - if line.strip() and line.strip() not in old_lines_set: - # Выделяем новую или измененную строку красным цветом - diff_lines.append(f'{line}') - else: - diff_lines.append(line) - - return "\n".join(diff_lines) \ No newline at end of file diff --git a/modules/web_api/llm/core/tool_injector.py b/modules/web_api/llm/core/tool_injector.py index 3dd45c3..40381d8 100644 --- a/modules/web_api/llm/core/tool_injector.py +++ b/modules/web_api/llm/core/tool_injector.py @@ -3,9 +3,14 @@ FILE: modules/web_api/llm/core/tool_injector.py PROJECT: SCUD Orion AI (Unified Architecture) MODULE: web_api / llm / core -ROLE: Санитарная очистка сырых артефактов и тегов из ответов LLM. +ROLE: Семантический анализ намерений оператора (Intent Classifier) и + детерминированная сборка вызовов инструментов при сбоях нативного Function Calling. + +AI-CONTEXT-ANCHORS: + - ANCHOR[INTENT_INJECTOR_MAIN]: Точка входа inject_tools_if_needed. =============================================================================== """ + import re import logging from typing import List, Dict, Any @@ -14,37 +19,120 @@ logger = logging.getLogger("TOOL_INJECTOR") def clean_raw_tool_tags(text: str) -> str: - """Удаляет сырые теги вызова инструментов, если модель случайно вывела их в текст.""" + """Удаляет сырые теги вызова инструментов и системный шум.""" if not text: return "" - text = re.sub(r'\{"name":\s*"db_[^}]+\}\s*()?', '', text) - text = re.sub(r'.*?', '', text, flags=re.DOTALL) - text = re.sub(r'\w*\[\]\(\)', '', text) - text = re.sub(r'', '', text) - return text.strip() - - -def clean_output(text: str) -> str: - """Удаляет слова-паразиты и склейки в начале ответа.""" - if not text: - return text - - artifacts = [ - "почемучка", "почемучка,", "почемучка!", "почемучка?", - "почемучто", "почто", "почему что", "почему-то", - "здравствуйте!", "привет!" - ] - - cleaned = text.strip() - for art in artifacts: - if cleaned.lower().startswith(art): - cleaned = cleaned[len(art):].lstrip(",.!?:; -") - + cleaned = re.sub(r'.*?', '', text, flags=re.DOTALL) + cleaned = re.sub(r'<\|.*?\|>', '', cleaned) return cleaned.strip() -def inject_tools_if_needed(user_message: str, raw_text_content: str, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]: +def clean_output(text: str) -> str: + """Очищает маркеры форматирования.""" + return text.strip() if text else "" + + +# ANCHOR[INTENT_INJECTOR_MAIN] +def inject_tools_if_needed(user_message: str, raw_reply: str, existing_tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """ - Проходной фильтр: все решения о вызове инструментов принимает исключительно LLM. + Гибридный семантический анализатор: + Если модель ответила текстом с сомнениями или пропустила tool_call, + распознает доменное намерение и конструирует синтетический tool_call. """ - return tool_calls \ No newline at end of file + if existing_tool_calls: + return existing_tool_calls + + msg_clean = user_message.strip().lower() + + # 1. СЕМАНТИКА: Просмотр системного промпта + # Паттерны: "покажи системный промпт", "выведи промпт", "текущий промпт", "какой сейчас системный промпт" + if "промпт" in msg_clean and any(kw in msg_clean for kw in ["покажи", "выведи", "какой", "дай", "текст", "актуальн"]): + logger.info("[IntentInjector] Распознано намерение просмотра системного промпта") + return [{ + "function": { + "name": "db_get_system_prompt", + "arguments": {} + } + }] + + # 2. СЕМАНТИКА: Удаление задач + # Паттерны: "удали задачу 37", "убери 37 задачу", "сотри таску #37", "сними с повестки задачу 37" + if any(kw in msg_clean for kw in ["удали", "удалить", "убери", "сотри", "сними"]) and any(kw in msg_clean for kw in ["задач", "таск"]): + task_match = re.search(r'#?\s*(\d+)', msg_clean) + if task_match: + task_id = task_match.group(1) + logger.info(f"[IntentInjector] Распознано намерение удаления задачи: #{task_id}") + return [{ + "function": { + "name": "db_tasks_edit", + "arguments": {"action": "DELETE", "task_id": task_id} + } + }] + + # 3. СЕМАНТИКА: Управление системным промптом (удаление и мульти-удаление) + # Паттерны: "удали 1.8 и 3.4", "удали пункт 2.3", "вычеркни 1.8, 3.4 из промпта" + if any(kw in msg_clean for kw in ["удали", "удалить", "убери", "вычеркни", "сотри"]) and not any(kw in msg_clean for kw in ["задач", "снапшот", "срез"]): + node_matches = re.findall(r'(\d+)[\.\s]+(\d+)', user_message) + if node_matches: + formatted_nodes = [f"{s}.{i}" for s, i in node_matches] + logger.info(f"[IntentInjector] Распознано намерение удаления узлов промпта: {formatted_nodes}") + return [{ + "function": { + "name": "db_prompt_node_edit", + "arguments": { + "action": "BATCH_DELETE" if len(formatted_nodes) > 1 else "DELETE", + "section_id": int(node_matches[0][0]), + "item_id": int(node_matches[0][1]), + "nodes_list": formatted_nodes, + "content": "" + } + } + }] + + # 4. СЕМАНТИКА: Добавление пункта промпта + # Паттерны: "добавь 3.4 Текст", "добавь пункт 3.4 Текст", "впиши в 3.4 Текст" + if any(kw in msg_clean for kw in ["добавь", "добавить", "впиши", "запиши"]) and not any(kw in msg_clean for kw in ["задач", "таск"]): + add_match = re.search(r'(\d+)[\.\s]+(\d+)[\.\s\:\-]+(.*)', user_message) + if add_match: + sec_id = int(add_match.group(1)) + itm_id = int(add_match.group(2)) + content = add_match.group(3).strip() + logger.info(f"[IntentInjector] Распознано намерение добавления узла промпта: {sec_id}.{itm_id}") + return [{ + "function": { + "name": "db_prompt_node_edit", + "arguments": { + "action": "ADD", + "section_id": sec_id, + "item_id": itm_id, + "content": content + } + } + }] + + # 5. СЕМАНТИКА: Смена статуса задач + if any(kw in msg_clean for kw in ["в работу", "начни", "стартуй", "за работу"]): + task_match = re.search(r'#?\s*(\d+)', msg_clean) + if task_match: + task_id = task_match.group(1) + logger.info(f"[IntentInjector] Распознано намерение взятия в работу задачи: #{task_id}") + return [{ + "function": { + "name": "db_tasks_edit", + "arguments": {"action": "UPDATE", "task_id": task_id, "status": "IN_PROGRESS"} + } + }] + + if any(kw in msg_clean for kw in ["заверши", "закрой", "готово", "выполнено"]): + task_match = re.search(r'#?\s*(\d+)', msg_clean) + if task_match: + task_id = task_match.group(1) + logger.info(f"[IntentInjector] Распознано намерение закрытия задачи: #{task_id}") + return [{ + "function": { + "name": "db_tasks_edit", + "arguments": {"action": "UPDATE", "task_id": task_id, "status": "COMPLETED"} + } + }] + + return existing_tool_calls \ No newline at end of file diff --git a/modules/web_api/llm/db/db_snapshots.py b/modules/web_api/llm/db/db_snapshots.py deleted file mode 100644 index 6918033..0000000 --- a/modules/web_api/llm/db/db_snapshots.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -FILE: modules/web_api/llm/db/db_snapshots.py -""" -import json -from typing import Dict, Any, Optional -from .connection import get_db_connection -from .db_prompts import db_set_session_state - -def db_get_snapshots(session_id: str = "web_session_main", date_str: Optional[str] = None, original_user_message: str = "") -> Dict[str, Any]: - conn = get_db_connection() - cursor = conn.cursor() - query = "SELECT snapshot_id, log_date, snapshot_time, COUNT(*) as record_count FROM scud_logs " - params = [] - if date_str: - iso_date = date_str - if "." in date_str: - parts = date_str.split(".") - if len(parts) == 3: - iso_date = f"{parts[2]}-{parts[1]}-{parts[0]}" - query += " WHERE log_date = ? OR log_date = ? OR snapshot_time LIKE ? " - params.extend([date_str, iso_date, f"{iso_date}%"]) - - query += " GROUP BY snapshot_id ORDER BY id DESC LIMIT 50" - cursor.execute(query, params) - rows = cursor.fetchall() - snapshots = [dict(r) for r in rows] - - result_data = { - "query_date": date_str or "все", - "snapshots_count": len(snapshots), - "snapshots": snapshots - } - db_set_session_state(session_id=session_id, state_type="SNAPSHOTS_VIEW", data=json.dumps(result_data, ensure_ascii=False)) - conn.close() - return result_data - -def db_delete_snapshots(snapshot_id: Optional[str] = None, day_str: Optional[str] = None) -> Dict[str, Any]: - if not snapshot_id and not day_str: - return {"status": "error", "message": "Необходимо указать snapshot_id или day_str (ДД.ММ.ГГГГ)."} - conn = get_db_connection() - cursor = conn.cursor() - if snapshot_id: - cursor.execute("DELETE FROM scud_logs WHERE snapshot_id = ?", (snapshot_id,)) - else: - cursor.execute("DELETE FROM scud_logs WHERE log_date = ? OR snapshot_id LIKE ?", (day_str, f"%{day_str.replace('.', '')}%")) - deleted = cursor.rowcount - conn.commit() - conn.close() - return {"status": "success", "message": f"Успешно удалено записей: {deleted}"} \ No newline at end of file diff --git a/modules/web_api/llm/db/db_tasks.py b/modules/web_api/llm/db/db_tasks.py deleted file mode 100644 index 4bb97bd..0000000 --- a/modules/web_api/llm/db/db_tasks.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -FILE: modules/web_api/llm/db/db_tasks.py -""" -import re -from typing import List, Dict, Any, Optional -from .connection import get_db_connection - -def normalize_task_id(task_id_input: str) -> str: - if not task_id_input: - return "" - clean_id = str(task_id_input).strip().upper().replace("TASK-", "").replace("TASK", "") - if clean_id.isdigit(): - num = int(clean_id) - return f"TASK-{(num):02d}" if num < 100 else f"TASK-{(num):03d}" - return f"TASK-{clean_id}" - -def db_get_tasks(user_id: int) -> List[Dict[str, Any]]: - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute(""" - SELECT id, task_id, module, title, priority, status, due_date, created_at - FROM tasks - WHERE user_id = ? - ORDER BY id DESC - """, (user_id,)) - rows = cursor.fetchall() - conn.close() - return [dict(r) for r in rows] - -def db_add_task(user_id: int, module: str, title: str, priority: str = "MEDIUM", due_date: Optional[str] = None) -> Dict[str, Any]: - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute("SELECT MAX(id) FROM tasks") - max_id = cursor.fetchone()[0] or 0 - new_task_id = f"TASK-{(max_id + 1):02d}" - - cursor.execute(""" - INSERT INTO tasks (task_id, module, title, priority, status, due_date, user_id) - VALUES (?, ?, ?, ?, 'BACKLOG', ?, ?) - """, (new_task_id, module, title, priority.upper(), due_date, user_id)) - conn.commit() - conn.close() - return {"status": "success", "task_id": new_task_id, "message": f"Задача {new_task_id} создана"} - -def db_update_task_status(user_id: int, task_id: str, status: str = "COMPLETED", due_date: Optional[str] = None) -> Dict[str, Any]: - conn = get_db_connection() - cursor = conn.cursor() - formatted_id = normalize_task_id(task_id) - if due_date: - cursor.execute(""" - UPDATE tasks - SET status = ?, due_date = ? - WHERE (UPPER(task_id) = ? OR task_id LIKE ?) AND user_id = ? - """, (status.upper(), due_date, formatted_id, f"%{task_id.strip()}", user_id)) - else: - cursor.execute(""" - UPDATE tasks - SET status = ? - WHERE (UPPER(task_id) = ? OR task_id LIKE ?) AND user_id = ? - """, (status.upper(), formatted_id, f"%{task_id.strip()}", user_id)) - - if cursor.rowcount == 0: - conn.close() - return {"error": f"Задача {task_id} не найдена или принадлежит другому пользователю"} - conn.commit() - conn.close() - return {"status": "success", "message": f"Статус задачи {formatted_id} обновлен на {status.upper()}"} - -def db_delete_task(user_id: int, task_id: str) -> Dict[str, Any]: - conn = get_db_connection() - cursor = conn.cursor() - formatted_id = normalize_task_id(task_id) - cursor.execute(""" - DELETE FROM tasks - WHERE (UPPER(task_id) = ? OR task_id LIKE ?) AND user_id = ? - """, (formatted_id, f"%{task_id.strip()}", user_id)) - if cursor.rowcount == 0: - conn.close() - return {"error": f"Задача {task_id} не найдена"} - conn.commit() - conn.close() - return {"status": "success", "message": f"Задача {formatted_id} удалена"} \ No newline at end of file diff --git a/modules/web_api/llm/db_tools.py b/modules/web_api/llm/db_tools.py index 0eec0d2..c2a5b9b 100644 --- a/modules/web_api/llm/db_tools.py +++ b/modules/web_api/llm/db_tools.py @@ -1,17 +1,53 @@ """ +=============================================================================== FILE: modules/web_api/llm/db_tools.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: web_api / llm +ROLE: Фасадная точка доступа к доменным сервисам (Domain Facade). + +AI-CONTEXT-ANCHORS: + - ANCHOR[FACADE_EXPORTS]: Экспорт методов предметных сервисов для LLM и API. +=============================================================================== """ -from datetime import datetime -from .db.connection import DB_PATH, get_db_connection -from .db.db_chat import db_save_chat_message, db_get_chat_history, db_purge_ephemeral_messages -from .db.db_tasks import normalize_task_id, db_get_tasks, db_add_task, db_update_task_status, db_delete_task -from .db.db_snapshots import db_get_snapshots, db_delete_snapshots + +# ANCHOR[FACADE_EXPORTS] +from typing import Optional, List, Dict, Any +from core.connection import DB_PATH, get_connection as get_db_connection + +# Домен: Задачи +from services.tasks.service import ( + get_tasks as db_get_tasks, + add_task as db_add_task, + update_task_details as db_update_task_details, + delete_task as db_delete_task, + execute_task_action as db_tasks_edit +) +from services.tasks.exporter import export_tasks_to_markdown as db_export_tasks_markdown +from services.tasks.repository import normalize_task_id + +# Домен: Системный промпт +from services.prompts.service import ( + get_active_system_prompt as db_get_active_system_prompt, + apply_prompt_action as db_apply_prompt_node_action, + save_full_prompt_draft, + create_prompt_preview +) + +# Домен: База знаний +from services.knowledge.service import ( + get_rules as db_get_rules, + add_rule as db_add_rule +) + +# Чат, сессии, статистика +from .db.db_chat import ( + db_save_chat_message, + db_get_chat_history, + db_purge_ephemeral_messages, + db_clear_chat_history +) from .db.db_prompts import ( - db_get_active_system_prompt, - db_add_system_prompt, - db_apply_prompt_node_action, db_get_tool_action, - db_get_rules, db_set_session_state, db_get_session_state, db_clear_session_state, @@ -19,13 +55,42 @@ from .db.db_prompts import ( db_get_anomalies, db_get_reference ) +from .core.calendar_utils import get_dynamic_calendar_context as db_get_current_server_time -def db_get_current_server_time(): - now = datetime.now() - days_ru = ["понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"] - return { - "current_date": now.strftime("%d.%m.%Y"), - "current_time": now.strftime("%H:%M:%S"), - "day_of_week": days_ru[now.weekday()], - "iso_date": now.strftime("%Y-%m-%d") - } \ No newline at end of file + +def db_add_system_prompt(name_or_text: str, draft_text: str = None) -> None: + """Совместимая обертка для сохранения системного промпта.""" + if draft_text is not None: + save_full_prompt_draft(draft_text, prompt_name=name_or_text) + else: + save_full_prompt_draft(name_or_text, prompt_name="main_agent") + + +def db_get_snapshots(session_id: str = "web_session_main", date_str: str = None, original_user_message: str = "") -> Dict[str, Any]: + """Совместимый фасад выборки снапшотов с сохранением стейта сессии.""" + from services.snapshots.service import get_snapshots_registry + from .core.calendar_utils import parse_relative_date_ru + + clean_date = (date_str or "").strip() + if not clean_date and original_user_message: + clean_date = parse_relative_date_ru(original_user_message) + + res = get_snapshots_registry(date_str=clean_date if clean_date else None) + db_set_session_state(session_id=session_id, state_type="SNAPSHOTS_VIEW", data=res) + return res + + +def db_delete_snapshots(snapshot_id: str = None, snapshot_ids: List[str] = None, day_str: str = None) -> Dict[str, Any]: + """Совместимый фасад безопасного удаления снапшотов.""" + from services.snapshots.service import delete_snapshots_safely + + target_ids = [] + if snapshot_ids: + target_ids.extend(snapshot_ids) + if snapshot_id: + if isinstance(snapshot_id, str) and "," in snapshot_id: + target_ids.extend([s.strip() for s in snapshot_id.split(",")]) + else: + target_ids.append(snapshot_id) + + return delete_snapshots_safely(snapshot_ids=target_ids) \ No newline at end of file diff --git a/modules/web_api/llm/schemas.py b/modules/web_api/llm/schemas.py index 386139e..dfe1567 100644 --- a/modules/web_api/llm/schemas.py +++ b/modules/web_api/llm/schemas.py @@ -1,50 +1,82 @@ +""" +=============================================================================== +FILE: modules/web_api/llm/schemas.py +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: web_api / llm +ROLE: Декларативная схема нативных инструментов (Function Calling) для Ollama. + +AI-CONTEXT-ANCHORS: + - ANCHOR[SCHEMA_PROMPT_EDIT]: Схема управления узлами системного промпта. + - ANCHOR[SCHEMA_TASKS_EDIT]: Консолидированная схема управления задачами. + - ANCHOR[SCHEMA_SNAPSHOTS]: Схема доступа к логам и срезам СКУД. +=============================================================================== +""" + +# ANCHOR[SCHEMA_PROMPT_EDIT] TOOLS_SCHEMA = [ { "type": "function", "function": { "name": "db_prompt_node_edit", "description": ( - "ЕДИНСТВЕННЫЙ инструмент для добавления, изменения или УДАЛЕНИЯ пунктов системного промпта. " - "Вызывай ВСЕГДА при фразах 'удали X.Y', 'удалить пункт X.Y', 'добавь X.Y', 'измени X.Y'. " - "При удалении: action='DELETE', section_id=X, item_id=Y, content=''. " - "Запрещено отвечать текстовым подтверждением без вызова этой функции!" + "Управление элементами системного промпта (добавление, изменение, удаление пунктов).\n" + "Поддерживает как одиночные пункты (section_id, item_id), так и список пунктов для удаления (nodes_list=['1.8', '3.4']).\n" + "При любом запросе на удаление или добавление пунктов системного промпта ТЫ ОБЯЗАН вызвать этот инструмент." ), "parameters": { "type": "object", "properties": { "action": { "type": "string", - "enum": ["ADD", "UPDATE", "DELETE"], - "description": "ADD (добавить), UPDATE (изменить), DELETE (удалить)" + "enum": ["ADD", "EDIT", "DELETE", "BATCH_DELETE"], + "description": "Тип действия" }, "section_id": { "type": "integer", - "description": "Номер раздела (например: 1, 2, 3)" + "description": "Номер раздела (например 1)" }, "item_id": { "type": "integer", - "description": "Номер пункта (например: 4, 8, 9)" + "description": "Номер пункта (например 8)" + }, + "nodes_list": { + "type": "array", + "items": {"type": "string"}, + "description": "Список пунктов для удаления/изменения, например ['1.8', '3.4']" }, "content": { "type": "string", - "description": "Текст пункта (для DELETE передается пустая строка)" + "description": "Текст пункта" } }, - "required": ["action", "section_id", "item_id"] + "required": ["action"] } } }, + { + "type": "function", + "function": { + "name": "db_get_system_prompt", + "description": "Просмотр текущего активного системного промпта ассистента из базы данных.", + "parameters": { + "type": "object", + "properties": {} + } + } + }, + # ANCHOR[SCHEMA_TASKS_EDIT] { "type": "function", "function": { "name": "db_get_tasks", - "description": "ПОЛУЧИТЬ СПИСОК ЗАДАЧ ТЕКУЩЕГО ПОЛЬЗОВАТЕЛЯ. Вызывай СРАЗУ при запросе 'покажи мои задачи' или 'список задач'. ВАЖНОЕ ПРАВИЛО ВЫВОДА: Выводи задачи ЕДИНЫМ плоским списком (нумерованным или маркированным) по порядку ID. КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО группировать задачи по статусам (В процессе, Бэклог, Завершены) или создавать подзаголовки, если оператор явно не попросил о группировке!", + "description": "Просмотр реестра задач и бэклога текущего пользователя.", "parameters": { "type": "object", "properties": { "status": { "type": "string", - "description": "Фильтр статуса: BACKLOG, IN_PROGRESS или COMPLETED." + "enum": ["ALL", "IN_PROGRESS", "PLANNED", "COMPLETED"], + "description": "Опциональный фильтр статуса задач" } } } @@ -53,64 +85,70 @@ TOOLS_SCHEMA = [ { "type": "function", "function": { - "name": "db_get_rules", - "description": "ПОЛУЧИТЬ БАЗУ ЗНАНИЙ ИИ И ПРАВИЛА АРБИТРАЖА (ai_knowledge_base). Вызывай когда пользователь просит показать базу знаний, правила, инструкции или промпты.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_get_system_prompt", - "description": "ВЫЗЫВАЙ ВСЕГДА при наличии в сообщении фраз: 'покажи системный промпт', 'покажи промпт', 'выведи промпт', 'системный промпт'. Запрещено отвечать текстом без вызова этого инструмента.", - "parameters": { - "type": "object", - "properties": {}, - "required": [] - } - } - }, - { - "type": "function", - "function": { - "name": "db_update_task_status", - "description": "Изменить статус и/или срок выполнения задачи в реестре.", + "name": "db_tasks_edit", + "description": ( + "Единый инструмент управления задачами: создание (ADD), изменение статуса/срока/названия (UPDATE), удаление (DELETE) и экспорт (EXPORT).\n" + "СТРОГИЕ ПРАВИЛА ВЫЗОВА:\n" + "- На любые фразы вида 'удали задачу N', 'удалить N', 'убери задачу N' ТЫ ОБЯЗАН СРАЗУ вызвать инструмент с action='DELETE', task_id='N'.\n" + "- На фразы 'возьми в работу N' вызывай action='UPDATE', task_id='N', status='IN_PROGRESS'.\n" + "- На фразы 'заверши N', 'готово N' вызывай action='UPDATE', task_id='N', status='COMPLETED'.\n" + "- КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО писать текстовые вопросы или запрашивать подтверждения словами! ТЫ ОБЯЗАН СРАЗУ вызвать инструмент." + ), "parameters": { "type": "object", "properties": { - "task_id": {"type": "string", "description": "Идентификатор задачи, например TASK-17"}, - "status": {"type": "string", "description": "Новый статус: COMPLETED, IN_PROGRESS или BACKLOG"}, - "due_date": {"type": "string", "description": "Срок выполнения задачи"} + "action": { + "type": "string", + "enum": ["ADD", "UPDATE", "DELETE", "EXPORT"], + "description": "Тип действия: ADD, UPDATE, DELETE или EXPORT" + }, + "task_id": { + "type": "string", + "description": "Номер задачи (например: '37')" + }, + "title": { + "type": "string", + "description": "Описание или текст задачи" + }, + "status": { + "type": "string", + "enum": ["IN_PROGRESS", "COMPLETED", "BACKLOG"], + "description": "Новый статус задачи: IN_PROGRESS (В работу), COMPLETED (Завершено), BACKLOG (В планы)" + }, + "priority": { + "type": "string", + "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"], + "description": "Приоритет задачи" + }, + "module": { + "type": "string", + "description": "Модуль проекта" + }, + "due_date": { + "type": "string", + "description": "Срок в формате ГГГГ-ММ-ДД" + }, + "filename": { + "type": "string", + "description": "Имя файла для экспорта" + } }, - "required": ["task_id"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_delete_task", - "description": "Удалить задачу из реестра по её task_id (например, TASK-18).", - "parameters": { - "type": "object", - "properties": { - "task_id": {"type": "string", "description": "Идентификатор задачи для удаления, например TASK-18"} - }, - "required": ["task_id"] + "required": ["action"] } } }, + # ANCHOR[SCHEMA_SNAPSHOTS] { "type": "function", "function": { "name": "db_get_snapshots", - "description": "ПОЛУЧИТЬ АКТУАЛЬНЫЙ СПИСОК СНАПШОТОВ ИЗ БАЗЫ SQLITE. Вызывай ЭТУ ФУНКЦИЮ ВСЕГДА, даже если список снапшотов уже есть в истории чата или пользователь просит 'обновить', 'повторить запрос', 'проверить снова'. ЗАПРЕЩЕНО беречь контекст и выводить старые данные из истории!", + "description": "Получение списка снапшотов и срезов логов СКУД из базы данных за конкретную дату.", "parameters": { "type": "object", "properties": { "date_str": { "type": "string", - "description": "Точная дата в формате ДД.ММ.ГГГГ (например, '12.08.2026'), взятая из [СИСТЕМНОГО КАЛЕНДАРЯ СЕРВЕРА]." + "description": "Дата в формате ДД.ММ.ГГГГ или относительное слово" } } } @@ -120,12 +158,18 @@ TOOLS_SCHEMA = [ "type": "function", "function": { "name": "db_delete_snapshots", - "description": "УДАЛИТЬ СНАПШОТ(Ы) ИЗ БАЗЫ ДАННЫХ. Вызывай, когда пользователь явно просит удалить конкретный снапшот по ID или все снапшоты за выбранный день.", + "description": "Удаление снапшотов СКУД по идентификатору или дате.", "parameters": { "type": "object", "properties": { - "snapshot_id": {"type": "string", "description": "Идентификатор снапшота для удаления, например Y20260805-007"}, - "day_str": {"type": "string", "description": "Дата в формате ДД.ММ.ГГГГ для удаления всех снапшотов за день"} + "snapshot_id": { + "type": "string", + "description": "Идентификатор конкретного снапшота" + }, + "day_str": { + "type": "string", + "description": "Дата всех снапшотов за день" + } } } } @@ -133,29 +177,31 @@ TOOLS_SCHEMA = [ { "type": "function", "function": { - "name": "db_get_current_server_time", - "description": "ПОЛУЧИТЬ ТЕКУЩУЮ ДАТУ, ВРЕМЯ И ДЕНЬ НЕДЕЛИ СЕРВЕРА. Вызывай МГНОВЕННО при любых вопросах пользователя про точное текущее время или текущую дату.", + "name": "db_get_anomalies", + "description": "Просмотр истории аномалий и расхождений между СКУД и 1С.", "parameters": { "type": "object", - "properties": {}, - "required": [] + "properties": { + "date_str": { + "type": "string", + "description": "Опциональная дата в формате ДД.ММ.ГГГГ" + }, + "limit": { + "type": "integer", + "description": "Лимит записей" + } + } } } }, { "type": "function", "function": { - "name": "db_add_task", - "description": "Добавить новую задачу в бэклог проекта.", + "name": "db_get_rules", + "description": "Просмотр базы знаний и правил кадрового арбитража компании.", "parameters": { "type": "object", - "properties": { - "title": {"type": "string", "description": "Краткое описание задачи"}, - "priority": {"type": "string", "description": "Приоритет: HIGH, MEDIUM, LOW"}, - "module": {"type": "string", "description": "Модуль проекта, например general или services/scud_export"}, - "due_date": {"type": "string", "description": "Срок выполнения задачи, например '2026-08-07 12:00'"} - }, - "required": ["title"] + "properties": {} } } }, @@ -163,43 +209,35 @@ TOOLS_SCHEMA = [ "type": "function", "function": { "name": "db_get_stats", - "description": "ПОЛУЧИТЬ ОБЩУЮ СТАТИСТИКУ БАЗЫ ДАННЫХ. Вызывай, когда пользователь просит показать общую статистику БД, количество записей в таблицах или размер базы.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_get_anomalies", - "description": "ПОЛУЧИТЬ ИСТОРИЮ АНОМАЛИЙ СКУД ⟷ 1С. Вызывай при запросах на просмотр аномалий или расхождений. Передавай date_str если пользователь просит аномалии за конкретный день, или увеличенный limit (например 100) если просит все.", + "description": "Получение статистики количества записей в таблицах базы данных.", "parameters": { "type": "object", - "properties": { - "limit": {"type": "integer", "description": "Максимальное количество записей (по умолчанию 100)"}, - "date_str": {"type": "string", "description": "Опциональная дата в формате ДД.ММ.ГГГГ"} - } + "properties": {} } } }, { "type": "function", "function": { - "name": "db_get_session_states", - "description": "ПОЛУЧИТЬ АКТИВНЫЕ СЕССИИ И ПРЕВЬЮ (session_states). Вызывай, когда пользователь просит показать текущие сессии или статус превью.", - "parameters": {"type": "object", "properties": {}} + "name": "db_get_current_server_time", + "description": "Получение текущего точного времени сервера.", + "parameters": { + "type": "object", + "properties": {} + } } }, { "type": "function", "function": { "name": "db_get_reference", - "description": "ПОЛУЧИТЬ СИСТЕМНЫЙ СПРАВОЧНИК И ПРИМЕРЫ КОМАНД ДЛЯ ОПЕРАТОРА (system_reference). Вызывай ВСЕГДА, когда пользователь спрашивает про возможности ассистента, список команд, примерах промптов или справе по работе с системой.", + "description": "Справка о возможностях ассистента и примеры доступных команд.", "parameters": { "type": "object", "properties": { "category": { "type": "string", - "description": "Фильтр категории: scud, tasks, calendar или system. Если просят всё — не передавай параметр." + "description": "Категория справки" } } } diff --git a/modules/web_api/main.py b/modules/web_api/main.py index 1a64668..fc65afd 100644 --- a/modules/web_api/main.py +++ b/modules/web_api/main.py @@ -16,6 +16,12 @@ CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) if CURRENT_DIR not in sys.path: sys.path.insert(0, CURRENT_DIR) +ROOT_DIR = os.path.abspath(os.path.join(CURRENT_DIR, "../../")) + +for p in [ROOT_DIR, CURRENT_DIR]: + if p not in sys.path: + sys.path.insert(0, p) + from fastapi import FastAPI, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse, JSONResponse @@ -25,6 +31,7 @@ from routers.auth import router as auth_router from routers.admin import router as admin_router from routers.tasks import router as tasks_router from routers.chat import router as chat_router +from routers.files import router as files_router # ANCHOR[APP_CONFIG] logging.basicConfig( @@ -53,6 +60,7 @@ app.include_router(auth_router) app.include_router(admin_router) app.include_router(tasks_router) app.include_router(chat_router) +app.include_router(files_router) # ANCHOR[ROOT_STATIC_ROUTES] @app.get("/") @@ -81,7 +89,6 @@ def serve_static_fallback(file_path: str): return FileResponse(target, media_type="text/css") return FileResponse(target) - # Резервный рекурсивный поиск файла в static filename = os.path.basename(clean_path) for root, _, files in os.walk(STATIC_DIR): if filename in files: diff --git a/modules/web_api/routers/auth.py b/modules/web_api/routers/auth.py index 73ba0c4..94ff0b1 100644 --- a/modules/web_api/routers/auth.py +++ b/modules/web_api/routers/auth.py @@ -5,8 +5,6 @@ ROLE: Аутентификация, валидация JWT-токенов и у =============================================================================== """ -# ANCHOR[AUTH_ROUTER_IMPORTS] -import sqlite3 import logging from datetime import datetime, timedelta from typing import Dict, Any, Optional @@ -17,7 +15,7 @@ from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from pydantic import BaseModel -from llm.db_tools import DB_PATH +from core.connection import get_connection JWT_SECRET = "scud_jwt_secret_key_2026_orion_ai_super_secure" ALGORITHM = "HS256" @@ -27,11 +25,10 @@ security = HTTPBearer() router = APIRouter(prefix="/api/v1/auth", tags=["auth"]) -# ANCHOR[AUTH_DB_HELPERS] + def get_db(): - conn = sqlite3.connect(DB_PATH) - conn.row_factory = sqlite3.Row - return conn + return get_connection(row_factory=True) + def create_access_token(user_id: int, username: str, is_admin: bool) -> str: payload = { @@ -42,6 +39,7 @@ def create_access_token(user_id: int, username: str, is_admin: bool) -> str: } return jwt.encode(payload, JWT_SECRET, algorithm=ALGORITHM) + def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> Dict[str, Any]: try: token = credentials.credentials @@ -58,21 +56,20 @@ def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(securit headers={"WWW-Authenticate": "Bearer"}, ) -# ANCHOR[AUTH_SCHEMAS] + class AuthRequest(BaseModel): username: str password: str + class ChangePasswordRequest(BaseModel): old_password: str new_password: str -# ANCHOR[AUTH_ENDPOINTS] + @router.post("/login") def login(req: AuthRequest): username = req.username.strip().lower() - logging.info(f"===> Попытка входа для пользователя: {username}") - conn = get_db() cursor = conn.cursor() cursor.execute("SELECT id, username, password_hash, is_admin FROM users WHERE username = ?", (username,)) @@ -80,15 +77,14 @@ def login(req: AuthRequest): conn.close() if not user or not pwd_context.verify(req.password, user["password_hash"]): - logging.warning(f"===> Ошибка: Неверный логин или пароль для {username}") raise HTTPException(status_code=401, detail="Неверное имя пользователя или пароль") is_admin = bool(user["is_admin"]) or (user["username"] == "puh") token = create_access_token(user["id"], user["username"], is_admin) - logging.info(f"===> УСПЕХ: Авторизован пользователь {username}") return {"status": "success", "token": token, "username": user["username"], "is_admin": is_admin} + @router.post("/change-password") def change_password(req: ChangePasswordRequest, current_user: Dict[str, Any] = Depends(get_current_user)): if not req.new_password or len(req.new_password) < 4: @@ -108,5 +104,4 @@ def change_password(req: ChangePasswordRequest, current_user: Dict[str, Any] = D conn.commit() conn.close() - logging.info(f"Пароль успешно изменен для пользователя ID: {current_user['id']}") return {"status": "success", "message": "Пароль успешно изменен"} \ No newline at end of file diff --git a/modules/web_api/routers/chat.py b/modules/web_api/routers/chat.py index 1dce55e..256c78b 100644 --- a/modules/web_api/routers/chat.py +++ b/modules/web_api/routers/chat.py @@ -1,93 +1,97 @@ """ =============================================================================== FILE: modules/web_api/routers/chat.py -PROJECT: SCUD Orion AI (Unified Architecture) -MODULE: web_api / routers -ROLE: Маршрутизация диалогов с LLM и эндпоинт сохранения онлайн-черновиков. +ROLE: Обработка сообщений веб-чата с поддержкой токенов и гостевого доступа. =============================================================================== """ -# ANCHOR[CHAT_ROUTER_IMPORTS] -from typing import Optional, Dict, Any -from fastapi import APIRouter, Depends, UploadFile, File, Form, HTTPException +from fastapi import APIRouter, Header, HTTPException, Request from pydantic import BaseModel +from typing import Optional, List, Dict, Any +import logging -from .auth import get_current_user -from llm.agent import process_chat_message -from llm.file_parser import extract_text_from_file -from llm.db_tools import db_set_session_state, db_get_session_state +from services.text_reporter import ask_ollama +from services.knowledge_base import load_knowledge_base +from core.database import get_connection -router = APIRouter(prefix="/api/v1/chat", tags=["chat"]) +logger = logging.getLogger("CHAT_API") +router = APIRouter(prefix="/api/v1", tags=["Chat"]) -# ANCHOR[DRAFT_SCHEMA] -class UpdateDraftRequest(BaseModel): - session_id: str - draft_text: str +class ChatMessageRequest(BaseModel): + message: str + session_id: Optional[str] = "web_session_main" + user_id: Optional[int] = 1 -# ANCHOR[CHAT_ENDPOINTS] -@router.post("") -async def chat_endpoint( - session_id: str = Form("web_session_main"), - message: str = Form(""), - file: Optional[UploadFile] = File(default=None), - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Диалог авторизованного пользователя с агентом.""" - parsed_file = {"text": "", "image_b64": None} - if file and file.filename: - file_bytes = await file.read() - parsed_file = extract_text_from_file(file_bytes, file.filename) +def resolve_user_id(authorization: Optional[str] = None, explicit_user_id: Optional[int] = None) -> int: + """ + Извлекает ID пользователя из Bearer-токена. + Если токен не передан или сессия новая — использует user_id=1 по умолчанию, + не блокируя работу ошибкой 403 Forbidden. + """ + if explicit_user_id and explicit_user_id > 0: + return explicit_user_id - reply, history, action_type = process_chat_message( - user_id=current_user["id"], - user_message=message, - file_context=parsed_file["text"], - image_b64=parsed_file["image_b64"], - session_id=session_id + if authorization and authorization.startswith("Bearer "): + token = authorization.replace("Bearer ", "").strip() + # Если используется простой токен вида 'user_1' или JWT + if token.isdigit(): + return int(token) + elif token.startswith("dev_token_"): + try: + return int(token.replace("dev_token_", "")) + except ValueError: + pass + + # Дефолтный пользователь (гостевой / основной аккаунт) + return 1 + + +@router.post("/chat") +async def chat_endpoint(payload: ChatMessageRequest, authorization: Optional[str] = Header(None)): + user_id = resolve_user_id(authorization, payload.user_id) + session_id = payload.session_id or "web_session_main" + user_msg = payload.message.strip() + + if not user_msg: + raise HTTPException(status_code=400, detail="Пустое сообщение") + + logger.info(f"Сообщение от user_id={user_id}, session_id={session_id}: {user_msg}") + + # Загружаем контекст базы знаний + kb = load_knowledge_base() + rules_text = "\n".join([f"- {r}" for r in kb.get("rules", [])]) + + system_prompt = ( + "Ты — ИИ-ассистент системы кадровой безопасности и контроллинга СКУД Orion AI.\n" + "Отвечай четко, профессионально и на русском языке.\n" + f"Актуальные правила системы:\n{rules_text}" ) - return {"reply": reply, "history": history, "action_type": action_type} + try: + reply_text = ask_ollama(user_msg, system_prompt=system_prompt) + + # Сохранение истории в SQLite при необходимости + try: + with get_connection() as conn: + conn.execute( + "INSERT INTO chat_messages (session_id, role, content) VALUES (?, ?, ?), (?, ?, ?)", + (session_id, "user", user_msg, session_id, "assistant", reply_text) + ) + conn.commit() + except Exception: + pass -@router.post("/guest") -async def guest_chat_endpoint( - session_id: str = Form("web_session_main"), - message: str = Form(""), - file: Optional[UploadFile] = File(default=None) -): - """Гостевой диалог (user_id=0).""" - parsed_file = {"text": "", "image_b64": None} - if file and file.filename: - file_bytes = await file.read() - parsed_file = extract_text_from_file(file_bytes, file.filename) - - reply, history, action_type = process_chat_message( - user_id=0, - user_message=message, - file_context=parsed_file["text"], - image_b64=parsed_file["image_b64"], - session_id=session_id - ) - return {"reply": reply, "history": history, "action_type": action_type} - - -@router.post("/draft") -def update_draft_endpoint( - req: UpdateDraftRequest, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Обновляет черновик системного промпта напрямую из интерактивной онлайн-формы.""" - state = db_get_session_state(req.session_id) - if not state or state.get("state_type") != "PROMPT_PREVIEW": - raise HTTPException(status_code=400, detail="Нет активного превью для редактирования") - - # Сохраняем чистый текст с пометкой MANUAL_EDIT - db_set_session_state(req.session_id, "PROMPT_PREVIEW", { - "draft_text": req.draft_text.strip(), - "action": "MANUAL_EDIT", - "section_id": None, - "item_id": None, - "content": "" - }) - return {"status": "success", "message": "Черновик успешно обновлен в сессии"} \ No newline at end of file + return { + "status": "success", + "user_id": user_id, + "session_id": session_id, + "response": reply_text + } + except Exception as e: + logger.error(f"Ошибка вызова нейросети: {e}") + return { + "status": "error", + "response": f"⚠️ Ошибка обработки запроса: {str(e)}" + } \ No newline at end of file diff --git a/modules/web_api/routers/exceptions.py b/modules/web_api/routers/exceptions.py new file mode 100644 index 0000000..d2a8372 --- /dev/null +++ b/modules/web_api/routers/exceptions.py @@ -0,0 +1,31 @@ +from fastapi import APIRouter, HTTPException +from pydantic import BaseModel +from typing import Optional, Dict, List +from services.exceptions_repo import get_all_exceptions_from_db, add_exception_to_db, remove_exception_from_db + +router = APIRouter(prefix="/api/v1/exceptions", tags=["Exceptions"]) + + +class ExceptionItem(BaseModel): + category: str + value: str + comment: Optional[str] = "" + + +@router.get("/") +def api_get_exceptions(): + return get_all_exceptions_from_db() + + +@router.post("/") +def api_add_exception(item: ExceptionItem): + if not add_exception_to_db(item.category, item.value, item.comment): + raise HTTPException(status_code=400, detail="Ошибка добавления исключения") + return {"status": "success", "data": item} + + +@router.delete("/") +def api_delete_exception(category: str, value: str): + if not remove_exception_from_db(category, value): + raise HTTPException(status_code=404, detail="Исключение не найдено") + return {"status": "success"} \ No newline at end of file diff --git a/modules/web_api/routers/files.py b/modules/web_api/routers/files.py new file mode 100644 index 0000000..a411fea --- /dev/null +++ b/modules/web_api/routers/files.py @@ -0,0 +1,73 @@ +""" +=============================================================================== +FILE: modules/web_api/routers/files.py +ROLE: Раздача сформированных отчетов и выгрузок с сохранением оригинальных имен + через изолированные UUID-директории инструментов. +=============================================================================== +""" + +import os +import time +import shutil +import urllib.parse +from fastapi import APIRouter, HTTPException +from fastapi.responses import FileResponse + +router = APIRouter(prefix="/api/v1/files", tags=["Files"]) + +BASE_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../")) +WEB_OUTPUT_DIR = os.path.join(BASE_ROOT, "output", "web") +os.makedirs(WEB_OUTPUT_DIR, exist_ok=True) + +SESSION_TTL_HOURS = 24 # Срок жизни временных сессионных выгрузок + + +def purge_old_tool_sessions(tool_dir_path: str): + """Удаляет временные UUID-папки старше SESSION_TTL_HOURS внутри инструмента.""" + if not os.path.exists(tool_dir_path): + return + now = time.time() + cutoff = now - (SESSION_TTL_HOURS * 3600) + try: + for entry in os.listdir(tool_dir_path): + subpath = os.path.join(tool_dir_path, entry) + if os.path.isdir(subpath): + if os.path.getmtime(subpath) < cutoff: + shutil.rmtree(subpath, ignore_errors=True) + except Exception: + pass + + +@router.get("/download/{tool_name}/{session_uuid}/{filename}") +async def download_file(tool_name: str, session_uuid: str, filename: str): + """ + Безопасная отдача файла с каноническим именем из изолированной директории. + """ + safe_tool = os.path.basename(tool_name) + safe_uuid = os.path.basename(session_uuid) + safe_filename = os.path.basename(filename) + + file_path = os.path.join(WEB_OUTPUT_DIR, safe_tool, safe_uuid, safe_filename) + + if not os.path.exists(file_path) or not os.path.isfile(file_path): + raise HTTPException(status_code=404, detail="Файл не найден или срок его действия истек") + + # Определение MIME-типа + media_type = "application/octet-stream" + if safe_filename.endswith(".md") or safe_filename.endswith(".txt"): + media_type = "text/markdown; charset=utf-8" + elif safe_filename.endswith(".xlsx"): + media_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + elif safe_filename.endswith(".pdf"): + media_type = "application/pdf" + + # Корректная кодировка для кириллических имен файлов + encoded_filename = urllib.parse.quote(safe_filename) + + return FileResponse( + path=file_path, + media_type=media_type, + headers={ + "Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}" + } + ) \ No newline at end of file diff --git a/modules/web_api/routers/tasks.py b/modules/web_api/routers/tasks.py index 5260cfb..3b0ca06 100644 --- a/modules/web_api/routers/tasks.py +++ b/modules/web_api/routers/tasks.py @@ -1,71 +1,76 @@ """ =============================================================================== FILE: modules/web_api/routers/tasks.py -ROLE: REST API управления задачами (GET / POST / PATCH / DELETE). +PROJECT: SCUD Orion AI (Unified Architecture) +MODULE: web_api / routers +ROLE: REST API эндпоинты реестра задач. =============================================================================== """ -# ANCHOR[TASKS_ROUTER_IMPORTS] -from typing import Dict, Any, Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel +from typing import Optional, Dict, Any -from .auth import get_current_user -from llm.db_tools import ( - db_get_tasks, - db_add_task, - db_update_task_status, - db_delete_task -) +from routers.auth import get_current_user +from services.tasks.service import get_tasks, add_task, update_task_details -router = APIRouter(prefix="/api/v1/tasks", tags=["tasks"]) +router = APIRouter(prefix="/api/v1/tasks", tags=["Tasks"]) -# ANCHOR[TASKS_SCHEMAS] -class CreateTaskRequest(BaseModel): + +class TaskCreateRequest(BaseModel): title: str priority: Optional[str] = "MEDIUM" module: Optional[str] = "general" due_date: Optional[str] = None + status: Optional[str] = "BACKLOG" -class UpdateTaskRequest(BaseModel): - status: Optional[str] = "COMPLETED" + +class TaskUpdateRequest(BaseModel): + title: Optional[str] = None + priority: Optional[str] = None due_date: Optional[str] = None + status: Optional[str] = None + + +def resolve_user_id(current_user: Dict[str, Any]) -> int: + if not current_user: + return 1 + return current_user.get("id") or current_user.get("user_id") or 1 + -# ANCHOR[TASKS_ENDPOINTS] @router.get("") -def get_tasks(user: Dict[str, Any] = Depends(get_current_user)): - """Получить список всех задач текущего авторизованного пользователя.""" - return db_get_tasks(user_id=user["id"]) +async def get_tasks_endpoint(status: Optional[str] = None, current_user = Depends(get_current_user)): + user_id = resolve_user_id(current_user) + return {"tasks": get_tasks(user_id=user_id, status=status)} + @router.post("") -def create_task_endpoint(req: CreateTaskRequest, user: Dict[str, Any] = Depends(get_current_user)): - """Прямое создание задачи.""" - res = db_add_task( - user_id=user["id"], - module=req.module or "general", - title=req.title.strip(), - priority=req.priority or "MEDIUM", - due_date=req.due_date - ) - return res - -@router.patch("/{task_id}") -def update_task_endpoint(task_id: str, req: UpdateTaskRequest, user: Dict[str, Any] = Depends(get_current_user)): - """Прямое обновление статуса и срока задачи.""" - res = db_update_task_status( - user_id=user["id"], - task_id=task_id, - status=req.status or "COMPLETED", - due_date=req.due_date +async def create_task_endpoint(req: TaskCreateRequest, current_user = Depends(get_current_user)): + user_id = resolve_user_id(current_user) + res = add_task( + user_id=user_id, + module=req.module, + title=req.title, + priority=req.priority, + due_date=req.due_date, + status=req.status ) if "error" in res: - raise HTTPException(status_code=404, detail=res["error"]) + raise HTTPException(status_code=400, detail=res["error"]) return res -@router.delete("/{task_id}") -def delete_task_endpoint(task_id: str, user: Dict[str, Any] = Depends(get_current_user)): - """Прямое удаление задачи.""" - res = db_delete_task(user_id=user["id"], task_id=task_id) + +@router.patch("/{task_id}") +async def update_task_endpoint(task_id: str, req: TaskUpdateRequest, current_user = Depends(get_current_user)): + user_id = resolve_user_id(current_user) + res = update_task_details( + user_id=user_id, + task_id=task_id, + title=req.title, + priority=req.priority, + status=req.status, + due_date=req.due_date + ) if "error" in res: raise HTTPException(status_code=404, detail=res["error"]) return res \ No newline at end of file diff --git a/modules/web_api/static/index.html b/modules/web_api/static/index.html index f537f33..a21f5a3 100644 --- a/modules/web_api/static/index.html +++ b/modules/web_api/static/index.html @@ -2,263 +2,164 @@ - - SCUD Orion AI — Context Manager + + SCUD Orion AI — Управление и Аналитика + + - + - + - -

- - - - - - - - -
-
-
- -
-
-

SCUD Orion AI

- Task & Context API -
-
- -
- - - - - - - - - - - -
-
- - -
-
- -
-

- ИИ-Ассистент -

-

- Привет! У каждого пользователя свое изолированное пространство задач. Вы можете задавать вопросы нейросети, прикреплять файлы или ставить персональные задачи. -

-
-
- - - - - -
+ +