1+ /*
2+ * Copyright 2024 - 2024 the original author or authors.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * https://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package org .springframework .ai .openai .api ;
17+
18+ import java .util .Map ;
19+ import java .util .Objects ;
20+
21+ import com .fasterxml .jackson .annotation .JsonInclude ;
22+ import com .fasterxml .jackson .annotation .JsonInclude .Include ;
23+ import com .fasterxml .jackson .annotation .JsonProperty ;
24+
25+ import org .springframework .ai .model .ModelOptionsUtils ;
26+ import org .springframework .util .StringUtils ;
27+
28+ /**
29+ * An object specifying the format that the model must output.
30+ *
31+ * Setting the type to JSON_SCHEMA, enables Structured Outputs which ensures the model
32+ * will match your supplied JSON schema. Learn more in the
33+ * <a href="https://platform.openai.com/docs/guides/structured-outputs"> Structured
34+ * Outputs guide.</a <br/>
35+ *
36+ * References: <a href=
37+ * "https://platform.openai.com/docs/api-reference/chat/create#chat-create-response_format">OpenAi
38+ * API - ResponseFormat</a>,
39+ * <a href="https://platform.openai.com/docs/guides/structured-outputs#json-mode">JSON
40+ * Mode</a>, <a href=
41+ * "https://platform.openai.com/docs/guides/structured-outputs#structured-outputs-vs-json-mode">Structured
42+ * Outputs vs JSON mode</a>
43+ *
44+ * @author Christian Tzolov
45+ * @since 1.0.0
46+ */
47+
48+ @ JsonInclude (Include .NON_NULL )
49+ public class ResponseFormat {
50+
51+ /**
52+ * Type Must be one of 'text', 'json_object' or 'json_schema'.
53+ */
54+ @ JsonProperty ("type" )
55+ private Type type ;
56+
57+ /**
58+ * JSON schema object that describes the format of the JSON object. Only applicable
59+ * when type is 'json_schema'.
60+ */
61+ @ JsonProperty ("json_schema" )
62+ private JsonSchema jsonSchema = null ;
63+
64+ public Type getType () {
65+ return type ;
66+ }
67+
68+ public void setType (Type type ) {
69+ this .type = type ;
70+ }
71+
72+ public JsonSchema getJsonSchema () {
73+ return jsonSchema ;
74+ }
75+
76+ public void setJsonSchema (JsonSchema jsonSchema ) {
77+ this .jsonSchema = jsonSchema ;
78+ }
79+
80+ private ResponseFormat (Type type , JsonSchema jsonSchema ) {
81+ this .type = type ;
82+ this .jsonSchema = jsonSchema ;
83+ }
84+
85+ public ResponseFormat (Type type , String schema ) {
86+ this (type , StringUtils .hasText (schema ) ? JsonSchema .builder ().schema (schema ).strict (true ).build () : null );
87+ }
88+
89+ public static Builder builder () {
90+ return new Builder ();
91+ }
92+
93+ public static class Builder {
94+
95+ private Type type ;
96+
97+ private JsonSchema jsonSchema ;
98+
99+ private Builder () {
100+ }
101+
102+ public Builder type (Type type ) {
103+ this .type = type ;
104+ return this ;
105+ }
106+
107+ public Builder jsonSchema (JsonSchema jsonSchema ) {
108+ this .jsonSchema = jsonSchema ;
109+ return this ;
110+ }
111+
112+ public Builder jsonSchema (String jsonSchema ) {
113+ this .jsonSchema = JsonSchema .builder ().schema (jsonSchema ).build ();
114+ return this ;
115+ }
116+
117+ public ResponseFormat build () {
118+ return new ResponseFormat (this .type , this .jsonSchema );
119+ }
120+
121+ }
122+
123+ public enum Type {
124+
125+ /**
126+ * Generates a text response. (default)
127+ */
128+ @ JsonProperty ("text" )
129+ TEXT ,
130+
131+ /**
132+ * Enables JSON mode, which guarantees the message the model generates is valid
133+ * JSON.
134+ */
135+ @ JsonProperty ("json_object" )
136+ JSON_OBJECT ,
137+
138+ /**
139+ * Enables Structured Outputs which guarantees the model will match your supplied
140+ * JSON schema.
141+ */
142+ @ JsonProperty ("json_schema" )
143+ JSON_SCHEMA
144+
145+ }
146+
147+ /**
148+ * JSON schema object that describes the format of the JSON object. Applicable for the
149+ * 'json_schema' type only.
150+ */
151+ @ JsonInclude (Include .NON_NULL )
152+ public static class JsonSchema {
153+
154+ @ JsonProperty ("name" )
155+ private final String name ;
156+
157+ @ JsonProperty ("schema" )
158+ private final Map <String , Object > schema ;
159+
160+ @ JsonProperty ("strict" )
161+ private final Boolean strict ;
162+
163+ public String getName () {
164+ return this .name ;
165+ }
166+
167+ public Map <String , Object > getSchema () {
168+ return this .schema ;
169+ }
170+
171+ public Boolean getStrict () {
172+ return this .strict ;
173+ }
174+
175+ private JsonSchema (String name , Map <String , Object > schema , Boolean strict ) {
176+ this .name = name ;
177+ this .schema = schema ;
178+ this .strict = strict ;
179+ }
180+
181+ public static Builder builder () {
182+ return new Builder ();
183+ }
184+
185+ public static class Builder {
186+
187+ private String name = "custom_schema" ;
188+
189+ private Map <String , Object > schema ;
190+
191+ private Boolean strict = true ;
192+
193+ private Builder () {
194+ }
195+
196+ public Builder name (String name ) {
197+ this .name = name ;
198+ return this ;
199+ }
200+
201+ public Builder schema (Map <String , Object > schema ) {
202+ this .schema = schema ;
203+ return this ;
204+ }
205+
206+ public Builder schema (String schema ) {
207+ this .schema = ModelOptionsUtils .jsonToMap (schema );
208+ return this ;
209+ }
210+
211+ public Builder strict (Boolean strict ) {
212+ this .strict = strict ;
213+ return this ;
214+ }
215+
216+ public JsonSchema build () {
217+ return new JsonSchema (name , schema , strict );
218+ }
219+
220+ }
221+
222+ @ Override
223+ public int hashCode () {
224+ return Objects .hash (name , schema , strict );
225+ }
226+
227+ @ Override
228+ public boolean equals (Object o ) {
229+ if (this == o )
230+ return true ;
231+ if (o == null || getClass () != o .getClass ())
232+ return false ;
233+ JsonSchema that = (JsonSchema ) o ;
234+ return Objects .equals (name , that .name ) && Objects .equals (schema , that .schema )
235+ && Objects .equals (strict , that .strict );
236+ }
237+
238+ }
239+
240+ @ Override
241+ public boolean equals (Object o ) {
242+ if (this == o )
243+ return true ;
244+ if (o == null || getClass () != o .getClass ())
245+ return false ;
246+ ResponseFormat that = (ResponseFormat ) o ;
247+ return type == that .type && Objects .equals (jsonSchema , that .jsonSchema );
248+ }
249+
250+ @ Override
251+ public int hashCode () {
252+ return Objects .hash (type , jsonSchema );
253+ }
254+
255+ @ Override
256+ public String toString () {
257+ return "ResponseFormat{" + "type=" + type + ", jsonSchema=" + jsonSchema + '}' ;
258+ }
259+
260+ }
0 commit comments