Class: PromptWarden::CostCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/prompt_warden/cost_calculator.rb

Constant Summary collapse

MODEL_PRICING =

Model pricing (per 1K tokens) - updated as of 2024

{
  # OpenAI Models
  'gpt-4o' => { input: 0.0025, output: 0.01 },
  'gpt-4o-mini' => { input: 0.00015, output: 0.0006 },
  'gpt-4-turbo' => { input: 0.01, output: 0.03 },
  'gpt-4' => { input: 0.03, output: 0.06 },
  'gpt-3.5-turbo' => { input: 0.0005, output: 0.0015 },

  # Anthropic Models
  'claude-3-opus-20240229' => { input: 0.015, output: 0.075 },
  'claude-3-sonnet-20240229' => { input: 0.003, output: 0.015 },
  'claude-3-haiku-20240307' => { input: 0.00025, output: 0.00125 },
  'claude-3-5-sonnet-20241022' => { input: 0.003, output: 0.015 },

  # Default fallback
  'default' => { input: 0.001, output: 0.002 }
}.freeze

Class Method Summary collapse

Class Method Details

.calculate_cost(prompt:, model:, response_tokens: nil) ⇒ Object



27
28
29
30
31
32
33
34
35
36
# File 'lib/prompt_warden/cost_calculator.rb', line 27

def calculate_cost(prompt:, model:, response_tokens: nil)
  input_tokens = count_tokens(prompt, model)
  output_tokens = response_tokens || estimate_output_tokens(prompt, model)

  pricing = get_model_pricing(model)
  input_cost = (input_tokens / 1000.0) * pricing[:input]
  output_cost = (output_tokens / 1000.0) * pricing[:output]

  (input_cost + output_cost).round(6)
end

.count_tokens(text, model = nil) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/prompt_warden/cost_calculator.rb', line 38

def count_tokens(text, model = nil)
  return 0 if text.nil? || text.empty?

  # Use tiktoken for OpenAI models if available
  if model&.start_with?('gpt-') && defined?(Tiktoken)
    count_tokens_tiktoken(text, model)
  else
    # Fallback to approximate counting
    count_tokens_approximate(text)
  end
end

.estimate_output_tokens(prompt, model) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/prompt_warden/cost_calculator.rb', line 50

def estimate_output_tokens(prompt, model)
  return 0 if prompt.nil? || prompt.empty?

  # Rough estimation based on prompt length and model
  base_tokens = prompt.length / 4  # ~4 chars per token

  # Adjust based on model type
  case model
  when /gpt-4o/
    (base_tokens * 0.8).round  # More efficient
  when /claude-3-opus/
    (base_tokens * 1.2).round  # More verbose
  when /claude-3-sonnet/
    (base_tokens * 1.0).round  # Standard
  when /claude-3-haiku/
    (base_tokens * 0.7).round  # Concise
  else
    base_tokens.round
  end
end

.get_model_pricing(model) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/prompt_warden/cost_calculator.rb', line 71

def get_model_pricing(model)
  return MODEL_PRICING['default'] unless model

  # Try exact match first
  return MODEL_PRICING[model] if MODEL_PRICING[model]

  # Try partial matches for model variants
  MODEL_PRICING.each do |key, pricing|
    next if key == 'default'
    return pricing if model.include?(key.split('-').first) || key.include?(model.split('-').first)
  end

  MODEL_PRICING['default']
end