gproxy-protocol 4.1.4

GPROXY v4 connection modelling, operation declarations, vendor wire types and pairwise conversion
Documentation
use crate::{
    transform::{Report, TransformError},
    wire::openai::{chat::response as c, responses::response as r},
};

pub(crate) fn to_responses(
    value: c::ModerationResponse,
    report: &mut Report,
) -> Result<r::ResponseModerationReport, TransformError> {
    Ok(r::ResponseModerationReport {
        input: outcome_to_responses(value.input, report)?,
        output: outcome_to_responses(value.output, report)?,
        rest: Default::default(),
    })
}

fn outcome_to_responses(
    value: c::ModerationResultOrError,
    report: &mut Report,
) -> Result<r::ResponseModerationOutcome, TransformError> {
    Ok(match value {
        c::ModerationResultOrError::Error(value) => {
            r::ResponseModerationOutcome::Error(r::ResponseModerationError {
                code: value.code,
                message: value.message,
                type_: r::ResponseModerationErrorType::Error,
                rest: Default::default(),
            })
        }
        c::ModerationResultOrError::Result(value) => {
            if value.results.len() != 1 {
                return Err(TransformError::unsupported(
                    "moderation.results",
                    "Responses has one moderation result per input/output, not a batch",
                ));
            }
            let item = value.results.into_iter().next().expect("one result");
            if value.model != item.model {
                report.omitted(
                    "moderation.model",
                    "Responses retains per-result model; Chat batch model differs",
                );
            }
            r::ResponseModerationOutcome::Result(r::ResponseModerationResult {
                categories: item.categories,
                category_applied_input_types: item
                    .category_applied_input_types
                    .into_iter()
                    .map(|(k, v)| {
                        (
                            k,
                            v.into_iter()
                                .map(|v| match v {
                                    c::ModerationInputType::Text => {
                                        r::ResponseModerationInputType::Text
                                    }
                                    c::ModerationInputType::Image => {
                                        r::ResponseModerationInputType::Image
                                    }
                                })
                                .collect(),
                        )
                    })
                    .collect(),
                category_scores: item
                    .category_scores
                    .into_iter()
                    .map(|(k, v)| {
                        Ok((
                            k,
                            serde_json::Number::from_f64(v).ok_or_else(|| {
                                TransformError::invalid_result(
                                    "moderation.category_scores",
                                    "non-finite score",
                                )
                            })?,
                        ))
                    })
                    .collect::<Result<_, TransformError>>()?,
                flagged: item.flagged,
                model: item.model,
                type_: r::ResponseModerationResultType::ModerationResult,
                rest: Default::default(),
            })
        }
    })
}

pub(crate) fn to_chat(
    value: r::ResponseModerationReport,
) -> Result<c::ModerationResponse, TransformError> {
    Ok(c::ModerationResponse {
        input: outcome_to_chat(value.input)?,
        output: outcome_to_chat(value.output)?,
        rest: Default::default(),
    })
}

fn outcome_to_chat(
    value: r::ResponseModerationOutcome,
) -> Result<c::ModerationResultOrError, TransformError> {
    Ok(match value {
        r::ResponseModerationOutcome::Error(value) => {
            c::ModerationResultOrError::Error(c::ModerationError {
                code: value.code,
                message: value.message,
                type_: c::ModerationErrorType::Error,
                rest: Default::default(),
            })
        }
        r::ResponseModerationOutcome::Result(value) => {
            c::ModerationResultOrError::Result(c::ModerationResult {
                model: value.model.clone(),
                type_: c::ModerationResultType::ModerationResults,
                results: vec![c::ModerationResultItem {
                    categories: value.categories,
                    category_applied_input_types: value
                        .category_applied_input_types
                        .into_iter()
                        .map(|(k, v)| {
                            (
                                k,
                                v.into_iter()
                                    .map(|v| match v {
                                        r::ResponseModerationInputType::Text => {
                                            c::ModerationInputType::Text
                                        }
                                        r::ResponseModerationInputType::Image => {
                                            c::ModerationInputType::Image
                                        }
                                    })
                                    .collect(),
                            )
                        })
                        .collect(),
                    category_scores: value
                        .category_scores
                        .into_iter()
                        .map(|(k, v)| {
                            Ok((
                                k,
                                v.as_f64().filter(|n| n.is_finite()).ok_or_else(|| {
                                    TransformError::invalid_result(
                                        "moderation.category_scores",
                                        "score exceeds target numeric range",
                                    )
                                })?,
                            ))
                        })
                        .collect::<Result<_, TransformError>>()?,
                    flagged: value.flagged,
                    model: value.model,
                    type_: c::ModerationItemType::ModerationResult,
                    rest: Default::default(),
                }],
                rest: Default::default(),
            })
        }
    })
}