127 lines
5.2 KiB
Python
127 lines
5.2 KiB
Python
"""
|
||
Однократная/повторная генерация criteria_interface_layout.json из Excel
|
||
«Запрос для ИИ Общий(2).xlsx» (листы с «интерфейс» в названии).
|
||
|
||
Запуск (путь к xlsx можно передать аргументом):
|
||
py extract_criteria_interface_layout.py "C:\\Users\\...\\Запрос для ИИ Общий(2).xlsx"
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
import sys
|
||
|
||
import openpyxl
|
||
|
||
SHEET_TO_SHIPPING_TYPES: dict[str, list[str]] = {
|
||
"Авто LTL интерфейс": ["Автомобильная перевозка (LTL)"],
|
||
"Авто FTL интерфейс": ["Автомобильная перевозка (FTL)"],
|
||
"Море, море+жд, жд LCL интерфейc": [
|
||
"Морская перевозка (LCL)",
|
||
"Железнодорожная перевозка (LCL)",
|
||
"Мультимодальная перевозка море + ж/д (LCL)",
|
||
],
|
||
"Море, море+жд, жд FCL интерфейc": [
|
||
"Морская перевозка (FCL)",
|
||
"Железнодорожная перевозка (FCL)",
|
||
"Мультимодальная перевозка море + ж/д (FCL)",
|
||
],
|
||
"Авиа Интерфейс": ["Авиаперевозка"],
|
||
}
|
||
|
||
|
||
def _row_cells(ws, r: int, max_c: int = 12) -> list[tuple[int, str]]:
|
||
out: list[tuple[int, str]] = []
|
||
for c in range(1, max_c + 1):
|
||
v = ws.cell(r, c).value
|
||
if v is not None and str(v).strip():
|
||
out.append((c, str(v).strip()))
|
||
return out
|
||
|
||
|
||
def parse_interface_sheet(ws) -> list[dict]:
|
||
"""Разбор листа интерфейса в последовательность визуальных блоков."""
|
||
blocks: list[dict] = []
|
||
r = 1
|
||
max_r = ws.max_row or 1
|
||
while r <= max_r:
|
||
cells = _row_cells(ws, r)
|
||
if not cells:
|
||
r += 1
|
||
continue
|
||
|
||
# Заголовок: 7 ячеек в колонках 1,2,3,4,5,7,9 и все значения — «номера пунктов»
|
||
if (
|
||
len(cells) == 7
|
||
and {c[0] for c in cells} == {1, 2, 3, 4, 5, 7, 9}
|
||
and all(str(c[1]).strip().isdigit() or c[1].strip().replace(".", "").isdigit() for c in cells)
|
||
):
|
||
nums = [c[1] for c in sorted(cells, key=lambda x: (x[0] not in (1, 2, 3, 4, 5, 7, 9), x[0]))]
|
||
# порядок как в Excel слева направо по колонкам
|
||
nums = [c[1] for c in sorted(cells, key=lambda x: x[0])]
|
||
r2 = r + 1
|
||
cells2 = _row_cells(ws, r2)
|
||
if len(cells2) == 7 and {c[0] for c in cells2} == {1, 2, 3, 4, 5, 7, 9}:
|
||
labels = [c[1] for c in sorted(cells2, key=lambda x: x[0])]
|
||
blocks.append({"type": "header", "nums": nums, "labels": labels})
|
||
r += 2
|
||
continue
|
||
|
||
# Только правая пара (6 = номер, 7 = текст) — например «20 Место таможни»
|
||
if len(cells) == 2 and cells[0][0] == 6 and cells[1][0] == 7:
|
||
blocks.append({"type": "right_67", "num": cells[0][1], "label": cells[1][1]})
|
||
r += 1
|
||
continue
|
||
|
||
# Две пары: 1-2 и 6-7
|
||
if len(cells) == 4 and {cells[i][0] for i in range(4)} == {1, 2, 6, 7}:
|
||
blocks.append(
|
||
{
|
||
"type": "pair",
|
||
"left": {"num": cells[0][1], "label": cells[1][1]},
|
||
"right": {"num": cells[2][1], "label": cells[3][1]},
|
||
}
|
||
)
|
||
r += 1
|
||
continue
|
||
|
||
# Только левая пара 1-2 (один блок на строку)
|
||
if len(cells) == 2 and cells[0][0] == 1 and cells[1][0] == 2:
|
||
blocks.append({"type": "left_12", "num": cells[0][1], "label": cells[1][1]})
|
||
r += 1
|
||
continue
|
||
|
||
r += 1
|
||
return blocks
|
||
|
||
|
||
def main() -> None:
|
||
xlsx = (
|
||
sys.argv[1]
|
||
if len(sys.argv) > 1
|
||
else os.path.join(os.path.dirname(__file__), "Запрос для ИИ Общий(3).xlsx")
|
||
)
|
||
if not os.path.isfile(xlsx):
|
||
print("Файл не найден:", xlsx)
|
||
sys.exit(1)
|
||
|
||
wb = openpyxl.load_workbook(xlsx, read_only=False, data_only=True)
|
||
out: dict = {"version": 1, "source_xlsx": os.path.basename(xlsx), "by_shipping_type": {}}
|
||
|
||
for sheet_name, type_names in SHEET_TO_SHIPPING_TYPES.items():
|
||
if sheet_name not in wb.sheetnames:
|
||
print("Пропуск: лист не найден:", sheet_name)
|
||
continue
|
||
blocks = parse_interface_sheet(wb[sheet_name])
|
||
for tn in type_names:
|
||
out["by_shipping_type"][tn] = {"sheet": sheet_name, "blocks": blocks}
|
||
|
||
out_path = os.path.join(os.path.dirname(__file__), "criteria_interface_layout.json")
|
||
with open(out_path, "w", encoding="utf-8") as f:
|
||
json.dump(out, f, ensure_ascii=False, indent=2)
|
||
print("Записано:", out_path, "типов:", len(out["by_shipping_type"]))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|