Skip to main content

gproxy_protocol/transform/openai/count_tokens/
utils.rs

1use crate::openai::count_tokens::types::{
2    ResponseFunctionCallOutputContent, ResponseInput, ResponseInputContent, ResponseInputItem,
3    ResponseInputMessage, ResponseInputMessageContent, ResponseInputMessageRole,
4    ResponseInputMessageType, ResponseSummaryTextContent,
5};
6
7pub fn openai_input_to_items(input: Option<ResponseInput>) -> Vec<ResponseInputItem> {
8    match input {
9        Some(ResponseInput::Items(items)) => items,
10        Some(ResponseInput::Text(text)) => vec![ResponseInputItem::Message(ResponseInputMessage {
11            content: ResponseInputMessageContent::Text(text),
12            role: ResponseInputMessageRole::User,
13            phase: None,
14            status: None,
15            type_: Some(ResponseInputMessageType::Message),
16        })],
17        None => Vec::new(),
18    }
19}
20
21pub fn openai_input_content_to_text(content: &ResponseInputContent) -> String {
22    match content {
23        ResponseInputContent::Text(part) => part.text.clone(),
24        ResponseInputContent::Image(part) => part
25            .image_url
26            .clone()
27            .or(part.file_id.clone())
28            .unwrap_or_else(|| "[input_image]".to_string()),
29        ResponseInputContent::File(part) => part
30            .file_url
31            .clone()
32            .or(part.file_id.clone())
33            .or(part.filename.clone())
34            .or(part.file_data.clone())
35            .unwrap_or_else(|| "[input_file]".to_string()),
36    }
37}
38
39pub fn openai_message_content_to_text(content: &ResponseInputMessageContent) -> String {
40    match content {
41        ResponseInputMessageContent::Text(text) => text.clone(),
42        ResponseInputMessageContent::List(parts) => parts
43            .iter()
44            .map(openai_input_content_to_text)
45            .collect::<Vec<_>>()
46            .join("\n"),
47    }
48}
49
50pub fn openai_function_call_output_content_to_text(
51    content: &ResponseFunctionCallOutputContent,
52) -> String {
53    match content {
54        ResponseFunctionCallOutputContent::Text(text) => text.clone(),
55        ResponseFunctionCallOutputContent::Content(parts) => parts
56            .iter()
57            .map(openai_input_content_to_text)
58            .collect::<Vec<_>>()
59            .join("\n"),
60    }
61}
62
63pub fn openai_reasoning_summary_to_text(summary: &[ResponseSummaryTextContent]) -> String {
64    summary
65        .iter()
66        .map(|item| item.text.clone())
67        .filter(|text| !text.is_empty())
68        .collect::<Vec<_>>()
69        .join("\n")
70}