• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

box / box-java-sdk / #4027

11 Oct 2024 12:22PM UTC coverage: 71.745% (+0.04%) from 71.703%
#4027

push

github

web-flow
feat: Support AI extract and AI extract structured (#1266)

125 of 167 new or added lines in 8 files covered. (74.85%)

1 existing line in 1 file now uncovered.

8039 of 11205 relevant lines covered (71.74%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.83
/src/main/java/com/box/sdk/BoxAI.java
1
package com.box.sdk;
2

3
import com.box.sdk.http.HttpMethod;
4
import com.eclipsesource.json.Json;
5
import com.eclipsesource.json.JsonArray;
6
import com.eclipsesource.json.JsonObject;
7
import java.net.URL;
8
import java.util.List;
9

10

11
public final class BoxAI {
12

13
    /**
14
     * Ask AI url.
15
     */
16
    public static final URLTemplate SEND_AI_REQUEST_URL = new URLTemplate("ai/ask");
1✔
17
    /**
18
     * Text gen AI url.
19
     */
20
    public static final URLTemplate SEND_AI_TEXT_GEN_REQUEST_URL = new URLTemplate("ai/text_gen");
1✔
21
    /**
22
     * AI agent default config url.
23
     */
24
    public static final URLTemplate AI_AGENT_DEFAULT_CONFIG_URL = new URLTemplate("ai_agent_default");
1✔
25
    /**
26
     * AI extract metadata freeform url.
27
     */
28
    public static final URLTemplate EXTRACT_METADATA_FREEFORM_URL = new URLTemplate("ai/extract");
1✔
29
    /**
30
     * AI extract metadata structured url.
31
     */
32
    public static final URLTemplate EXTRACT_METADATA_STRUCTURED_URL = new URLTemplate("ai/extract_structured");
1✔
33

34
    private BoxAI() {
35
    }
36

37
    /**
38
     * Sends an AI request to supported LLMs and returns an answer specifically focused
39
     * on the user's question given the provided items.
40
     *
41
     * @param api    the API connection to be used by the created user.
42
     * @param prompt The prompt provided by the client to be answered by the LLM.
43
     * @param items  The items to be processed by the LLM, currently only files are supported.
44
     * @param mode   The mode specifies if this request is for a single or multiple items.
45
     * @return The response from the AI.
46
     */
47
    public static BoxAIResponse sendAIRequest(BoxAPIConnection api, String prompt, List<BoxAIItem> items, Mode mode) {
48
        return sendAIRequest(api, prompt, items, mode, null, null, null);
1✔
49
    }
50

51
    /**
52
     * Sends an AI request to supported LLMs and returns an answer specifically focused
53
     * on the user's question given the provided items.
54
     *
55
     * @param api             the API connection to be used by the created user.
56
     * @param prompt          The prompt provided by the client to be answered by the LLM.
57
     * @param items           The items to be processed by the LLM, currently only files are supported.
58
     * @param mode            The mode specifies if this request is for a single or multiple items.
59
     * @param dialogueHistory The history of prompts and answers previously passed to the LLM.
60
     *                        This provides additional context to the LLM in generating the response.
61
     * @param agent           The AI agent configuration to be used for the request.
62
     * @param includeCitations Whether to include citations in the response.
63
     * @return The response from the AI.
64
     */
65
    public static BoxAIResponse sendAIRequest(BoxAPIConnection api, String prompt, List<BoxAIItem> items, Mode mode,
66
                                              List<BoxAIDialogueEntry> dialogueHistory, BoxAIAgentAsk agent,
67
                                              Boolean includeCitations) {
68
        URL url = SEND_AI_REQUEST_URL.build(api.getBaseURL());
1✔
69
        JsonObject requestJSON = new JsonObject();
1✔
70
        requestJSON.add("mode", mode.toString());
1✔
71
        requestJSON.add("prompt", prompt);
1✔
72

73
        JsonArray itemsJSON = new JsonArray();
1✔
74
        for (BoxAIItem item : items) {
1✔
75
            itemsJSON.add(item.getJSONObject());
1✔
76
        }
1✔
77
        requestJSON.add("items", itemsJSON);
1✔
78

79
        if (dialogueHistory != null) {
1✔
80
            JsonArray dialogueHistoryJSON = new JsonArray();
1✔
81
            for (BoxAIDialogueEntry dialogueEntry : dialogueHistory) {
1✔
82
                dialogueHistoryJSON.add(dialogueEntry.getJSONObject());
1✔
83
            }
1✔
84
            requestJSON.add("dialogue_history", dialogueHistoryJSON);
1✔
85
        }
86
        if (agent != null) {
1✔
87
            requestJSON.add("ai_agent", agent.getJSONObject());
1✔
88
        }
89
        if (includeCitations != null) {
1✔
90
            requestJSON.add("include_citations", includeCitations);
1✔
91
        }
92

93
        BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
1✔
94
        req.setBody(requestJSON.toString());
1✔
95

96
        try (BoxJSONResponse response = req.send()) {
1✔
97
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
98
            return new BoxAIResponse(responseJSON);
1✔
99
        }
100
    }
101

102
    /**
103
     * Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.
104
     *
105
     * @param api    the API connection to be used by the created user.
106
     * @param prompt The prompt provided by the client to be answered by the LLM.
107
     * @param items  The items to be processed by the LLM, currently only files are supported.
108
     * @return The response from the AI.
109
     */
110
    public static BoxAIResponse sendAITextGenRequest(BoxAPIConnection api, String prompt, List<BoxAIItem> items) {
111
        return sendAITextGenRequest(api, prompt, items, null);
1✔
112
    }
113

114
    /**
115
     * Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.
116
     *
117
     * @param api             the API connection to be used by the created user.
118
     * @param prompt          The prompt provided by the client to be answered by the LLM.
119
     * @param items           The items to be processed by the LLM, currently only files are supported.
120
     * @param dialogueHistory The history of prompts and answers previously passed to the LLM.
121
     *                        This provides additional context to the LLM in generating the response.
122
     * @return The response from the AI.
123
     */
124
    public static BoxAIResponse sendAITextGenRequest(BoxAPIConnection api, String prompt, List<BoxAIItem> items,
125
                                                     List<BoxAIDialogueEntry> dialogueHistory) {
126
        return sendAITextGenRequest(api, prompt, items, dialogueHistory, null);
1✔
127
    }
128

129
    /**
130
     * Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.
131
     *
132
     * @param api             the API connection to be used by the created user.
133
     * @param prompt          The prompt provided by the client to be answered by the LLM.
134
     * @param items           The items to be processed by the LLM, currently only files are supported.
135
     * @param dialogueHistory The history of prompts and answers previously passed to the LLM.
136
     *                        This provides additional context to the LLM in generating the response.
137
     * @param agent           The AI agent configuration to be used for the request.
138
     * @return The response from the AI.
139
     */
140
    public static BoxAIResponse sendAITextGenRequest(BoxAPIConnection api, String prompt, List<BoxAIItem> items,
141
                                                     List<BoxAIDialogueEntry> dialogueHistory,
142
                                                     BoxAIAgentTextGen agent) {
143
        URL url = SEND_AI_TEXT_GEN_REQUEST_URL.build(api.getBaseURL());
1✔
144
        JsonObject requestJSON = new JsonObject();
1✔
145
        requestJSON.add("prompt", prompt);
1✔
146

147
        JsonArray itemsJSON = new JsonArray();
1✔
148
        for (BoxAIItem item : items) {
1✔
149
            itemsJSON.add(item.getJSONObject());
1✔
150
        }
1✔
151
        requestJSON.add("items", itemsJSON);
1✔
152

153
        if (dialogueHistory != null) {
1✔
154
            JsonArray dialogueHistoryJSON = new JsonArray();
1✔
155
            for (BoxAIDialogueEntry dialogueEntry : dialogueHistory) {
1✔
156
                dialogueHistoryJSON.add(dialogueEntry.getJSONObject());
1✔
157
            }
1✔
158
            requestJSON.add("dialogue_history", dialogueHistoryJSON);
1✔
159
        }
160

161
        if (agent != null) {
1✔
162
            requestJSON.add("ai_agent", agent.getJSONObject());
1✔
163
        }
164

165
        BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
1✔
166
        req.setBody(requestJSON.toString());
1✔
167

168
        try (BoxJSONResponse response = req.send()) {
1✔
169
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
170
            return new BoxAIResponse(responseJSON);
1✔
171
        }
172
    }
173

174
    /**
175
     * Get the default AI Agent use for the given mode.
176
     *
177
     * @param api  The API connection to be used by the created user.
178
     * @param mode The mode to filter the agent config to return.
179
     * @return A successful response including the default agent configuration.
180
     */
181
    public static BoxAIAgent getAiAgentDefaultConfig(BoxAPIConnection api, BoxAIAgent.Mode mode) {
182
        return getAiAgentDefaultConfig(api, mode, null, null);
×
183
    }
184

185
    /**
186
     * Get the default AI Agent use for the given mode.
187
     *
188
     * @param api      The API connection to be used by the created user.
189
     * @param mode     The mode to filter the agent config to return.
190
     * @param language The language to filter the agent config to return.
191
     * @param model    The model to filter the agent config to return.
192
     * @return A successful response including the default agent configuration.
193
     */
194
    public static BoxAIAgent getAiAgentDefaultConfig(BoxAPIConnection api,
195
                                                     BoxAIAgent.Mode mode,
196
                                                     String language,
197
                                                     String model) {
198
        QueryStringBuilder builder = new QueryStringBuilder();
1✔
199
        builder.appendParam("mode", mode.toString());
1✔
200
        if (language != null) {
1✔
201
            builder.appendParam("language", language);
1✔
202
        }
203
        if (model != null) {
1✔
204
            builder.appendParam("model", model);
1✔
205
        }
206
        URL url = AI_AGENT_DEFAULT_CONFIG_URL.buildWithQuery(api.getBaseURL(), builder.toString());
1✔
207
        BoxAPIRequest req = new BoxAPIRequest(api, url, HttpMethod.GET);
1✔
208
        try (BoxJSONResponse response = (BoxJSONResponse) req.send()) {
1✔
209
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
210
            return BoxAIAgent.parse(responseJSON);
1✔
211
        }
212
    }
213

214
    public enum Mode {
1✔
215
        /**
216
         * Multiple items
217
         */
218
        MULTIPLE_ITEM_QA("multiple_item_qa"),
1✔
219

220
        /**
221
         * Single item
222
         */
223
        SINGLE_ITEM_QA("single_item_qa");
1✔
224

225
        private final String mode;
226

227
        Mode(String mode) {
1✔
228
            this.mode = mode;
1✔
229
        }
1✔
230

231
        static BoxAI.Mode fromJSONValue(String jsonValue) {
232
            if (jsonValue.equals("multiple_item_qa")) {
×
233
                return BoxAI.Mode.MULTIPLE_ITEM_QA;
×
234
            } else if (jsonValue.equals("single_item_qa")) {
×
235
                return BoxAI.Mode.SINGLE_ITEM_QA;
×
236
            } else {
237
                System.out.print("Invalid AI mode.");
×
238
                return null;
×
239
            }
240
        }
241

242
        String toJSONValue() {
243
            return this.mode;
×
244
        }
245

246
        public String toString() {
247
            return this.mode;
1✔
248
        }
249
    }
250

251
    /**
252
     * Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs.
253
     * Freeform metadata extraction does not require any metadata template setup before sending the request.
254
     *
255
     * @param api    the API connection to be used by the created user.
256
     * @param prompt The prompt provided by the client to be answered by the LLM.
257
     * @param items  The items to be processed by the LLM, currently only files are supported.
258
     * @return The response from the AI.
259
     */
260
    public static BoxAIResponse extractMetadataFreeform(BoxAPIConnection api,
261
                                                        String prompt,
262
                                                        List<BoxAIItem> items) {
NEW
263
        return extractMetadataFreeform(api, prompt, items, null);
×
264
    }
265

266
    /**
267
     * Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs.
268
     * Freeform metadata extraction does not require any metadata template setup before sending the request.
269
     *
270
     * @param api    the API connection to be used by the created user.
271
     * @param prompt The prompt provided by the client to be answered by the LLM.
272
     * @param items  The items to be processed by the LLM, currently only files are supported.
273
     * @param agent  The AI agent configuration to be used for the request.
274
     * @return The response from the AI.
275
     */
276
    public static BoxAIResponse extractMetadataFreeform(BoxAPIConnection api,
277
                                                        String prompt,
278
                                                        List<BoxAIItem> items,
279
                                                        BoxAIAgentExtract agent) {
280
        URL url = EXTRACT_METADATA_FREEFORM_URL.build(api.getBaseURL());
1✔
281

282
        JsonObject requestJSON = new JsonObject();
1✔
283
        JsonArray itemsJSON = new JsonArray();
1✔
284
        for (BoxAIItem item : items) {
1✔
285
            itemsJSON.add(item.getJSONObject());
1✔
286
        }
1✔
287
        requestJSON.add("items", itemsJSON);
1✔
288
        requestJSON.add("prompt", prompt);
1✔
289
        if (agent != null) {
1✔
290
            requestJSON.add("ai_agent", agent.getJSONObject());
1✔
291
        }
292

293
        BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
1✔
294
        req.setBody(requestJSON.toString());
1✔
295

296
        try (BoxJSONResponse response = req.send()) {
1✔
297
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
298
            return new BoxAIResponse(responseJSON);
1✔
299
        }
300
    }
301

302
    /**
303
     * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of
304
     * key-value pairs. For this request, you need to use an already defined metadata template or a define a
305
     * schema yourself.
306
     *
307
     * @param api     The API connection to be used by the created user.
308
     * @param items  The items to be processed by the LLM, currently only files are supported.
309
     * @param template The metadata template to be used for the request.
310
     * @return The response from the AI.
311
     */
312
    public static BoxAIExtractStructuredResponse extractMetadataStructured(BoxAPIConnection api, List<BoxAIItem> items,
313
                                                       BoxAIExtractMetadataTemplate template) {
NEW
314
        return extractMetadataStructured(api, items, template, null, null);
×
315
    }
316

317
    /**
318
     * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of
319
     * key-value pairs. For this request, you need to use an already defined metadata template or a define a
320
     * schema yourself.
321
     *
322
     * @param api     The API connection to be used by the created user.
323
     * @param items  The items to be processed by the LLM, currently only files are supported.
324
     * @param template The metadata template to be used for the request.
325
     * @param agent The AI agent configuration to be used for the request.
326
     * @return The response from the AI.
327
     */
328
    public static BoxAIExtractStructuredResponse extractMetadataStructured(BoxAPIConnection api, List<BoxAIItem> items,
329
                                                       BoxAIExtractMetadataTemplate template,
330
                                                       BoxAIAgentExtractStructured agent) {
331
        return extractMetadataStructured(api, items, template, null, agent);
1✔
332
    }
333

334
    /**
335
     * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of
336
     * key-value pairs. For this request, you need to use an already defined metadata template or a define a
337
     * schema yourself.
338
     *
339
     * @param api     The API connection to be used by the created user.
340
     * @param items  The items to be processed by the LLM, currently only files are supported.
341
     * @param fields The fields to be extracted from the items.
342
     * @return The response from the AI.
343
     */
344
    public static BoxAIExtractStructuredResponse extractMetadataStructured(BoxAPIConnection api, List<BoxAIItem> items,
345
                                                       List<BoxAIExtractField> fields) {
NEW
346
        return extractMetadataStructured(api, items, null, fields, null);
×
347
    }
348

349
    /**
350
     * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of
351
     * key-value pairs. For this request, you need to use an already defined metadata template or a define a
352
     * schema yourself.
353
     *
354
     * @param api     The API connection to be used by the created user.
355
     * @param items  The items to be processed by the LLM, currently only files are supported.
356
     * @param fields The fields to be extracted from the items.
357
     * @param agent The AI agent configuration to be used for the request.
358
     * @return The response from the AI.
359
     */
360
    public static BoxAIExtractStructuredResponse extractMetadataStructured(BoxAPIConnection api, List<BoxAIItem> items,
361
                                                       List<BoxAIExtractField> fields,
362
                                                       BoxAIAgentExtractStructured agent) {
363
        return extractMetadataStructured(api, items, null, fields, agent);
1✔
364
    }
365

366
    /**
367
     * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of
368
     * key-value pairs. For this request, you need to use an already defined metadata template or a define a
369
     * schema yourself.
370
     *
371
     * @param api     The API connection to be used by the created user.
372
     * @param items  The items to be processed by the LLM, currently only files are supported.
373
     * @param template The metadata template to be used for the request.
374
     * @param fields The fields to be extracted from the items.
375
     * @param agent The AI agent configuration to be used for the request.
376
     * @return The response from the AI.
377
     */
378
    private static BoxAIExtractStructuredResponse extractMetadataStructured(BoxAPIConnection api, List<BoxAIItem> items,
379
                                                       BoxAIExtractMetadataTemplate template,
380
                                                       List<BoxAIExtractField> fields,
381
                                                       BoxAIAgentExtractStructured agent) {
382
        URL url = EXTRACT_METADATA_STRUCTURED_URL.build(api.getBaseURL());
1✔
383

384
        JsonObject requestJSON = new JsonObject();
1✔
385
        JsonArray itemsJSON = new JsonArray();
1✔
386
        for (BoxAIItem item : items) {
1✔
387
            itemsJSON.add(item.getJSONObject());
1✔
388
        }
1✔
389
        requestJSON.add("items", itemsJSON);
1✔
390

391
        if (template != null) {
1✔
392
            requestJSON.add("metadata_template", template.getJSONObject());
1✔
393
        }
394

395
        if (fields != null) {
1✔
396
            JsonArray fieldsJSON = new JsonArray();
1✔
397
            for (BoxAIExtractField field : fields) {
1✔
398
                fieldsJSON.add(field.getJSONObject());
1✔
399
            }
1✔
400
            requestJSON.add("fields", fieldsJSON);
1✔
401
        }
402

403
        if (agent != null) {
1✔
404
            requestJSON.add("ai_agent", agent.getJSONObject());
1✔
405
        }
406

407
        BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
1✔
408
        req.setBody(requestJSON.toString());
1✔
409

410
        try (BoxJSONResponse response = req.send()) {
1✔
411
            return new BoxAIExtractStructuredResponse(response.getJSON());
1✔
412
        }
413
    }
414
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc