Class: Assistant::PdfUrlReader

Inherits:
Object
  • Object
show all
Defined in:
app/services/assistant/pdf_url_reader.rb

Overview

Downloads a PDF from a public URL and reads it via Claude (full text +
visual content extraction). Used by the fetch_url tool for .pdf URLs and
for pages that turn out to serve application/pdf without the suffix.

Split out of WebFetchToolBuilder to keep the tool factory
thin (Metrics/AbcSize on the builder) — the crawler's
Heatwave::Crawler::Result carries extracted content, not binary
bodies, so the PDF byte download stays here rather than in a tier.

Constant Summary collapse

MAX_PDF_BYTES =

Returns maximum PDF size in bytes.

Returns:

  • (Integer)

    maximum PDF size in bytes

20 * 1024 * 1024

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url, timeout_seconds) ⇒ void

Parameters:

  • url (String)

    the PDF URL

  • timeout_seconds (Integer)

    download timeout



29
30
31
32
# File 'app/services/assistant/pdf_url_reader.rb', line 29

def initialize(url, timeout_seconds)
  @url = url
  @timeout_seconds = timeout_seconds
end

Class Method Details

.call(url, timeout_seconds: 15) ⇒ String

Returns JSON: { url:, content:, retrieval_method: } or { error:, url: }.

Parameters:

  • url (String)

    the PDF URL

  • timeout_seconds (Integer) (defaults to: 15)

    download timeout (clamped 5..30 by caller)

Returns:

  • (String)

    JSON: { url:, content:, retrieval_method: } or { error:, url: }



21
22
23
# File 'app/services/assistant/pdf_url_reader.rb', line 21

def call(url, timeout_seconds: 15)
  new(url, timeout_seconds).call
end

Instance Method Details

#callString

Returns JSON result or error envelope.

Returns:

  • (String)

    JSON result or error envelope



35
36
37
38
39
40
41
42
43
44
# File 'app/services/assistant/pdf_url_reader.rb', line 35

def call
  response = download
  return error_json('Failed to download PDF from URL') unless response&.status&.success?
  return error_json('PDF is too large to process safely (>20MB)') if too_large?(response)

  read_via_claude(response)
rescue StandardError => e
  Rails.logger.error("[PdfUrlReader] failed for #{Heatwave::Crawler::Guards.sanitize_url_for_log(url)}: #{e.message}")
  error_json("PDF reading failed: #{e.message}")
end