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)]
19#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
20pub struct CreateModerationRequestBody {
21    pub input: ModerationInput,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub model: Option<String>,
24    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
25    pub rest: Rest,
26}
27
28#[derive(
29    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
30)]
31#[serde(untagged)]
32#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
33#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
34pub enum ModerationInput {
35    Text(String),
36    Texts(Vec<String>),
37    Multimodal(Vec<ModerationContent>),
38}
39
40#[derive(
41    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
42)]
43#[serde(tag = "type", rename_all = "snake_case")]
44#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
45#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
46pub enum ModerationContent {
47    Text {
48        text: String,
49        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
50        rest: Rest,
51    },
52    ImageUrl {
53        image_url: ModerationImageUrl,
54        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
55        rest: Rest,
56    },
57}
58
59#[derive(
60    Debug,
61    Clone,
62    PartialEq,
63    Serialize,
64    Deserialize,
65    gproxy_protocol_macros::WireBuilder,
66    gproxy_protocol_macros::DeclaredFields,
67)]
68#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
69#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
70pub struct ModerationImageUrl {
71    pub url: String,
72    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
73    pub rest: Rest,
74}
75
76#[derive(
77    Debug,
78    Clone,
79    PartialEq,
80    Serialize,
81    Deserialize,
82    gproxy_protocol_macros::WireBuilder,
83    gproxy_protocol_macros::DeclaredFields,
84)]
85#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
86#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
87pub struct CreateModerationResponseBody {
88    pub id: String,
89    pub model: String,
90    pub results: Vec<ModerationResult>,
91    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
92    pub rest: Rest,
93}
94
95#[derive(
96    Debug,
97    Clone,
98    PartialEq,
99    Serialize,
100    Deserialize,
101    gproxy_protocol_macros::WireBuilder,
102    gproxy_protocol_macros::DeclaredFields,
103)]
104#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
105#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
106pub struct ModerationResult {
107    pub flagged: bool,
108    pub categories: BTreeMap<String, Option<bool>>,
109    pub category_scores: BTreeMap<String, serde_json::Number>,
110    pub category_applied_input_types: BTreeMap<String, Vec<String>>,
111    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
112    pub rest: Rest,
113}
114
115pub type CreateModerationRequest = WireRequest<CreateModerationRequestBody>;
116pub type CreateModerationResponse = WireResponse<CreateModerationResponseBody>;