Turns the bytes of an attachment into what the model reads (spec §9): the text of a text file, a CSV file or a PDF; CSV text of a workbook; JPEG or PNG pictures of an image or of the first pages of a scan.
Every function takes the path of a file already read from Storage and
answers {:ok, result} or {:error, code}; the codes are the ones the
attachment row keeps in error (unreadable, too_large,
pdf_tools_missing, image_tools_missing) and say nothing of the content.
A file that makes a parser raise is unreadable; what the parser said is
dropped, as it can quote the file.
What is not shown
A text that holds less than the file is truncated, and says so where it
ends, in a line the model reads with it (continues/1): [... the file continues: 12 more rows not shown in full], [... the sheet continues: 1240 of 1300 rows not shown in full], [... the workbook continues: 2 more sheets not shown: Q3, Q4], [... the document continues: 38 of 50 pages not shown in full] — so that a total or a count is not taken from part of the data
without a word. These lines are not counted in text_chars.
A workbook's sheets share text_chars: a sheet that needs less than an
equal share leaves the rest to the others, and each is cut between rows, so
one large sheet does not push the others out.
Summary
Types
The text of a PDF, with how many pages it has.
Text for the model, cut to the limit; truncated when the file had more.
Functions
The first rows of a CSV file, as written in it (any delimiter).
The text of a PDF (pdftotext) with its page count. {:ok, {:scan, pages}}
when it holds (almost) no text: a scan, to be read as pictures.
The first pages of a PDF as PNG binaries (at most scan_pages, 1600 px on the long side) and the page count.
A picture as a JPEG whose long side is at most 1600 px (never enlarged),
upright, on white where it was transparent, without its camera metadata
(EXIF with the place and time of a photo, XMP, IPTC, comments:
PhoenixKitAgent.Attachments.Jpeg.strip_metadata/1) — what goes to a model
provider is the picture, not where it was taken.
The start of a text file as text (a byte order mark and NUL bytes dropped). A byte that is not UTF-8 shows as U+FFFD, it is not silently left out.
A workbook as CSV: for each sheet (hidden ones left out) a ## Name line and
its first rows, blank rows skipped, each sheet within its share of
text_chars (see the moduledoc). The parts of the workbook are inflated
by PhoenixKitAgent.Attachments.Unzip, which counts the bytes it produces
and does not believe the sizes the file declares: one that unpacks to more
than the limit is :too_large, however it was forged, and is not opened.
Types
@type pdf_text() :: %{text: String.t(), pages: pos_integer(), truncated: boolean()}
The text of a PDF, with how many pages it has.
Text for the model, cut to the limit; truncated when the file had more.
Functions
The first rows of a CSV file, as written in it (any delimiter).
@spec pdf(Path.t()) :: {:ok, pdf_text()} | {:ok, {:scan, pos_integer()}} | {:error, :unreadable | :pdf_tools_missing}
The text of a PDF (pdftotext) with its page count. {:ok, {:scan, pages}}
when it holds (almost) no text: a scan, to be read as pictures.
@spec pdf_pages(Path.t()) :: {:ok, [binary()], pos_integer()} | {:error, :unreadable | :pdf_tools_missing}
The first pages of a PDF as PNG binaries (at most scan_pages, 1600 px on the long side) and the page count.
A picture as a JPEG whose long side is at most 1600 px (never enlarged),
upright, on white where it was transparent, without its camera metadata
(EXIF with the place and time of a photo, XMP, IPTC, comments:
PhoenixKitAgent.Attachments.Jpeg.strip_metadata/1) — what goes to a model
provider is the picture, not where it was taken.
The start of a text file as text (a byte order mark and NUL bytes dropped). A byte that is not UTF-8 shows as U+FFFD, it is not silently left out.
A workbook as CSV: for each sheet (hidden ones left out) a ## Name line and
its first rows, blank rows skipped, each sheet within its share of
text_chars (see the moduledoc). The parts of the workbook are inflated
by PhoenixKitAgent.Attachments.Unzip, which counts the bytes it produces
and does not believe the sizes the file declares: one that unpacks to more
than the limit is :too_large, however it was forged, and is not opened.