Module: LlmCostTracker::Providers::Openai::ResponseParser

Includes:
ServiceCharges
Included in:
Azure::Parser, Parser, LlmCostTracker::Providers::OpenaiCompatible::Parser
Defined in:
lib/llm_cost_tracker/providers/openai/response_parser.rb

Constant Summary

Constants included from ServiceCharges

ServiceCharges::CHAT_COMPLETIONS_ANNOTATION_PROVIDER_FIELD, ServiceCharges::CHAT_COMPLETIONS_SEARCH_MODEL_PROVIDER_FIELD, ServiceCharges::RESPONSE_OUTPUT_RENAMES

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ServiceCharges

billable?, build_line_item, chat_completions_search_model?, chat_completions_search_provider_field, chat_completions_used_web_search?, chat_completions_web_search_items, dimension_key_for, line_item_details, line_items_from_output, local_model_name, openai_stream_service_line_items, output_dimension, reasoning_model?, service_line_items_for, store_output_item, transcription_line_items, web_search_preview_used?

Class Method Details

.combined_pricing_mode(host:, model:, service_tier:) ⇒ Object



17
18
19
20
21
# File 'lib/llm_cost_tracker/providers/openai/response_parser.rb', line 17

def combined_pricing_mode(host:, model:, service_tier:)
  modes = [Pricing::Mode.normalize(service_tier)]
  modes << "data_residency" if Hosts.data_residency?(host) && ModelFamilies.data_residency?(model)
  Pricing::Mode.compose(modes)
end

.event_from_response(response:, request:, provider:, host:, usage_source:, pricing_mode: nil) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/llm_cost_tracker/providers/openai/response_parser.rb', line 23

def event_from_response(response:, request:, provider:, host:, usage_source:, pricing_mode: nil)
  usage = response["usage"]&.deep_symbolize_keys
  return nil unless usage

  model = response["model"] || request["model"]
  service_line_items =
    ServiceCharges.service_line_items_for(response, request: request, model: response["model"]) +
    ServiceCharges.transcription_line_items(usage)
  Event.build(
    provider: provider,
    provider_response_id: response["id"],
    pricing_mode: pricing_mode || combined_pricing_mode(
      host: host, model: model, service_tier: response["service_tier"] || request["service_tier"]
    ),
    model: model,
    token_usage: UsageExtractor.token_usage(usage, model: model),
    usage_source: usage_source,
    service_line_items: service_line_items
  )
end

Instance Method Details

#auto_enable_stream_usage?(request_url) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/llm_cost_tracker/providers/openai/response_parser.rb', line 70

def auto_enable_stream_usage?(request_url)
  openai_chat_completions_url?(request_url)
end

#parse(request_url:, request_body:, response_status:, response_body:) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/llm_cost_tracker/providers/openai/response_parser.rb', line 45

def parse(request_url:, request_body:, response_status:, response_body:, **)
  return nil unless response_status == 200

  ResponseParser.event_from_response(
    response: safe_json_parse(response_body),
    request: safe_json_parse(request_body),
    provider: provider_for(request_url),
    host: parsed_uri(request_url)&.host,
    usage_source: Usage::Source::RESPONSE
  )
end

#parse_stream(response_status:, request_url: nil, request_body: nil, events: []) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/llm_cost_tracker/providers/openai/response_parser.rb', line 57

def parse_stream(response_status:, request_url: nil, request_body: nil, events: [], **)
  return nil unless response_status == 200

  request = safe_json_parse(request_body)
  usage = detect_stream_usage(events)
  context = stream_capture_context(events: events, request: request, request_url: request_url)

  return build_known_stream_usage(usage: usage, **context) if usage

  warn_missing_stream_usage(request_url: request_url, request: request)
  build_unknown_stream_usage(**context)
end