Class: PublicationVisionWorker
- Inherits:
-
Object
- Object
- PublicationVisionWorker
- Includes:
- Sidekiq::Worker, Workers::StatusBroadcastable
- Defined in:
- app/workers/publication_vision_worker.rb
Overview
Background worker for analyzing PDF publications using Claude's native PDF vision capabilities.
Passes the full PDF directly to Claude, which natively 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 =
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
58 59 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 |
# File 'app/workers/publication_vision_worker.rb', line 58 def perform(item_id, = {}) = .with_indifferent_access 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 Claude Vision...' log_info "Analyzing publication #{item_id}: #{item.sku}" description = analyze_pdf(item) at 3, 'Saving results...' item.update!( pdf_image_descriptions: description.presence, pdf_images_analyzed_at: Time.current ) if description.present? EmbeddingWorker.perform_async('Item', item_id, force: true) 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 |