#!/usr/bin/env python3 """ Универсальный скрипт для улучшения MD-файлов документов АО «ХК «Сибцем». Применяет паттерны: 1. Удаляет футеры страниц 2. Форматирует блок "УТВЕРЖДАЮ" 3. Выравнивает иерархию заголовков 4. Объединяет таблицы терминов 5. Добавляет разделители между разделами 6. Приводит таблицы к единому виду Использование: python3 optimize_document.py <путь_к_оригиналу_на_сервере> Пример: python3 optimize_document.py "/opt/documents_xk/АОХКСибцем/07 Служба.../08 Положение Управление ИТ-инцидентами от 20.02.2024 № ПОЛ-123-2.md" """ import subprocess import re import sys import time import requests import urllib.parse # Конфигурация SSH_KEY = "/home/hermes/.ssh/192.168.1.106" SSH_USER = "administrator@192.168.1.106" SERVER_BASE = "/opt/documents_xk/АОХКСибцем" FILEBROWSER_URL = "https://smb.dddennnisss.ru" FILEBROWSER_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJGaWxlQnJvd3NlciBRdWFudHVtIiwiZXhwIjoyMzAyNzM1NzA3LCJpYXQiOjE3ODQzMzU3MDcsImJlbG9uZ3NUbyI6MSwiUGVybWlzc2lvbnMiOnsiYXBpIjp0cnVlLCJhZG1pbiI6dHJ1ZSwibW9kaWZ5Ijp0cnVlLCJzaGFyZSI6dHJ1ZSwicmVhbHRpbWUiOmZhbHNlLCJkZWxldGUiOnRydWUsImNyZWF0ZSI6dHJ1ZSwiZG93bmxvYWQiOnRydWV9fQ.QBKlh3NQJeh4aeMiKLkhg0tF8hxk-Oh2KLsXLSbuvm8" SOURCE_NAME = "SSD-Storage" def run_ssh(command): """Выполнить команду на сервере через SSH.""" result = subprocess.run( ["ssh", "-i", SSH_KEY, "-o", "StrictHostKeyChecking=no", SSH_USER, command], capture_output=True, text=True, timeout=30 ) return result def scp_download(remote_path, local_path): """Скачать файл с сервера.""" result = subprocess.run( ["scp", "-i", SSH_KEY, "-o", "StrictHostKeyChecking=no", f"{SSH_USER}:{remote_path}", local_path], capture_output=True, text=True, timeout=60 ) return result.returncode == 0 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 '' + header + body + '
' return re.sub(r'.*?
', lambda m: fix_table(m.group(0)), content, flags=re.DOTALL) 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_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 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 optimize_document(md_path): """Основная функция оптимизации документа.""" start_time = time.time() print(f"📄 Обработка документа: {md_path}") print("=" * 60) # Шаг 1: Скачать MD с сервера print("\n📥 Шаг 1: Скачивание MD...") result = run_ssh(f"cat '{md_path}'") if result.returncode != 0: print(f"✗ Ошибка при скачивании: {result.stderr}") return md_content = result.stdout 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 = "/tmp/improved_document.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...") upload_to_filebrowser(content, md_path) elapsed = time.time() - start_time print(f"\n{'=' * 60}") print(f"✅ Готово! Время выполнения: {elapsed:.1f} сек") print(f"{'=' * 60}") def upload_to_filebrowser(content, md_path): """Загрузить файл в filebrowser.""" # Извлечь имя файла из пути filename = md_path.split('/')[-1] # Добавить "_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]}") if __name__ == "__main__": if len(sys.argv) < 2: print("Использование:") print(" python3 optimize_document.py <путь_к_оригиналу_на_сервере>") print("\nПример:") print(" python3 optimize_document.py \"/opt/documents_xk/АОХКСибцем/07 Служба.../08 Положение Управление ИТ-инцидентами от 20.02.2024 № ПОЛ-123-2.md\"") sys.exit(1) md_path = sys.argv[1] optimize_document(md_path)