diff --git a/search_bot/optimize_documents.py b/search_bot/optimize_documents.py
new file mode 100644
index 0000000..9ec28eb
--- /dev/null
+++ b/search_bot/optimize_documents.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python3
+"""
+Универсальный скрипт для улучшения MD-файлов документов АО «ХК «Сибцем».
+
+Выполняется на сервере 192.168.1.106.
+Применяет паттерны:
+1. Удаляет футеры страниц
+2. Форматирует блок "УТВЕРЖДАЮ"
+3. Выравнивает иерархию заголовков
+4. Объединяет таблицы терминов
+5. Добавляет разделители между разделами
+6. Приводит таблицы к единому виду
+
+Использование:
+ python3 /opt/trueconf_bot/search_bot/optimize_documents.py <путь_к_каталогу>
+
+Пример:
+ python3 /opt/trueconf_bot/search_bot/optimize_documents.py "/opt/documents_xk/ready_md/АОХКСибцем/07 Служба Вице-президента по экономике и финансам/ДИТ/02 Регламенты деятельности/"
+"""
+
+import os
+import re
+import sys
+import time
+import requests
+import base64
+
+# Конфигурация
+FILEBROWSER_URL = "https://smb.dddennnisss.ru"
+FILEBROWSER_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJGaWxlQnJvd3NlciBRdWFudHVtIiwiZXhwIjoyMzAyNzM1NzA3LCJpYXQiOjE3ODQzMzU3MDcsImJlbG9uZ3NUbyI6MSwiUGVybWlzc2lvbnMiOnsiYXBpIjp0cnVlLCJhZG1pbiI6dHJ1ZSwibW9kaWZ5Ijp0cnVlLCJzaGFyZSI6dHJ1ZSwicmVhbHRpbWUiOmZhbHNlLCJkZWxldGUiOnRydWUsImNyZWF0ZSI6dHJ1ZSwiZG93bmxvYWQiOnRydWV9fQ.QBKlh3NQJeh4aeMiKLkhg0tF8hxk-Oh2KLsXLSbuvm8"
+SOURCE_NAME = "SSD-Storage"
+
+
+def remove_footers(content):
+ """Удалить футеры страниц."""
+ # Удалить "АО «ХК «Сибцем»\nТип документа: ...\nНаименование документа: ..."
+ content = re.sub(
+ r'АО «ХК «Сибцем»\nТип документа:.*?\nНаименование документа:.*?\n\n',
+ '',
+ content,
+ flags=re.DOTALL
+ )
+ # Удалить "Стр. X из Y"
+ content = re.sub(r'Стр\. \d+ из \d+\n\n', '', content)
+ # Удалить "Дата утверждения: DD.MM.YYYY"
+ content = re.sub(r'Дата утверждения: \d{2}\.\d{2}\.\d{4}\n\n', '', content)
+ # Удалить "Ведущее подразделение: ..."
+ content = re.sub(r'Ведущее подразделение:.*?\n\n', '', content)
+ return content
+
+
+def fix_headings(content):
+ """Выровнять иерархию заголовков: все на уровень ##."""
+ content = re.sub(r'^(#+)\s+(.+)$', r'## \2', content, flags=re.MULTILINE)
+ return content
+
+
+def add_dividers(content):
+ """Добавить разделители между основными разделами."""
+ # Разделитель перед Оглавлением
+ content = re.sub(
+ r'(\n)(## )(Оглавление)',
+ r'\1\n---\n\1\2\3',
+ content
+ )
+ # Разделители перед разделами 1-9
+ content = re.sub(
+ r'(\n)(## )(\s*(?:1\.|2\.|3\.|4\.|5\.|6\.|7\.|8\.|9\.))',
+ r'\1\n---\n\1\2\3',
+ content
+ )
+ # Разделители перед Приложениями
+ content = re.sub(
+ r'(\n)(## )(Приложение)',
+ r'\1\n---\n\1\2\3',
+ content
+ )
+ # Разделитель перед Листом согласований
+ content = re.sub(
+ r'(\n)(## )(Лист согласований)',
+ r'\1\n---\n\1\2\3',
+ content
+ )
+ return content
+
+
+def fix_tables(content):
+ """Привести все таблицы к единому виду с thead/tbody."""
+ def fix_table(table):
+ if '' in table and '
' in table:
+ return table
+ rows = re.findall(r'(.*?)
', table, re.DOTALL)
+ if not rows:
+ return table
+
+ header = '' + rows[0] + '
'
+ body = ''
+ for row in rows[1:]:
+ body += '' + row + '
'
+ body += ''
+
+ return ''
+
+ return re.sub(r'', lambda m: fix_table(m.group(0)), content, flags=re.DOTALL)
+
+
+def merge_terms_tables(content):
+ """Объединить разбитые таблицы терминов."""
+ # Поиск таблиц терминов
+ terms_pattern = r'()'
+ matches = re.findall(terms_pattern, content, re.DOTALL)
+
+ if len(matches) > 1:
+ # Объединяем все таблицы терминов в одну
+ merged = '| Термин | Определение |
'
+ for table in matches:
+ rows = re.findall(r'(.*?)
', table, re.DOTALL)
+ for row in rows[1:]: # Пропускаем заголовок
+ merged += row
+ merged += '
'
+ content = content.replace(matches[0], merged)
+
+ return content
+
+
+def fix_approval_block(content):
+ """Форматировать блок УТВЕРЖДАЮ."""
+ # Паттерн 1: "УТВЕРЖДАЮ\nПрезидент\n\nО.В. Шарыкин\n\n«XX» месяц год г."
+ approval_patterns = [
+ r'(УТВЕРЖДАУ\nПрезидент\n\nО\.В\. Шарыкин\n\n«\d+» \w+ \d{4} г\.)',
+ r'(УТВЕРЖДАУ\nПрезидент\n\nО\.В\. Шарыкин\n\n«\d+» \w+ \d{4} г\.)',
+ ]
+
+ for pattern in approval_patterns:
+ match = re.search(pattern, content)
+ if match:
+ old_text = match.group(0)
+ new_text = f'''
+УТВЕРЖДАУ
+Президент
+О.В. Шарыкин
+{old_text.split("«")[1].split("г.")[0]} г.
+
'''
+ content = content.replace(old_text, new_text)
+ break
+
+ return content
+
+
+def upload_to_filebrowser(content, filename):
+ """Загрузить файл в filebrowser."""
+ # Добавить "_improved" перед расширением
+ if filename.endswith('.md'):
+ improved_filename = filename[:-3] + '_improved.md'
+ else:
+ improved_filename = filename + '_improved'
+
+ session = requests.Session()
+ session.cookies.set("filebrowser_quantum_jwt", FILEBROWSER_TOKEN, domain="smb.dddennnisss.ru")
+
+ url = f"{FILEBROWSER_URL}/api/resources"
+ params = {"path": improved_filename, "source": SOURCE_NAME}
+
+ r = session.put(url, params=params, data=content)
+
+ if r.status_code == 200:
+ print(f"✓ Файл загружен: {improved_filename}")
+
+ # Проверить
+ r = session.get(f"{FILEBROWSER_URL}/api/resources", params={"path": "/", "source": SOURCE_NAME})
+ if r.status_code == 200:
+ data = r.json()
+ items = data.get("files", []) + data.get("folders", [])
+ for item in items:
+ if improved_filename in item["name"]:
+ print(f"✓ Размер: {item['size']} байт")
+ break
+ else:
+ print(f"✗ Ошибка загрузки: {r.status_code} - {r.text[:200]}")
+
+ return improved_filename
+
+
+def optimize_document(md_path):
+ """Основная функция оптимизации документа."""
+ start_time = time.time()
+
+ print(f"\n📄 Обработка документа: {md_path.split('/')[-1]}")
+ print("=" * 60)
+
+ # Шаг 1: Читать MD файл
+ print("\n📥 Шаг 1: Чтение MD...")
+ try:
+ with open(md_path, 'r', encoding='utf-8') as f:
+ md_content = f.read()
+ except Exception as e:
+ print(f"✗ Ошибка при чтении: {e}")
+ return
+
+ print(f"✓ MD прочитан: {len(md_content)} символов")
+
+ # Шаг 2: Применить паттерны
+ print("\n🔧 Шаг 2: Применение паттернов...")
+
+ # 2.1 Удалить футеры
+ content = remove_footers(md_content)
+ print(" ✓ Футеры удалены")
+
+ # 2.2 Выровнять иерархию заголовков
+ content = fix_headings(content)
+ print(" ✓ Иерархия заголовков выровнена")
+
+ # 2.3 Добавить разделители
+ content = add_dividers(content)
+ print(" ✓ Разделители добавлены")
+
+ # 2.4 Привести таблицы к единому виду
+ content = fix_tables(content)
+ print(" ✓ Таблицы приведены к единому виду")
+
+ # 2.5 Объединить таблицы терминов
+ content = merge_terms_tables(content)
+ print(" ✓ Таблицы терминов объединены")
+
+ # 2.6 Форматировать блок УТВЕРЖДАЮ
+ content = fix_approval_block(content)
+ print(" ✓ Блок УТВЕРЖДАУ отформатирован")
+
+ # Сохранить улучшенную версию
+ improved_path = md_path.replace('.md', '_improved.md')
+ with open(improved_path, "w", encoding="utf-8") as f:
+ f.write(content)
+
+ print(f"\n📊 Результаты:")
+ print(f" Исходный размер: {len(md_content)} символов")
+ print(f" Улучшенный размер: {len(content)} символов")
+
+ # Показать структуру
+ sections = re.findall(r'^(##)\s+(.+)$', content, re.MULTILINE)
+ print(f" Разделов: {len(sections)}")
+
+ tables = re.findall(r'', content)
+ print(f" Таблиц: {len(tables)}")
+
+ # Показать первые 300 символов
+ print(f"\n📝 Начало файла:")
+ print(content[:300].replace('\n', '\\n'))
+
+ # Загрузить в filebrowser
+ print("\n📤 Шаг 3: Загрузка в filebrowser...")
+ filename = md_path.split('/')[-1]
+ upload_to_filebrowser(content, filename)
+
+ elapsed = time.time() - start_time
+ print(f"\n{'=' * 60}")
+ print(f"✅ Готово! Время выполнения: {elapsed:.1f} сек")
+ print(f"{'=' * 60}")
+
+
+def process_directory(directory):
+ """Обработать все MD файлы в каталоге."""
+ start_time = time.time()
+
+ print(f"📂 Обработка каталога: {directory}")
+ print("=" * 60)
+
+ # Найти все MD файлы
+ md_files = []
+ for root, dirs, files in os.walk(directory):
+ for file in files:
+ if file.endswith('.md'):
+ md_files.append(os.path.join(root, file))
+
+ print(f"Найдено {len(md_files)} MD файлов")
+
+ # Обработать каждый файл
+ for md_path in md_files:
+ try:
+ optimize_document(md_path)
+ except Exception as e:
+ print(f"✗ Ошибка при обработке {md_path}: {e}")
+
+ elapsed = time.time() - start_time
+ print(f"\n{'=' * 60}")
+ print(f"✅ Обработка каталога завершена! Общее время: {elapsed:.1f} сек")
+ print(f"{'=' * 60}")
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("Использование:")
+ print(" python3 optimize_documents.py <путь_к_каталогу>")
+ print("\nПример:")
+ print(' python3 optimize_documents.py "/opt/documents_xk/ready_md/АОХКСибцем/07 Служба Вице-президента по экономике и финансам/ДИТ/02 Регламенты деятельности/"')
+ sys.exit(1)
+
+ directory = sys.argv[1]
+ process_directory(directory)