Skip to main content

gproxy_protocol/wire/openai/
moderation.rs

1//! Standard OpenAI `/v1/moderations`, not Codex Guardian. Source: openai-python
2//! src/openai/types/{moderation_create_params,moderation_create_response,
3//! moderation,moderation_text_input_param,moderation_image_url_input_param}.py
4//! (verified 2026-10-01). Category keys remain open as upstream adds categories.
5use crate::{Rest, WireRequest, WireResponse};
6use serde::{Deserialize, Serialize};
7use std::collections::BTreeMap;
8
9#[derive(
10    Debug,
11    Clone,
12    PartialEq,
13    Serialize,
14    Deserialize,
15    gproxy_protocol_macros::WireBuilder,
16    gproxy_protocol_macros::DeclaredFields,
17)]
18#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
19pub struct CreateModerationRequestBody {
20    pub input: ModerationInput,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub model: Option<String>,
23    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
24    pub rest: Rest,
25}
26
27#[derive(
28    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
29)]
30#[serde(untagged)]
31#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
32pub enum ModerationInput {
33    Text(String),
34    Texts(Vec<String>),
35    Multimodal(Vec<ModerationContent>),
36}
37
38#[derive(
39    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
40)]
41#[serde(tag = "type", rename_all = "snake_case")]
42#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
43pub enum ModerationContent {
44    Text {
45        text: String,
46        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
47        rest: Rest,
48    },
49    ImageUrl {
50        image_url: ModerationImageUrl,
51        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
52        rest: Rest,
53    },
54}
55
56#[derive(
57    Debug,
58    Clone,
59    PartialEq,
60    Serialize,
61    Deserialize,
62    gproxy_protocol_macros::WireBuilder,
63    gproxy_protocol_macros::DeclaredFields,
64)]
65#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
66pub struct ModerationImageUrl {
67    pub url: String,
68    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
69    pub rest: Rest,
70}
71
72#[derive(
73    Debug,
74    Clone,
75    PartialEq,
76    Serialize,
77    Deserialize,
78    gproxy_protocol_macros::WireBuilder,
79    gproxy_protocol_macros::DeclaredFields,
80)]
81#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
82pub struct CreateModerationResponseBody {
83    pub id: String,
84    pub model: String,
85    pub results: Vec<ModerationResult>,
86    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
87    pub rest: Rest,
88}
89
90#[derive(
91    Debug,
92    Clone,
93    PartialEq,
94    Serialize,
95    Deserialize,
96    gproxy_protocol_macros::WireBuilder,
97    gproxy_protocol_macros::DeclaredFields,
98)]
99#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
100pub struct ModerationResult {
101    pub flagged: bool,
102    pub categories: BTreeMap<String, Option<bool>>,
103    pub category_scores: BTreeMap<String, serde_json::Number>,
104    pub category_applied_input_types: BTreeMap<String, Vec<String>>,
105    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
106    pub rest: Rest,
107}
108
109pub type CreateModerationRequest = WireRequest<CreateModerationRequestBody>;
110pub type CreateModerationResponse = WireResponse<CreateModerationResponseBody>;