from collections.abc import Sequence
from os import PathLike
from pathlib import Path
from typing import cast
from ._lib import BpeEncoderBase
from .trainer import FileFormat, Unit, _resolve_format, _validate_unit
import numpy as np
IdxArray = np.ndarray[tuple[int], np.dtype[np.uint32]]
class BpeEncoder:
def __init__(
self,
unit: "Unit" = "byte",
*,
special_tokens: Sequence[str] | None = None,
merges: list[tuple[bytes, bytes]] | None = None,
vocab: dict[bytes, int] | None = None,
pat_str: str | None = None,
) -> None:
_validate_unit(unit)
self.unit = unit
file_format = _resolve_format(unit, None)
self._encoder = BpeEncoderBase(
format=file_format,
unit=unit,
merges_file=None,
vocab_file=None,
merges=merges,
vocab=cast(dict[Sequence[int], int], vocab),
special_tokens=special_tokens,
pat_str=pat_str,
)
@classmethod
def _from_encoder(cls, unit: "Unit", encoder: BpeEncoderBase) -> "BpeEncoder":
instance = cls.__new__(cls)
instance.unit = unit
instance._encoder = encoder
return instance
@classmethod
def load(
cls,
name: str | None = None,
*,
unit: "Unit" = "byte",
format: "FileFormat | None" = None,
special_tokens: Sequence[str] | None = None,
input_dir: str | PathLike | None = None,
merges_file: str | PathLike | None = None,
vocab_file: str | PathLike | None = None,
pat_str: str | None = None,
) -> "BpeEncoder":
resolved_format = _resolve_format(unit, format)
if name is not None:
if merges_file is None:
merges_file = f"merges.{name}[{unit}].txt"
if vocab_file is None:
vocab_file = f"vocab.{name}[{unit}].json"
if input_dir is not None:
if merges_file is not None:
merges_file = Path(input_dir) / merges_file
if vocab_file is not None:
vocab_file = Path(input_dir) / vocab_file
return cls._from_encoder(
unit,
BpeEncoderBase(
format=resolved_format,
unit=unit,
merges_file=merges_file,
vocab_file=vocab_file,
merges=None,
vocab=None,
special_tokens=special_tokens,
pat_str=pat_str,
),
)
def encode_word(self, /, word: str) -> list[int]:
return self._encoder.encode_word(word)
def encode_words(self, /, words: Sequence[str]) -> list[list[int]]:
return self._encoder.encode_words(words)
def encode(self, /, text: str) -> list[int]:
return self._encoder.encode(text)
def encode_to_numpy(self, /, text: str) -> IdxArray:
return self._encoder.encode_to_numpy(text)
def encode_file(self, /, path: str | PathLike, num_chunks: int = 1024) -> IdxArray:
return self._encoder.encode_file(path, num_chunks)
def decode(self, /, idxs: Sequence[int] | IdxArray) -> str:
return self._encoder.decode(idxs)