-
Couldn't load subscription status.
- Fork 0
159 alt text sidekiq job #184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
99d63de
ba44a8d
86f5bdf
325806d
f19e69c
aa7db13
7eda02f
ce5a8fd
af3e6a9
adc6ebf
1337da8
2855f6f
86d26bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,33 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class ImageAltTextJob < ApplicationJob | ||
| def perform(job_uuid, uploaded_io, output_polling_timeout: OUTPUT_POLLING_TIMEOUT) | ||
| # To be implemented in #159 | ||
| # Open the file file in a temp/uploads path | ||
| # Call AltTextGem with path, prompt, llm_model | ||
| # Poll and reroute | ||
| # File.delete(tmp_path) if File.exist?(tmp_path) | ||
| include AppJobModule | ||
|
|
||
| def perform(job_uuid, tmp_path, output_polling_timeout: OUTPUT_POLLING_TIMEOUT) | ||
| client = AltText::Client.new( | ||
| access_key: ENV.fetch('AWS_ACCESS_KEY_ID', nil), | ||
| secret_key: ENV.fetch('AWS_SECRET_ACCESS_KEY', nil), | ||
| region: ENV.fetch('AWS_REGION', 'us-east-1') | ||
| ) | ||
| job = Job.find_by!(uuid: job_uuid) | ||
| timer = 0 | ||
| until alt_text = client.process_image(tmp_path, prompt: File.read('prompt.txt'), | ||
| model_id: ENV.fetch('LLM_MODEL', nil)) | ||
| sleep OUTPUT_POLLING_INTERVAL | ||
| timer += OUTPUT_POLLING_INTERVAL | ||
| if timer > output_polling_timeout | ||
| update_with_failure(job, 'Timed out waiting for alt-text') | ||
| FileUtils.rm_f(tmp_path) | ||
| return true | ||
| end | ||
| end | ||
|
||
| job.update( | ||
| status: 'completed', | ||
| finished_at: Time.zone.now, | ||
| alt_text: alt_text | ||
| ) | ||
| FileUtils.rm_f(tmp_path) | ||
|
||
| rescue StandardError => e | ||
| update_with_failure(job, e.message) | ||
| end | ||
| end | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| You are a professional technical writer trained in crafting image alternative text for accessibility purposes. Your task is to describe the visual content of uploaded images in clear, concise, and objective language that supports screen reader users. Describe the visual content of the image in one concise, objective sentence (≤100 characters). | ||
| When given an image, follow these guidelines to create appropriate and effective alternative text descriptions. | ||
| 1. Technical guidelines: | ||
| - Descriptions should not exceed 100 characters. | ||
| - Use precise, simple language and clear terminology. | ||
| - Use bias-free language: avoid assumptions about gender, ability, race, or age. | ||
| 2. Language guidelines: | ||
| - Do not use ambiguous adjectives (e.g., “tranquil,” “vintage,” “rural”). | ||
| - Do not use subjective adjectives (e.g., "traditional," "rustic") | ||
| - Avoid assumptions or guessing unclear elements. | ||
| - Do not include “image of,” “photo of,” or similar phrases. | ||
| - Focus only on the visible, essential elements in the image. | ||
| 3. Output guidelines: | ||
| - Assume one image per input and respond with one alt text string. | ||
| Please see the examples provided to help guide your description structure. | ||
| <examples> | ||
| "A lighthouse on a rocky coast under a cloudy sky." | ||
| "Three people walking along a path surrounded by green trees." | ||
| “A person wearing a beret and glasses eating from a bowl.” | ||
| </examples> | ||
| Generate the alt text description following these rules. | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'rails_helper' | ||
|
|
||
| RSpec.describe ImageAltTextJob do | ||
| let!(:job) { create(:image_job) } | ||
| let!(:alt_text_response) { 'Generated Alt-text' } | ||
| let(:alt_text_gem) { | ||
| instance_spy( | ||
| AltText::Client, | ||
| process_image: alt_text_response | ||
| ) | ||
| } | ||
| let!(:file_path) { Rack::Test::UploadedFile.new(File.new("#{Rails.root}/spec/fixtures/files/lion.jpg"), | ||
| 'image/jpg', | ||
| original_filename: 'lion.jpg').path } | ||
|
|
||
| before do | ||
| allow(AltText::Client).to receive(:new).and_return alt_text_gem | ||
| end | ||
|
|
||
| describe '#perform' do | ||
| context 'when the job is called with job uuid and file' do | ||
| before do | ||
| described_class.perform_now(job.uuid, file_path) | ||
| end | ||
|
|
||
| it 'calls the Alt Text gem' do | ||
| expect(alt_text_gem).to have_received(:process_image).with( | ||
| /.+\.jpg/, prompt: File.read('prompt.txt'), model_id: ENV.fetch('LLM_MODEL', nil) | ||
| ) | ||
| end | ||
|
|
||
| it 'updates the alt_text of the given image job record' do | ||
| reloaded_job = job.reload | ||
| expect(reloaded_job.status).to eq 'completed' | ||
| expect(reloaded_job.finished_at).to be_within(1.minute).of(Time.zone.now) | ||
| expect(job.reload.alt_text).to eq(alt_text_response) | ||
| end | ||
| end | ||
|
|
||
| context 'when alt-text is not produced before the timeout is exceeded' do | ||
| let(:alt_text_response) { nil } | ||
|
|
||
| it 'updates the status and metadata of the given image job record' do | ||
| described_class.perform_now(job.uuid, file_path, output_polling_timeout: 1) | ||
| reloaded_job = job.reload | ||
| expect(reloaded_job.status).to eq 'failed' | ||
| expect(reloaded_job.finished_at).to be_within(1.minute).of(Time.zone.now) | ||
| expect(reloaded_job.alt_text).to be_nil | ||
| expect(reloaded_job.processing_error_message).to eq 'Timed out waiting for alt-text' | ||
| expect(job.reload.alt_text).to be_nil | ||
| end | ||
| end | ||
|
|
||
| context 'when an error occurs while uploading the image file' do | ||
| before do | ||
| allow(alt_text_gem).to receive(:process_image).and_raise(StandardError) | ||
| end | ||
|
|
||
| it 'updates the status and metadata of the given image job record' do | ||
| described_class.perform_now(job.uuid, file_path) | ||
| reloaded_job = job.reload | ||
| expect(reloaded_job.status).to eq 'failed' | ||
| expect(reloaded_job.finished_at).to be_within(1.minute).of(Time.zone.now) | ||
| expect(reloaded_job.processing_error_message).to eq 'StandardError' | ||
| expect(job.reload.alt_text).to be_nil | ||
| end | ||
| end | ||
| end | ||
| end |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the
output_polling_timeoutargument can be removed.