马一丁

Fix-“必须是非空数组”

@@ -686,6 +686,123 @@ class ChapterGenerationNode(BaseNode): @@ -686,6 +686,123 @@ class ChapterGenerationNode(BaseNode):
686 block_type = block.get("type") 686 block_type = block.get("type")
687 if block_type == "paragraph": 687 if block_type == "paragraph":
688 self._normalize_paragraph_block(block) 688 self._normalize_paragraph_block(block)
  689 + elif block_type == "table":
  690 + self._sanitize_table_block(block)
  691 +
  692 + def _sanitize_table_block(self, block: Dict[str, Any]):
  693 + """保证表格的rows/cells结构合法且每个单元格包含至少一个block"""
  694 + rows = self._normalize_table_rows(block.get("rows"))
  695 + block["rows"] = rows
  696 +
  697 + def _normalize_table_rows(self, rows: Any) -> List[Dict[str, Any]]:
  698 + """确保rows始终是由row对象组成的列表"""
  699 + if rows is None:
  700 + rows_iterable: List[Any] = []
  701 + elif isinstance(rows, list):
  702 + rows_iterable = rows
  703 + else:
  704 + rows_iterable = [rows]
  705 +
  706 + normalized_rows: List[Dict[str, Any]] = []
  707 + for row in rows_iterable:
  708 + sanitized_row = self._normalize_table_row(row)
  709 + if sanitized_row:
  710 + normalized_rows.append(sanitized_row)
  711 +
  712 + if not normalized_rows:
  713 + normalized_rows.append({"cells": [self._build_default_table_cell()]})
  714 + return normalized_rows
  715 +
  716 + def _normalize_table_row(self, row: Any) -> Dict[str, Any] | None:
  717 + """将各种行表达统一成{'cells': [...]}结构"""
  718 + if row is None:
  719 + return None
  720 + if isinstance(row, dict):
  721 + result = dict(row)
  722 + cells_value = result.get("cells")
  723 + else:
  724 + result = {}
  725 + cells_value = row
  726 +
  727 + cells = self._normalize_table_cells(cells_value)
  728 + if not cells:
  729 + cells = [self._build_default_table_cell()]
  730 + result["cells"] = cells
  731 + return result
  732 +
  733 + def _normalize_table_cells(self, cells: Any) -> List[Dict[str, Any]]:
  734 + """清洗单元格,保证每个cell下都有非空blocks"""
  735 + if cells is None:
  736 + cell_entries: List[Any] = []
  737 + elif isinstance(cells, list):
  738 + cell_entries = cells
  739 + else:
  740 + cell_entries = [cells]
  741 +
  742 + normalized_cells: List[Dict[str, Any]] = []
  743 + for cell in cell_entries:
  744 + sanitized = self._normalize_table_cell(cell)
  745 + if sanitized:
  746 + normalized_cells.append(sanitized)
  747 +
  748 + return normalized_cells
  749 +
  750 + def _normalize_table_cell(self, cell: Any) -> Dict[str, Any] | None:
  751 + """把各种单元格写法规整为schema认可的形式"""
  752 + if cell is None:
  753 + return {"blocks": [self._as_paragraph_block("")]}
  754 +
  755 + if isinstance(cell, dict):
  756 + normalized = dict(cell)
  757 + blocks = self._coerce_cell_blocks(normalized.get("blocks"), normalized)
  758 + elif isinstance(cell, list):
  759 + normalized = {}
  760 + blocks = self._coerce_cell_blocks(cell, None)
  761 + elif isinstance(cell, (str, int, float)):
  762 + normalized = {}
  763 + blocks = [self._as_paragraph_block(str(cell))]
  764 + else:
  765 + normalized = {}
  766 + blocks = [self._as_paragraph_block(str(cell))]
  767 +
  768 + normalized["blocks"] = blocks or [self._as_paragraph_block("")]
  769 + return normalized
  770 +
  771 + def _coerce_cell_blocks(
  772 + self, blocks: Any, source: Dict[str, Any] | None
  773 + ) -> List[Dict[str, Any]]:
  774 + """将cell.blocks字段强制转换为合法的block数组"""
  775 + if isinstance(blocks, list):
  776 + entries = blocks
  777 + elif blocks is None:
  778 + entries = []
  779 + else:
  780 + entries = [blocks]
  781 +
  782 + normalized_blocks: List[Dict[str, Any]] = []
  783 + for entry in entries:
  784 + if isinstance(entry, dict):
  785 + normalized_blocks.append(entry)
  786 + elif isinstance(entry, list):
  787 + normalized_blocks.extend(self._coerce_cell_blocks(entry, None))
  788 + elif isinstance(entry, (str, int, float)):
  789 + normalized_blocks.append(self._as_paragraph_block(str(entry)))
  790 + elif entry is None:
  791 + continue
  792 + else:
  793 + normalized_blocks.append(self._as_paragraph_block(str(entry)))
  794 +
  795 + if normalized_blocks:
  796 + return normalized_blocks
  797 +
  798 + text_hint = ""
  799 + if isinstance(source, dict):
  800 + text_hint = self._extract_block_text(source).strip()
  801 + return [self._as_paragraph_block(text_hint or "--")]
  802 +
  803 + def _build_default_table_cell(self) -> Dict[str, Any]:
  804 + """生成一个最小可渲染的空白单元格"""
  805 + return {"blocks": [self._as_paragraph_block("--")]}
689 806
690 def _normalize_paragraph_block(self, block: Dict[str, Any]): 807 def _normalize_paragraph_block(self, block: Dict[str, Any]):
691 """将paragraphinlines统一规整,剔除非法marks""" 808 """将paragraphinlines统一规整,剔除非法marks"""