Skip to content

如何標註文件與 PDF

把合同、報告和論文當作文件來標註,而不是壓平成純文本,讓版面、頁碼和跨頁引用都保留下來。

在文件渲染出來的頁面上標註,而不是在從中抽取的文本上標註,因為版面承載著抽取會丟掉的意義,也因為複核的人需要在頁面上找到那個標籤。 把一份合同壓平成一個字串,頁碼、分欄順序、表格結構以及腳註和正文的區別都會丟失。

文件標註正是常規文本標註那套做法失效的場合。PDF 描述的是頁面上的標記,而不是一串字元,所以兩個不同的抽取器會從同一個檔案裡給出兩個不同的字串。多欄頁面會相互穿插,頁首頁尾會出現在正文流中間,表格會變成一長串空白。在那個字串上打標籤的標註者,實際上是在給抽取器的產物打標籤,而後來開啟原件的複核者,並不總能判斷某個片段指的是哪一段。

位置、頁碼和引用結構

文件有三項屬性只在頁面上留存,在抽取出的文本里不留存。位置告訴複核者某個條款是標題、腳註還是正文,而抽取會把三者壓成同一串沒有區別的字元。頁碼是此後每一位讀者引用這段話的依據,而它只在頁面存在時才存在。引用結構記錄一段話指向什麼,只要某一頁上的論斷依賴於九頁之後的一張表,這一點就很重要。

最常逼人換工具的是第三項屬性。文件內部的引用結構是兩個位置之間的關係,而把文件建模成一個扁平字串的工具,沒有地方放第二個位置。法律審查、科學論斷核實和財報分析,都圍繞著這種關係。

三種錨定方式

文件上的標註有三種錨定方式,選哪一種取決於問題本身,而不是偏好。

  • 文本片段錨定在選中的詞上,適合關於措辭的問題。片段要求文件帶有文本層,原生數字 PDF 有這一層,掃描件沒有。
  • 區域框錨定在頁面座標上,適合圖、表、印章、簽名,以及任何文本層從未捕獲的內容。它在完全沒有文本抽取的掃描件上也能用。
  • 連結連線兩個錨點,適合引用結構。一條連結記錄文件中兩個位置之間帶類型、可選帶方向的關係。

在一個任務裡混用多種錨定方式很常見。論斷核實任務把論斷標為文本片段,把表格標為區域框,再用連結把二者連起來。

在 Potato 中的配置

Potato 的 pdf 顯示類型用 PDF.js 渲染檔案,並把標註層放在渲染後的頁面上。annotation_mode 選項決定錨定方式,取值為 span、bounding_box 或 link。回答引用問題的是連結模式,它把錨點和連結記在兩個不同的 schema 名下,所以匯出時二者可以區分開。

yaml
instance_display:
  fields:
    - key: pdf
      type: pdf
      label: "Document"
      display_options:
        annotation_mode: link
        view_mode: scroll
        zoom: page-width
        enable_text_anchors: true
        enable_region_anchors: true
        anchor_schema: pdf_anchors
        link_schema: pdf_links
        anchor_labels:
          - name: claim
            color: "#dc2626"
          - name: figure
            color: "#2563eb"
        link_types:
          - name: refers_to
            directed: true
            allowed_source_labels: [claim]
            allowed_target_labels: [figure]

view_mode: scroll 把各頁堆疊在一個容器裡,於是第 2 頁和第 9 頁之間的連結可以畫成、也看成一道完整的弧線。分頁的那種方式一次只顯示一頁,長文件讀起來更舒服,但標註者畫跨頁連結時看不到另一端。

allowed_source_labels 和 allowed_target_labels 是把一條指南變成介面會強制執行的東西。按上面的配置,refers_to 連結只能從論斷出發、只能落在圖上,標註者沒法把這種關係記反。只寫在文件裡的指南,執行程度參差不齊,而工具施加的約束,執行起來不花成本。

Word 或 Markdown 檔案改用 document 顯示類型,它保留標題和段落結構,並接受 span_target,所以片段 schema 可以直接指向它。

掃描文件

掃描件不帶文本層,文本錨點沒有可以附著的東西。有兩個選擇,各自適合不同的語料。按區域標註完全不需要文本,可以立刻上手。開啟 OCR 會在服務端生成一層文本,讓文本錨點成為可能,代價是一次緩慢的處理過程和對 Tesseract 的依賴。

yaml
instance_display:
  fields:
    - key: pdf
      type: pdf
      display_options:
        annotation_mode: link
        ocr: auto

auto 只在內嵌文本層返回為空時才執行 OCR,混有原生數字檔案和掃描件的語料就該用這個設定。Potato 只在連結模式下讀取 ocr 選項。

OCR 的輸出並不完美,錨定在識別錯誤的詞上的標註會繼承這個錯誤。在識別品質較差的語料上,區域錨點比文本錨點留下的記錄更耐久,因為圍著一段內容畫出的框,無論底下的字元被讀成什麼,都還是對的。

拿標籤去核對原件

每條標註返回時都帶著它所在的頁,這正是標籤可以拿回原件核對的原因。拿到頁碼和區域的複核者,可以開啟原件確認這個判斷。拿到拼接字串中字元偏移量的複核者通常做不到,因為要復現那個偏移量,就得復現生成它的那個抽取器及其版本。

這種做法得不償失的場合,是由短小的、單欄的、原生數字的、沒有引用結構的文件構成的語料,那裡抽取可靠,頁碼也不承載什麼。在這種情況下,對抽取文本做普通的片段標註更簡單,而且給出同樣的答案。

延伸閱讀

  • PDF 標註記錄了 pdf 顯示類型接受的每一個選項。
  • 實例顯示列出了各種顯示類型,以及哪些接受片段目標。
  • 片段連結講的是文本中片段之間帶類型的關係。
  • 撰寫標註指南講的是受約束的連結類型可以替代掉的那些指南。