Spaces:
Sleeping
Sleeping
...
Browse files- app/main_WS_FS_pure_test.py +47 -21
app/main_WS_FS_pure_test.py
CHANGED
|
@@ -55,7 +55,6 @@ def generate_presigned_url(bucket_name, object_key, expiration=3600):
|
|
| 55 |
return None
|
| 56 |
|
| 57 |
|
| 58 |
-
from bs4 import BeautifulSoup
|
| 59 |
|
| 60 |
def force_links_new_tab(html: str) -> str:
|
| 61 |
"""
|
|
@@ -575,52 +574,79 @@ with gr.Blocks(theme=theme, css_paths=css_path) as demo:
|
|
| 575 |
from htmldocx import HtmlToDocx
|
| 576 |
from docx import Document
|
| 577 |
from docx.enum.section import WD_ORIENT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
|
| 579 |
|
| 580 |
def preprocess_html(html: str) -> str:
|
| 581 |
-
# Переводим **ЗАГОЛОВОК** в <h3>ЗАГОЛОВОК</h3>
|
| 582 |
return re.sub(r"\*\*(.+?)\*\*", r"<h3>\1</h3>", html)
|
| 583 |
|
| 584 |
|
| 585 |
def generate_docx(html: str) -> str:
|
| 586 |
-
#
|
| 587 |
html = preprocess_html(html)
|
| 588 |
-
|
| 589 |
-
# 1. Оборачиваем и парсим
|
| 590 |
soup = BeautifulSoup(f"<body>{html}</body>", "html.parser")
|
| 591 |
|
| 592 |
-
#
|
| 593 |
for span in soup.select("span.cell-label"):
|
| 594 |
span["style"] = "display:block;font-size:9pt;margin-bottom:0.2em"
|
| 595 |
for span in soup.select("span.cell-value"):
|
| 596 |
span["style"] = "display:block;font-size:12pt"
|
| 597 |
|
| 598 |
-
#
|
| 599 |
-
import re as _re
|
| 600 |
-
for h in soup.find_all(_re.compile(r"^h[1-6]$")):
|
| 601 |
-
p = soup.new_tag("p")
|
| 602 |
-
p["style"] = "font-size:12pt;font-weight:bold;margin-bottom:0.2em"
|
| 603 |
-
p.string = h.get_text()
|
| 604 |
-
h.replace_with(p)
|
| 605 |
-
|
| 606 |
-
clean_html = str(soup)
|
| 607 |
-
|
| 608 |
-
# 4. Создаём документ в альбомной ориентации
|
| 609 |
doc = Document()
|
| 610 |
sec = doc.sections[-1]
|
| 611 |
sec.orientation = WD_ORIENT.LANDSCAPE
|
| 612 |
sec.page_width, sec.page_height = sec.page_height, sec.page_width
|
| 613 |
|
| 614 |
-
#
|
| 615 |
parser = HtmlToDocx()
|
| 616 |
parser.table_style = "TableGrid"
|
| 617 |
-
parser.add_html_to_document(clean_html, doc)
|
| 618 |
|
| 619 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 620 |
tmp = tempfile.gettempdir()
|
| 621 |
fname = f"lesson_plan_{datetime.now():%Y%m%d%H%M%S}.docx"
|
| 622 |
path = os.path.join(tmp, fname)
|
| 623 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 624 |
return path
|
| 625 |
|
| 626 |
|
|
|
|
| 55 |
return None
|
| 56 |
|
| 57 |
|
|
|
|
| 58 |
|
| 59 |
def force_links_new_tab(html: str) -> str:
|
| 60 |
"""
|
|
|
|
| 574 |
from htmldocx import HtmlToDocx
|
| 575 |
from docx import Document
|
| 576 |
from docx.enum.section import WD_ORIENT
|
| 577 |
+
import traceback
|
| 578 |
+
|
| 579 |
+
|
| 580 |
+
def safe_convert(parser, html_part, doc, section_name):
|
| 581 |
+
try:
|
| 582 |
+
parser.add_html_to_document(str(html_part), doc)
|
| 583 |
+
except Exception as e:
|
| 584 |
+
print(f"Ошибка конвертации {section_name}: {str(e)}")
|
| 585 |
+
error_msg = doc.add_paragraph()
|
| 586 |
+
error_msg.add_run(f"[ОШИБКА КОНВЕРТАЦИИ {section_name.upper()}]: ").bold = True
|
| 587 |
+
error_msg.add_run(str(html_part))
|
| 588 |
|
| 589 |
|
| 590 |
def preprocess_html(html: str) -> str:
|
|
|
|
| 591 |
return re.sub(r"\*\*(.+?)\*\*", r"<h3>\1</h3>", html)
|
| 592 |
|
| 593 |
|
| 594 |
def generate_docx(html: str) -> str:
|
| 595 |
+
# Предварительная обработка HTML
|
| 596 |
html = preprocess_html(html)
|
|
|
|
|
|
|
| 597 |
soup = BeautifulSoup(f"<body>{html}</body>", "html.parser")
|
| 598 |
|
| 599 |
+
# Обработка стилей
|
| 600 |
for span in soup.select("span.cell-label"):
|
| 601 |
span["style"] = "display:block;font-size:9pt;margin-bottom:0.2em"
|
| 602 |
for span in soup.select("span.cell-value"):
|
| 603 |
span["style"] = "display:block;font-size:12pt"
|
| 604 |
|
| 605 |
+
# Создаем базовый документ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 606 |
doc = Document()
|
| 607 |
sec = doc.sections[-1]
|
| 608 |
sec.orientation = WD_ORIENT.LANDSCAPE
|
| 609 |
sec.page_width, sec.page_height = sec.page_height, sec.page_width
|
| 610 |
|
| 611 |
+
# Инициализация парсера
|
| 612 |
parser = HtmlToDocx()
|
| 613 |
parser.table_style = "TableGrid"
|
|
|
|
| 614 |
|
| 615 |
+
# Извлекаем и конвертируем основные блоки
|
| 616 |
+
header = soup.find('section', class_='header-block')
|
| 617 |
+
plan_tables = soup.find_all('table', {'border': '1'})
|
| 618 |
+
materials = soup.find('div', class_='reference-block')
|
| 619 |
+
|
| 620 |
+
# Конвертация шапки
|
| 621 |
+
if header:
|
| 622 |
+
safe_convert(parser, header, doc, "шапки")
|
| 623 |
+
else:
|
| 624 |
+
doc.add_paragraph("Отсутствует блок шапки")
|
| 625 |
+
|
| 626 |
+
# Конвертация этапов плана
|
| 627 |
+
if plan_tables:
|
| 628 |
+
for table in plan_tables:
|
| 629 |
+
safe_convert(parser, table, doc, "таблицы плана")
|
| 630 |
+
else:
|
| 631 |
+
doc.add_paragraph("Отсутствуют таблицы плана")
|
| 632 |
+
|
| 633 |
+
# Конвертация дополнительных материалов
|
| 634 |
+
if materials:
|
| 635 |
+
safe_convert(parser, materials, doc, "дополнительных материалов")
|
| 636 |
+
else:
|
| 637 |
+
doc.add_paragraph("Отсутствуют дополнительные материалы")
|
| 638 |
+
|
| 639 |
+
# Сохранение документа
|
| 640 |
tmp = tempfile.gettempdir()
|
| 641 |
fname = f"lesson_plan_{datetime.now():%Y%m%d%H%M%S}.docx"
|
| 642 |
path = os.path.join(tmp, fname)
|
| 643 |
+
|
| 644 |
+
try:
|
| 645 |
+
doc.save(path)
|
| 646 |
+
except Exception as e:
|
| 647 |
+
print(f"Критическая ошибка при сохранении: {str(e)}")
|
| 648 |
+
raise
|
| 649 |
+
|
| 650 |
return path
|
| 651 |
|
| 652 |
|