Class: Seo::AnthropicBatchClient
- Inherits:
-
Object
- Object
- Seo::AnthropicBatchClient
- Defined in:
- app/services/seo/anthropic_batch_client.rb
Overview
Lightweight Faraday client for the Anthropic Message Batches API.
Used by the SEO batch pipeline to submit analysis requests at 50% cost.
API reference: https://platform.claude.com/docs/en/build-with-claude/batch-processing
Defined Under Namespace
Classes: BatchError, RateLimitError
Constant Summary collapse
- BASE_URL =
URL for base.
'https://api.anthropic.com'- API_VERSION =
Api version.
'2023-06-01'
Class Method Summary collapse
-
.build_request(custom_id:, system_prompt:, user_prompt:, model:, max_tokens: Seo::PageAnalysisService::MAX_OUTPUT_TOKENS, temperature: Seo::PageAnalysisService::TEMPERATURE, thinking: nil) ⇒ Hash
Build a single batch request entry from prompt data.
Instance Method Summary collapse
-
#cancel_batch(batch_id) ⇒ Hash
Cancel a batch that is still processing.
-
#create_batch(requests) ⇒ Hash
Create a new Message Batch.
-
#get_batch(batch_id) ⇒ Hash
Retrieve the current status of a Message Batch.
-
#initialize(api_key: nil) ⇒ AnthropicBatchClient
constructor
A new instance of AnthropicBatchClient.
-
#stream_results(batch_id) {|Hash| ... } ⇒ Object
Stream results from a completed batch as JSONL.
Constructor Details
#initialize(api_key: nil) ⇒ AnthropicBatchClient
Returns a new instance of AnthropicBatchClient.
25 26 27 28 |
# File 'app/services/seo/anthropic_batch_client.rb', line 25 def initialize(api_key: nil) @api_key = api_key || Heatwave::Configuration.fetch(:claude_ai, :api_key) raise ArgumentError, 'Anthropic API key is required' if @api_key.blank? end |
Class Method Details
.build_request(custom_id:, system_prompt:, user_prompt:, model:, max_tokens: Seo::PageAnalysisService::MAX_OUTPUT_TOKENS, temperature: Seo::PageAnalysisService::TEMPERATURE, thinking: nil) ⇒ Hash
Build a single batch request entry from prompt data.
Wraps the system prompt with cache_control for prompt caching
(shared system prompt across all batch items = high cache hit rate).
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 123 124 125 126 127 128 129 |
# File 'app/services/seo/anthropic_batch_client.rb', line 96 def self.build_request(custom_id:, system_prompt:, user_prompt:, model:, max_tokens: Seo::PageAnalysisService::MAX_OUTPUT_TOKENS, temperature: Seo::PageAnalysisService::TEMPERATURE, thinking: nil) params = { model: model, max_tokens: max_tokens, system: [ { type: 'text', text: system_prompt, cache_control: { type: 'ephemeral' } } ], messages: [ { role: 'user', content: user_prompt } ] } # Opus 4.7+ / Sonnet 5+ removed BOTH sampling params and budget_tokens # thinking — either one 400s, so the premium (Opus) batch takes adaptive # thinking and no temperature at all. Older models keep the legacy shape, # where Anthropic requires temperature=1 when thinking is enabled. if AiModelConstants.rejects_sampling_params?(model) params[:thinking] = { type: 'adaptive' } if thinking elsif thinking params[:thinking] = thinking params[:temperature] = 1 else params[:temperature] = temperature end { custom_id: custom_id, params: params } end |
Instance Method Details
#cancel_batch(batch_id) ⇒ Hash
Cancel a batch that is still processing.
79 80 81 82 |
# File 'app/services/seo/anthropic_batch_client.rb', line 79 def cancel_batch(batch_id) response = connection.post("/v1/messages/batches/#{batch_id}/cancel") handle_response(response) end |
#create_batch(requests) ⇒ Hash
Create a new Message Batch.
36 37 38 39 40 41 42 |
# File 'app/services/seo/anthropic_batch_client.rb', line 36 def create_batch(requests) response = connection.post('/v1/messages/batches') do |req| req.body = { requests: requests }.to_json end handle_response(response) end |
#get_batch(batch_id) ⇒ Hash
Retrieve the current status of a Message Batch.
48 49 50 51 |
# File 'app/services/seo/anthropic_batch_client.rb', line 48 def get_batch(batch_id) response = connection.get("/v1/messages/batches/#{batch_id}") handle_response(response) end |
#stream_results(batch_id) {|Hash| ... } ⇒ Object
Stream results from a completed batch as JSONL.
Each line is a JSON object with custom_id and result.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'app/services/seo/anthropic_batch_client.rb', line 58 def stream_results(batch_id) batch = get_batch(batch_id) results_url = batch['results_url'] raise BatchError, "Batch #{batch_id} has no results_url (status: #{batch['processing_status']})" unless results_url response = connection.get(results_url) raise BatchError, "Failed to fetch results: #{response.status}" unless response.success? response.body.each_line do |line| line = line.strip next if line.empty? result = JSON.parse(line) yield result end end |