Files
trueconf_bot/search_bot/optimize_document.py
T
2026-07-18 12:17:07 +07:00

290 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 '<thead>' in table and '<tbody>' in table:
return table
rows = re.findall(r'<tr>(.*?)</tr>', table, re.DOTALL)
if not rows:
return table
header = '<thead><tr>' + rows[0] + '</tr></thead><tbody>'
body = ''
for row in rows[1:]:
body += '<tr>' + row + '</tr>'
body += '</tbody>'
return '<table>' + header + body + '</table>'
return re.sub(r'<table>.*?</table>', 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'''<div align="right">
<strong>УТВЕРЖДАУ</strong><br>
Президент<br>
О.В. Шарыкин<br>
{old_text.split("«")[1].split("г.")[0]} г.
</div>'''
content = content.replace(old_text, new_text)
break
return content
def merge_terms_tables(content):
"""Объединить разбитые таблицы терминов."""
# Поиск таблиц терминов
terms_pattern = r'(<table>.*?Термины.*?</table>)'
matches = re.findall(terms_pattern, content, re.DOTALL)
if len(matches) > 1:
# Объединяем все таблицы терминов в одну
merged = '<table><thead><tr><th>Термин</th><th>Определение</th></tr></thead><tbody>'
for table in matches:
rows = re.findall(r'<tr>(.*?)</tr>', table, re.DOTALL)
for row in rows[1:]: # Пропускаем заголовок
merged += row
merged += '</tbody></table>'
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'<table>', 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)