Module: Braintrust::Contrib::Support::OpenAI
- Defined in:
- lib/braintrust/contrib/support/openai.rb
Overview
OpenAI API-specific utilities shared across OpenAI integrations. These work with normalized data structures (hashes), not library-specific objects.
Class Method Summary collapse
-
.parse_usage_tokens(usage) ⇒ Hash<String, Integer>
Parse OpenAI usage tokens into normalized Braintrust metrics.
Class Method Details
.parse_usage_tokens(usage) ⇒ Hash<String, Integer>
Parse OpenAI usage tokens into normalized Braintrust metrics. Handles standard fields and *_tokens_details nested objects. Works with both Hash objects and SDK response objects (via to_h).
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/braintrust/contrib/support/openai.rb', line 14 def self.parse_usage_tokens(usage) metrics = {} return metrics unless usage usage_hash = usage.respond_to?(:to_h) ? usage.to_h : usage return metrics unless usage_hash.is_a?(Hash) # Field mappings: OpenAI → Braintrust # Supports both Chat Completions API (prompt_tokens, completion_tokens) # and Responses API (input_tokens, output_tokens) field_map = { "prompt_tokens" => "prompt_tokens", "completion_tokens" => "completion_tokens", "total_tokens" => "tokens", # Responses API uses different field names "input_tokens" => "prompt_tokens", "output_tokens" => "completion_tokens" } # Prefix mappings for *_tokens_details prefix_map = { "prompt" => "prompt", "completion" => "completion", # Responses API uses input/output prefixes "input" => "prompt", "output" => "completion" } usage_hash.each do |key, value| key_str = key.to_s if value.is_a?(Numeric) target = field_map[key_str] metrics[target] = value.to_i if target elsif key_str.end_with?("_tokens_details") # Convert to hash if it's an object (OpenAI SDK returns objects) details_hash = value.respond_to?(:to_h) ? value.to_h : value next unless details_hash.is_a?(Hash) raw_prefix = key_str.sub(/_tokens_details$/, "") prefix = prefix_map[raw_prefix] || raw_prefix details_hash.each do |detail_key, detail_value| next unless detail_value.is_a?(Numeric) metrics["#{prefix}_#{detail_key}"] = detail_value.to_i end end end # Calculate total if missing if !metrics.key?("tokens") && metrics.key?("prompt_tokens") && metrics.key?("completion_tokens") metrics["tokens"] = metrics["prompt_tokens"] + metrics["completion_tokens"] end metrics end |