跳转至

Product Library Parse Technical Design

Goal

产品库导入的目标是稳定、可解释地把用户上传的产品清单文件转换为 products 数据。中文产品清单通常包含多 sheet、多行表头、合并单元格、空列、备注行、技术参数大段文本和内嵌图片,因此不能把模型抽取作为主路径。

最终策略:

Excel 原始结构解析
-> 中文表头识别
-> 行级产品结构化
-> Excel 内嵌图片抽取、上传与锚点关联
-> 入库

Current Flow

入口位于 ProductLibraryService.process_parse_orchestrator

  1. 任务进入 PROCESSING,记录 ProductParseStage.INIT
  2. 校验文件为 .xlsx.xls,读取源文件二进制。
  3. 调用 _extract_products_from_xlsx_structured_bytes 执行结构化解析。
  4. 调用 upload_xlsx_images 处理 Excel 内嵌图片并按锚点关联产品。
  5. 写入 parse_job.result_data
  6. 自动调用 _auto_apply_parse_job_results 入库。
  7. result_summary 记录 parse_mode、产品数、图片数和关联数。

Structured Excel Parser

结构化解析不依赖 openpyxl,直接读取 OOXML:

  • xl/workbook.xml:读取 sheet 名称和顺序
  • xl/_rels/workbook.xml.rels:解析 sheet 路径
  • xl/sharedStrings.xml:解析共享字符串
  • xl/worksheets/sheet*.xml:读取单元格值
  • mergeCells:将合并单元格锚点值补齐到被合并区域

这样能保留 Excel 原始行列结构,避免 xlsx -> markdown 后丢失表头和合并单元格语义。

Header Detection

字段识别由 _product_field_aliases 维护中文同义词。

当前字段:

  • name:产品名称、物品名称、名称、品名、设备名称、货物名称、项目名称、项目、标的名称
  • category:分类、类别、品类、区域、类型
  • model_spec:规格型号、型号规格、规格、型号、技术规格
  • unit:单位、计量单位
  • brand:品牌、参考品牌、推荐品牌、报价品牌
  • quantity:数量、采购数量、数 量、单位数量
  • price:单价、最高限价、限价、控制单价、综合单价、报价单价、预算单价
  • technical_params:技术参数、技术规格、技术规格要点、设备参数、需求说明

每个 sheet 会扫描前 20 个非空行,选择包含 name 且得分最高的行作为表头。得分依据是命中的字段数量,name 字段额外加权。

Row Mapping

命中表头后,从表头下一行开始逐行生成产品:

  • name 为空则跳过
  • category 为空默认 设备物资
  • technical_params 为空时使用 model_spec
  • quantityprice 合并写入 quantity_desc
  • 每条结果带内部诊断字段:
  • _parse_mode=structured_xlsx
  • _source_sheet
  • _source_row

内部诊断字段只用于流程调试和图片关联,入库时不会写入 Product 字段。

Embedded Images

Excel 图片处理由 upload_xlsx_images 完成。

读取路径:

worksheet drawing r:id
-> xl/worksheets/_rels/sheet*.xml.rels
-> xl/drawings/drawing*.xml
-> xl/drawings/_rels/drawing*.xml.rels
-> xl/media/image*

处理逻辑:

  1. 读取图片 anchor 的 sheet、row、col。
  2. 读取图片二进制并计算 sha256。
  3. 上传到对象存储: product-libraries/{library_id}/parse/{parse_job_id}/images/{sha}.ext
  4. 写入 product_parse_images
  5. image_role
  6. upload_status=UPLOADED
  7. related_product_key
  8. oss_url
  9. reason=xlsx_anchor ...
  10. 根据同 sheet 最近的产品行,把图片 URL 追加到 Product.product_image

当前流程不调用文本或视觉模型;无法识别产品名称列时任务直接失败。 - 大量行级产品 - 成本和稳定性敏感的批量导入

Observability

结构化解析成功时日志会包含:

parse_mode=structured_xlsx, sheets={n}, parsed_items={n}, images={...}

AI 兜底时日志会包含:

parse_mode=llm_fallback, parsed_items={n}

ProductParseJob.result_summary 会记录:

  • parse_mode
  • parsed_count
  • applied_count
  • image_total
  • image_uploaded
  • image_linked
  • image_classified
  • image_role_counts

Limitations

当前实现已覆盖 Excel 原始结构解析、内嵌图片抽取和视觉分类,但仍有边界:

  • 图片与产品行按同 sheet 最近 row 关联,复杂浮动布局可能需要人工确认。
  • .xls 依赖 LibreOffice 转 .xlsx 后再解析。
  • 低置信字段未逐行调用模型补全;当前只有结构化解析为 0 时才调用模型。

Next Improvements

建议后续按收益排序扩展:

  1. 对字段缺失较多的产品行做局部 AI 补全,而不是全文 AI 抽取。
  2. 将 header mapping 和 sheet 命中摘要暴露到管理端,便于运营排查模板适配问题。
  3. 为典型产品清单样例增加单元测试,覆盖合并单元格、多 sheet、图片 anchor 和中文表头变体。