Class: PublicationVisionWorker
- Inherits:
-
Object
- Object
- PublicationVisionWorker
- Includes:
- Sidekiq::Job, Workers::StatusBroadcastable
- Defined in:
- app/workers/publication_vision_worker.rb
Overview
Background worker for analyzing PDF publications with a vision model's native
PDF support (the :vision_analysis role — Gemini since f0ed0bae01, Claude before
that). Passes the full PDF inline, which reads all pages including vector
graphics, diagrams, photos, and embedded text — eliminating the need to extract
images before sending to a vision model.
Constant Summary collapse
- VISION_MODEL =
Vision model.
AiModelConstants.id(:vision_analysis)
- MAX_TOKENS_PDF_ANALYSIS =
Max tokens for full-document visual analysis
2_000- SYSTEM_PROMPT =
System prompt for analyzing full PDF documents
<<~PROMPT You are an expert analyst for technical product documentation PDFs. Analyze ALL pages of this document and describe the visual content you find. For each page containing meaningful visual content, describe: 1. DIAGRAMS: Wiring diagrams, installation layouts, floor plans, electrical schematics 2. ILLUSTRATIONS: Step-by-step instructions, cross-sections, product cutaways 3. PHOTOS: Product photos, installation examples, finished installations 4. TABLES/CHARTS: Specification tables, sizing charts, temperature curves 5. LABELS: Warning labels, certification marks, control panel layouts Be specific about what you can actually read or see: - Product names and model numbers if visible - Technical specifications shown - Installation steps or procedures depicted - Safety warnings or important notes Write in plain text, no markdown. Be concise but capture key technical details. Skip pages that contain only text. Do not hallucinate content that is not visible. PROMPT
Instance Attribute Summary
Attributes included from Workers::StatusBroadcastable
Instance Method Summary collapse
Methods included from Workers::StatusBroadcastable::Overrides
Instance Method Details
#perform(item_id, options = {}) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'app/workers/publication_vision_worker.rb', line 60 def perform(item_id, = {}) force = [:force].to_b redirect_to_path = [:redirect_to] store redirect_to: redirect_to_path if redirect_to_path.present? total 4 at 1, 'Loading publication...' item = Item.find_by(id: item_id) unless item store error_message: "Item #{item_id} not found" return log_info("Item #{item_id} not found, skipping") end unless item.is_publication? store error_message: "Item #{item_id} is not a publication" return log_info("Item #{item_id} is not a publication, skipping") end if item.pdf_images_analyzed_at.present? && !force store info_message: "Already analyzed at #{item.pdf_images_analyzed_at}" return log_info("Publication #{item_id} already analyzed at #{item.pdf_images_analyzed_at}") end unless item.literature&. && File.exist?(item.literature..path) store error_message: 'PDF file not found' return log_info("No PDF attachment found for publication #{item_id}") end at 2, "Analyzing PDF with #{VISION_MODEL}..." log_info "Analyzing publication #{item_id}: #{item.sku}" # Deliberately unrescued: a swallowed failure would stamp the update! below # with a blank description, which reads as "no visual content" and latches # the record out of future runs via the `analyzed && !force` guard above. description = analyze_pdf(item) at 3, 'Saving results...' item.update!( pdf_image_descriptions: description.presence, pdf_images_analyzed_at: Time.current ) if description.present? (item) at 4, 'Complete!' store info_message: 'Vision analysis complete' log_info "Publication #{item_id} vision analysis complete: #{description.length} chars" else at 4, 'Complete!' store info_message: 'No visual content found in PDF' log_info "No visual content found in publication #{item_id}" end rescue RubyLLM::Error => e log_error "RubyLLM error for Publication #{item_id}: #{e.}" raise rescue StandardError => e log_error "Error analyzing Publication #{item_id}: #{e.}" ErrorReporting.error(e) raise end |