From 24a8886e61d3904cb259c2525f8e36a5ffb75197 Mon Sep 17 00:00:00 2001 From: manoraga Date: Fri, 7 Aug 2026 17:05:28 +0300 Subject: [PATCH] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B5=D0=B3=D0=BE=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=20=D0=B0=D0=B2=D0=B0=D1=80=D0=B8=D0=B8,=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20=D0=B7=D0=B0=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=87=D0=B8=D0=B9=20=D0=B4=D0=B5=D0=BD=D1=8C=2007.?= =?UTF-8?q?08.2026?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/__init__.py | 1 - app/core/__init__.py | 1 - app/core/ollama_client.py | 32 --- app/db/__init__.py | 1 - app/db/database.py | 152 ----------- app/orchestrator.py | 101 -------- app/tools/__init__.py | 1 - app/tools/definitions.py | 111 -------- app/tools/handlers.py | 101 -------- core/database.py | 53 +++- data/scud_orion_ai.db | Bin 2560000 -> 2560000 bytes frontend/__init__.py | 0 frontend/index.html | 342 ------------------------- init_db.py | 78 ------ llm_agent.py | 474 ---------------------------------- main.py | 35 +++ migrate_structure.py | 60 ----- ref.py | 525 -------------------------------------- scripts/migrate_db.py | 47 ---- services/ai_verifier.py | 58 +++++ services/feedback_loop.py | 17 +- services/scud_export.py | 6 +- update_imports.py | 41 --- 23 files changed, 154 insertions(+), 2083 deletions(-) delete mode 100644 app/__init__.py delete mode 100644 app/core/__init__.py delete mode 100644 app/core/ollama_client.py delete mode 100644 app/db/__init__.py delete mode 100644 app/db/database.py delete mode 100644 app/orchestrator.py delete mode 100644 app/tools/__init__.py delete mode 100644 app/tools/definitions.py delete mode 100644 app/tools/handlers.py delete mode 100644 frontend/__init__.py delete mode 100644 frontend/index.html delete mode 100644 init_db.py delete mode 100644 llm_agent.py delete mode 100644 migrate_structure.py delete mode 100644 ref.py delete mode 100644 scripts/migrate_db.py delete mode 100644 update_imports.py diff --git a/app/__init__.py b/app/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/app/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/core/__init__.py b/app/core/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/app/core/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/core/ollama_client.py b/app/core/ollama_client.py deleted file mode 100644 index 24465e0..0000000 --- a/app/core/ollama_client.py +++ /dev/null @@ -1,32 +0,0 @@ -import json -import urllib.request -import urllib.error - -OLLAMA_URL = "http://192.168.11.3:11434/api/chat" -MODEL_NAME = "qwen2.5:14b" - -def send_ollama_request(messages: list, tools: list) -> dict: - """Отправляет HTTP-запрос к локальной модели Ollama.""" - payload = { - "model": MODEL_NAME, - "messages": messages, - "tools": tools, - "stream": False, - "options": { - "num_predict": 2048, - "num_ctx": 8192, - "temperature": 0.1 - } - } - - req = urllib.request.Request( - OLLAMA_URL, - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"} - ) - - try: - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode("utf-8")) - except urllib.error.URLError as e: - raise ConnectionError(f"Ошибка связи с Ollama ({OLLAMA_URL}): {e}") diff --git a/app/db/__init__.py b/app/db/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/app/db/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/db/database.py b/app/db/database.py deleted file mode 100644 index 0b349de..0000000 --- a/app/db/database.py +++ /dev/null @@ -1,152 +0,0 @@ -import sqlite3 - -DB_NAME = "/home/puh/scud_orion_ai_v2/data/scud_orion_ai.db" - -def get_connection(): - return sqlite3.connect(DB_NAME) - -def db_get_active_system_prompt() -> str: - """Извлекает активный системный промпт из базы данных SQLite.""" - try: - conn = get_connection() - cursor = conn.cursor() - cursor.execute("SELECT prompt_text FROM system_prompts WHERE name = 'main_agent' AND is_active = 1 LIMIT 1") - row = cursor.fetchone() - conn.close() - if row and row[0]: - return row[0].replace("**", "") - except Exception as e: - print(f"Ошибка чтения системного промпта из БД: {e}") - - return "Ты — интеллектуальный ИИ-ассистент и архитектурный координатор проекта SCUD Orion AI." - -def db_add_system_prompt(name: str = "main_agent", prompt_text: str = "") -> dict: - """Обновляет или добавляет активный системный промпт в БД.""" - clean_text = prompt_text.replace("**", "") - conn = get_connection() - cursor = conn.cursor() - cursor.execute(""" - INSERT INTO system_prompts (name, prompt_text, is_active) - VALUES (?, ?, 1) - ON CONFLICT(name) DO UPDATE SET prompt_text=excluded.prompt_text, updated_at=CURRENT_TIMESTAMP - """, (name, clean_text)) - conn.commit() - conn.close() - return {"status": "success", "message": f"Системный промпт '{name}' успешно обновлен в базе!"} - -def db_get_rules() -> list: - """Извлекает правила из таблицы ai_knowledge_base.""" - conn = get_connection() - conn.row_factory = sqlite3.Row - cursor = conn.cursor() - cursor.execute("SELECT id, rule_text, added_by FROM ai_knowledge_base ORDER BY id") - rows = [dict(r) for r in cursor.fetchall()] - conn.close() - return rows - -def db_add_rule(rule_text: str, added_by: str = "Operator") -> dict: - """Добавляет новое правило или инструкцию в таблицу ai_knowledge_base.""" - clean_text = rule_text.replace("**", "") - conn = get_connection() - cursor = conn.cursor() - cursor.execute( - "INSERT INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", - (clean_text, added_by) - ) - rule_id = cursor.lastrowid - conn.commit() - conn.close() - return {"status": "success", "message": f"Правило #{rule_id} успешно добавлено в базу знаний!", "rule_id": rule_id} - -def db_get_tasks(status: str = None) -> list: - """Извлекает список задач из реестра БД.""" - conn = get_connection() - conn.row_factory = sqlite3.Row - cursor = conn.cursor() - if status: - cursor.execute("SELECT * FROM tasks WHERE status = ? ORDER BY task_id", (status.upper(),)) - else: - cursor.execute("SELECT * FROM tasks ORDER BY task_id") - rows = [dict(r) for r in cursor.fetchall()] - conn.close() - return rows - -def db_update_task_status(task_id: str, status: str = None, due_date: str = None) -> dict: - """Обновляет статус и/или срок выполнения задачи.""" - conn = get_connection() - cursor = conn.cursor() - updates = [] - params = [] - - if status: - status_upper = status.upper() - updates.append("status = ?") - params.append(status_upper) - if status_upper == "COMPLETED": - updates.append("completed_at = CURRENT_TIMESTAMP") - else: - updates.append("completed_at = NULL") - - if due_date: - updates.append("due_date = ?") - params.append(due_date) - - if not updates: - conn.close() - return {"error": "Не указаны параметры для обновления"} - - params.append(task_id.upper()) - query = f"UPDATE tasks SET {', '.join(updates)} WHERE task_id = ?" - cursor.execute(query, tuple(params)) - - if cursor.rowcount == 0: - conn.close() - return {"error": f"Задача {task_id} не найдена"} - - conn.commit() - conn.close() - return {"status": "success", "message": f"Задача {task_id} обновлена"} - -def db_delete_task(task_id: str) -> dict: - """Удаляет задачу из базы данных по её task_id.""" - conn = get_connection() - cursor = conn.cursor() - cursor.execute("DELETE FROM tasks WHERE task_id = ?", (task_id.upper(),)) - deleted_count = cursor.rowcount - conn.commit() - conn.close() - - if deleted_count == 0: - return {"error": f"Задача {task_id} не найдена"} - return {"status": "success", "message": f"Задача {task_id} удалена"} - -def db_add_task(module: str = "general", title: str = "", priority: str = "MEDIUM", due_date: str = None, task_id: str = None) -> dict: - """Добавляет новую задачу в реестр с авто-генерацией TASK-ID.""" - conn = get_connection() - cursor = conn.cursor() - - if not task_id: - cursor.execute("SELECT task_id FROM tasks WHERE task_id LIKE 'TASK-%'") - rows = cursor.fetchall() - max_num = 0 - for r in rows: - try: - num = int(r[0].replace("TASK-", "")) - if num > max_num: - max_num = num - except ValueError: - pass - task_id = f"TASK-{max_num + 1:02d}" - - try: - cursor.execute( - "INSERT INTO tasks (task_id, module, title, status, priority, due_date) VALUES (?, ?, ?, 'BACKLOG', ?, ?)", - (task_id.upper(), module, title, priority.upper(), due_date) - ) - conn.commit() - res = {"status": "success", "message": f"Задача {task_id} создана", "task_id": task_id} - except sqlite3.IntegrityError: - res = {"error": f"Задача с ID {task_id} уже существует"} - finally: - conn.close() - return res diff --git a/app/orchestrator.py b/app/orchestrator.py deleted file mode 100644 index dcf4396..0000000 --- a/app/orchestrator.py +++ /dev/null @@ -1,101 +0,0 @@ -import json -from typing import List, Dict, Any, Tuple -from datetime import datetime - -from app.db import database -from app.tools.definitions import TOOLS_SCHEMA -from app.tools.handlers import handle_tool_call, get_system_capabilities_text -from app.core.ollama_client import send_ollama_request - -def process_chat_message(user_message: str, chat_history: List[Dict[str, Any]] = None) -> Tuple[str, List[Dict[str, Any]]]: - if chat_history is None: - chat_history = [] - - current_now = datetime.now().strftime("%Y-%m-%d %H:%M") - user_clean = user_message.replace("\xa0", " ").strip() - user_lower = user_clean.lower() - - # 1. Жесткий перехват: Помощь и варианты команд (чистый Plain Text без Markdown) - if any(phrase in user_lower for phrase in ["помощь", "возможности", "что ты умеешь", "помощь в общении", "варианты команд"]): - formatted_text = get_system_capabilities_text() - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 2. Жесткий перехват: Системный промпт из БД - if any(phrase in user_lower for phrase in ["системный промпт", "покажи промпт", "промпт системы", "промпт из базы"]): - prompt_text = database.db_get_active_system_prompt() - formatted_text = f"⚙️ Актуальный системный промпт ИИ (из базы SQLite):\n\n{prompt_text}" - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 3. Жесткий перехват: База знаний из БД - if any(phrase in user_lower for phrase in ["базу знаний", "база знаний", "покажи правила", "инструкции ии"]): - rules = database.db_get_rules() - if not rules: - formatted_text = "База знаний пуста." - else: - formatted_text = "🧠 База знаний ИИ (ai_knowledge_base):\n\n" - for r in rules: - formatted_text += f"{r.get('id')}. {r.get('rule_text')}\n\n" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # Динамическая подгрузка системного промпта из БД SQLite - dynamic_prompt_text = database.db_get_active_system_prompt() - system_prompt = { - "role": "system", - "content": f"Текущая дата и время сервера: {current_now}.\n\n{dynamic_prompt_text}" - } - - messages = [system_prompt] + chat_history + [{"role": "user", "content": user_message}] - - try: - res_data = send_ollama_request(messages=messages, tools=TOOLS_SCHEMA) - msg = res_data.get("message", {}) - - tool_calls = msg.get("tool_calls", []) - content_str = msg.get("content", "").strip().replace("**", "").replace("```", "").replace("###", "") - - # Перехват текстового JSON с именем функции - if not tool_calls and "name" in content_str and "db_" in content_str: - try: - start_idx = content_str.find("{") - end_idx = content_str.rfind("}") + 1 - if start_idx != -1 and end_idx != -1: - parsed = json.loads(content_str[start_idx:end_idx]) - if "name" in parsed: - tool_calls = [{"function": parsed}] - except Exception: - pass - - if tool_calls: - for tool in tool_calls: - fn_name = tool["function"]["name"] - fn_args = tool["function"].get("arguments", {}) - - formatted_text = handle_tool_call(fn_name, fn_args) - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": content_str} - ] - return content_str, updated_history - - except Exception as e: - return f"Ошибка обработки запроса: {e}", chat_history \ No newline at end of file diff --git a/app/tools/__init__.py b/app/tools/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/app/tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/tools/definitions.py b/app/tools/definitions.py deleted file mode 100644 index 34f4a8d..0000000 --- a/app/tools/definitions.py +++ /dev/null @@ -1,111 +0,0 @@ -TOOLS_SCHEMA = [ - { - "type": "function", - "function": { - "name": "db_get_tasks", - "description": "ПОЛУЧИТЬ СПИСОК ЗАДАЧ ПРОЕКТА. Вызывай ТОЛЬКО когда пользователь просит показать задачи, бэклог или список дел.", - "parameters": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "Фильтр статуса: BACKLOG, IN_PROGRESS или COMPLETED." - } - } - } - } - }, - { - "type": "function", - "function": { - "name": "db_get_rules", - "description": "ПОЛУЧИТЬ БАЗУ ЗНАНИЙ ИИ И ПРАВИЛА АРБИТРАЖА (ai_knowledge_base). Вызывай когда пользователь просит показать базу знаний, правила, инструкции или промпты.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_add_rule", - "description": "Добавить новое правило, инструкцию или факт в базу знаний (ai_knowledge_base). Вызывай при командах 'добавь в базу знаний', 'запомни правило', 'запиши инструкцию'.", - "parameters": { - "type": "object", - "properties": { - "rule_text": {"type": "string", "description": "Текст правила, инструкции или факта для сохранения"}, - "added_by": {"type": "string", "description": "Автор или источник правила, по умолчанию Operator"} - }, - "required": ["rule_text"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_get_system_prompt", - "description": "ПОЛУЧИТЬ ТЕКУЩИЙ СИСТЕМНЫЙ ПРОМПТ ИИ (system_prompts). Вызывай когда пользователь просит показать системный промпт, инструкции ассистента или промпт из базы.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_add_system_prompt", - "description": "Обновить или добавить системный промпт ИИ в базу данных. Вызывай при командах 'задай системный промпт', 'измени промпт', 'обнови системный промпт'.", - "parameters": { - "type": "object", - "properties": { - "prompt_text": {"type": "string", "description": "Полный новый текст системного промпта"}, - "name": {"type": "string", "description": "Имя промпта, по умолчанию main_agent"} - }, - "required": ["prompt_text"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_update_task_status", - "description": "Изменить статус и/или срок выполнения задачи в реестре.", - "parameters": { - "type": "object", - "properties": { - "task_id": {"type": "string", "description": "Идентификатор задачи, например TASK-17"}, - "status": {"type": "string", "description": "Новый статус: COMPLETED, IN_PROGRESS или BACKLOG"}, - "due_date": {"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"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_add_task", - "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"] - } - } - } -] diff --git a/app/tools/handlers.py b/app/tools/handlers.py deleted file mode 100644 index 259043a..0000000 --- a/app/tools/handlers.py +++ /dev/null @@ -1,101 +0,0 @@ -from app.db import database - -def get_system_capabilities_text() -> str: - """Формирует список возможностей и примеров команд для текущей стадии проекта.""" - return ( - "🛠 Доступные команды и возможности системы SCUD Orion AI:\n\n" - "1. Управление задачами (Бэклог):\n" - " • «Покажи последние задачи» — вывод списка задач проекта.\n" - " • «Добавь задачу: Настроить интеграцию 1С с REST API» — создание новой задачи.\n" - " • «Измени статус задачи TASK-01 на COMPLETED» — обновление состояния.\n" - " • «Удали задачу TASK-02» — удаление задачи из реестра.\n\n" - "2. База знаний и правила (ai_knowledge_base):\n" - " • «Покажи базу знаний» (или «покажи правила») — вывод текущих правил проекта.\n" - " • «Добавь в базу знаний: Офисные сотрудники отдела разработки работают по гибкому графику с 09:00 до 11:00» — запись нового правила.\n\n" - "3. Системные промпты (system_prompts):\n" - " • «Покажи системный промпт» — просмотр активных инструкций ИИ.\n" - " • «Обнови системный промпт: Ты — ассистент SCUD Orion AI. Отвечай кратко и строго в формате Plain Text.» — смена роли ИИ на лету.\n\n" - "Вы можете написать любой из этих запросов в чат в свободной форме." - ) - -def handle_tool_call(fn_name: str, fn_args: dict) -> str: - """Диспетчеризация вызова функций и форматирование текстового ответа.""" - - if fn_name == "db_get_tasks": - tasks = database.db_get_tasks(status=fn_args.get("status")) - if not tasks: - return "Список задач пуст." - tasks_sorted = sorted(tasks, key=lambda x: x.get('task_id', ''), reverse=True) - formatted_text = "📋 Последние задачи проекта:\n\n" - for t in tasks_sorted: - due = f" (до {t['due_date']})" if t.get('due_date') else "" - priority = t.get('priority') or 'MEDIUM' - status_str = t.get('status') or 'BACKLOG' - module_str = t.get('module') or 'general' - formatted_text += f"{t.get('task_id')} — {t.get('title')} [{status_str}]\n" - formatted_text += f" • Приоритет: {priority} | Модуль: {module_str}{due}\n\n" - return formatted_text - - elif fn_name == "db_get_rules": - rules = database.db_get_rules() - if not rules: - return "База знаний пуста." - formatted_text = "🧠 База знаний ИИ (ai_knowledge_base):\n\n" - for r in rules: - formatted_text += f"{r.get('id')}. {r.get('rule_text')}\n\n" - return formatted_text - - elif fn_name == "db_add_rule": - res = database.db_add_rule( - rule_text=fn_args.get("rule_text", ""), - added_by=fn_args.get("added_by", "Operator") - ) - return res.get("message", "Правило добавлено в базу знаний.") - - elif fn_name == "db_get_system_prompt": - prompt_text = database.db_get_active_system_prompt() - return f"⚙️ Актуальный системный промпт ИИ (из базы SQLite):\n\n{prompt_text}" - - elif fn_name == "db_add_system_prompt": - res = database.db_add_system_prompt( - name=fn_args.get("name", "main_agent"), - prompt_text=fn_args.get("prompt_text", "") - ) - return res.get("message", "Промпт обновлен.") - - elif fn_name == "db_add_task": - res = database.db_add_task( - module=fn_args.get("module", "general"), - title=fn_args.get("title"), - priority=fn_args.get("priority", "MEDIUM"), - due_date=fn_args.get("due_date") - ) - if "error" in res: - return f"Ошибка добавления задачи: {res['error']}" - assigned_id = res.get("task_id", "TASK") - due_str = fn_args.get('due_date') or 'Без срока' - return ( - f"Задача {assigned_id} успешно создана!\n\n" - f"• Название: {fn_args.get('title')}\n" - f"• Приоритет: {fn_args.get('priority', 'MEDIUM')}\n" - f"• Срок: {due_str}\n" - f"• Модуль: {fn_args.get('module', 'general')}" - ) - - elif fn_name == "db_update_task_status": - res = database.db_update_task_status( - task_id=fn_args.get("task_id"), - status=fn_args.get("status"), - due_date=fn_args.get("due_date") - ) - if "error" in res: - return f"Ошибка обновления задачи: {res['error']}" - return f"Статус задачи {fn_args.get('task_id')} успешно обновлен!" - - elif fn_name == "db_delete_task": - res = database.db_delete_task(task_id=fn_args.get("task_id")) - if "error" in res: - return f"Ошибка удаления задачи: {res['error']}" - return f"Задача {fn_args.get('task_id')} успешно удалена из базы!" - - return f"Функция {fn_name} выполнена." \ No newline at end of file diff --git a/core/database.py b/core/database.py index 2edc040..a57063e 100644 --- a/core/database.py +++ b/core/database.py @@ -98,7 +98,6 @@ def init_db(): sync_knowledge_base_to_db() - def has_scud_logs_for_date(date_str): """Проверяет, есть ли в базе данные СКУД за указанную дату.""" with get_connection() as conn: @@ -106,6 +105,16 @@ def has_scud_logs_for_date(date_str): 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): """ @@ -393,4 +402,44 @@ def delete_snapshots_by_date(date_str: str): deleted_count = cursor.rowcount conn.commit() print(f"[✓] Удалены все снапшоты за дату [{date_str}]. Удалено строк: {deleted_count}") - return deleted_count \ No newline at end of file + 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}'") diff --git a/data/scud_orion_ai.db b/data/scud_orion_ai.db index 90f2085d5b215e5ecd18aee763e116f126e1900c..8c3871cef55b4e2359983364b9b9be7ae09210a8 100644 GIT binary patch delta 261290 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

W3iTjUXS|(wVc9*s`Tdvr;&<3W^}8wqD$5VJ zvyY&>Kf^n)sl8EFxYafs%)h*E2*K^>aAr8Q9N33Tq}xC@$WsS^Q7(fL;Eqe34tCeT zS2N%-^;2@VQ_>(K*l#81a~zllo>~e81Ef3M5=p^e;rkdYGmdT+8-OQ@?tMYF9I%X+ z(B)%qjeRfLJtkg-*hnk*4lJ{ngZu1YPdv4luo}=VxNlHj4HyZZS_FlOjf8`o&355b z4zU;x?l^Wh)=H2X`Fgg>K-JeEu>k#?*)|!CTgp#wQFw#JzIyc8($ZP&dtt_ zL0Q#+AO+>L!U_V!Kx!%mdSh#=Ek@c1RVs8~GMHLyT*;pjwJ{)TkY5RHge#cSq82G9 zqAqX6q@k$at$wWwBwrQmLKTfSK*eouuWpSuM~F}*$Dov7iddAA6|(el$3Gf25A6?A z`)R-f%09tkfT5RRkOUHQ9c_)R2#qqz{n{0%UeLf*$&hh9|8C1Hf)`9ay0xAco7GE; z*`AUazvf;t%+&MRbDAdg`>L_ZMEO;=hItA^3JV#N&{t@j0lb679f!@*Uc1v8hSrAY zAjZ^t39}P>-~cPw<__*2IC6`~iO^S+Va3v#`(gU!<&AfjwWYW9Eg}p7!59&ScyEJ# zC76w?~CqZ@>3s}she+GVlCles4dwOWo&qi8EMPD5GK zquZeW^|hYD4D|p}7H(3{+cIRx6&kUiBRhMNz@WOppJx?v=5lQRb{rE!vW5Sd|Eem7d918it*6 zai@6SNPKy-f~R>SwvH#(6qL6gu_Yu3MSJvy+$r8Jf_`rs1_+J!(zlsOq)Q7!V0<$} ztzU_Iv|t684>nGOtkb9Wb^!Qe=Yor!8QL;Iuae=4+* za4vRPqQp5GCSjup&<0Q&lgb;<#u*roG0Ox;!@W?_ym?EOq*aQ$?4CwA#yJ}9Av`V^ zMQl=@k9*tGfOU?B4B!oHMEj3NwPxE~ba7tjYQmGpHe|7*A)PkBP8tyVs5}Q9O;ngr z+9BKh-W}G-(J&5o7z7k@j3dSd}Qcppr&iG506 z$8gMH-BEKS-Y9FmTQS1XFoulTRAS2mc@BFFV8%EaMgtMzHxd3!b#Vtt6FfQQIvPen zj=Ve=D5zq|adVTWeWM)>BY}aetiH5EGmx^<%dAI`I~wi=Itb&bp;6p+9@JZ!z%UPkX=i2Wb93EjFzS zKE6GAVVtp5=LKA0wx|FPK77j-%oss@Hi3Q@aT@5rg$;IR!D=~uI<*S~cH!{r#CZ?k zxa#k)v=|QD8l7&wEC*m-kTF>wjUv-cN6_x0`b3mopl?^%CBw83ZX`Q$UpGqyD4rsE*IvOo8m&_ z^5BHJNs@3}<$iE(?sxp)+}spDI5#(iz`5mn$ss*_`{B8{U-E-FqPi(pBq`rYQofO-eC?*Va6;V`U3Qb4IH7LJSCW)3B`IG>Qa+~? zFPu0?RCea`OJlR!{0bF5xH{P-{k}rKINjWV^IVDM{@lbp=-m(uo zBnr^&o(u0wQcg-zswF8WoD~0!x9mO1m#QQw$0aGpBq>KRCE&(e_O9eh??_VKmZTh! zq`W1$@s_PEe9sJH z1Eo!U3K4QhDs4b9ELJYKReczPDu60m2p8&!4ROmVo3NnuqY9xu3HbHa(s=ZvQtC{Z zP>)S|Zljn1eWpmp*0Sn%olxHm%9PZ};BE`7`jyt=)^`n{hH2+%pOnecDxn_R`Cy

i@QOAI z6)cV=(HJ4{Giv`h;L^GKLTVzx>}yB*!l{TGJ&WH>0S|6Gs1iqq4us#v5xBwV&|5a@nUP)*GVmSDX)D`PC;Lk_Kz355AHry~ zziCfvU(_zs4%LQhzSF#;*{YeX>1~M8=$IkO?Yh|_rm{swn(jP8(#n&i z+H(wBazD*g#L;x;TO_S~Zl888qtJ)RVz&+^fr2PIY}rRNU)gz55nGZ)N>h~X)K{YG zo#kC=%$}dhwLREX1Xm=ZmzY*h(m#Of|!HJKk95_z=+7(%Ecva{Jh|q zvE#-L4REdZnq|Gfm!x?ft%&NPp`r-n3KiCg=~4KmI{Z#hI{fo0KylhUH&7rkP@D(H zEX4V3o&(I1$bR@sBh0>-&2A(?wle`#6xKwrAnOfw%7I``lUvs*LLZ^|0it`bgYLmA z=quJm5tY|6bCvml#b5}Id{CRnJd z`uWWGg(&Tkb#l*OX9Va^o3qeUbL{T~+l?xrIg?B!YD?>~ZaJ2!dx7oI2fcekWy90{ zpLZjutea<`t@G^P4Ggk-SfLrKQlbB;T?-oOoE;LdDj5*m{LH@Z$49Am2}b0LDgVfTBf5;zgF<>2_gE?qRisiXe=! z_Vo4z0(>ntJtJURIMO;4=o2A6#2aYGQ=pVbXsA%ViYRX^Ed_=5c$eaXOrX||5vo^0 zS#Ycl6bBv-z!F}S65g8Nja$8f^q$yQRUG>LHr|?4o7ofGhs8L`j8L8H0|)A9oYYIu zQ4a?_m+1wkJ1fHp{e&i$3B*K{ zHzCx9(#MAazR#7&li1A(+zyhG!O8?L*C|QZ2f=?8rG8@A%0b(7FN|z%?xb8)ba$u~ zjT;~Oqu3S#dy{F02~F4W!z3`@IQw2iBU(H$G|E4}qO;I60Uezf`jfIJ@h)Es|~6;RiSFCDpvWGa-XsXQ()?<_)GDg;z`9l3cLKG{AKwfxw$9%7hA<yKGS! zO?O@;Y2{yKJj1F=Kh!@Y0|b8jX1NC4dX?|XmTaME@f?~K4WjAJA4rP+ewANEpFAB; zpY+ffZ(`1TYkFTKoV_iw4qk=l3M7jC_HQVaPwxpHK5It4dFqB4xed zSd&WGDcMBRVu+xD*((}A)1BXuv~tfjo@Lo`H4P+OS_8NB5OjSfKa4Hc(WaMdq-pW& zy-RH7!Zh$oS|BrNxm%nLLgyN_^_t7-Z&Y>4lZqnwc6J++BU=E~57l9_{e@&Qc_cYO zn(M|1rxp;gPJi<4CHDw$MkQwvde(FbKYD;Q>nVKyr8}O4jHh60sA8l@CKp^CU?GmL zzOJYQNG$!?cBTzCIB4GjXzyII{(vt$aUsFNASHZjDJk^U2*Nw>uZ}KBt?m|ZU6|u> znI9Njd%-Ro-)g~&&WQ=T{Q>?}%o{j?WDKy{z=h8Lgx6|M1@J&WmF?{f6D%hnNi(t=zw>PC%U&X!!dGH2)25;zO%DGQ4xa*8BS$RZcfv0I&qoeW z22ah9#2W~*qn8P%@C6xz4^TI)#r!4=$djCcm`JM)6^xAM#s@nEuyoES`%Gs1kgG5p z0*|I_?F7v*^$67%WsD+Ju4eVJXXDIog$Nyl^MjqAQCCv^fi)&Ox^_7VfYUxUPDE9w zLc_;^wAXuOa&FYEmB6eN&Zm))aC)Oc4cpMII;{$@ZwD`AumC`WeH&cypd>nv{WxLa z6Tu`MyBWO<;~;inlbj0z$Qc40H(J>W@H#t>JwII#%jo@erkC*T87?8o6j>_5n!xo7 zR^|hsisuKw0C<5aUI%Aa*{TH*wDxB}_bOR7y?=CfR zHg-M>YZom{AQ9@+pE1Wp+M1+Wig9x*E7;I0K4Hmr4nixRX| zga+U)S4u6KCe*tQZZ!7EqOa}0wx~e_S$RFyNWeK&0`9gnx=Izi9 zK))@zMYmWez+lwl)0qUo0oHDdHg|V_N$G3#Lj7z+!ry%INO(5N?-4asG=5V3++V1l zh2>3P`cE-&`JKAA(2@u?MfAFa#?~=SsHbNvfT+jAA9B^c0Ui9BQ^h2KMgjwS14s=F ze&EJPl?uv#e5zWyG;Rpl(V^5fXu#>vnP~mk_;ze+D$2jaU?*wOlGAdh=Lq#w$pH9@ znA`3l{4;IgHINH{6av_VIolK1l_*xqQ-6t2KLgl>^ADMHF41Dh74C6>IZVz8#jFO0 zEC4P?_4G_7UUaV|hk|nL7rBB-qL2~d8-jb9V3}F~+mXT~{#CZ>E_5J?KP|F34`fXb zez8?UaM+9p^lgWj*L=Mm1HA(F@KtxB{V6^$Wr4E7l3z6#@5(JR0*BSAG<;Y+-y+XA z>mZyp65ah*LMHm4oez?DK!?Z}p$eajR=MTMn@O=Y1Y9t6%1DxAP6kVg> zy*7o9#BFUomS4C~bq9*>%YWCZmi4DCyE4R*iQfHI9>DHDVDkWLt{*fnC&$TVW`7^V zxj-HVLRX=xFB~jD#7VHS7vJIIw;AxIWT6V5Mpmz;Fa18uvIwOOFb^dwN~>njP@$@K z{W1<;}fCsqJ0YRw$1MSVADh=3Zp zQ~4`V6|fX1A*NltEluQ?7aV7TU8u>%O4RRzyCQ<_sRj!Qpzj0dP?rt{X?1BvC>LaN z4MGi8jQbt1eH5qQ1?heM4YI{bp=PF7aXL9jnVVLq$-)Yek@2KkxHn^gbyk! z%ii?#zX!T)iLaf>&8j&lNyjPB(O1;%S#Z0< zh$O>d6Biwug8Dcd3xpcHolTj7jy(zXVPlV*ii4a%&=FWm?z$wSZdIl|1ogK!ijA_^ z(f-e)j6rt5dZC6!(Gqun@oUX|l)2E*NrAEG2!JozzdqIo)(}C?oi;+vRP^_c5MuHE z6Q)zaAtdZIhnt^?R7JgSvlVJA=;0`RN2BNi(bT?Wu)wvt6`($*1rIXgR!UX`G58^FlKt0~52 z=DXU73ViD(60YHJ9scJ6G;An_;oMw7F`!Q%h*ELGlfmwJ9p*b8X)BVjmrGqy1s2SN_-Yiy9kYlY^v z_`nEvEil2r7m!!ihV8$f%H&gf#DFR8 zSoruw`(bd607um31SlTXVLAX8^1`+f7*9E<6wt97D$7J@#J@0yf=?&j`F)1qPI6tR z(hnQn$cHN*RujYB27(lUJ+Jq@GPs6N>(4nd<5eSLIHRxAeWX1J=(q2vUQ<4+cwYV( zn*(7C=D194ohj%zQ*59NtHIC`FinVH-o;?ZB10iaC{mJ9Ru?Ou;VnH1Zr_0QyawY< zxU>qc3etXznh#dhhE8lsPht}`7P`Z`r-Q2o2G`hbLJc-G0WKv&Bcemqq2?ePKUb(31B?a^ju@UM_FV{$ zV;G*%ba=#Z65)mz1VpP&b6s|dsoi$#pbbUWnpA0q!G>E6`6qT8-}RJTHxt(%}5qTY?#)ta)po7p5b zmR-VTvgvFZdyw7DZea`LX1R>L&R%3|*`x9T`4aG!NSCL{ljO0eww4J)eCHxK=A3TpAfCIOu1D^BEvcvbmcHalc_d%iWgJ*po zJmdWU9H?dG+q|FP2T%Jx*y{UWi|>QYz7IC}KG^8{;3;@8STx{I`eu2;_rc@74<4(0 z_!9_>m|y;=FXa*62M_x`c*ys`2HyvQ?*oVLg97>>!!wHczFF4$KFA|ldxn)6|1`3O zj{!mbDeVKA#p-FQ`vHfvv)s&vGA!I#KT|?*>6%d_=4x=#6c8KNjHJq3aRAmqL9Jf+ z>~ptB2Z%1}AzVS;)7*q$qSBgp`B23r*mRC z5wK6kS&tHvGYVQf0*pj?{sRzo~ z5Xay1Zw{SsDZ@G(-%A;@nO}r9y})%qwR==biXK02sl}WT)VD{CkRuklCfm9SDr9(#&vpH8SH@d19 zp_?78ZSho2>Pe!Ip{O^*LV~;%DTErVj3SmEUaova3z%J~jS;}%F@|sOeFMu9HnxGj z$@LZ*0D^ot+HKXgL(xxK`ff|F>W!v#v1+i)1q=beF%kO8TZRx^UqO7s8m#VuzM?CN ztFxfm%5)6ki19G-28UObM&VL{DX!7SADa&2=W<@80JMnGqO3Q?l; zW_2VwyMn{UYy|TChXq!1aD$2k78q8&MFBME+F>n8CLrAZTt0%=*dC&N)P`eRWybUb1QTBz~OeT6{b=BIq4+piqYBo_@*xQsyA%a3`S#M`xFiGKbIj7gnb9G&mkd-1yaSL*Jk)(B^8U zs=8Xq>+*rz-bvr3@aFYdWduy=1!lkx!Z4d>Q;+Laa_Jl5l&zg9&>o?s$kN}PoYT8u} zd@VGd3G(g(Hx#0WfS|$7a5OJggjRsPEspwu<5{53;w{D?*CP175~&yH=mqi9QPQE% zX~C5MCUG?h=$%8MH9<uZ<&N5ju`I-D`IlzTKsFIaYC@44yXT8 zrdEzs87^`^>W*sfR^L*cRgQK2kGX>#B`d8=o}})iR0`{aMrGyQIhHYje9}4#jS65B zJi*{zNJ5jfL2K^?xcfniEsJBYOIZ?Fk>m410Oh9J4a}+-Dm2Ouqc+w6b#M^Ij&*vE zI{KrnnN|xb?;XDyEk0}3qKkir75lp%Vx(|}%us^z4H47Ypq=M*hfrqUco#@^%W&Zq zh4HHFFE|4KrUVCSwh5O0yoBnIv7465GFV*K%HOeE3L-PNyrA)DGTSmb&gAgU0QsI>l(37Yw0)$Oc zpvaTT)$Zfa*r4Ug*gr}MZE#0hCh?sXzOQ_Y7(?REY5^SklWb;P@MS~H2L+VvGIQ~X zMTHmcf3Bnf%llJuDBNv%A1E-D4UJwCiyZ@kT>Iq0DIEUUJ3du#O9I&5pJJ%#42+V> zCrlN=1P*RL!BI$Lq`A`3ss52-0RnT>FzJag) zWh@?$B;s&M-chi|2Q`9JdH%f2c#HeP@VWj1gwp#`^OgF)s?*BjiX-yZS;Ragdmgrf zTqPJY)+G{SM$c+4VMq;!r8;a|0D5n7|8gCcyg^{XV1kRJXKs^cDa&}fP!~^37CrS# z*qwuwVqF~6?>>C{BE8tqmWSi?BExv8rZ7TXEEGi+Z7(AR4C>OBfVzPH2kdCzj0w?T zu{DF2!H36?U8+q=p)SV9DACh8sh6}uU9`sz(UZS@;Jp=(Mid-aS~5KZ+jj9(caMlf z-+t(|ybf zZQzh0!G%;K*9&!aC=lkdsF4AT3$aUz*ay|!M5&={Bh-a^3=2K2lVAppCv`Sp1}3&h zDk-v9!EHn^iw6^zkLNorFT}Kl1@!`mqd|-2y?6xKMBog^d(X;pa5%)${$(cfVT8R&^v-+rozO4*Zn`AAcZy9`CNs@3o;CL49x{AvXschPdq-#2&eojNgs3M0 z^y3f835u8He*lW_f7lRanyd_;VmL?FihgQ53rVP(tXE>6vv{V8Be|k45cBeer=q%3 zrgf+w+SbnC>H$Y$MIY2JJAS7pe2=-JH{{RCB5{lszs65T1#hvjMz0b(R`f!(bK=9$ zg2jm&Jwq*QcA{T9UU^E|OvbVJt{#BcRHNv`OMHZF{RCDh#k zaTQ&l=A4}2=vq#^6%~A~%JXFJRnZxJo#S0e$BIs6io(*k>*{QLh-9zPJ=tTu!F5`qb$-Qzs4>oua<2RN-)CLzXg&PEFAE9fCpW!-s;f#F?c z2%(O1Rvh~Ygn^FEBo0$%gXT}0rxqdAan1q-%$p~49FNi#05;^&PwZ-x)}Yw$mCcdl zI2Q&@0;nhW49*-1osEpmntooKIOaOewSj`BOj+u%V0J-3S3|-|g?nmqtaF?Tg-j3y z&pt5~T|6AR3SIxnFt_k(q~7jkI?-`11cGVhhfgbIkW2#cJ4YQljC?lIU`AUq^$N5;-E<$SU1E+0U|ruJ0p+hqA(fYxN>W~yr0kWXlz1pUK?2HO z@{q(q0?LaeDSIR-MUs@=PKtk!fbth5UwT23vP+V(QL42 z-tUN_^OWa#lf0wzl&_Pdtd*p!k)*74Q+%WIl&^A=e4_J|uau;$kfh{FQXZs~0MU8M zmrK61Op>xxlCngSvKT0Vqw|z6l6)yglCn^evOtnDUwWF%lYD8eBxQ~y>PK=>?vtcU zk)%wPq)ZZ1^4*9vvhsVyBrnQDNy-FC%6Li2JzkXjuA*fo!;2)Qq)Sr9Nm9m2QpUI_ zP`}SPXS9ptM;Rqa87WD*Taq$@Q1ZP1TbrM7{Q4s# zU*aVx_Py7`&4sa?f=cEdG}ap1b88K+8#MY^x@ujV_I}N)>c7;ZRb|RQl~WW4md)lRgo>^hiAuw5g`PZJD(*%j z?Y5UZPogSDpg-)kXFX54R18PY^WJ&7Rt!UqQ68>236dJUX8R>dh*0o z3_(kxY&$$XVXwH82)sy7%owG7#9L|^S23811&cxL>Y9#%S33`FCy;&*$Vw5=F`{>+N^8m8Ea zJD}*LONkUTxiog8cafTk{%FLk_yUbfMshe)-G(tVs)%@HX)>1STRPjz$HM_&7KaFx95=;mCZ7orDfH>D0*lN5W(* zYVwGE+Bh2JAZh~1^iT*hj`L@twAtzxy@XAI%F)QuB8N`Ij1BrL;TusYjwy~t1~^~6 zdOQ)-75$xX1Rb3$4qLBxG|F58COgS?qhHK-XvyIy4?7MBBcD&Ypzl0f(~UXmx4k)m zp!MsWoDf;w#UYmKUUbJAM?)T^cP2H29Ekeb-FpJ-XjlhS06wQOM@MYPH4jzgXjltW zkjzo)^mCASQE#f8KrWqmxxbLI2u-yYWh0Hq@shd{DWxs z-IhFWJ{LL~R#85=DY%`-l%_K%y-!8wF9OJ=-ijNnxIU-W8Sg!T^2Ky@Eg zlyZn-7PiS7qG$usw#GOpiD(v}B=BZKOZDtDwCDkDAX?H}+fgi*ZHy(oOC!?XFc_B= zCUPot@KyQUkzP%;IvQi}PyvzyV8oMw;Ee0h=GmMU#V%8<@@k5}I2xl#YaMnX88(@W z%hB!})oQOyj@6FFD9D6y^2xZ=X^k_{!Sg!7o4flQjgi3J(xvbn$)Z-b>E%LnZjcDaE@xP7{s1_fD0 zywKc_bcCg~PF>)O;qCeoTzxoD8Fshg1T9Q_dv0P~G4HezqaSQ4YIl=|kXMhONj8Se|bl?KC>VK|Fg^&}?)EP%?Cm6_q zYa)2#{2MGKz?#7@w_trCG5~QqbKx=h7xoQCp&9$*{9C84AV&!RXk7j}A^@6}ow|ao z2&P;zcIs*z9^{K=p*hL99#NcIm)VQ7SJ!k{q5e5OGudoqr)9>^xow~bZKwTEGh3Yk z-j5gLkF$ehr(rEFR|<=S<~Ef}j)o2jV47|mDl~_}`UGbSFzy5M_miP*3Xg|gBJoeK z?+Ix6MMyBtF7asj4H-gn2$VqfNK`jCGz>*-POL{s-`IQjDf_Klw9ssZxq~-LXLV@b zd!cU;s{&XVdP037yJ^4rxXwbe2};PxS?OXJz4a|@nXs$QKnGKzRB@>(5WNMQhQXn& zB^w1J*eDo*dpL)*1?(r>{!d~sdNu|#gSV5saeVxEG0Ya4Id~hkOxT!l+bh%G548vA zXT=1e*?_LkH;18aPg!*6tq(%KZjU_?p^pKQ7ut-u1)CXfBTB#eIQX#j(006oQ)a`^ zR5oH~0)!*#gTwU@vqkXR4S+x988PDwp;{*%q4&86ML%JopF4}LjFKIIkEA<81 zNW)v2&o!l*98HS)SM?FKLp@BbSJkSXRo!Pgp?^;mW4NXKT6sXZLODRGP@Gact(c;S zm47YYFV8g$WJb&HkTtM3*`ut3y%S=+zQ;Uldc-u`q%nSAd_sSV;f$kX)@O|t?gCfJ zE#>+FC$9g{r5pSJw!9s>aS5W?l((h7OTVSROTQt%QNy47U`lyNto#FzT7ELB8`r!v&k4|3ZlPdL>`Pq!3 zuRNDU$CB9|=(%tBJJ8~<`8(ON5SkV{Xj(Ldrn}T6t(^8PKY?LOzosRZUZ$Lulv6%R z%4qJAeKajkr1{Dd;GV|!MC<p{jj&kR*KB!I7d=Dc!TNA7PM7>=-!BES{jGWrc zJ)=6W+O3+S>Zbffc|^HEIZ_#-IInoofMh52>l6=gQx)Ch|C7Hhe@H$`9?E_M;5BpD zZp<%+`(>NJ(&&3Go(U0{yG&1+#+Zy?g0#h$A(NrH2{J-~Epz5B8cE(lyEAw#IzIu1pkh1^v3p4oWh_mL?xyL^UrAbd zWg^akOJ~cRY0(J!d*}a1TG?kZKb~bvw$s{*hSPNCFC<03+{Z7ZMV2n?9YYbg(}My8F-_y_l?;c*D2JX{Gzo&_6X>v$P_2gLOv+O>$l#M;}Vw6*b3&sVk>nwGZN+DfRos_ z$Zbv^(3e%jS%<)!31LDtiw`^$IWd6yD#n8MK4^LdQ;InVT8Q1=TJ~7=bh<=QfI?Rd zhGO^>90(H8?W8JdX*Y?MT7(n%WXlZTml_9+lte%Dv>01!2N+&3;yi)}PiHsJg|){qTBe~T7nFG@ z{b!vj4#JPXVGn{x;!u4MnbGg2={`GHjXi~?c2HbSPG1PhLW=tmpLu$M-8(U74R8|o zylu%4ns5YrI4WaiC<11C+7O0> z8@df>%Ug<-I4&lfTfqeda4^9Bz7KH(zfF@Y{06Jgl;HF&6*^9I^97ca5H>|X1;-+E zDE(8_UbN-&C`AHjXK;*3ICiG?#2ntX#fsiSQ#^Y0qp;tRd4{DHZxU1tOjGfMy1|e|q{_@qo}2i$XrPMWXwjkVDk# z|3;{g*`~}z>6^j=T`PE@DTaJRlYkEt5((b2XFd(9#McTqS^|0y=HNCRY31xfQ#36B z&ooyFhQbrkdr&q#hd}VDEwi#*sHR{Ol8C9I9*}C$Dxn&~V7uINQ2>xs4=+*& znQlTg-NahJMfH><5eIs2EFYV%V-jUUWUtB;FDPcf^?46_iTP1}NuDK-HRYN58-F)e z8gq@Q+zsvkm&0|Iea^nf95j3jYGj9Dw85tTT>q+mm41lcsQUeA)lry*=2fH7QJ;akLo^v`&^kC)t$ySH_#zr za+%WW22-Y>nMyyQnMyyVnM(ibm8tY2^zK=>y}o^xAL4x%D%t7Iq?VOiy?zug_xe#Z z%Kbww+xa`Ks5~59JqcVDjic$#ze!qId6K`tu;q5jR`Cj&7LBFp&c8@nS@;3INRk4I zSJDEDb7@*MhNe6JBxz;!DZZ2;jbh7fG%bFRrbVM^y7P}p=$SL19hJ%O|KW-Y9hYD7 zq7IyI2FX5GYiDY%%X=};Dz9iZXvS*n?6>S8HlH1-dPnuRYJw_8`MP|u>USnnxmGz? zsR9Yh7R5vbFTY?qVR}MmF^yyO@|U#d)t{N#7@LjH8K)a#xi7fA+&r#};hLdBoy45c zKF`F+J~yl|^aJeLqxuc{VfqlQ?zC>R?jCgxyOtd$yCQoXwz3H*{R_a}@3j{PB{rg@ zy?lSwzQ2I1Kr#EEJIgs5%D7xlXl%(dg|F~^RV7c$qiL1~h3Y3+_}0N;G~d48>3gNM zI3HVj7AKWsO8HubE!l>)mhn9p8O>5WpQc53(sbu_lB#wbQty+gP*xG&Q?c(4=se66 zTf6`WHo&mNODjnb` zqeq6P5$_Lzw;}{R{e8 z`VIi$T%lX3yFCutKjS2h39JcRY`n^knag-^%xEriaMaud3~2fmzr zH|g(vf1_K|@w9KC&r8qI=cV;Tu2cEJRGx$H0MT6gZqc-O5lxGR(RAm}B&{4ho##Mw zRY=P!H`BB@ho(hCX}a?#n(lamq-e_lehGc@bO-w6>K^`Le#x^s<`danvL=~!t<2rm`N}VF)55EjE@+H z8#M~6Jcav!wR2m!DO{}KYr}p+uHg=Y9Kf-+>L=@C3;=4|kz2KI40<%Jix7c`QoqZRy5Z4xme)@X2g> zG)+q{kyKS?P(A{S&ZY}kHVkpUny{=m5?!jsYgYtay~}x;mT73d(u*`-=>?jv^fO8? z{gl#6iYdKh52cqBk>99uGygU^kQdRDg>`|{P`rw!Md>u%d6T9)s%W~soTQcgs`-%& zWxV7ibm0?NM2pwb-$mnTx{IlV27Um!FzaPnbm=oJj9x=oD!PZJyJRFq{006p{nrN# zd>Li8Oh?n=)if>2py|$ABt_R7`J0Ci@{Bp3%>+6Bc7!O#bAX-epWu6S!dBrkZqUq zY%{w}ChI59mDldX`{9;aJ`tr|P*~)$@_3YS4Vqsbhpv4DX_*m);7%*!Q0DhA(xqQf zdg+&xUit;0D@s3?7ov-AG0EuqSe**JafLsP=6=t2SCy1%M!_^8g_Ot8LW=WgS~Q8I zXzCZdj^wWV{yV;oLHAwblh~4%X-#D&nij98Y0Xpd zI6K{Yjqg!8>ngvCA$2Lr%+O%cwBkIP7EL56s{IPo4ZnQ^RquG8JgHvhKfpE(T|pb%jr;BVCz({)q39UmlB>!C{P1X8OSNv}vj- z(fEV$urc2_!WhE+m)pm!;qKtEQ-8LI1N~nX9}*DOc1ewkjqoV&s<@ zquh2#F388pBjG@EnB4$)_fgChrjmIGxLkweH}Hqs2_5_&Y_sJZ(bm7=BQJi8rbU@F z-DRZdj&mff%=nRK7)7!?8x%3Gsk^B9{_g%adiiHOU&7JYzwtczfumI@gp=Xx}T=I3^d(QN7L1ev+EJ;!G@1PdaF(%n?SuM*RV>dAsiU$<~6>52{e209dyfgc= zdwLw!oo6R8YmI}Aa_&9uVQv_wHoOme<4A*Ee_Fp$Z(_cZ)iQVJ_UIne4b@q-UxPa7 zaqWHD&YHh8A8KCEq-hqj9h4_vPrax&ln#z{-mF# zyiXac_)4)a58cSnw?Ws+bZ{bxjtE5;%XDG*Uwu?%5p1HYE4p!%??xW5*J@vMl5u520X060$>PxF-7X)?=|<^7wI6AB zYv*XYX@1chVc%p|uqllGDzlH712^7_vYr1oc*{W+y=#tuML&fM1Y4erwp#G-B>KGc z7y7*PXZpPKCz4hcheb5OAXHLnSu{gIyG8V7i{_FP_39SUx3aWb#AMis6XbpHpI&HhNJM|O&+m>aK1V-_h?G2EYAp5d5bsi7;J8cyn0=zHol z(kW?`)K}8$)+s-Mqk45X=&Q8vX_o}t(q}01)h~)4!+z=$RlaJFI7rkBA40=*;_vc@ z_*r~&?j`0JvxsZV{>*yV1#CwadPv2;jlI|1r3+?cJyToOord)FOmKTz8zt3-$}rV2 z)nl~W4N%&p|7eA|lSwdX&uuaPo>#5}8biT56dju=+NV&o#S-+qU)L1D@Vaw~_OKR! z^Le~x&uU<5E4owZX?}Q2OE~nWRQ});u9_&ffvJs}@Da28#Ac1X05VrY@cX4NMmpvEUGttOI1C4V{D7;W5Bm;aFdphEieAuKa;k zG%}@ol#O8o!i0KV(Vj_DXisRL(+i?;W)GO7GspC{%t6ovf zhG|g^gX~FWKi@{VU0GMWE;_|Yu*LpCcv+Y#G~;jb`}yhIugr8w)UDy(_P<|eeleUh ztT7BR#Oc4(=jqPqhQQ<;E=gBF611qiUG_i$T)5*YQOnxUwOw^kQGZiAcF*7FYE4tB zwC68A+1FADeWBNHIYru--Sa2HzdbYhm|*S0Uug=C=$MMh3chAtb!lvle2Vs|6m4+? zQMZ1kyZEmTp_Q?d%ueD5V(4^X?cD&S8F&HXg04WUXZcTIOZbg5)>XYBRtDgQP zpE%&$Ws87PI++?GWpC48?4CPhZm8QADzM-v{m_9Z+NV*pnJI4l;$WhQ4O?6dxHQJ1KQS@DdxMH~kz8Gj1z32WIt zOh@((&%*L~jW@Y?taxzGKaezCP!vLK6j1Tqg>+L>*2$p6?$7{E1=`=kl*I1&2Q}+t zYNpw9mpxS8*!VZ=ZiDi=n3CCo_egk6!Mof!xch~F=xkp+C%2{VU5#mcu0}LIS3?pX z?`j~7p!-!KIwWbk+taY_b|}0vEVM^EoA$FRHIT8JS|Sp{v7N?he~O|l!2`MYlwq|N zUwe`KJGRld?9&ON_8p9;_i_BAzT9b0Mk?0FPz7J{Ay zJxnJdaFL-c+I88ILb?I#*h0#{+H)z|Y7j)7dzqfZ+w1qBPLD3uutPw-X1_u;N|m6z zrgSNDm8s%w{&_Z*8^v@H*NS7It?me?h3p_QQGFDUjK&he9(ZxvrK)eI92&B1rf zd-~P-p?ZsSUD^+u@XnHsPhk#lb=bFb4qcwEJ?ys1v<2Gf+74PBNOTJ|Pw@=17^d(Q znrL4AzWOx){-8*XpE^LYoCdB4ua-%HKpiICsoh7VUUi1 z=64GDqha_tdHUMPk=MMFyCeO`l}LWNnvuYwtBH6-F$wBqJR180 z?BB>I1@DtE1t)351t(~_1;_F4B=XR+XAE9sa|fCdc}=>a4aAT}4=quhO)0G7dHRWc z20?UjplJ?$vUwxMHlD@9OfNCadB2Q0cG4W$XH&Gn1PI0StQuk3!tjP2iZnbL60=^IPG zNr$E7FuG%OU+7%A8M=0=NM)hA9rLBOSi23RM~yYV0p-$i%>bZX`a} zWd(FR&(wl-cSFn&D1*BzDjtNf3xdjk^HXQE>nRvn@E@4k%Lt<5i(z)ePf)eIiofClr$bc6Qu?V=L`UH@TX35Gb|ul@4hKd1e1fRF#@uXglj>P-5x4eJECB+ipl zMf2oT(%%KA=CD4;| zh*QN@BCoh9oYQS)yGSizz)ujG^LP07`HlP-z5(|ucZ6HXj8QGpWneQQ&H@MF18~%e zx%VjU&^6F~2nX^UXl|gv!FMj-E;MOTzXhgRtfLU^pJ__wT`gb^w#~*R-%XlTS8zs~ zq`)V9_(z-GsX;qu!|d&9iP|r~m`0zwfJ$zz$&C)pgt?*MEDdB|Oc1qQ07>nc4eMa~ zobtas`SVN*7}R|M4t|ctWnV$?rd0fc z{3n^+a*@38L@zS6XGr!$$BSAAoZxUVS*MmhvoC;Bk*kD?`e@3!d(h&zyW`?Om($b4 zoD$87Q%9e>T9N0xyBAapt_acHGnLB$iQ>tyMArBz4OLJ=(cPP(V-H395{kB_6u16D zam!}}QOsP^ZrJ|uunL@H^*`y~&|CGr^wp%#qylNGl&1TDnaPdfd$BL;*6N1nVzrmG zFKV;lMD&a14b4JLC-rHjHJ88}*y-wZ>cQ%0*tpwN8LC>amN;R>Z>BgY{>*;GdD&Dr zH_KvAF-*81>=3eq#{4h*A?9!9UEZpRP;y%hjTw!kG~^qy7#Sp}X#F~HyVdb&Qw=Po zG%Pc<(K%d<8=nZ9ahXtd4cCx0UPe2X!!lm*5e}Iu7I?Xhis z0@mG+26y)*!C7}7`rH{#pF6|IbCuHoT1fclNn&w$1YQ}B@*<^ ze8yD9kVGYi(@XV_uLF|-ZX4}LA}hO4-Sy6<&vU5>7)_9yK= zZJxF{^oG|oGc_&Lf51`UIp_yw5U}l4%~5q!X_Ox+p9i68Q}GY+C|m(PF4hr#7LEw3 zgyBM6=mSUj)%*y)9!xJq+#1DJZZJqxqb{>Ave}@E`wR01vykb;D8ZNkYNyBsi@p0X zl=nO|x??{@`?C~nz#0b6Jx^~psae(qt2_?vjG|a@k)mTCMf(bhwiX0Et8At-Ae zfub{#V!;K9j#nt!pTW4mv;A39JyvuNsB9Uf!qwjIhqIdBkAhOaAC8y(e%P1!{jeoh z{s8KHQ~tr5CMMUz?5p#SA%7hwc!b`C^RuFEa3CJ(o{6(pE7y}s0?tMYM2a~ZQBv=SIFz_kSqE8mDqEnP^F;}* zyDG-|?2{WDsDUOekF)z|3u6wL;q$Dl?x^DramIWXGozaC0?nFmAdci1{j)wH5B;>1 z3$TbzIbcG=pN(_-;vaG#7KN{jJL7v2cOV9Rw=!;%?@9Fo)zQl5;?`9fWI`&@Bo#3D zY=PpJb8GywU_KB9FM(b^Z*`mz6>rxKMj5??I{p<`=YSDSSsiEdm8#BxNcbo(uRH1x zrOidTk3AvKX_qR9=I}i>p36CWlK|hy9qyACR zHGR?bIS__gX4VccqBkJb6SV`3==JE(6Se(vSmS^MvCf^_03Cgzb|gB|MVN>A9?H%6 zH0%ULSH%ko!*O=1s*k>=bQNwYM@uH%MID0mq?)!wyH=%P>oA?PeGPrI(VDB8mo!ho zU8SHtt41KIZ=m{F`4Mx&utxQk!KhlU+^L+TOjRmCSf4Luij9Rogk!=m=1oRoKi6Lo zYJ>3ME#CYLKah_DtBnJoo8E(~2Is}4iZWrf-ld)lAF8G{2F1Um&tT~k}_>8<(7ksK8MXjfPA)4rO3 ztqlgxU5yzuD@Y=a*T@T3H~Q1QilVJGL62TC&tPbJj#p`R90zDZ?!l;^-rSruUZd|_ zT`1b0qiAbI5Y;r8Kc`RDHm6TkZ85#Vx`1u~m(IQtV<+;%(|W5ZjK#;n2$U(CtKn*C ziIiG19G8aCjJY4Dak+=m&)q}lZ)Xh2RX1le*4Z^Enqd0pqq-wn7kClPQ%z9jiBAcW z_b>O0=Ali0&ikai%p% zOiZyZluu*g?5r#l{%%YZYSoh)j?(K|hPSS=GmJR-bQGxc0q6da#!=DeySf$^I9yAg z6d(Ox+(YNer;Q|E37v_jvO|fntCU#x6jb=o{tu(0^Or{IyI?)Thc2reEuW?=x-m)3 zlA~40=8nmAz&aaP77l^t0Z|5o$cX1W@aGg&w^Ac7u+DIMR3mw#w$c^0iB}s~wuz7< zsAg1jOEjXms-Svno=5Q zGDFST7qCWfZXcl4T+uWS*Qe!J`Lw=58=oqJLJGC=pGnvNMDjq7fLXPXIKIY_r&P0&`c57{7i>l~pu8DjaTRqO4 ziLTU$jYiYj#(wo*ylV_p=&wuP=ziBaHP5K$fziT3nEn>=3pttX#*9!5gu`&7Fc@rQ zV`-%m9c1L05W9=V+Wf@P=wKNBk6=kYK`t8uk%K`{JAcQ8*4pt)nC2+yXH9g^d%XNs ztkOZ+w4ARA>&BN)uPx*>xokATO#s5m?JhboejgEyA4QIJbeS0xTh(cQ_o z-`Q0CkY%H;E{Hmt{;Y}Z3#PV@P!kK}vXP`)lq>l{8e7n=yTl#wt!vTI;O)415Vik@ zB)PZd%4H)UdT@b7TTzu0yNV7N%iG54oxs94h@tI6MlK6-*>F4~nb7rRTm~92NhhMU zUvV|D|D=?vR`ztcY#6C*Bc*)^n-;qUyT}Be*-TtiG&nQ}u*0fie_-UY$Ekr&{Ipme zT?qsCX#MkIM^%;RUMZIiMW5%zUhH1Q4AhXzhEy1u1^A#@-%alUj{|wn>Wt9mgPF5D zY;*LG%LbF_A;yZ5ev3AuMKfcoq01YEp~#@*GSL{1r8&4Hs#?au%TC#2&@Ne77P`Vs zof*3kJo@pO(C=G;tu-+L$BssV7(G8^&S3^F8{{_#Di-#=>vfyK#hx`!BF-3sSo%C< z0&+FEY#`b@EXIUZ&yM}DY1OKr@Mv7vrZ~{7%8lHpDtZz!3hro8<_Va@d)BTo9=$SK zYJ$T4j80X;oCS74Em6{JL$&I#X98O&lIikkskz)tE*j_An-|G40by$d3tLStdV-`? z&fRi%dgQ5quY#t~T`tP>{Pk31Y+wpO!y4tHjC;&gHL!X zQaBp?v@r7E13!`*$VHFC;LppWdxPNzbuN@^Vw>MvMQwuAFFqB8;rrBT;Jl)TuBEoW z=2`Ut)d}TH@ipOf{uFl-bXB!X$5%V9i(v$yD=Qg@N}SR=K6T&}Ysmn#{UyomV?$eH zE$L5)r@*i-8CmDVS4X>M$M-=Q<09195N?q_f7D`YNk0gjlY`mSXy9|Pnjz?@&NPd# ztof44vX=BkBVU#-RVq;f_gG0E_B5Dv?XA#ExeJN|LC0#wM zQ|oYkImoe=bV0Tjb-wmh!eDDjXS6o0&S~GHiPn-%XkyDcS1ODgJ^%a^2Uq31QjyNq zR~SYa>gaEPHOmrEafy&Vm0px`bpNo&l{IzebUSrZb?tOI?Wfw8v~#sRK(=vB^Ezk| z)nqsETJ;a0JG@xk11>&4Q8_>rF;#h2c~ZGfIb8gn9WAv0Y3$QtKQTu53dktt30*;R z=~KRt&*R&IEWN(baEg15>%#sGwiQ#@+RSInCZ-ROnHPd>z>nn8W%D(2Q`XfB?Gr$B z;p&O5Dna1k>VdAP@bB&@x4*d?>e|KJ6B+7r-8Ww~CyP#t<}tXrAR*l&@FTY13j&Te z3E0;Yuyw%TIn0`0X3*<`Igxe3q=Vyi52xuBT&3uEgQ9&MMO%A<9xreHhT)xN!$x{z zeNAbGyO}FAX@`fReJw%Ho1*zmhQ{xVqw%;$(%%J_DLM{Pw6CFPYfI4cxyo!L%A_q} z{|!!8;4+HTi+j|;Ff)_581x9+DasW5ue_Uo5=2HHbE~*6hBpkk`YWJ0I7$DCegU*> z6qumwlNL(7K%Mw2-G1F7U2pBzQ0-}27f8QbX#Ub1)hyHW(iqeqtGBAhfO_e5)pX`t zPOWOI5|!sbV?Ps=ihmK`2HT{5Vzh8Ya4O1}1FSbnXv(ZO)>`quZGln!E>mH2;cEko5eQ^|Aqv<-{p=jSs(bk!ur+!cKEk<`2Byz$SMg$FrIm)ie2=TJw zBgHPm8N)Wi1Oo%wzN2ucr@?3QFS4Aocpw{fPi_Pq6Zj6-O%xCCpXKh1@ ze-H4a!_-pn4UN-rn4&!&V;cE^+H^PPqT-?EG}hLgplAOOGqBS*KotoW#95c3eG5ff zH-hNEoGsRlNZ!%tzA!$>lWm%V8D>y)P`;sP&o<|Y zhFKiwp}ncUu73^m!+QZC&lSlf&5}AwI^6}Z2guQJx|XWiAbj4bouX}}6*V7ec4=}n zt>NzDW3^p9RjpFDQQlIWRc%rYS1yD*a;11$TrUmYW zr-Z>23x1&Jc$cDmJ4IVhf}XLX&8HaFS)az@dW>Sh_Y@t+DB8DCwDll}8jdx8%x+jn zAFl04ABGJv+gWElqKbBYD2T2Lz9S`F>?qPOT18vM2MWziSQO`JIxrDjYY_QwQD>?f zs(w+uty%`wgVCUP?Nm-zwo&rp8QltTmDn5XF-{80gw6uPAK@4BZ9v!5!_8EDpgW@L z#_{Y~7O@#@1LkMuEoLdx*H0B(r8DSdeLsDS^pzC8SDLrB_?_Z?@x|+k-zt8+_z?8{ zHrT>ZL zNmVtr&oVdlhuIrXO;p#2O#CFCf?G5bj`u0rcVSEeMY7(YW>lXQUSL1rPG~m@ zjrgD7=5Qw8vO@6)D3ms+V3lKS+_U;2Km&Uf>^dh)iMro(hjfc|U36;gS(U(i#6H3G zW5&WXT1)etX1`{Rrh`UQpHXj8k5t!Go@TZQ6F8&lThL`$sNAd^qpT<16yFq$ve;X= zBu0W}S$!^w{fgbsE@CmE!6sY>urYZG?Ry5Vd3h*lDNIWR|D(SPfNp7pxs6!xJCv2E z4iH0^*Pns0>r5fjFMG9G7bheeW7g-@8W9w45zG5N9)ngyx;8 zFsRA*1;5evj$(=he^RvXp=cY5(S^Eff}Psh{`BGMdNfhTIhv^BEKSsL22GRA4%R)L zzPIlt=!tmR+?r+G(`aaWAw}C@f}Z8e%+=s+E{(%pKoD(PZvLInrloUn3RNGlpSz}f zRk;N09b(0A#MeZt*iX35FB46iM>r@f6$T15`0x2Q%2&q}1EW8ypU4kV{lqQRr|1=+ z>YXoTg2C<|x?`YAKMYK9ZfKYCX6>6?f9)V`JlG>10*$i4Ko@>P{g!%#dWgEFD*A2i zJN8$M_HVfu?RW zPvD8}?|KK@5^dOuH^z5p%&ttDqT^$Vb~i=a2!fvDTk&jK@Hfqm>j{dEk0{!~=na>{ zHk_bm-FEXu2>ln0!!?ek;qX$lzeLeCj3COknJ4D2Qg@%mK)AJT|3h4L zxK&r70pF@m`X4iMtlpjw1gvc(peYWU7N3ib_7#ERR}=OX@%N!vh1g? z3;v<#8c)$tO40rbMcXKf+rR__qVv4F*}RQmU0JB(df4m1e^SwCWbVKg+@;C5o}}nF zPtpD|McYUZWa~}lV7k%3sJv6iN&hiqahu~&{4n0>SL1M8_fGaixy>9?S>-^a?wthR z%$x~C>gejWh=b^z&c*;S12jrD`uk<`9iOyhp4B^%wiD2&V@;LM2|asd8{si90nLgJ z_l*Hrw0g&*g$dzzeW99Ky;+_WHN)%rIwFvwd!Iya)e8UHCoq{}^^T*dVG?xEE2K#iH1KAElRjiM`8Yt6|J6gSCJdZaBZ^cxy^1l`r%_xtx1UcBkh3Mw3=xFrM-RO@4 zc))#kEDg0`;{xSumLO6uIbJ?SNt2B;(XHu*NOV*c$D_Lg^x3FGsdD1IlCz+3 znB`-sSgfzMszGxJq;({YxRb(MbncgM0S&mI?00WO!Q`Z}T0Vvek8^SoP{&y@(P+~9 z!b*IP@(@C0qkJqGi*e1UvCEYIa35J0%g34{yE4ujP^H1-kuoPAOMK_0hcF{`hUr;Q7gng?q}kWwGRbVFHLG5u**81ZNLB9!sf!^rfj$;TR_;)4+;l>LT~ zgQn@@#ymKKjC`ySzK;s*(XE1XQ=+oM2nzjgz&?2c^xon$Dz#dr6K@MQ_`i8QmjwF{ z0k)5q1zECs=X><-+JfKkH(I^(Jn=8rmVD2w!>r!9sP!wgi+uw(+v=TzqWAi7Q&?fO zoDBmvD+`E)@xV=J9Wf5=dXJy!HwVZ{t9KTvYd8N>IpA?FX2N%bWe$G_`Z7S<*@Jt= zkE-7~$LgIyBgbwITA;+9+?Rgwf=t)@6zce*`RB?k$_A@*W? zZ;p_;4MH9AVXfZRT@0AtVPeifOoRXd3U1l(Ax-FCA;P@%TdW?CHPah1Nz5sQB&#c z9`h{)adwa6!57&6@$3?kKqn;?F`Et14;>L)BYW{Jb>%hk=&0CLM3S$I{ zuK?;oU*<3sSFp@AlD#9)faut}pd13MW!7-1T8MI3b7b#uNFKCoC=cdy)nlJU>z-Be z3@9^iHpHO#>b0~1H4-XOlk6Ra=Eua|@Fj}1je_M*BYPi*M1hnQ2%jleBGy_;vYVem zHy1K#bzrlUjI|W-*HHRaiAjN%puQ>ykp!;Rp^!vYRy}gJT5<0Q18o!VoF#(Sf!1)d zntZ?JP-TsUh#9y15R!R%?_Uvfh3Z-)(3&Rt->3TWiV0wYR0k-mc?Xlc-lMP zD5Wn-uj^K7pVZ{2N2o>t{ZRu!&xdge<_5aeS93YcI#E7R8}d1Pc)3={62Z6>6?cyi zQG(f6JtBZ-lIVc_E2kdN%GIK@a_a;mkEB^*7Wzpv`Z1`6V&elwyqcI1?{gnlTZo`g z6DJaIO_$kzrIi==iq;s37H*JsvY=cN{zuJN)MjG5 z26yBK@+Vf8PgtNMXJ;F&Mlv;%xXx*eJF%_`Ob_cWfiXz>@Q83(`Y}#FV#wa1T4Ma0Sqk`l1ZgZWj4O zby}B|PIWH$T02w$Ysx30Ndb)y=SIf}9#jHc!uT@wuY|;93cW*`pc6Ik0l!@n@f!Fw zn#bj_QHnCyTfAYATgm5ZK|b(RJ1jaVGXscbwb@K2db=~%D_>C6M2U@+d@bzB0;p$G zV4c83z`=aE`1oS=L*?@|AyV+*g;{iIq#c$UzpDodLip=6Ac0K*?WR=h7RH~kv|Qle ziwYb>oKJw-g@b4RikMzrVYFi&TpSbT!42m2$1jHJ^7(j(Vdl)oD)Zu+%uGOQl&WrM z>PjOe!iAoN<4O&p|K^JeyhNP0c+RXent~AF@}1=KHPF5%z=gyoZNtWIT#}rJ46BXt z6}vuPG}=V@ycx0txBvaAgONq6jo0oE2ZYM!;|QU0c7{=hzSpR3pmVb%l3{R*Noa?I zDeU=D(zlb(o1i5?#8uI}V9(P-Dz0c%Ph@%o|KM~&--sRVUbBQU;z*m8+n~4Dp>5_Q?YemIGdG);H=7Ic~ssiK9u78Pr zyQfe)3|=moOZsHsek||2X*$yXqG`ycHb4~#+Qvy&CbXr(;yq*<}AzqxD-B6H5pC4qiIobTxv;=ODRdA zk4qu41Tw3Vsi1FVFrnBdYJ<7VSB8;z^HbSgp}w0Zm*k)}OZ`g`Y8RbbBN1i`!2(Ws z^nXZS>%P!#&)~sG5C(fe>y^z>_rifQ{^ z8;;Ne5pVW_Rfbyj_8<}anQi#0Fw}XsiR|qTtChc{#)ChqFMGSeM|0;=L#{u&8KOH^Q&^LyQ)=x9siW z*%=>O13WLmHsN0dGmB(zXIkyFqufr2-6p^uFC_(qKN}g1nk_XxM2eE^?S!P-u~#0L zAUN8j7B67H}jp^`rE)|pPR5WFJc-;Pfx z+7D2)Wf1gi>0`MIUuDy{oE<0@vJ@Q`Dcbi_w2k#Zn)?{?3%%dPa-4O~M{B!60)ZH>C ze_!+}*4y5*e``WdzdN=5R&P5H^JZsH?wyRTJg3V>r@vD+LGg3>dj3M=1y*lc^y&75 zUwz`=X;yC=^x5+X-&8)58(O`sJ;kD%_}gY} zrJ&r}$LdW5Ido=bD{ue}((8dp@c3O<%beAl0`Kwu810pi z<6&CA$^wGt=8){nnK)a9<&lTb%hv<+oUKqPNvOujFrSBJE8Nm0Qki)9E#2KHdQ0ak z4m3hDh&MZX?BmJ#r=zpc-a>w`8b%j2p!WQ8t_G91DO!x}pwMrWnrgq$3{!_GKM-FR zw)5jTfmuTc-z&;;7}EZV2-JVy^i)?n~)A{7sHJQw&274JLR=tjwZ?Z5hp#kXt;c^jUbKVze%|-K0ZS(&GPIz9NE%$@r+8gMEK+P_An zM?^vYf}=Ays>Da<6#os~y%8H1YqZBKW2f_H+a#U7$0c)=oR zl#l>)bh(Om`6jTy6auMi4fYc@pOprIiuQ-hGfXGNUBw|xQ5KtJsiuY{kN!h>nJ_`S zt?2M1ODDEaMbUAYqTNH$mPOF>_9V-2Pz=l=YZC7U_Cxx;vkS#SB}K>Q6zvDm{wF|z z11I7!=2(C~-8BXMI2A8&ODH-!Q!ErIIxbPPzfRFM&I94Afnp(ig+3f-`HXcMb#^MpjuZ=pa^xvGJ}bvhDcWBv$5#oW5#u16c%@~x)xp@33G)D$nS=2b zCVsJD4sf;apj7_z&UAyGz18oKLrh#OkHgzT>B090eMQ>66l+c zfxcKDO*k~+cHo4l19a2&c+lr3dGa+Gxsv`nsxT1Sg51u_>!XiEsC~mg6P0J zOD_HEo+b27^U+}@ORXn%vE zZ9GBGhKZKz4Br3Y|HD60U!q&~RZ{Cg2M1U{Pn*3Cqj(j6{~l3gVP}aiF}aWQQ-FAQ5~AkpxyrywDcB?pjv;H=pXQ?yN?xUCsYxKK|ME|kb~k7I`A zN7$aupl=;tQ?$QB(Kealwx%8^U=70f!PAVmSJH?aUs1HbP0==qpr>Gtr2!DcLW}lP zoDIbawHLUPJ4ssI$2yyCJh+_xA5gEa)IJ7k6<=#!0ZWLknrc9_|FU|Xy1P13broo2 z=L1)>QTYY%YA;asR2szd;x^!#tSx*C)dGregD4gn zDLQ_jXn&8QZ8||u=@v_CsK|LV7Uw{Ug^?5;Kzfd2x4%o#mPgPNw#@>pQ|{HM-}8`` zYc56S0E&gxC_28QXg@~LmP-)DJa3supKLlypPXD_@gn6)=s51@5VI1`NOLGU`%x?e zM;-XN<2ptAQHnN@=D>5$KhIjefn&oebZa@p;+jp-392~wcVPrY$F~&iMFi2c=PV~k zV|Q1$g7fS$S?zZ1L~W{;)tu8jugTW5&~WNvb-sF(Iss_F zT&i3!Zo92KqFf3MtrtH60@%@tYhtZnP0elRGPvkE>~{(m`v&_A`xqO~{Ky<)mNSEy zg!LVb)UqOFg9R)rHlg%QxScm3X0Ij5bNUra3WLJe!$jE{80gnqCbO=^sM!Vx;(VN9 zVJt<*EsFLJDB5OI+}4VqXTf?4P;t8!(FB}BC>Br-Giamb zEL8k@l#q|R!a|D9!4wOlDLTN;1;4kSplF*x&=bGef{Do1p`Y?`qc5Q7e2iitSgzvd zjvp!7k5jZgMbPtOzNHTxtUd5xrRGaiL3@{ey1uhMQuU((JFtW~r`e*()HGE80=$vSfSEN~bp?DSOjji-Z^E_c6fk7FE*6SUiZ#I! zW(Ul$vEWlVU-1t=o^Js>VIPA{Q_OU(BNxVAW?x|!vVB++_(^yZ2I@klBMj9Rl-G6B zZc9Vfy#>YZv81zZgl-jBcC)UfXzgz3oX(LH3u{nx{6^7!hN2Bl(h$zGrO@&|wA0fx z7Uu|xg=UJ5Un$y8Q?!A`)*j0M7Il09YS5ie(Ir!K4yRZcN73;MMf)j=wz&j7pS@)H z8ro+wN_g1<4E}E(mW!)Pox|UFM4y9NaL(y@Q;9~px zc+TyjxXptrlN-!_W`^>Ha=&thGEIDkJE&?T-e%H3Gry~-5>5$gKqo(vzX06!!1BtE z=H{|qLr=wRgHeA~@7B-OcLE|KiW`2*DJd$ z;7;q9r2*^ShSu9*;c{;!i2i!f@+KO1#sc(OV^Pw37{{RX4hZ1{+eQ4muqJ(8m_VNw zg03-+q0mC#JN~5a9si^69e)r+U%zYVK%Z>BLC|A#Sf((n<9GVKYZ*oRS&Fs=1d;Vc z%RJUOibm?*j+(uPm-ywd^4d?q#5wVl1-#sloViv|w3kq{EhgxRJ!1hnFA~K4JdMX* zj4_q`Kn>4XO6gx`k6AupUC+>L+Rst6Ej+jnZ-kg*igYH7WuEhyDX}fIAL+Y6Yke$j zm!5z@dJ{Oe7wNi!9q~5i4l_tQ9@rM|z-DNpW{jqR`d9T4pk^PUj#quJvNG?h4yw|X z|0v&4&R4bqzQxzYr^F=TC!l4YEHvN?_-~jnJ_ojze{=70E4hJTTy+?vg<#2+!u$n! zxe3j=q}&MVxTQ7g-i7i$fL*+M2dNm)G82r52V? zgL`pgeLtc(8`Tu;I}XF!IgX-h6~)536diXc+Rsz8Jx$P4_@2ecqB_7;sE@ z+whC3U8)JHrpn)xZ!4cx_ELreRqsx5yznd2(Xa-X@74*Ug@*hey!k!wR5ONe#Ql#u z&TZhvvVXFJ)k~R=nXSwirWUm8ZZza0XiC>QwEq%bSJtAWkMXu(4T464=c_5Y?dbAF zylTPfg`XGJqv*IxpF1a#?|AnMP^lzjVIzt!vJ~x~P_(Te=y~a)1#EMRaN^DhByryD zfRD+O!iE%IEDvD^mQEbfww$2nz^5?5laEB_c-;~(fFo(T3uq|{8&G@^Xy9?F>}3>f z&v@WBY=?DU;Jx@5)|rKNT()Geh4pE%9pFm}7vBy-Q;fD{6u0#t==tzt%V-9j{0M5o z{UWJ>#m*=3bld^>?qLAk1}@~KTu%@?f5dLlv`|$u92Z5wtZc}R)_gqWCfx^UiGgy0962UD%YyTG)if zQP`M1e^H>}T$|}{*CraywULH%ZJ_V%Aico3vtOd`?Vr*2_D{)s&%)~#uSotBUWBOy z+)3gxyvWl~FLH%9E$R7TSOc%ILjSFFS@))PpT?zLrg~bLC3X?o@`+q)HWeF*X&4P$ zWR&HAd=HEp)=vPlfz>Bt-l`&FlB|%+ra%;+i$>|(c6}HFY85M#t2j^_B}%zK9u;u^ zUoNM5NY)%6w=2V<%Sv)Pl0egDVJrG$b;u;FnF`W7qN8=cW9o-YLRVGB3VycXQa%McjRx8$|I7KRl>kf^%CbobK*2T{{d6YAh!%dW9*YuB$21Y( zRwxNa`|-3M^&Ykijm7Eps&xweBZKase@*2 z*?35uQb|@v@#kU=R5k4cxhxAwnX$jLty<4X_@(67RBV`<^-11xYKI39{p>-1sA{+yiQT?zW{=fG=DEJdZpd4duL@pG^J{kMA zfG?w)ql~|6Mq`Gw7XLkZU`WfP3~9Ek*ta`Wv2r8ivJ4`9HSfO zRCGHidys36ha7o@>G5HUH9W6KoT9G_Oa!qFrC+NEOuNpwM{g+}VZ2z8C zcT-o&p!r^gXE?3F_X1XnqbxeQ#N34~_!Skc1l%Ruu7YnIr|3714=LIP5JVl z%yz{RNN`jbXn0&y!%zsV;n5$ih8|(4#mW~|57PXAHHDIzHA!sQB(d`L?;$%KaCu%- z($O56%X9sPi0DC&kO*jlTofS@vT*$yqvs=yA24ydD3DZqsv$?KICslUQT&VANM|r233j9Uux-{>zR2FEO#+0Bk23N0mM=0`%f!r7aoYp*XcxgT z5^mg}IwzfAZ{n|OSH(G3lFJrjU6jjJ%og6zErM+Qt7b~yN25ucESD{$B~S7xzqG3p zI|Hu?$;l`lIH_R<2&RntuuUB=mn|s2G%l}RqG6N0LAeN>c{i#taN+*6Tv@#x+}H-W z0DZ_*3U|ea<)qcj-6K$-SZRsxN^x+#zwlu%AcVY<3wlM3DirUh6QhlDdfX z?f=F243mRC!nD^&z8H-y(e6~S&A~41ViawVpmu45wDi9((6ULsXvD^9KX$ERCpO9# zDd9GluKCS>m8NT0^BkM5p@iA-(Srh5jjNUt=&4>Tr{pI5vK4xF*n*7%)qipd84NQ; zkZbsd>?|;_E=E8lhhkxm?EXm6!|wTFI7ABVn zKJZ&bQE-ZUq?4HSDY*=r6~Qb**UrCI$E+oqs^Ac_jRm5IZG*qjXw_;-7UeQ(b5y=+ z{=FvV1>6cC#7H5E_b>?tv)p;uPCrL3vq1KNiacPR4L8KEMj6owO7vwLOC&jI|M&IA z3Vi3-AQ4y)=+0^<8*4=SnAnB+2UI*-bd{-&3O7U;syObji~t)y<>eVGqkX=zZm{h* z94Q{5Ze+b&=5O1GAlqg%_ONn2hbtdj1VbNvlmy@$j%})Pa*XsGUa`tChFULiAYvnF zfFR-#wnTDYxeVJsV#CtKWOMhO5PKbsX>U|+TwyfgCG@{Htjx+~F{A~|0llZVJ!qJ( z8Y4AB>o2K|ow1ze5fTB4_3D&jT^9=$Fh^BYXIF=cjz(8=5~`sm)Ukyq_eqw|kBh>) z&6NMnfxnyCRU@qMN_>2zq?!tsLQ56O2EzaN@41oSuWjk(r1(63wtQaeX`f~65yZ+b z3~U=U)ykDk8)1`4=1C*?KKfX74QSAn@hzxQU`h&>%LJK0e5#Pb(^~nw+7my~I4Vdw zyh=W=Li@6f7w@+V)HjyTE1`D`AD#zh$0P^U&?l3O?-PwgI8>xU;=!h`%EY7e>GF9I zq5u=k7;F{^g{X!me_QiHZ4iTkeI^_rfWCmJl?LepmGKzC0grM6rgB=NEDTEs%U_ou z)*PbHeuLI^JHa);cJW1F4WGkJV<&;?%MjSeHxcCO){=0~!JbkWQ^~Gj zeac!AMs=J8&~Z+zWxRmGrUue!D6Az0bgH-Xze*Ku>s)Jz9u@bIZdE>#YQ0aC-1~uSuo)0=kR14PU#>k~lc)~hIGz;=lJ3ubYgdPL@FKy8Jj3}dL zZI=ikNIV$WgPhM@I2ka_JaPvmOyG?$4W1_cSM$j;8&7E-3|S+dCqh zcx>B!u10)Njc>^;mtx)&(4Zd)L#1Kwh%F@yPPsQAl-UUfk@ z4O-W&aE@SN#MasW9;LpkTsj=802J8U;Gs|AEbbQpTHK(|3|BbV4m#M{<;#^JRW2Qd z3&mKOyz)4{Bue10D{F<7!2fm9$j`;5xakSEo8{+%Def-{gHpN$qRxw&V)Z-FX|3Ws zVGKWr>%(?c`~uzfTsW+UCAir_tcRiPxI!3+!4g=4n=~))-V2A|3M8(R&D_m z%32D{9!CbQdZT?-Orbtf$|WP{omb^LmjIm$csF1PfsTUZb^d++!P$tGONOIqn%M7r ziT_JY3?nr`cX<_?nM>c++75I&#BW%$IrkWehKdVpeKAMQy|%tfZYNAd``WYhk>!S2 z0PiN)xfC`=_8&RELSZR#5DP82xm+@|eC0IG{lrl=!$95w7NbLBlJcWR<=}Vz$ zh!pg4$&m71#`v8+HYW5Kk3Jp1w#B3#DZud`7ZrnkoFxU4wuGt_usp_0Irj=I_TEjH zjs|Qukb5y;U&4LZe=6|h_Fp2#u2^6n8X(r`UFq95B7yF_O)z8Ca@Dy=$9+0*q{u=#(uWN>|5w*^cOE7;< zc6K@MRs65u#pb79)brV-MAZK<7z}Bxy1+&VVaR)MNdg~M)1YuG^q<4VLDbdNHdcS4 zTBY10zAZclw^a++EzBN;8z!4)1mFlO$w0qdH2+k&-dZPHOU9yGpP0Y&JsN8*8H28V zYQ9kU2)GqXMx*1Ong8}ZVyq>j(Ai7oKP&e*a${@BNZ8}R)@v@9l3mSCn1lWqRAWp2 zjW})PcUJH-F#@gLC0+JCf&_=-1f$SeyHr&9T<&Qt8Ri-Ng4EHst&#g$OCI;Q98y=` zGwV!i$xw9XMd`=LiYCfO8>Sj31#e81xF=Kiaz*kJ_nv zUb$0zK{&*3;+|s{G1-a{DB-9vHB2Ly4S+!i@?AQ}(bf52)HxangHYqQEM34%KeKvN zG|14B{D(_L&K^#rf(0f0p=*KX9wM8c4hWF@CrZ??d(qM(~^lte8kXL&PJn8Dvnwht*3T7T z&j3qZg@mg4e;2q}K{kRd%VDcP%`1g3!S***5WZmJ@_U6ZS8c+0 zbhCaGA$kze(OY5^7HtOE2|Z*&GW4Jx=u)2Hld9@(sO7Tmlx_3&tXf& z>jWu)9GzY(EuLdofpS~uc&H*O)5V$}|GgCok0zv3mWw|W`Y)w2-C?a;Q=s0i+OFIx zt`|1)qc{l;kbl79_)(awlgs9l`YfM0;X-f^Fh?3i^m9>^5z8Ed+1fsAmj~hCJcxbf z%K=FdZ&jSPvMG z{I1g0Cxo3wPk$cyh$9{@GsIQ3%%_N--^E!fi)~2zqwyI(j^W`#3wFBNf5z{0#3eDZk4nwiORe!uqRda(~N@8jq z*y2(zsZvqQ+f}{&1Zn4Vh~wU)UYI3p3%ChR0nI{$HB8bUQB5EZvk{q58z(yft$R0S zWL4*Eqgy&#F&zcfFpzf^gZr^J_q z7x?|0jorblRm_H2XrKTd98YvY>EmLq`Iz?bF)0|=p+-J|IYRE8pe;2tFW?i>zL&&k z)Mp+&;bPedA-BXwk|2>;=gBA1NoOj*UYnm40~Fgy8lD3qbK(#?BJiwL86#$t2@)e{ zK%MA7vS*||B)4bOoPyG?Mh(NvE|p*7BUO;EVQo0k9<7=XbL7GGAj&7&K|-J?6L4HC zO4jV)vHd^7T%-|!#8eMTUyhMav_!6{W{7{SYKe@`?DrG61MUFTdxOJCCoJ^TA{yg zfM3R*S5;YP{!cN(e3=PR|Dg1Bq9xsF-OY(9@`bM#yuILJ@I)Fp+!)JsIB(bQ!5~jdMa3Z12-1J?;3*}^}@n&NT zdgTkV-WLl#uLnuGFurE`!2$6?m`BL1`IjL-9k{YVJLo1{fS=SJ)9h7mQf*YO5oZZc z@e{c@>|ACl)eaJ%K`xA}Y>=Z>Rk0Q23nLz)dEovH$e6*w^nX%%gl4;d`KuqU*}7vk zjQ^h2WcdOX@A@pD&4O8(tT_O`|6PO~4CUZ|^x=CZd9jM301O{kf`y;^0VLL?7|OK)p@xIFDE ze<;F2PWHAU9XaqgiMOPc$%Ob8dj@C;-%<@qa)Nx#mmuB+2f5n;#Zhk>`RLv=V?dH2 zzQ+8Rcpv0{Onk?eW~loUR`%lU%>xdGgsnATCs|noAu3u10>hNR)8HsyZbE%zl)cIL z{CC|KG(C7_Ny;z5!($zVcnZ96zsbGIu4Y=nPdG^w;guAx)6M8FbZZT4XP>=Va}wIS zFJknA{m}H6i-vgG?~kY%=*m5qlN>ogE*gwSFtDysPe6MQL|k}q65zc3F?vJVXL8Na zDDkz3Q4jpcI$JIpgbu$J@!K!h_4Rbg?>0r|N)0k)>9mW*`XNO|%abx($kcKA-sBvjmk4?|0y z*Y-gJUNy(~6ibF!&qor*ypiDfDh&;^aYg<9`+RAdv2J3kxjc0D>WOO7k_DM8mv1$uA`l`rJVPY*Xai}TQ z2v_KT0kf`a+8;G1)Gw%HPR*&I>2^cSzi_e3lbPop z*A)+%DPc(h%_ic;qr!DXj`p+f~?{()^Jkm>*J$NKG=;#WhI2#J(=X<#pPWDwmG;tPbWkjtpi7T z&`JWyBWcOxWKbLlFf{OGI8;koZ;L{8D1}^%FElES5)~baSsObQt=S>fN5wCQ0(xRH6NTdr-u|KD z=Hz00odGwV0kSG4o7qAp z-Non3(e%%(I{hF#IpN! z0Hb@#r9GkZz%1L|J2 zyLgHwMO42hcet9vrpl$Au|gDHl>38vpeJTZgo)6Srh=9v)=fmAP5iJ})k$dW-=!zkxu+p)U#O-ltG;@a-t_1jmTU>ej%lVr5NX?w={pk-TP z4TuzPFiplgS_Xco0osw8KET4#|G*k-r7tDyEM|uiGM(&S*35@la+$-#f$kIl?yr0) zLVb7A6@h1?brWBwHo=i^Qts#O6hdLl>{6Hb~26pg*_FDGwFqG2# z;!}6pOkiY{S5%yH*(A1ZKu2w%4P}>88VvoR8-(#0U2t;ImQaKdS?l~xWXZRKr=;(H z%vEenji-=}e#mA5I0jCr^oc(neS_qcRw)Q6h2^DQa@Tpb?K@~Pu-l5$(uobF3mstF zDKtqnLivM)X*|FVT}d&3W1pNn)5N^ zEXxhVBhHh0&|55Ib7!Z7-l{`dTd23k>pX`@cj?dk>vGd40@D`bP3x@qVPY#0lOygf zOed_ClfApyb16=5KYchMmLDm>@5&a>LlmY%`4Z{#pFf~0`H)hU!jl@uEB58KRLdU{ zcO~3t?qPf$)PFhJ^Q@sLK`@FV#8z|DO&6Vx81Ir}h}as=TpSQrYVX&S zqe6xVS@cql%C_&FZF5w1Y;dKUPj5vtT&{V$P-*e=YjPHmU0>UsD4>v=F#yM%&$PYX zNF_lU!?Et)jzTHll2VQ1d;7Pr>_4`g26=(c{F3RQ@oB?e{jIv$+G(0nNg)aUx9Aqn zq!B_t?id5$EH2!OFjt~tz6!iP1?0ML@dAS7lsbsASz?0tXQQhaYt-2r3vjA#@gVvs zakC5EAu}`;+fF`^4&eQ6(xYO0MxC7)V7bI15QgQ34YanHe~Kgjcol>=Mv~D>hY0}S z1Bi;w#Q8`9;YfS~?Pmi}$gK-+SBiMX5lIbrE8aJ2y?BP022>LTykJ`Cf{ITIZR6V+ zdbW8YLe8qB2Mpw4k(6S%o4TNg;HxGwf^aN?p$8|s?SJn3NL|&IGC(KXNGa|LMlDG^ zW5MYMP7J4?Tt@T1cK@!DlquZI#Z;LSK#akdP^=0bojmwN4?vVu2rWll9@D?f|0#R@ zDRUYroj?9=BJl|j9|jAs2flTqz!Z$#Vh*(3-X%*;!k-mu9ADVKw0&c3w!E77d_t4? z5#+8uf+U5#x|?8G7Kd+evMv+E=1{zM1}~4uKC4N37ex)>2`Da&k%_>OE>dJY6j>+* zV5NDo1Xzi}YR?`UpP1{#W&-NtBUOcJLvK?qJ?(tw#|dmgvjpCc#wJ9d+Qp@5?nzPp zhWI-mrxEs6vJ0;UY6G00yp!XT47GDnl<294V>1v=h;{N?g z(>ynIVR^(Xv6*Vf;j$O{@Xz<)W>mVr@M#t*AHMInWgb))4jQHx8DDagX&2`_Hj2&U z_o}Fnyp{|-?PWjs6HT~?Xq(wojwt*nzJ4Wp9sA*s={j8z z=P~rKQSLOyh`3HCeTjtf4q z)4emA?wt>2#I@4WCAmVAlxY9T_BD!ny_xt-!f(uvo9=^$c!j=NSF2sDSpgsM4avyg zYo!X5aFIw~wBy~R28o{JKd+}byGk%&7h5Mu6<}|w%wNvR*V%gUH1l|shug(gx_9s{ zO6e6Nbgl;_Lec&Qqz9`@$w;lrTp>16??N)taJz{;wA_|PWI0{X|N4rp<8dhIMenW5 zM$jghkK<>Q-JUY0AZtZV8xHV_bQZzgLnx(v*| z!BojEm|SrK=K+TrOK_+U8G>r6I}C0$EhE~tuv;Bcr8@7 z{>s}Y&K}am*6Xp+Qt+0dUy#5q-92MG?}VR(0P>}W%0^;CFo2_>c)>s^G!>;lA>Zb^sM zOB}BMwl!OSZFvrUuG`G>O>>Mx4E^=Jbwye)?#Qo~SkBur`{>@KrZvx~48dJn`(Q88g?n#dyT^PLsxBXAfR>e;21- z06o*j_HS`!u|I$34#anMNXa2H7A|P19`EPhyB`W&QIv?pe)E^C&iVAKK1X|Be*L`UM`I(rxC& z+u`TxiUR|=k^PwUHqW2pToBlnXZm8G3l=EMZ(5Kv_R((RjqH23{#ru`1(FW@&P@5S zT>;l46|oPSz7f#TY{7FfUJyJIgs;O$fq99d{Y;q-T9Vb@TLv0&6iNp0LJMOkGNUxO z<2xn7cJWLh({4{fJ<~-6u!BEInjgQ$vROQHEgN>H=VY9Du418hrZ?UkxLnv_J7Tm) z(%q}rq36xF$F23y?)Ji(Ra8i6&tcOzJMkVHctCq#cx~ev$EMpKh5KaGirn-OU5co` zIIX~t+~2ADr6y^H<7xXh_Db6;wgl^JOS7eC;4+)IIM48F6eAk1`=xHC zX1`|t^JNV+I;)V?Xfx9b0NCy86=~qXEKj?cevS>3Z9Vr$!*l4pPHHxV60hcTf=_#tK3{dl7(QzLP8@j=`a-W_e;lJvsuv+ zz%0t|&&*cL_3(Cit`)z|eblM=eevOK_+x$jI9Br&7;avD!L@>|`IjkAIhTUN^(tBMM~;A;*8WVYjFU9R#sy$^3;x1KX~XU7EZe75%Yx*G6!c-!^jDWNhEFUGFh2Qug z_>D#I^H%D{XkB=BFBzeeoiUS6cDW?HZk@BL;QTvdiYR3*@p?Ewj3U9%f8 zHUj@D)T=;({^ZzCe!IaY~h2o|iWqD|=}r`l>B&? z7U8!-5Mjxy$NT8}Y{sKffCnK3rIS9s2@v{(Y8q5lhPcv(GN-U+VVBwF%dD`%nwkk2h1S?Eq_yu*E8XW#~740u{BZ-=wqG z?snSc>?ai@IM&|3LV3oo)?)~#t+WZ`@u?+WfiJNtqPn~*k3nTVL?5{vV`xWNal$vM z^!UkRP{Z^mi~eO{H)4caJ({~6Nbx9IUsh*S*L)CU_rRcAKT+X&m(fKI0^*lmwU^|Eo zl=5>_GCx&h(dT-e5@|RKAu{ZzZNsvD_=MY?srIyXZI*(Kv0m^OvBBSF{a2?!#BH4VL-m7`!- z1f6qVqI2%XR=w;x$n)MJKM>{#{yuE<_gO9SKg|~W*Rh-{S?@;vNd%R2A-jAfOF<>7IBld$4VHc@;dD!vuc;TYb0pdAZdB!QY+r-RXT#{wMUF&yw%){yic5 z%DtGIJwR&@T#L*&@HES7YswWT&+xyrIlI^az1o zlz9koQ;|; zN_r$>0J9W;Rpi)=;4d07Ny8!*-s$`cVO~q&1m&pJ7@kmth}q)l;Sd4n@Yva55thqo zpR@gUI}->*jQX`C`-_+&D7I)6u#DMbp&5P~5qHJhs> zI7-CRLot%->V<+mECQ6BIme;kt8;CRY{cc z{2!5pCuA|w%TE;$^O4PvYuA-&9G6g1;U64tQIoLLe3R*B z;{@<@^wyPWAA*Z2OP36K)l;Mx!_1eW6wlN-x3keHIy0LwFO}06D8GY_l_#BestWSL zN-leBv-4+kpeetQilIVjhywr064g{(r+8{Psklg33)y$S-Qs-CNZFtR*~OjUsDfpu zJm0cNH9f>2o?3=MhB2`0Pg|Y)dBkZ5uQuB`z7L^RJQY%trKS70-noa9gz90$aif_^ z-6YF~ftnKI5>JJ-W1jFE_T)}`(e_dvu%g8{o|H0(a+c8_jXYB|o5LiY3Tekt!0#RB z;iCG%)BU=Ak0kNz*C>o%M4eT$e5Q)07E6o|^5oREFI_yfC}g38w(rTt)JA}q$g?1v z*Sgs7_1X3)gHWwot$3=U4GV2ECCeAy*J@ZLZSIS(}$++#`_GvHKgko>3*-%YiHq8&)3?8-i^yb zE=oM9mu!xjHcm?UvG3ow6puN5aqy9%t=&=2{(YA=%17Fxv67v*JN*geua+o(1+IsB zmMmr}T-hm&i&^h`((jG1AP93C7jdmZ7)u=$P0&}812>VaZPv|p$cm5PYD5j>d(wBy zUfh9=<(Lf=K>DF}oB1ha^WKdMS;~Fs3I}#p<8AEK`_dm#_;4E+u!Z+4+w^I?mDzTs z|3cYjK6_=CvW=&49$T?HeUChlyvDhFAf#rp^S?s=@xSiW7br(l+Bk>(=7IFz$iK;K zoXvm3m-pkl^!F;8r#H@GCz9O_a`U{#TjVZscj_NdHqUFE$*igFpUR`oYMj9irMeY! z?a_EMo8Ha+L}BRdFP5+-dX3|c_D0*&*56uQOnfXX6b#4b&@o=Zli z>hWp(flx_Vgx@5}cSrCEi4HTD?;pUFQtnR(?Nb8u%JHfE_KjpIzAbb6(PzvN&uxB` zDjuH_D=!iJ-2K_~+fvHjj z#9}*1hajqSvuEFS^Rfex^`RRx))3RgzBdaMm6tyfXkSa;hM`y(L8)?wlH>hjqC4 zbUX=c7|Ezb=3x#iN;77$gTK{Y$EJO2x)woyPVNcKBZ~ecGDWqat{0CJq&Wgbh3pJ= zXsK}u%eoA)rTdPU>G6z8eUL}2c9PBF@v-be9xx7$tsW~&zR7qC`yfB_R=WK=8WQ~I z#|g3=j*~M!q$ewNyCpVl0-v%&^=)`*`>Jf=VDUKNlK~G9cp>fZd$*?`^IcuhVA9vT zY|WPzP6ZJeni~6Na*yPFxpqU2L%Uq#_`UsE+t0uVelXFOaKQW%)BQ%luueZuH&@Gq z99!kyX$`nqR*5ZXe0_5`hXY$(>)lJ}<~$_+QCyv>i2;%jU00|>od-z=EtKpQ&It(5 z>fj#RBY41t8oP(BtifH;p_g4advLoT~* z!3p;8q_j>D;2FdgN-YcHZ=&l;T>5KPdWzCcljluWOssk5i7iQ3Pjc?Hts@boDyb;H zux(l-tX$7-QR-Zq(h<1(q7xrFS~OIPXpvIKLih94)gn09u~UPr7F#GyjJt+Id?7tZ zk%%e`ky8ZbCX5p4R&eA-xhCXgRMCKu=FnoLiV*M1Cs?g%qS#`Il~*MHlJ1gNdv(3o zl8C*+IZ{a_B1e1_G)x|N$K*071j9@X=I3m|jZhbBYKF`wWvlF1+G^H!kNF0r6K#?Z z+`wH&wZ%xF>EW$rStralNtZDeuz#_zO$gS)iAF4vHQc?l;34xr6n;8kyAWJ2ImINF zuu~5A`DoTMu}lcwjwZFW;t)jq*Y@((vJq2VzgI|sqcpe@}m(mxpg^MyI2cArBW)gy{(GCnUQ_1=E(1c1hN^97q6tzhRR!gEJYO~kR zW&TZ8@5cziRa{q}LBD5feyKaC{PFEVa3y}stMbv`L6yH+s>gRM;Hr|xVHbic&<-w4 ziDa$l*SfD2a>PO*ScSjCD^|z*sd-lC<)!x6yPss9jW~+;ol87!3ogfisKOp~h=y+} zmKLt_;4<1~UPF%>fO-B6rIWE-2rk9%sY)LGx#%AAvPgxz30FC9wL-8GbrR=Uo2ri-SU^J2Ad=UHiZ+R_Lo+&bQVS^A{EQ#pBTh#n5@w{?CONAg=Lzqx4 z7qBOxMRBr4oe->$R?c3_*6vPsv3K9dXyLSSvO{-<5G?1rRC5cpS_b|DK#N&)8Yp zC6@|#96RXnk=V}m0;OfatE6GW90d2O$X1V1kvPl#uT|eUaYW~CZ1RyZ9~N1J&CeQMv>Ck`O%|;+oL;(Hc}?WGEzD( zewcV-9iFH*7E63P2=nDc4OUpqe3^8$`O@hD!j?I)7P32G%ix$q>v?f4G;-`t5KT_I zhRyY{44Y2RMKp^iR>!h(fN0@XPUj`zOjq+24{Ka7dWhhU8mypdneh#aw$RKhan zyK5A;JSkISd5aL`>ZvPfk}@T~M^lC14d{qsJtZt@ySIv>JTnzS#8M$R210lQ2Tw^8 zwBwv8Eohw(yq-4@q^EUHz_E<&c+$8*Aw^g#1k2Ef0yF&my|kfw4a>C{5FV{{4WhWr zb&BRF%orSv<~$lh?^p7dx(mwZdVvreg<)4$*K%n{YDe*b{2;zMDO3 z**Sm4w&>+|3BeMyfdVb5o97>QWV3U>Gu_J8er&v3xjsGlV6n z!waoww&V2-3!C<#>7a5!mkYtZIBE6ugfw|=j%O=dv)7u)_Rlc%+V^c%p}b^Rkv@?X zfk-6htY#yB0DgJeW!*OAM6lo2g(ku~pMIadmW}>%hKVJ+joTD}0>t8jh0--}3%lTQ zyO2!7lU#nIY=pbwTB*^DaHFUBWr15cyfTvRRibgcZQpFGwJx!YN}LKFuToR7;k! z=qu+IEPD-P$?TgOU8~vX5y>}_?OV*_f-d-?qUgY6f1P9rTo-`x%8WODEBZ#m@=A!2Q&J}%gNwe&ra0JUf;#5de85o?fzBzngA&n%u znxVv?JKC*u%d1J!h(4)GPP>&0oiGZbV4;!us_orG(KjnpG$PVg%?sRL^ilolc8W&C zvPpQsGbxv&?Wt$yU)B~8E3iK)&2DjP5;Xla3D=r>8~R#qb-ZkQN7sktZOF(>zGLGZ zeaZJBOue%{gDyb$K87&IfQ*!;-HS4RstsLhB}I4C-_ZvR>mm(TXQqu}^HygbW_=cC zPGq-MXC4f_Qzb=BeV1f@W;9qI(Ts&5SLP50+;J^_Tq$%DM`R%1rQ9}%*`74D^q_A8 zV3gu%m8+LjtzM>}`3PTF8jY6a9rC6>Kdm8K>$s!pj_V)@{*yZ^A;{mH!>>llzZKePgZ=OvIn- z>Sl1S6$)$DvWD!0X^NKu=&vBL&y$WfgH6wHZ)N2(O_qHb)-AGL2ffA2@9M=|PRgpJ zbugzb*D~ad^-;VL0&H&+gyFqM;Q)FO|C6|s9h+=gp?HJ^_5ZH!h z_4U#QUi>a`GyC8T<6LE%$wHtWZK|s3C2j6K^HNs6+b~1fW`z*giZ*q1k|PKyUUh8R zqlN`a{b8yQ*g_+RdrR`4G$r|rgSCqK0s9UaAGZZILl9Cs_#?mYE#s5Q*<)IDSit&v zu{SMXlmES}fm%5@zg7rr!kl8NaDSe?r3<^vHHliKQNg?m1p(L|4 zN(+NODX;-8BL1Z5Cyi&65;h8fTB#@QaozXltWV@Ku~G=E=c_9D)z(Z%dna1@LLorT zSd7!o(V)}6NmMm1!5{cVqh>&VHGV7}7)je#8tRFbhM${@0D6Mr&ElA6yM=!O$KG z17@xexCMj_&0O#c*KE1g1z6lMJxp zOIiPu&*oquFd2U(UnxI$sP5Jy{6ON^RSAKc_>V(N*YBSRL8Wl4+9XN1v}!4HOc#_l z#c204_P|86AnY+8BU&JVeXi*>rVJL-)=<8hKm>5!uA*{8~NEf)ee^0k+M-qV|0f8;Rx$kGV) zLVz3$_?|+aZH;Xa?PEQ+%OVF}>?s6pKs&(oh52lBW&V2hvz9z7D_>~Zr|j?+AuvYT z>;bgdc>|*B?aUJb#%QY#78SG{V`G{O_+1)*n;ur$Y#kQz2}v@7n-XAbF_%PDLAnWRq6` zZKPXq^kny+l_SLiG8`k7aQ=fh&R==K=!L+rkbN2&#G!8Kf8}c``vmrP`-3$=UWKZv z*@6owd5a6ATCVhEJba?;ZI}=k!k1Ngi5ecZKe6}XP>XWF3xoi<7l;g*-_G0rU$?iE zA~2yr5K&(*eTFFB^1kxVHw%G*d_J|(=l(DE@3=!Na#H9MBZmSV%vxIdJ&Uwk*us&C zn-!yg`5q_@&zsyF{=Bri*s-U(ZC5r*6apcyf`_YW+Cn>uDrKby+J=pU3L!vV1^Q$r zQJ;Ccz3)UuL@y_~6QD3iS03bSW(_$;3oEKI+^XymV=qEW+@R9+fJ!6s^+0m^;ja`% zLEX#+J5;P*wpt;Hdb`jxJ9{|qlG{ptR_OO z{7Jpk$NUtqtlq%r zDhlh{JpD#9L6fAje_}V=43=*!xry@=ZZJG{_Jfg^j!Ls`^*>}6W|BmW4qv@*$l)X|j@4hm-qE)Kk_cVQ5X1B=W z5Jn6Bbe1y4{*wG|%oP0Y$O0o3C%nLlF^DF?pT-W}V80R>0|MNB7dtZ6{+0Ysa|FMW zy>g@dROFv%ExNIWENdD&G|sNb=BX3>sqCfk_Dk0(_r;+dqj8+Hzij)h^`PYi1kLKq zt4-^SV^M`_tnLQwnCHtHahQQI@VuHxFj&>!nCuM}j1%4+$law>xQ$mDq-;{I@TRYH3B~m5E zUy>Pn?mc7AUF;>c7+{`D6rMy<6;0vE{@9%AO^sq5>v%mkiY=5nACs$-c8K-cBtghJ zTt<`FLK*ZO(Q~?4!>dXpyvjxsRE09;V>5DAp#BEieV%hS_1v_JN7Q^WD}6a8EGaq|d+l%Od{ew)oett@t7 zWtsvzH$3*-=_*gsOecDa|FeB(Gg~c|#KbJ~ho(On{f4*nZ|m;V)@Y{VA}=(G8RFTV zY|q1%Zme&u$HKm~JKjN*FnsxRk{ZDwp1npoh|6f$tn5?IGpzh5>RJ`?x>gg3n@0(tn;kZAx2^ zRGgzUh-bT_gGgcv@8H$XJiFMT{#oGPJnBjVxo51ztIl#DZWPbvqld`VarAS~UNCBB zns~7@BD(tV)J&pPJd4T^o1Gc#gS*o!+4j<``ElbEi!PdwlBwu;SS)ekMXb=6)&OhY4`qzldG>)Xl4p|M>4hSSy~*lvaoz z>F`CA^11z9;B|_tQ>lZfdo#}ASBqyecn1LNEAWvQic^7k{;%FJuL#MOAfg9Y7$>g{ z{b784A&zm@i@u-~NZ;oqmp6;b#O!4LkIm_z(kkh~;f8Qe8{zvYK2kJ*$43@)Nji{D z8k6oLO~Nkoa?_2*KKg&_K9c`eTL|^+Rb4W{3-Y8fNZAipr6Ij@-klsL_ak66x$Ko| zy_sz2E$$2PqcEJ}i5z~jw#mAxndSbC9-wBHw=vg!W7H9f5BdNiq!Xy2O1GlKxpuia zABAs^q@IX#ra9t?EF|ftei0vL2!s+R=o}cx$W2Y`<8$hBqfE}*4yV=Lf zTn?nh#(|d7XiQa2#k0+orhP!imh{#*{%rT#-mo6AJe#;T;UV(@K-!88J@h%cUfOI; zZ@kC&R((`28~Ai-_Yg;`NXI_Kn}{0z7-?S1#l%L@h*^upf&@u=qq6#)p-9bH|-aDv|_gC>rWv>JS$mT z#Ry+@dv0_zLEYloDe^;P6j zMB0b?Cik(S;+K_H$`oO8kc2i5z$`gIPrJFBi21R5ShQ;0m zNsHg3ah!t||El$E%dy0!gg4EnOaWty;Zyz7x_#P5HEhp0$Esw!oo{LQp>grAgA{Nl zi&j0!f{G6Uuu=4pNv5K0vit6HDZ=$?N6#wywzbhJqrNV+&vcmRtBh0xQuZgUhb_NMJe=^n`5Ds##-AEC={M-A zwbhy#@CfvAi!RYeAnV%Np8PHepRVEqS+}!`_1Zy1oKXToLbm52a8%%A#7WX-|n$)Yy?(mmIMJ62#f>eiZ?C_A!733UX-H*E5DNzgyk#nm8 zMic5q-)e}ftYj&F^rW#N6ZBvzz9wgG)Xk&vV=+_oRr6b4Lb9P!;j^ghK|U<@!g1wC zsdheaC|B{`Ll@4GBJVD$po*KOm=UAazB`q#kJ_5JMIRCPVNHs8rK_y65=w15*DL1; zJlK*FkAyZNaRF#5?HV;XSX+ssB$^!heD9n`O;|}>4iekOf>)L3EtMk+ubi)nymBYy zBdfL!HKLCg`?w-RiI>eKum_Wybu-z>m08#3qq=Dk4_;sdl$RH0A~2MZWu!i5vI*aH zFK2IGlXh!|LqZaUk4Q&Q2$_Ex?8AZHMl+TW-`fCoV5`nWk8EtPm>M|FEBY!!X%|@% z;~j){-*l?mZ$eCy1QVHkZ+bL)29phju8jNHy5*v~IKP zOsr41$Gp?D%Q(%jL_Z%f4VHH<*Ryw8!xba+#+Cxf(s`oN`-<$ICG9na=NHLCE!{(U z7pJ9TKUwPiE!CVund9jr(%f-}7I43`kl!tQzp$od-u(vRz+pT3!gf=oz@c@GF+yl3 zE#wJ6GRz32n^!2v-J$Kz^W|B3W}1S$hP0#@g2X{$OKu2SiSRENO;1&M|1GZ&os<|q zgR{Lw@~nkuC9bTblk!Bu6qd8sb`8ja`hH>YI*~FOb+t!a?rLHYDI$+r*mPkK`xEIo z1#Sc0F1BU7WK?!2X|32oZnMb4+{Rc2El<>q9+5}aPK*iD5z16ImLoq`o7g(BMRJ41 zG?qQ7$PZSS?h$cnqtS{j-k2tHhrcw7Egs2ajx;5cIo6c3#g_E;OlG_!=_#>!bkt7U zc(KKe4-20``=)bbZ0*J;wjxGh|I~Ke8npa8@nFK!<|jfEr)Pj0{bVlsQgb%P zGEL$VPS>kaxYACU+$HI>_;kxg?#7r#OZ-W5h2lx1BEy1-&%X+D<|O%7+c#(8A5MmN zGK1ST@f{*qFDEIA&^ha6W-RNa)B7xJ5l>Q30d(Kor5iRoqD+}#SDP}O?qFY$d5AUW z1r~;|W=PM|KImD`8piAAv*fo^J*=o#N}3EWDiMMn4x5oOwix)00T?efzodYu3uA>~ zIzTOzm4LCc{aWv0mOR8Yj-6U+kHS(T#hkD&0G>*i$-i_@V-2sE=MYrg!bT5ujck*y zxKIeD;RnD{g@3S_{ctgFd^8A*Kz1|nfN7yKu~&(~E6$QmvL9lTKpNs1Ef*;?u>14eZz5oCzng`nMr zArX5n2)hAWYf2hnwnimfRtP~G#1QU}gLP}Z&-)_>2g<`iLY);&2!O~zX((hK;CSjN zU{R80geFPvFxj)MUt2CD{w3jz`EAo-;~~Rq`gOXg+A++Zo#-)&TCsUSEQKY`5RO@F zzLje)H^%kc!291kzdcnZ;{A`apx1b@d0t2QO#DwRY6{Qgw?dn^Kt;R6N^z|S46|k_ z2})603dX%6NN|0uAVH^Z9gQ#=zLbt143-@6G7qIhGJwqCMhuMHRRb&=&oq0G|Nt`+;PZ;XgwV z3oMQ=+KJrRDOATWiw*m=ZW(L%qetP|Q*lg^*LyO{e#7&R4hIiJfsZIB!-#^g+NUi{ zei9US++jE9s4_OD7S&D{eVl6&S!9wUCM*hMNq4jQ%jvyzC4*Q+I(J#c$@2-f?L-U` zHJrfbR{|ST;wX25J+2#^{G0m zRtJ~GM-+_p)8WSXkZ!izFM%@1S(WsF0Z8cx5;>|SWrwI?s$Vk&LffsxOODOhelayy zDN4gk<{FSos^HP42rnBlSqU6gb7!Jt4Sf)*Rd?fdxKa_ENqnzD`ScHb>qb63h`5WT z>a7`R-T5huc$(B)ZM{YRL|#)@c8aPs%@X|+A{E;La(gwWAP~!Rz;SQJtegv{cxhB9 zATn0Ey<>UoFaTmxRg`55%A;uKM|7%V|441oiXU_QS3D>jPz(VF6`uO-dP$v!^m3CdTl+PmWs zeK)Yb{mJt$xoJDE`xx{fz3%BO_g&BP@{iQy1B7xtvsZY(l$#dBzTmKIzB0%MKpHnT zyYMGG8zVnYtYACV{kO-F>uHv~h#4KtN*R_q8<+lp%)ibX(@3X`Zs zn7q*ejfgmv$ppl|JK*R^4V+{)xLZ-U^_0 z@oX=toOaG9o;PMCi>i`wP^pwyFZUi+q5lq|Kg2w9XG(g|x!J&LUM0R!~c zL*mwrOi8UNsEi6?a_dHZsm9Q9z38K8a(mpmVE2hqyCO2x76r$c;wRx_99H`yiF#yK zt6^Z&HVrZiyBTcVu3ROqLBp7HYND}4Wj!M&u`_2PwmVzU2nzu>QL&gFyS01%_ ztKG_3qA!Fm7y3|+LYox5y#7Or2h+C)w+b*U{i=Tw=Wk2{6O~CYU z=f`VP+FYb6drnrPghQ89+VGx(>TMnS;gIP%T@gnoc-Sa6QoJI2qq5yd*7Hdr=@1Rl qTU(QUZYCWIQF~T%ugwKCoC*|0MZZAap3jSu9+kHj8HWn-{Qn0t?C5j= delta 58744 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 diff --git a/frontend/__init__.py b/frontend/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index c7508ba..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,342 +0,0 @@ -cat << 'EOF' > /home/puh/scud_orion_ai_v2/frontend/index.html - - - - - - SCUD Orion AI — Context Manager - - - - - - - -

-
-
- -
-
-

SCUD Orion AI

- Context & Task Manager -
-
- -
- - API Online - - -
-
- - -
-
- -
-

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

-

- Для вывода возможных команд управления локальными системами, спросите об этом в произвольном формате или нажмите на кнопку ниже. -

- -
-
- - -
-
-
- -
- -
- - -
- -
-
-
- - - - - - - - - -EOF - -# Копируем файл в корень для совместимости с веб-сервером -cp /home/puh/scud_orion_ai_v2/frontend/index.html /home/puh/scud_orion_ai_v2/index.html \ No newline at end of file diff --git a/init_db.py b/init_db.py deleted file mode 100644 index e279610..0000000 --- a/init_db.py +++ /dev/null @@ -1,78 +0,0 @@ -import sqlite3 -import os -from datetime import datetime - -DB_NAME = "context_memory.db" - -def init_db(): - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - - # 1. Таблица трекинга задач - cursor.execute(""" - CREATE TABLE IF NOT EXISTS tasks ( - task_id TEXT PRIMARY KEY, - module TEXT NOT NULL, - title TEXT NOT NULL, - status TEXT NOT NULL, - priority TEXT NOT NULL, - completed_at TEXT - ) - """) - - # 2. Таблица архитектурных правил и контекста - cursor.execute(""" - CREATE TABLE IF NOT EXISTS architecture_memory ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - category TEXT NOT NULL, - rule_text TEXT NOT NULL, - is_active INTEGER DEFAULT 1, - created_at TEXT DEFAULT CURRENT_TIMESTAMP - ) - """) - - # Первичное заполнение реестра задач [TASK-01] .. [TASK-17] - tasks_data = [ - ("TASK-01", "services/data_loader", "Исправление KeyError по ФИО в Excel экспорте 1С (переход на .iloc)", "COMPLETED", "HIGH", "2026-08-03"), - ("TASK-02", "services/zup_extractor", "Перевод подключения 1С:ЗУП на продакшн MS SQL сервер ACCOUNT-01 + гибридный фоллбэк", "COMPLETED", "HIGH", "2026-08-04"), - ("TASK-03", "services/scud_export", "Инцидент Равина В.Э.: Фиксация 100% приоритета сырых логов pLogData СКУД над расчетом УРВ Ориона", "COMPLETED", "HIGH", "2026-08-04"), - ("TASK-04", "core/database", "Реализация схемы SQLite WAL, сохранение снапшотов и маппинг колонок (department/position)", "COMPLETED", "HIGH", "2026-08-05"), - ("TASK-05", "core/database", "Исправление бага дублирования номеров снапшотов (переход на вычисление MAX() по суффиксу)", "COMPLETED", "HIGH", "2026-08-05"), - ("TASK-06", "scripts/fix_snapshots", "Создание и выполнение скрипта сквозной переиндексации снапшотов с префиксом Y", "COMPLETED", "HIGH", "2026-08-05"), - ("TASK-07", "scripts/db_cli", "Реализация CLI-инспектора БД и выравнивание номеров срезов для идеальной верстки в терминале", "COMPLETED", "HIGH", "2026-08-05"), - ("TASK-08", "main.py / logic", "Двойная проверка исключений по department_scud и 1С, удержание 100% приоритета кадровых документов", "COMPLETED", "HIGH", "2026-08-05"), - ("TASK-09", "services/text_reporter", "Лаконичный вывод неразмеченных сотрудников с короткими аббревиатурами отделов СКУД (РУК, ОИЗ, ПУ и др.)", "COMPLETED", "HIGH", "2026-08-05"), - ("TASK-10", "services/scud_export", "Внутридневной контроль: Извлечение полных цепочек проходов pLogData (входы/выходы за смену)", "BACKLOG", "HIGH", None), - ("TASK-11", "services/data_loader", "Внутридневной контроль: Расчет количества и суммарной длительности отлучек/перекуров сверх обеда", "BACKLOG", "HIGH", None), - ("TASK-12", "services/text_reporter", "Внутридневной контроль: Вывод списка системных нарушителей внутреннего распорядка в Markdown-отчет", "BACKLOG", "MEDIUM", None), - ("TASK-13", "automation", "Автоматизация сбора срезов по расписанию (Cron / Systemd Timers на 12:00, 17:00, 19:00)", "BACKLOG", "HIGH", None), - ("TASK-14", "services/notifications", "Интеграция Telegram-бота для алертов Администратору при массовых сбоях турникетов (>5%)", "BACKLOG", "MEDIUM", None), - ("TASK-15", "api / fastapi", "Создание REST API на FastAPI (/api/v1/snapshots, /api/v1/scud/logs, /api/v1/anomalies)", "BACKLOG", "HIGH", None), - ("TASK-16", "frontend / chat", "Веб-интерфейс с ИИ-чатом на базе Ollama (Qwen 2.5 14B) с поддержкой Function Calling к REST API", "BACKLOG", "HIGH", None), - ("TASK-17", "core/memory", "Создание модуля персистентной памяти проекта в SQLite и CLI-инструмента для фиксации архитектурных решений", "IN_PROGRESS", "HIGH", None), - ] - - cursor.executemany(""" - INSERT OR REPLACE INTO tasks (task_id, module, title, status, priority, completed_at) - VALUES (?, ?, ?, ?, ?, ?) - """, tasks_data) - - # Базовые правила архитектуры - rules_data = [ - ("logic_rule", "Сырые логи pLogData СКУД имееют 100% приоритет над расчетом УРВ Ориона."), - ("logic_rule", "Официальные кадровые документы 1С (отпуска, командировки, больничные) имеют абсолютный приоритет над отсутствием в СКУД."), - ("scud_override", "Запрещено переименовывать ФИО сотрудников при 100% совпадении строк между 1С и СКУД в AI-верификаторе."), - ("formatting", "Температура указывается исключительно в градусах Цельсия, скорости в км/ч.") - ] - - cursor.executemany(""" - INSERT INTO architecture_memory (category, rule_text) - VALUES (?, ?) - """, rules_data) - - conn.commit() - conn.close() - print("[✓] База данных контекста и трекинга задач успешно создана и заполнена!") - -if __name__ == "__main__": - init_db() \ No newline at end of file diff --git a/llm_agent.py b/llm_agent.py deleted file mode 100644 index 867274b..0000000 --- a/llm_agent.py +++ /dev/null @@ -1,474 +0,0 @@ -import sqlite3 -import json -import urllib.request -import urllib.error -from typing import List, Dict, Any, Tuple -from datetime import datetime - -# Абсолютный путь к базе данных проекта scud_orion_ai_v2 -DB_NAME = "/home/puh/scud_orion_ai_v2/data/scud_orion_ai.db" -OLLAMA_URL = "http://192.168.11.3:11434/api/chat" -MODEL_NAME = "qwen2.5:14b" - - -# === БЛОК РАБОТЫ С БАЗОЙ ДАННЫХ === - -def db_get_active_system_prompt() -> str: - """Извлекает активный системный промпт из базы данных SQLite.""" - try: - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - cursor.execute("SELECT prompt_text FROM system_prompts WHERE name = 'main_agent' AND is_active = 1 LIMIT 1") - row = cursor.fetchone() - conn.close() - if row and row[0]: - # Чистим от случайных звездочек - return row[0].replace("**", "") - except Exception as e: - print(f"Ошибка чтения системного промпта из БД: {e}") - - return "Ты — интеллектуальный ИИ-ассистент и архитектурный координатор проекта SCUD Orion AI." - - -def db_add_system_prompt(name: str = "main_agent", prompt_text: str = "") -> dict: - """Обновляет или добавляет активный системный промпт в БД.""" - clean_text = prompt_text.replace("**", "") - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - cursor.execute(""" - INSERT INTO system_prompts (name, prompt_text, is_active) - VALUES (?, ?, 1) - ON CONFLICT(name) DO UPDATE SET prompt_text=excluded.prompt_text, updated_at=CURRENT_TIMESTAMP - """, (name, clean_text)) - conn.commit() - conn.close() - return {"status": "success", "message": f"Системный промпт '{name}' успешно обновлен в базе!"} - - -def db_get_tasks(status: str = None) -> list: - """Извлекает список задач из реестра БД.""" - conn = sqlite3.connect(DB_NAME) - conn.row_factory = sqlite3.Row - cursor = conn.cursor() - if status: - cursor.execute("SELECT * FROM tasks WHERE status = ? ORDER BY task_id", (status.upper(),)) - else: - cursor.execute("SELECT * FROM tasks ORDER BY task_id") - rows = [dict(r) for r in cursor.fetchall()] - conn.close() - return rows - - -def db_update_task_status(task_id: str, status: str = None, due_date: str = None) -> dict: - """Обновляет статус и/или срок выполнения задачи.""" - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - updates = [] - params = [] - - if status: - status_upper = status.upper() - updates.append("status = ?") - params.append(status_upper) - if status_upper == "COMPLETED": - updates.append("completed_at = CURRENT_TIMESTAMP") - else: - updates.append("completed_at = NULL") - - if due_date: - updates.append("due_date = ?") - params.append(due_date) - - if not updates: - conn.close() - return {"error": "Не указаны параметры для обновления"} - - params.append(task_id.upper()) - query = f"UPDATE tasks SET {', '.join(updates)} WHERE task_id = ?" - cursor.execute(query, tuple(params)) - - if cursor.rowcount == 0: - conn.close() - return {"error": f"Задача {task_id} не найдена"} - - conn.commit() - conn.close() - return {"status": "success", "message": f"Задача {task_id} обновлена"} - - -def db_delete_task(task_id: str) -> dict: - """Удаляет задачу из базы данных по её task_id.""" - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - cursor.execute("DELETE FROM tasks WHERE task_id = ?", (task_id.upper(),)) - deleted_count = cursor.rowcount - conn.commit() - conn.close() - - if deleted_count == 0: - return {"error": f"Задача {task_id} не найдена"} - return {"status": "success", "message": f"Задача {task_id} удалена"} - - -def db_add_task(module: str = "general", title: str = "", priority: str = "MEDIUM", due_date: str = None, task_id: str = None) -> dict: - """Добавляет новую задачу в реестр с авто-генерацией TASK-ID.""" - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - - if not task_id: - cursor.execute("SELECT task_id FROM tasks WHERE task_id LIKE 'TASK-%'") - rows = cursor.fetchall() - max_num = 0 - for r in rows: - try: - num = int(r[0].replace("TASK-", "")) - if num > max_num: - max_num = num - except ValueError: - pass - task_id = f"TASK-{max_num + 1:02d}" - - try: - cursor.execute( - "INSERT INTO tasks (task_id, module, title, status, priority, due_date) VALUES (?, ?, ?, 'BACKLOG', ?, ?)", - (task_id.upper(), module, title, priority.upper(), due_date) - ) - conn.commit() - res = {"status": "success", "message": f"Задача {task_id} создана", "task_id": task_id} - except sqlite3.IntegrityError: - res = {"error": f"Задача с ID {task_id} уже существует"} - finally: - conn.close() - return res - - -def db_get_rules() -> list: - """Извлекает правила из таблицы ai_knowledge_base.""" - conn = sqlite3.connect(DB_NAME) - conn.row_factory = sqlite3.Row - cursor = conn.cursor() - cursor.execute("SELECT id, rule_text, added_by FROM ai_knowledge_base ORDER BY id") - rows = [dict(r) for r in cursor.fetchall()] - conn.close() - return rows - - -# === СХЕМА ИНСТРУМЕНТОВ ДЛЯ OLLAMA === - -TOOLS_SCHEMA = [ - { - "type": "function", - "function": { - "name": "db_get_tasks", - "description": "ПОЛУЧИТЬ СПИСОК ЗАДАЧ ПРОЕКТА. Вызывай ТОЛЬКО когда пользователь просит показать задачи, бэклог или список дел.", - "parameters": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "Фильтр статуса: BACKLOG, IN_PROGRESS или COMPLETED." - } - } - } - } - }, - { - "type": "function", - "function": { - "name": "db_get_rules", - "description": "ПОЛУЧИТЬ БАЗУ ЗНАНИЙ ИИ И ПРАВИЛА АРБИТРАЖА (ai_knowledge_base). Вызывай когда пользователь просит показать базу знаний, правила, инструкции или промпты.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_get_system_prompt", - "description": "ПОЛУЧИТЬ ТЕКУЩИЙ СИСТЕМНЫЙ ПРОМПТ ИИ (system_prompts). Вызывай когда пользователь просит показать системный промпт, инструкции ассистента или промпт из базы.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_add_system_prompt", - "description": "Обновить или добавить системный промпт ИИ в базу данных. Вызывай при командах 'задай системный промпт', 'измени промпт', 'обнови системный промпт'.", - "parameters": { - "type": "object", - "properties": { - "prompt_text": {"type": "string", "description": "Полный новый текст системного промпта"}, - "name": {"type": "string", "description": "Имя промпта, по умолчанию main_agent"} - }, - "required": ["prompt_text"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_update_task_status", - "description": "Изменить статус и/или срок выполнения задачи в реестре.", - "parameters": { - "type": "object", - "properties": { - "task_id": {"type": "string", "description": "Идентификатор задачи, например TASK-17"}, - "status": {"type": "string", "description": "Новый статус: COMPLETED, IN_PROGRESS или BACKLOG"}, - "due_date": {"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"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_add_task", - "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"] - } - } - } -] - - -# === ОСНОВНАЯ ФУНКЦИЯ ОБРАБОТКИ СООБЩЕНИЙ === - -def process_chat_message(user_message: str, chat_history: List[Dict[str, Any]] = None) -> Tuple[str, List[Dict[str, Any]]]: - if chat_history is None: - chat_history = [] - - current_now = datetime.now().strftime("%Y-%m-%d %H:%M") - user_lower = user_message.lower().strip() - - # Жесткие перехваты для 100% чистого вывода без участия генератора Ollama (без звездочек!) - if any(phrase in user_lower for phrase in ["системный промпт", "покажи промпт", "промпт системы", "промпт из базы"]): - prompt_text = db_get_active_system_prompt() - formatted_text = f"⚙️ Актуальный системный промпт ИИ (из базы SQLite):\n\n{prompt_text}" - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - if any(phrase in user_lower for phrase in ["базу знаний", "база знаний", "покажи правила", "инструкции ии"]): - rules = db_get_rules() - if not rules: - formatted_text = "База знаний пуста." - else: - formatted_text = "🧠 База знаний ИИ (ai_knowledge_base):\n\n" - for r in rules: - formatted_text += f"{r.get('id')}. {r.get('rule_text')}\n\n" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # Динамическая подгрузка системного промпта из БД SQLite - dynamic_prompt_text = db_get_active_system_prompt() - - system_prompt = { - "role": "system", - "content": f"Текущая дата и время сервера: {current_now}.\n\n{dynamic_prompt_text}" - } - - messages = [system_prompt] + chat_history + [{"role": "user", "content": user_message}] - - payload = { - "model": MODEL_NAME, - "messages": messages, - "tools": TOOLS_SCHEMA, - "stream": False, - "options": { - "num_predict": 2048, - "num_ctx": 8192, - "temperature": 0.1 - } - } - - req = urllib.request.Request( - OLLAMA_URL, - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"} - ) - - try: - with urllib.request.urlopen(req) as response: - res_data = json.loads(response.read().decode("utf-8")) - msg = res_data.get("message", {}) - - tool_calls = msg.get("tool_calls", []) - content_str = msg.get("content", "").strip().replace("**", "") - - # Перехват вызова функции из текста - if not tool_calls and "name" in content_str and "db_" in content_str: - try: - start_idx = content_str.find("{") - end_idx = content_str.rfind("}") + 1 - if start_idx != -1 and end_idx != -1: - parsed = json.loads(content_str[start_idx:end_idx]) - if "name" in parsed: - tool_calls = [{"function": parsed}] - except Exception: - pass - - if tool_calls: - for tool in tool_calls: - fn_name = tool["function"]["name"] - fn_args = tool["function"].get("arguments", {}) - - # 1. Вывод задач - if fn_name == "db_get_tasks": - tasks = db_get_tasks(status=fn_args.get("status")) - if not tasks: - formatted_text = "Список задач пуст." - else: - tasks_sorted = sorted(tasks, key=lambda x: x.get('task_id', ''), reverse=True) - formatted_text = "📋 Последние задачи проекта:\n\n" - for t in tasks_sorted: - due = f" (до {t['due_date']})" if t.get('due_date') else "" - priority = t.get('priority') or 'MEDIUM' - status_str = t.get('status') or 'BACKLOG' - module_str = t.get('module') or 'general' - - formatted_text += f"{t.get('task_id')} — {t.get('title')} [{status_str}]\n" - formatted_text += f" • Приоритет: {priority} | Модуль: {module_str}{due}\n\n" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 2. Вывод базы знаний - elif fn_name == "db_get_rules": - rules = db_get_rules() - if not rules: - formatted_text = "База знаний пуста." - else: - formatted_text = "🧠 База знаний ИИ (ai_knowledge_base):\n\n" - for r in rules: - formatted_text += f"{r.get('id')}. {r.get('rule_text')}\n\n" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 3. Вывод системного промпта - elif fn_name == "db_get_system_prompt": - prompt_text = db_get_active_system_prompt() - formatted_text = f"⚙️ Актуальный системный промпт ИИ (из базы SQLite):\n\n{prompt_text}" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 4. Добавление/обновление системного промпта - elif fn_name == "db_add_system_prompt": - res = db_add_system_prompt( - name=fn_args.get("name", "main_agent"), - prompt_text=fn_args.get("prompt_text", "") - ) - formatted_text = res.get("message", "Промпт обновлен.") - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 5. Добавление новой задачи - elif fn_name == "db_add_task": - res = db_add_task( - module=fn_args.get("module", "general"), - title=fn_args.get("title"), - priority=fn_args.get("priority", "MEDIUM"), - due_date=fn_args.get("due_date") - ) - - if "error" in res: - formatted_text = f"Ошибка добавления задачи: {res['error']}" - else: - assigned_id = res.get("task_id", "TASK") - due_str = fn_args.get('due_date') or 'Без срока' - formatted_text = ( - f"Задача {assigned_id} успешно создана!\n\n" - f"• Название: {fn_args.get('title')}\n" - f"• Приоритет: {fn_args.get('priority', 'MEDIUM')}\n" - f"• Срок: {due_str}\n" - f"• Модуль: {fn_args.get('module', 'general')}" - ) - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 6. Обновление статуса задачи - elif fn_name == "db_update_task_status": - res = db_update_task_status( - task_id=fn_args.get("task_id"), - status=fn_args.get("status"), - due_date=fn_args.get("due_date") - ) - - if "error" in res: - formatted_text = f"Ошибка обновления задачи: {res['error']}" - else: - formatted_text = f"Статус задачи {fn_args.get('task_id')} успешно обновлен!" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # 7. Удаление задачи - elif fn_name == "db_delete_task": - res = db_delete_task(task_id=fn_args.get("task_id")) - if "error" in res: - formatted_text = f"Ошибка удаления задачи: {res['error']}" - else: - formatted_text = f"Задача {fn_args.get('task_id')} успешно удалена из базы!" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": content_str} - ] - return content_str, updated_history - - except urllib.error.URLError as e: - return f"Ошибка связи с Ollama ({OLLAMA_URL}): {e}", chat_history \ No newline at end of file diff --git a/main.py b/main.py index 4babb73..e409130 100644 --- a/main.py +++ b/main.py @@ -28,6 +28,41 @@ from core.database import ( has_scud_logs_for_date ) +from services.ai_verifier import resolve_department_exception_ai + +def apply_exceptions_from_json(df, exceptions_cfg): + """ + Размечает флаг is_excluded=True на основе правил из exceptions.json и БД SQLite. + Сверяет одновременно 1С, СКУД и использует интеллектуальный поиск отделов. + """ + if df is None or df.empty or not exceptions_cfg: + if df is not None: + df['is_excluded'] = False + return df + + deps = exceptions_cfg.get("departments", []) + exact_pos = [p.lower() for p in exceptions_cfg.get("positions", [])] + pos_kw = [k.lower() for k in exceptions_cfg.get("position_keywords", [])] + exc_fios = [normalize_fio(f) for f in exceptions_cfg.get("fio", [])] + + df['is_excluded'] = False + + for idx, row in df.iterrows(): + fio_clean = row.get('fio_clean', '') + dep_1c = row.get('Подразделение', '') + dep_scud = row.get('department_scud', row.get('department', '')) + 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 pos else False + + # Двухуровневая интеллектуальная проверка отделов (1С + СКУД + ИИ-Кеш БД) + is_dep_exc = resolve_department_exception_ai(dep_1c, dep_scud, deps) + + if is_fio_exc or is_dep_exc or is_pos_exc: + df.at[idx, 'is_excluded'] = True + + return df def load_exceptions_config(): """Загружает файл exceptions.json из корня проекта.""" diff --git a/migrate_structure.py b/migrate_structure.py deleted file mode 100644 index 42500d5..0000000 --- a/migrate_structure.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -import subprocess - -def run_git_move(): - print("=== Безопасная миграция файлов в структуру проекта ===") - - # Словарь: имя файла -> целевая папка - file_mapping = { - "database.py": "core/database.py", - "scud_export.py": "services/scud_export.py", - "share_copier.py": "services/share_copier.py", - "data_loader.py": "services/data_loader.py", - "data_validator.py": "services/data_validator.py", - "zup_extractor.py": "services/zup_extractor.py", - "ai_verifier.py": "services/ai_verifier.py", - "excel_exporter.py": "services/excel_exporter.py", - "text_reporter.py": "services/text_reporter.py", - "feedback_loop.py": "services/feedback_loop.py", - "knowledge_base.py": "services/knowledge_base.py", - "db_cli.py": "scripts/db_cli.py" - } - - # Убедимся, что папки существуют и содержат __init__.py - for folder in ["core", "services", "api", "frontend", "scripts"]: - os.makedirs(folder, exist_ok=True) - init_file = os.path.join(folder, "__init__.py") - if not os.path.exists(init_file): - open(init_file, 'w').close() - - for filename, dest in file_mapping.items(): - if os.path.exists(filename): - src = filename - elif os.path.exists(dest): - print(f"[ℹ️ Уже на месте] {dest}") - continue - else: - found = None - for root, dirs, files in os.walk("."): - if filename in files and "venv" not in root: - found = os.path.join(root, filename) - break - src = found - - if src and os.path.exists(src): - if src == dest: - continue - dest_dir = os.path.dirname(dest) - os.makedirs(dest_dir, exist_ok=True) - try: - subprocess.run(["git", "mv", src, dest], check=True) - print(f"[git mv] Успешно перемещен: {src} -> {dest}") - except subprocess.CalledProcessError as e: - print(f"[⚠️ Ошибка] Не удалось переместить через git mv {src}: {e}") - else: - print(f"[❌ Не найден] Файл {filename} не обнаружен в репозитории.") - - print("\n=== Миграция завершена. Выполните 'git status' для проверки ===") - -if __name__ == "__main__": - run_git_move() \ No newline at end of file diff --git a/ref.py b/ref.py deleted file mode 100644 index 7359194..0000000 --- a/ref.py +++ /dev/null @@ -1,525 +0,0 @@ -#!/usr/bin/env python3 -import os - -# Базовый путь к проекту -BASE_DIR = "/home/puh/scud_orion_ai_v2" - -# 1. Данные для файла app/db/database.py -DB_PY = '''import sqlite3 - -DB_NAME = "/home/puh/scud_orion_ai_v2/data/scud_orion_ai.db" - -def get_connection(): - return sqlite3.connect(DB_NAME) - -def db_get_active_system_prompt() -> str: - """Извлекает активный системный промпт из базы данных SQLite.""" - try: - conn = get_connection() - cursor = conn.cursor() - cursor.execute("SELECT prompt_text FROM system_prompts WHERE name = 'main_agent' AND is_active = 1 LIMIT 1") - row = cursor.fetchone() - conn.close() - if row and row[0]: - return row[0].replace("**", "") - except Exception as e: - print(f"Ошибка чтения системного промпта из БД: {e}") - - return "Ты — интеллектуальный ИИ-ассистент и архитектурный координатор проекта SCUD Orion AI." - -def db_add_system_prompt(name: str = "main_agent", prompt_text: str = "") -> dict: - """Обновляет или добавляет активный системный промпт в БД.""" - clean_text = prompt_text.replace("**", "") - conn = get_connection() - cursor = conn.cursor() - cursor.execute(""" - INSERT INTO system_prompts (name, prompt_text, is_active) - VALUES (?, ?, 1) - ON CONFLICT(name) DO UPDATE SET prompt_text=excluded.prompt_text, updated_at=CURRENT_TIMESTAMP - """, (name, clean_text)) - conn.commit() - conn.close() - return {"status": "success", "message": f"Системный промпт '{name}' успешно обновлен в базе!"} - -def db_get_rules() -> list: - """Извлекает правила из таблицы ai_knowledge_base.""" - conn = get_connection() - conn.row_factory = sqlite3.Row - cursor = conn.cursor() - cursor.execute("SELECT id, rule_text, added_by FROM ai_knowledge_base ORDER BY id") - rows = [dict(r) for r in cursor.fetchall()] - conn.close() - return rows - -def db_add_rule(rule_text: str, added_by: str = "Operator") -> dict: - """Добавляет новое правило или инструкцию в таблицу ai_knowledge_base.""" - clean_text = rule_text.replace("**", "") - conn = get_connection() - cursor = conn.cursor() - cursor.execute( - "INSERT INTO ai_knowledge_base (rule_text, added_by) VALUES (?, ?)", - (clean_text, added_by) - ) - rule_id = cursor.lastrowid - conn.commit() - conn.close() - return {"status": "success", "message": f"Правило #{rule_id} успешно добавлено в базу знаний!", "rule_id": rule_id} - -def db_get_tasks(status: str = None) -> list: - """Извлекает список задач из реестра БД.""" - conn = get_connection() - conn.row_factory = sqlite3.Row - cursor = conn.cursor() - if status: - cursor.execute("SELECT * FROM tasks WHERE status = ? ORDER BY task_id", (status.upper(),)) - else: - cursor.execute("SELECT * FROM tasks ORDER BY task_id") - rows = [dict(r) for r in cursor.fetchall()] - conn.close() - return rows - -def db_update_task_status(task_id: str, status: str = None, due_date: str = None) -> dict: - """Обновляет статус и/или срок выполнения задачи.""" - conn = get_connection() - cursor = conn.cursor() - updates = [] - params = [] - - if status: - status_upper = status.upper() - updates.append("status = ?") - params.append(status_upper) - if status_upper == "COMPLETED": - updates.append("completed_at = CURRENT_TIMESTAMP") - else: - updates.append("completed_at = NULL") - - if due_date: - updates.append("due_date = ?") - params.append(due_date) - - if not updates: - conn.close() - return {"error": "Не указаны параметры для обновления"} - - params.append(task_id.upper()) - query = f"UPDATE tasks SET {', '.join(updates)} WHERE task_id = ?" - cursor.execute(query, tuple(params)) - - if cursor.rowcount == 0: - conn.close() - return {"error": f"Задача {task_id} не найдена"} - - conn.commit() - conn.close() - return {"status": "success", "message": f"Задача {task_id} обновлена"} - -def db_delete_task(task_id: str) -> dict: - """Удаляет задачу из базы данных по её task_id.""" - conn = get_connection() - cursor = conn.cursor() - cursor.execute("DELETE FROM tasks WHERE task_id = ?", (task_id.upper(),)) - deleted_count = cursor.rowcount - conn.commit() - conn.close() - - if deleted_count == 0: - return {"error": f"Задача {task_id} не найдена"} - return {"status": "success", "message": f"Задача {task_id} удалена"} - -def db_add_task(module: str = "general", title: str = "", priority: str = "MEDIUM", due_date: str = None, task_id: str = None) -> dict: - """Добавляет новую задачу в реестр с авто-генерацией TASK-ID.""" - conn = get_connection() - cursor = conn.cursor() - - if not task_id: - cursor.execute("SELECT task_id FROM tasks WHERE task_id LIKE 'TASK-%'") - rows = cursor.fetchall() - max_num = 0 - for r in rows: - try: - num = int(r[0].replace("TASK-", "")) - if num > max_num: - max_num = num - except ValueError: - pass - task_id = f"TASK-{max_num + 1:02d}" - - try: - cursor.execute( - "INSERT INTO tasks (task_id, module, title, status, priority, due_date) VALUES (?, ?, ?, 'BACKLOG', ?, ?)", - (task_id.upper(), module, title, priority.upper(), due_date) - ) - conn.commit() - res = {"status": "success", "message": f"Задача {task_id} создана", "task_id": task_id} - except sqlite3.IntegrityError: - res = {"error": f"Задача с ID {task_id} уже существует"} - finally: - conn.close() - return res -''' - -# 2. Данные для файла app/tools/definitions.py -TOOLS_DEFINITIONS_PY = '''TOOLS_SCHEMA = [ - { - "type": "function", - "function": { - "name": "db_get_tasks", - "description": "ПОЛУЧИТЬ СПИСОК ЗАДАЧ ПРОЕКТА. Вызывай ТОЛЬКО когда пользователь просит показать задачи, бэклог или список дел.", - "parameters": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "Фильтр статуса: BACKLOG, IN_PROGRESS или COMPLETED." - } - } - } - } - }, - { - "type": "function", - "function": { - "name": "db_get_rules", - "description": "ПОЛУЧИТЬ БАЗУ ЗНАНИЙ ИИ И ПРАВИЛА АРБИТРАЖА (ai_knowledge_base). Вызывай когда пользователь просит показать базу знаний, правила, инструкции или промпты.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_add_rule", - "description": "Добавить новое правило, инструкцию или факт в базу знаний (ai_knowledge_base). Вызывай при командах 'добавь в базу знаний', 'запомни правило', 'запиши инструкцию'.", - "parameters": { - "type": "object", - "properties": { - "rule_text": {"type": "string", "description": "Текст правила, инструкции или факта для сохранения"}, - "added_by": {"type": "string", "description": "Автор или источник правила, по умолчанию Operator"} - }, - "required": ["rule_text"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_get_system_prompt", - "description": "ПОЛУЧИТЬ ТЕКУЩИЙ СИСТЕМНЫЙ ПРОМПТ ИИ (system_prompts). Вызывай когда пользователь просит показать системный промпт, инструкции ассистента или промпт из базы.", - "parameters": {"type": "object", "properties": {}} - } - }, - { - "type": "function", - "function": { - "name": "db_add_system_prompt", - "description": "Обновить или добавить системный промпт ИИ в базу данных. Вызывай при командах 'задай системный промпт', 'измени промпт', 'обнови системный промпт'.", - "parameters": { - "type": "object", - "properties": { - "prompt_text": {"type": "string", "description": "Полный новый текст системного промпта"}, - "name": {"type": "string", "description": "Имя промпта, по умолчанию main_agent"} - }, - "required": ["prompt_text"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_update_task_status", - "description": "Изменить статус и/или срок выполнения задачи в реестре.", - "parameters": { - "type": "object", - "properties": { - "task_id": {"type": "string", "description": "Идентификатор задачи, например TASK-17"}, - "status": {"type": "string", "description": "Новый статус: COMPLETED, IN_PROGRESS или BACKLOG"}, - "due_date": {"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"] - } - } - }, - { - "type": "function", - "function": { - "name": "db_add_task", - "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"] - } - } - } -] -''' - -# 3. Данные для файла app/tools/handlers.py -TOOLS_HANDLERS_PY = '''from app.db import database - -def handle_tool_call(fn_name: str, fn_args: dict) -> str: - """Диспетчеризация вызова функций и форматирование текстового ответа.""" - - if fn_name == "db_get_tasks": - tasks = database.db_get_tasks(status=fn_args.get("status")) - if not tasks: - return "Список задач пуст." - tasks_sorted = sorted(tasks, key=lambda x: x.get('task_id', ''), reverse=True) - formatted_text = "📋 Последние задачи проекта:\n\n" - for t in tasks_sorted: - due = f" (до {t['due_date']})" if t.get('due_date') else "" - priority = t.get('priority') or 'MEDIUM' - status_str = t.get('status') or 'BACKLOG' - module_str = t.get('module') or 'general' - formatted_text += f"{t.get('task_id')} — {t.get('title')} [{status_str}]\n" - formatted_text += f" • Приоритет: {priority} | Модуль: {module_str}{due}\n\n" - return formatted_text - - elif fn_name == "db_get_rules": - rules = database.db_get_rules() - if not rules: - return "База знаний пуста." - formatted_text = "🧠 База знаний ИИ (ai_knowledge_base):\n\n" - for r in rules: - formatted_text += f"{r.get('id')}. {r.get('rule_text')}\n\n" - return formatted_text - - elif fn_name == "db_add_rule": - res = database.db_add_rule( - rule_text=fn_args.get("rule_text", ""), - added_by=fn_args.get("added_by", "Operator") - ) - return res.get("message", "Правило добавлено в базу знаний.") - - elif fn_name == "db_get_system_prompt": - prompt_text = database.db_get_active_system_prompt() - return f"⚙️ Актуальный системный промпт ИИ (из базы SQLite):\n\n{prompt_text}" - - elif fn_name == "db_add_system_prompt": - res = database.db_add_system_prompt( - name=fn_args.get("name", "main_agent"), - prompt_text=fn_args.get("prompt_text", "") - ) - return res.get("message", "Промпт обновлен.") - - elif fn_name == "db_add_task": - res = database.db_add_task( - module=fn_args.get("module", "general"), - title=fn_args.get("title"), - priority=fn_args.get("priority", "MEDIUM"), - due_date=fn_args.get("due_date") - ) - if "error" in res: - return f"Ошибка добавления задачи: {res['error']}" - assigned_id = res.get("task_id", "TASK") - due_str = fn_args.get('due_date') or 'Без срока' - return ( - f"Задача {assigned_id} успешно создана!\n\n" - f"• Название: {fn_args.get('title')}\n" - f"• Приоритет: {fn_args.get('priority', 'MEDIUM')}\n" - f"• Срок: {due_str}\n" - f"• Модуль: {fn_args.get('module', 'general')}" - ) - - elif fn_name == "db_update_task_status": - res = database.db_update_task_status( - task_id=fn_args.get("task_id"), - status=fn_args.get("status"), - due_date=fn_args.get("due_date") - ) - if "error" in res: - return f"Ошибка обновления задачи: {res['error']}" - return f"Статус задачи {fn_args.get('task_id')} успешно обновлен!" - - elif fn_name == "db_delete_task": - res = database.db_delete_task(task_id=fn_args.get("task_id")) - if "error" in res: - return f"Ошибка удаления задачи: {res['error']}" - return f"Задача {fn_args.get('task_id')} успешно удалена из базы!" - - return f"Функция {fn_name} выполнена." -''' - -# 4. Данные для файла app/core/ollama_client.py -OLLAMA_CLIENT_PY = '''import json -import urllib.request -import urllib.error - -OLLAMA_URL = "http://192.168.11.3:11434/api/chat" -MODEL_NAME = "qwen2.5:14b" - -def send_ollama_request(messages: list, tools: list) -> dict: - """Отправляет HTTP-запрос к локальной модели Ollama.""" - payload = { - "model": MODEL_NAME, - "messages": messages, - "tools": tools, - "stream": False, - "options": { - "num_predict": 2048, - "num_ctx": 8192, - "temperature": 0.1 - } - } - - req = urllib.request.Request( - OLLAMA_URL, - data=json.dumps(payload).encode("utf-8"), - headers={"Content-Type": "application/json"} - ) - - try: - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode("utf-8")) - except urllib.error.URLError as e: - raise ConnectionError(f"Ошибка связи с Ollama ({OLLAMA_URL}): {e}") -''' - -# 5. Данные для файла app/orchestrator.py -ORCHESTRATOR_PY = '''import json -from typing import List, Dict, Any, Tuple -from datetime import datetime - -from app.db import database -from app.tools.definitions import TOOLS_SCHEMA -from app.tools.handlers import handle_tool_call -from app.core.ollama_client import send_ollama_request - -def process_chat_message(user_message: str, chat_history: List[Dict[str, Any]] = None) -> Tuple[str, List[Dict[str, Any]]]: - if chat_history is None: - chat_history = [] - - current_now = datetime.now().strftime("%Y-%m-%d %H:%M") - user_lower = user_message.lower().strip() - - # Быстрые жесткие перехваты - if any(phrase in user_lower for phrase in ["системный промпт", "покажи промпт", "промпт системы", "промпт из базы"]): - prompt_text = database.db_get_active_system_prompt() - formatted_text = f"⚙️ Актуальный системный промпт ИИ (из базы SQLite):\n\n{prompt_text}" - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - if any(phrase in user_lower for phrase in ["базу знаний", "база знаний", "покажи правила", "инструкции ии"]): - rules = database.db_get_rules() - if not rules: - formatted_text = "База знаний пуста." - else: - formatted_text = "🧠 База знаний ИИ (ai_knowledge_base):\n\n" - for r in rules: - formatted_text += f"{r.get('id')}. {r.get('rule_text')}\n\n" - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - # Загрузка актуального промпта - dynamic_prompt_text = database.db_get_active_system_prompt() - system_prompt = { - "role": "system", - "content": f"Текущая дата и время сервера: {current_now}.\n\n{dynamic_prompt_text}" - } - - messages = [system_prompt] + chat_history + [{"role": "user", "content": user_message}] - - try: - res_data = send_ollama_request(messages=messages, tools=TOOLS_SCHEMA) - msg = res_data.get("message", {}) - - tool_calls = msg.get("tool_calls", []) - content_str = msg.get("content", "").strip().replace("**", "") - - # Перехват текстового JSON с именем функции - if not tool_calls and "name" in content_str and "db_" in content_str: - try: - start_idx = content_str.find("{") - end_idx = content_str.rfind("}") + 1 - if start_idx != -1 and end_idx != -1: - parsed = json.loads(content_str[start_idx:end_idx]) - if "name" in parsed: - tool_calls = [{"function": parsed}] - except Exception: - pass - - if tool_calls: - for tool in tool_calls: - fn_name = tool["function"]["name"] - fn_args = tool["function"].get("arguments", {}) - - formatted_text = handle_tool_call(fn_name, fn_args) - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": formatted_text} - ] - return formatted_text, updated_history - - updated_history = chat_history + [ - {"role": "user", "content": user_message}, - {"role": "assistant", "content": content_str} - ] - return content_str, updated_history - - except Exception as e: - return f"Ошибка обработки запроса: {e}", chat_history -''' - -# 6. Обновленный главный модуль llm_agent.py -LLM_AGENT_PY = '''""" -SCUD Orion AI — Главная точка входа для общения с LLM-ассистентом. -Перенаправляет вызовы в центральный оркестратор app.orchestrator. -""" - -from app.orchestrator import process_chat_message - -__all__ = ["process_chat_message"] -''' - -def build_structure(): - files = { - os.path.join(BASE_DIR, "app", "__init__.py"): "", - os.path.join(BASE_DIR, "app", "db", "__init__.py"): "", - os.path.join(BASE_DIR, "app", "db", "database.py"): DB_PY, - os.path.join(BASE_DIR, "app", "tools", "__init__.py"): "", - os.path.join(BASE_DIR, "app", "tools", "definitions.py"): TOOLS_DEFINITIONS_PY, - os.path.join(BASE_DIR, "app", "tools", "handlers.py"): TOOLS_HANDLERS_PY, - os.path.join(BASE_DIR, "app", "core", "__init__.py"): "", - os.path.join(BASE_DIR, "app", "core", "ollama_client.py"): OLLAMA_CLIENT_PY, - os.path.join(BASE_DIR, "app", "orchestrator.py"): ORCHESTRATOR_PY, - os.path.join(BASE_DIR, "llm_agent.py"): LLM_AGENT_PY, - } - - print("🚀 Начинаем рефакторинг проекта...") - for filepath, content in files.items(): - os.makedirs(os.path.dirname(filepath), exist_ok=True) - with open(filepath, "w", encoding="utf-8") as f: - f.write(content.strip() + "\n") - print(f" [✓] Создан/обновлен: {filepath}") - - print("\n✅ Рефакторинг завершен успешно!") - -if __name__ == "__main__": - build_structure() \ No newline at end of file diff --git a/scripts/migrate_db.py b/scripts/migrate_db.py deleted file mode 100644 index bad7120..0000000 --- a/scripts/migrate_db.py +++ /dev/null @@ -1,47 +0,0 @@ -import sqlite3 -import os - -DB_PATH = 'data/scud_orion_ai.db' - - -def migrate(): - if not os.path.exists(DB_PATH): - print(f"База данных {DB_PATH} не найдена. Создание будет выполнено при первом запуске.") - return - - conn = sqlite3.connect(DB_PATH) - cursor = conn.cursor() - - cursor.execute("PRAGMA table_info(scud_logs);") - columns = [row[1] for row in cursor.fetchall()] - - if 'first_activity' not in columns: - cursor.execute("ALTER TABLE scud_logs ADD COLUMN first_activity TEXT DEFAULT '—';") - print("[✓] Добавлена колонка 'first_activity'") - - if 'anomaly_flag' not in columns: - cursor.execute("ALTER TABLE scud_logs ADD COLUMN anomaly_flag TEXT DEFAULT 'NONE';") - print("[✓] Добавлена колонка 'anomaly_flag'") - - if 'snapshot_time' not in columns: - cursor.execute("ALTER TABLE scud_logs ADD COLUMN snapshot_time TEXT DEFAULT NULL;") - print("[✓] Добавлена колонка 'snapshot_time'") - - if 'snapshot_id' not in columns: - cursor.execute("ALTER TABLE scud_logs ADD COLUMN snapshot_id TEXT DEFAULT NULL;") - print("[✓] Добавлена колонка 'snapshot_id'") - - # Проставляем номера для ранее сохраненных срезов - cursor.execute("SELECT DISTINCT snapshot_time FROM scud_logs WHERE snapshot_time IS NOT NULL ORDER BY snapshot_time ASC") - snaps = cursor.fetchall() - for idx, (s_time,) in enumerate(snaps, 1): - s_id = f"{idx:07d}" - cursor.execute("UPDATE scud_logs SET snapshot_id = ? WHERE snapshot_time = ?", (s_id, s_time)) - - conn.commit() - conn.close() - print("[✓] Миграция схемы БД успешно завершена!") - - -if __name__ == "__main__": - migrate() \ No newline at end of file diff --git a/services/ai_verifier.py b/services/ai_verifier.py index cd37cf8..b33b361 100644 --- a/services/ai_verifier.py +++ b/services/ai_verifier.py @@ -4,7 +4,65 @@ 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): """ diff --git a/services/feedback_loop.py b/services/feedback_loop.py index 785fa73..c2b3463 100644 --- a/services/feedback_loop.py +++ b/services/feedback_loop.py @@ -40,17 +40,14 @@ def review_ai_decisions(report_text, suspicious_cases): elif user_input_clean in ['н', 'нет', 'no', 'n', '-']: print(" [ℹ️] Решение отклонено оператором.") elif user_input: - # Если оператор ввел действительно новое текстовое правило - new_rule = f"Правило по {fio_target}: {user_input}" - - add_rule_to_db(new_rule, added_by="Human_Admin") - if save_rule: - try: - save_rule(new_rule) - except Exception: - pass + # Если оператор обучает систему синониму отделов + if "отдел" in user_input_clean or "овк" in user_input_clean: + from core.database import add_department_synonym_to_db + add_department_synonym_to_db(user_input.strip(), "отдел внутреннего контроля") - print(f" [✓] Новое правило записано в Базу Знаний: {new_rule}") + new_rule = f"Правило: {user_input}" + add_rule_to_db(new_rule, added_by="Human_Admin") + print(f" [✓] Новое правило записано в Базу Знаний SQLite: {new_rule}") else: print(" [ℹ️] Запись пропущена.") diff --git a/services/scud_export.py b/services/scud_export.py index c1848ca..d5e74f3 100644 --- a/services/scud_export.py +++ b/services/scud_export.py @@ -15,7 +15,7 @@ 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 +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") @@ -227,8 +227,8 @@ def run_export(input_date: str | None = None, save_xlsx: bool = True, debug: boo # ⚡️ ПРОВЕРКА НАЛИЧИЯ ВЧЕРАШНЕГО ДНЯ В SQLITE: # Если это вчерашний день и его снапшот уже зафиксирован в SQLite — пропускаем тяжелый запрос к MS SQL - if is_yesterday and has_scud_logs_for_date(processing_date_str): - log(f"[ℹ️] Вчерашний день ({processing_date_str}) уже зафиксирован в 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: diff --git a/update_imports.py b/update_imports.py deleted file mode 100644 index fbbf5c8..0000000 --- a/update_imports.py +++ /dev/null @@ -1,41 +0,0 @@ -import os - -def update_file_imports(filepath): - with open(filepath, 'r', encoding='utf-8') as f: - content = f.read() - - # Заменяем старые пути на новые - new_content = content - new_content = new_content.replace("from modules.database", "from core.database") - new_content = new_content.replace("import modules.database", "import core.database") - - # Все остальные модули уехали в services/ - service_modules = [ - "ai_verifier", "data_loader", "data_validator", "excel_exporter", - "feedback_loop", "knowledge_base", "scud_export", "share_copier", - "text_reporter", "zup_extractor" - ] - - for mod in service_modules: - new_content = new_content.replace(f"from modules.{mod}", f"from services.{mod}") - new_content = new_content.replace(f"import modules.{mod}", f"import services.{mod}") - # Замена для прямых импортов между модулями внутри папки services/ - new_content = new_content.replace(f"from {mod}", f"from services.{mod}") - - if content != new_content: - with open(filepath, 'w', encoding='utf-8') as f: - f.write(new_content) - print(f"[Обновлено] Импорты в файле: {filepath}") - -def run_update(): - print("=== Автоматическое обновление импортов ===") - for root, dirs, files in os.walk("."): - if "venv" in root or ".git" in root: - continue - for file in files: - if file.endswith(".py") and file not in ["migrate_structure.py", "update_imports.py"]: - update_file_imports(os.path.join(root, file)) - print("=== Обновление импортов успешно завершено ===") - -if __name__ == "__main__": - run_update() \ No newline at end of file