$usage Response usage: input_tokens, input_tokens_details, output_tokens. * @param array|null $price USD per 1M tokens: text_input, image_input, image_output. */ public static function from_usage( array $usage, ?array $price ): ?string { if ( null === $price || ! isset( $usage['output_tokens'] ) || ! is_int( $usage['output_tokens'] ) ) { return null; } $details = isset( $usage['input_tokens_details'] ) && is_array( $usage['input_tokens_details'] ) ? $usage['input_tokens_details'] : array(); $text = (int) ( $details['text_tokens'] ?? 0 ); $image = (int) ( $details['image_tokens'] ?? 0 ); // No breakdown: price all input at the image rate, so the cost is over- rather than under-stated. if ( 0 === $text && 0 === $image ) { $image = (int) ( $usage['input_tokens'] ?? 0 ); } $micros = $text * (float) ( $price['text_input'] ?? 0 ) + $image * (float) ( $price['image_input'] ?? 0 ) + $usage['output_tokens'] * (float) ( $price['image_output'] ?? 0 ); return Money::format( (int) ceil( round( $micros, 6 ) ) ); } }