コンテンツにスキップ

チャンカー

理解できる形式について、埋め込み単位の切り方を決めるチャンカーを追加します。

チャンカーはチャンク——リトリーバーがインデックスする埋め込み単位——が何であるかを決めます。エンコードごとに一度、すべての読み取りがページを生成した後、埋め込みの前に、各読み取りが見たのと同じバイト列とともに呼ばれます。形式を知っているチャンカーは、フラットな文字列が失った構造を求めてバイト列を開き直せますし、テキストだけで足りるチャンカーはページ出力から読み取れます。indx-chunker-pdf(PDFium のテキストランから行境界を得る)と indx-chunker-page(1 ページ 1 チャンクの下限)は、あなたの配布物とまったく同じエントリーポイントグループを通じて届きます。パッケージ化とインストールは概要の手順に従います。

from typing import Any
from indx_interfaces import (
CapabilityDescriptor,
CapabilityId,
Chunker,
ChunkPiece,
PageChunks,
PageOutput,
)
class ParagraphChunker:
def chunk(
self, content: bytes, media_type: str, outputs: tuple[PageOutput, ...]
) -> tuple[PageChunks, ...]:
# 空を返すのが「自分のものではない」という表明です。回答はページ
# ごとに統合され、チャンカー順で先勝ちなので、主張しなかったページ
# は次のチャンカーへ渡ります。
if media_type != "text/plain":
return ()
return tuple(
PageChunks(
page=output.page,
pieces=tuple(
ChunkPiece(text=paragraph)
for paragraph in output.text.split("\n\n")
if paragraph.strip()
),
)
for output in outputs
if output.text
)
class Provider:
def descriptors(self) -> tuple[CapabilityDescriptor, ...]:
# このディストリビューションは境界を引くだけで、何も読みません。
return ()
def create(self, capability_id: CapabilityId) -> Any:
raise ValueError(f"this provider declares no capabilities, so not {capability_id}")
def chunkers(self) -> tuple[Chunker, ...]:
return (ParagraphChunker(),)

ChunkerProviderSourceObserverProvider と同じく任意です。ページを読むだけで境界を引かないプロバイダーは実装しません。チャンカーは ID を持たず、記述子にも加わらず、機能スナップショットにはまったく公開されません。変わるのは実行出力の切り方だけで、それはどの計画にも記録されていません。インストールされたチャンカーは indx 同梱のものより先に並びます。indx-chunker-page だけが fallback = True を設定してすべての後ろに並びます。あらゆるページに答えるものは最後に問われる必要があるからです。

各 piece は空でないテキストと、Block.bbox と同じ方法で正規化された任意の bbox を持ちます。エグゼキューターが piece の順序からすべての page:N/chunk:M ID を生成します。例外の送出は「自分のものだが、壊れている」——ソースではなくチャンカーへの判定——を意味するため、エグゼキューターはログを残して次のチャンカーへ進み、すでに読み取りコストを払ったエンコードを失敗させません。開けないバイト列に対して例外を送出してはいけません。そのバイト列への判定は読み取り側がすでに下しています。

  • 境界を引けない文書には空を返す。理解できなかったページに piece をでっち上げない。
  • piece を読み順に並べる。エグゼキューターのチャンクインデックスと ID はその順序から導出される。
  • モジュールスコープを軽量に保つ。重いインポートは chunk() の中に置く。