001package com.box.sdk;
002
003import com.box.sdk.http.HttpMethod;
004import com.eclipsesource.json.Json;
005import com.eclipsesource.json.JsonArray;
006import com.eclipsesource.json.JsonObject;
007import java.net.URL;
008import java.util.List;
009
010public final class BoxAI {
011
012  /** Ask AI url. */
013  public static final URLTemplate SEND_AI_REQUEST_URL = new URLTemplate("ai/ask");
014  /** Text gen AI url. */
015  public static final URLTemplate SEND_AI_TEXT_GEN_REQUEST_URL = new URLTemplate("ai/text_gen");
016  /** AI agent default config url. */
017  public static final URLTemplate AI_AGENT_DEFAULT_CONFIG_URL = new URLTemplate("ai_agent_default");
018  /** AI extract metadata freeform url. */
019  public static final URLTemplate EXTRACT_METADATA_FREEFORM_URL = new URLTemplate("ai/extract");
020  /** AI extract metadata structured url. */
021  public static final URLTemplate EXTRACT_METADATA_STRUCTURED_URL =
022      new URLTemplate("ai/extract_structured");
023
024  private BoxAI() {}
025
026  /**
027   * Sends an AI request to supported LLMs and returns an answer specifically focused on the user's
028   * question given the provided items.
029   *
030   * @param api the API connection to be used by the created user.
031   * @param prompt The prompt provided by the client to be answered by the LLM.
032   * @param items The items to be processed by the LLM, currently only files are supported.
033   * @param mode The mode specifies if this request is for a single or multiple items.
034   * @return The response from the AI.
035   */
036  public static BoxAIResponse sendAIRequest(
037      BoxAPIConnection api, String prompt, List<BoxAIItem> items, Mode mode) {
038    return sendAIRequest(api, prompt, items, mode, null, null, null);
039  }
040
041  /**
042   * Sends an AI request to supported LLMs and returns an answer specifically focused on the user's
043   * question given the provided items.
044   *
045   * @param api the API connection to be used by the created user.
046   * @param prompt The prompt provided by the client to be answered by the LLM.
047   * @param items The items to be processed by the LLM, currently only files are supported.
048   * @param mode The mode specifies if this request is for a single or multiple items.
049   * @param dialogueHistory The history of prompts and answers previously passed to the LLM. This
050   *     provides additional context to the LLM in generating the response.
051   * @param agent The AI agent configuration to be used for the request.
052   * @param includeCitations Whether to include citations in the response.
053   * @return The response from the AI.
054   */
055  public static BoxAIResponse sendAIRequest(
056      BoxAPIConnection api,
057      String prompt,
058      List<BoxAIItem> items,
059      Mode mode,
060      List<BoxAIDialogueEntry> dialogueHistory,
061      BoxAIAgentAsk agent,
062      Boolean includeCitations) {
063    URL url = SEND_AI_REQUEST_URL.build(api.getBaseURL());
064    JsonObject requestJSON = new JsonObject();
065    requestJSON.add("mode", mode.toString());
066    requestJSON.add("prompt", prompt);
067
068    JsonArray itemsJSON = new JsonArray();
069    for (BoxAIItem item : items) {
070      itemsJSON.add(item.getJSONObject());
071    }
072    requestJSON.add("items", itemsJSON);
073
074    if (dialogueHistory != null) {
075      JsonArray dialogueHistoryJSON = new JsonArray();
076      for (BoxAIDialogueEntry dialogueEntry : dialogueHistory) {
077        dialogueHistoryJSON.add(dialogueEntry.getJSONObject());
078      }
079      requestJSON.add("dialogue_history", dialogueHistoryJSON);
080    }
081    if (agent != null) {
082      requestJSON.add("ai_agent", agent.getJSONObject());
083    }
084    if (includeCitations != null) {
085      requestJSON.add("include_citations", includeCitations);
086    }
087
088    BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
089    req.setBody(requestJSON.toString());
090
091    try (BoxJSONResponse response = req.send()) {
092      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
093      return new BoxAIResponse(responseJSON);
094    }
095  }
096
097  /**
098   * Sends an AI request to supported LLMs and returns an answer specifically focused on the
099   * creation of new text.
100   *
101   * @param api the API connection to be used by the created user.
102   * @param prompt The prompt provided by the client to be answered by the LLM.
103   * @param items The items to be processed by the LLM, currently only files are supported.
104   * @return The response from the AI.
105   */
106  public static BoxAIResponse sendAITextGenRequest(
107      BoxAPIConnection api, String prompt, List<BoxAIItem> items) {
108    return sendAITextGenRequest(api, prompt, items, null);
109  }
110
111  /**
112   * Sends an AI request to supported LLMs and returns an answer specifically focused on the
113   * creation of new text.
114   *
115   * @param api the API connection to be used by the created user.
116   * @param prompt The prompt provided by the client to be answered by the LLM.
117   * @param items The items to be processed by the LLM, currently only files are supported.
118   * @param dialogueHistory The history of prompts and answers previously passed to the LLM. This
119   *     provides additional context to the LLM in generating the response.
120   * @return The response from the AI.
121   */
122  public static BoxAIResponse sendAITextGenRequest(
123      BoxAPIConnection api,
124      String prompt,
125      List<BoxAIItem> items,
126      List<BoxAIDialogueEntry> dialogueHistory) {
127    return sendAITextGenRequest(api, prompt, items, dialogueHistory, null);
128  }
129
130  /**
131   * Sends an AI request to supported LLMs and returns an answer specifically focused on the
132   * creation of new text.
133   *
134   * @param api the API connection to be used by the created user.
135   * @param prompt The prompt provided by the client to be answered by the LLM.
136   * @param items The items to be processed by the LLM, currently only files are supported.
137   * @param dialogueHistory The history of prompts and answers previously passed to the LLM. This
138   *     provides additional context to the LLM in generating the response.
139   * @param agent The AI agent configuration to be used for the request.
140   * @return The response from the AI.
141   */
142  public static BoxAIResponse sendAITextGenRequest(
143      BoxAPIConnection api,
144      String prompt,
145      List<BoxAIItem> items,
146      List<BoxAIDialogueEntry> dialogueHistory,
147      BoxAIAgentTextGen agent) {
148    URL url = SEND_AI_TEXT_GEN_REQUEST_URL.build(api.getBaseURL());
149    JsonObject requestJSON = new JsonObject();
150    requestJSON.add("prompt", prompt);
151
152    JsonArray itemsJSON = new JsonArray();
153    for (BoxAIItem item : items) {
154      itemsJSON.add(item.getJSONObject());
155    }
156    requestJSON.add("items", itemsJSON);
157
158    if (dialogueHistory != null) {
159      JsonArray dialogueHistoryJSON = new JsonArray();
160      for (BoxAIDialogueEntry dialogueEntry : dialogueHistory) {
161        dialogueHistoryJSON.add(dialogueEntry.getJSONObject());
162      }
163      requestJSON.add("dialogue_history", dialogueHistoryJSON);
164    }
165
166    if (agent != null) {
167      requestJSON.add("ai_agent", agent.getJSONObject());
168    }
169
170    BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
171    req.setBody(requestJSON.toString());
172
173    try (BoxJSONResponse response = req.send()) {
174      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
175      return new BoxAIResponse(responseJSON);
176    }
177  }
178
179  /**
180   * Get the default AI Agent use for the given mode.
181   *
182   * @param api The API connection to be used by the created user.
183   * @param mode The mode to filter the agent config to return.
184   * @return A successful response including the default agent configuration.
185   */
186  public static BoxAIAgent getAiAgentDefaultConfig(BoxAPIConnection api, BoxAIAgent.Mode mode) {
187    return getAiAgentDefaultConfig(api, mode, null, null);
188  }
189
190  /**
191   * Get the default AI Agent use for the given mode.
192   *
193   * @param api The API connection to be used by the created user.
194   * @param mode The mode to filter the agent config to return.
195   * @param language The language to filter the agent config to return.
196   * @param model The model to filter the agent config to return.
197   * @return A successful response including the default agent configuration.
198   */
199  public static BoxAIAgent getAiAgentDefaultConfig(
200      BoxAPIConnection api, BoxAIAgent.Mode mode, String language, String model) {
201    QueryStringBuilder builder = new QueryStringBuilder();
202    builder.appendParam("mode", mode.toString());
203    if (language != null) {
204      builder.appendParam("language", language);
205    }
206    if (model != null) {
207      builder.appendParam("model", model);
208    }
209    URL url = AI_AGENT_DEFAULT_CONFIG_URL.buildWithQuery(api.getBaseURL(), builder.toString());
210    BoxAPIRequest req = new BoxAPIRequest(api, url, HttpMethod.GET);
211    try (BoxJSONResponse response = (BoxJSONResponse) req.send()) {
212      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
213      return BoxAIAgent.parse(responseJSON);
214    }
215  }
216
217  public enum Mode {
218    /** Multiple items */
219    MULTIPLE_ITEM_QA("multiple_item_qa"),
220
221    /** Single item */
222    SINGLE_ITEM_QA("single_item_qa");
223
224    private final String mode;
225
226    Mode(String mode) {
227      this.mode = mode;
228    }
229
230    static BoxAI.Mode fromJSONValue(String jsonValue) {
231      if (jsonValue.equals("multiple_item_qa")) {
232        return BoxAI.Mode.MULTIPLE_ITEM_QA;
233      } else if (jsonValue.equals("single_item_qa")) {
234        return BoxAI.Mode.SINGLE_ITEM_QA;
235      } else {
236        System.out.print("Invalid AI mode.");
237        return null;
238      }
239    }
240
241    String toJSONValue() {
242      return this.mode;
243    }
244
245    public String toString() {
246      return this.mode;
247    }
248  }
249
250  /**
251   * Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of
252   * key-value pairs. Freeform metadata extraction does not require any metadata template setup
253   * 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(
261      BoxAPIConnection api, String prompt, List<BoxAIItem> items) {
262    return extractMetadataFreeform(api, prompt, items, null);
263  }
264
265  /**
266   * Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of
267   * key-value pairs. Freeform metadata extraction does not require any metadata template setup
268   * 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(
277      BoxAPIConnection api, String prompt, List<BoxAIItem> items, BoxAIAgentExtract agent) {
278    URL url = EXTRACT_METADATA_FREEFORM_URL.build(api.getBaseURL());
279
280    JsonObject requestJSON = new JsonObject();
281    JsonArray itemsJSON = new JsonArray();
282    for (BoxAIItem item : items) {
283      itemsJSON.add(item.getJSONObject());
284    }
285    requestJSON.add("items", itemsJSON);
286    requestJSON.add("prompt", prompt);
287    if (agent != null) {
288      requestJSON.add("ai_agent", agent.getJSONObject());
289    }
290
291    BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
292    req.setBody(requestJSON.toString());
293
294    try (BoxJSONResponse response = req.send()) {
295      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
296      return new BoxAIResponse(responseJSON);
297    }
298  }
299
300  /**
301   * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as
302   * a set of key-value pairs. For this request, you need to use an already defined metadata
303   * template or a define a schema yourself.
304   *
305   * @param api The API connection to be used by the created user.
306   * @param items The items to be processed by the LLM, currently only files are supported.
307   * @param template The metadata template to be used for the request.
308   * @return The response from the AI.
309   */
310  public static BoxAIExtractStructuredResponse extractMetadataStructured(
311      BoxAPIConnection api, List<BoxAIItem> items, BoxAIExtractMetadataTemplate template) {
312    return extractMetadataStructured(api, items, template, null, null);
313  }
314
315  /**
316   * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as
317   * a set of key-value pairs. For this request, you need to use an already defined metadata
318   * template or a define a schema yourself.
319   *
320   * @param api The API connection to be used by the created user.
321   * @param items The items to be processed by the LLM, currently only files are supported.
322   * @param template The metadata template to be used for the request.
323   * @param agent The AI agent configuration to be used for the request.
324   * @return The response from the AI.
325   */
326  public static BoxAIExtractStructuredResponse extractMetadataStructured(
327      BoxAPIConnection api,
328      List<BoxAIItem> items,
329      BoxAIExtractMetadataTemplate template,
330      BoxAIAgentExtractStructured agent) {
331    return extractMetadataStructured(api, items, template, null, agent);
332  }
333
334  /**
335   * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as
336   * a set of key-value pairs. For this request, you need to use an already defined metadata
337   * template or a define a 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(
345      BoxAPIConnection api, List<BoxAIItem> items, List<BoxAIExtractField> fields) {
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
351   * a set of key-value pairs. For this request, you need to use an already defined metadata
352   * template or a define a 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(
361      BoxAPIConnection api,
362      List<BoxAIItem> items,
363      List<BoxAIExtractField> fields,
364      BoxAIAgentExtractStructured agent) {
365    return extractMetadataStructured(api, items, null, fields, agent);
366  }
367
368  /**
369   * Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as
370   * a set of key-value pairs. For this request, you need to use an already defined metadata
371   * template or a define a schema yourself.
372   *
373   * @param api The API connection to be used by the created user.
374   * @param items The items to be processed by the LLM, currently only files are supported.
375   * @param template The metadata template to be used for the request.
376   * @param fields The fields to be extracted from the items.
377   * @param agent The AI agent configuration to be used for the request.
378   * @return The response from the AI.
379   */
380  private static BoxAIExtractStructuredResponse extractMetadataStructured(
381      BoxAPIConnection api,
382      List<BoxAIItem> items,
383      BoxAIExtractMetadataTemplate template,
384      List<BoxAIExtractField> fields,
385      BoxAIAgentExtractStructured agent) {
386    URL url = EXTRACT_METADATA_STRUCTURED_URL.build(api.getBaseURL());
387
388    JsonObject requestJSON = new JsonObject();
389    JsonArray itemsJSON = new JsonArray();
390    for (BoxAIItem item : items) {
391      itemsJSON.add(item.getJSONObject());
392    }
393    requestJSON.add("items", itemsJSON);
394
395    if (template != null) {
396      requestJSON.add("metadata_template", template.getJSONObject());
397    }
398
399    if (fields != null) {
400      JsonArray fieldsJSON = new JsonArray();
401      for (BoxAIExtractField field : fields) {
402        fieldsJSON.add(field.getJSONObject());
403      }
404      requestJSON.add("fields", fieldsJSON);
405    }
406
407    if (agent != null) {
408      requestJSON.add("ai_agent", agent.getJSONObject());
409    }
410
411    BoxJSONRequest req = new BoxJSONRequest(api, url, HttpMethod.POST);
412    req.setBody(requestJSON.toString());
413
414    try (BoxJSONResponse response = req.send()) {
415      return new BoxAIExtractStructuredResponse(response.getJSON());
416    }
417  }
418}