From 87e7e0f3fb8c0a2a0f44b0426aa0dff8ce6a712c Mon Sep 17 00:00:00 2001 From: box-sdk-build Date: Wed, 29 Jan 2025 06:44:40 -0800 Subject: [PATCH] feat: update /ai/extract_structured response schema (box/box-openapi#505) --- .codegen.json | 2 +- .../Test/Ai/AiManagerTests.cs | 4 +- Box.Sdk.Gen/Managers/Ai/AiManager.cs | 4 +- Box.Sdk.Gen/Managers/Ai/IAiManager.cs | 2 +- .../AiExtractStructuredResponse.cs | 49 +++++++++++++++++++ docs/Ai.md | 2 +- 6 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 Box.Sdk.Gen/Schemas/AiExtractStructuredResponse/AiExtractStructuredResponse.cs diff --git a/.codegen.json b/.codegen.json index 50059978..13614d84 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "cf82faa", "specHash": "3dc3f1e", "version": "1.6.0" } +{ "engineHash": "cf82faa", "specHash": "1fdcbef", "version": "1.6.0" } diff --git a/Box.Sdk.Gen.Tests.Integration/Test/Ai/AiManagerTests.cs b/Box.Sdk.Gen.Tests.Integration/Test/Ai/AiManagerTests.cs index 81772a0d..d50dcb19 100644 --- a/Box.Sdk.Gen.Tests.Integration/Test/Ai/AiManagerTests.cs +++ b/Box.Sdk.Gen.Tests.Integration/Test/Ai/AiManagerTests.cs @@ -71,7 +71,7 @@ public async System.Threading.Tasks.Task TestAiExtractStructuredWithFields() { Files uploadedFiles = await client.Uploads.UploadFileAsync(requestBody: new UploadFileRequestBody(attributes: new UploadFileRequestBodyAttributesField(name: string.Concat(Utils.GetUUID(), ".txt"), parent: new UploadFileRequestBodyAttributesParentField(id: "0")), file: Utils.StringToByteStream(text: "My name is John Doe. I was born in 4th July 1990. I am 34 years old. My hobby is guitar."))); FileFull file = NullableUtils.Unwrap(uploadedFiles.Entries)[0]; await Utils.DelayInSecondsAsync(seconds: 5); - AiExtractResponse response = await client.Ai.CreateAiExtractStructuredAsync(requestBody: new AiExtractStructured(items: Array.AsReadOnly(new [] {new AiItemBase(id: file.Id)})) { Fields = Array.AsReadOnly(new [] {new AiExtractStructuredFieldsField(key: "firstName") { DisplayName = "First name", Description = "Person first name", Prompt = "What is the your first name?", Type = "string" },new AiExtractStructuredFieldsField(key: "lastName") { DisplayName = "Last name", Description = "Person last name", Prompt = "What is the your last name?", Type = "string" },new AiExtractStructuredFieldsField(key: "dateOfBirth") { DisplayName = "Birth date", Description = "Person date of birth", Prompt = "What is the date of your birth?", Type = "date" },new AiExtractStructuredFieldsField(key: "age") { DisplayName = "Age", Description = "Person age", Prompt = "How old are you?", Type = "float" },new AiExtractStructuredFieldsField(key: "hobby") { DisplayName = "Hobby", Description = "Person hobby", Prompt = "What is your hobby?", Type = "multiSelect", Options = Array.AsReadOnly(new [] {new AiExtractStructuredFieldsOptionsField(key: "guitar"),new AiExtractStructuredFieldsOptionsField(key: "books")}) }}) }); + AiExtractStructuredResponse response = await client.Ai.CreateAiExtractStructuredAsync(requestBody: new AiExtractStructured(items: Array.AsReadOnly(new [] {new AiItemBase(id: file.Id)})) { Fields = Array.AsReadOnly(new [] {new AiExtractStructuredFieldsField(key: "firstName") { DisplayName = "First name", Description = "Person first name", Prompt = "What is the your first name?", Type = "string" },new AiExtractStructuredFieldsField(key: "lastName") { DisplayName = "Last name", Description = "Person last name", Prompt = "What is the your last name?", Type = "string" },new AiExtractStructuredFieldsField(key: "dateOfBirth") { DisplayName = "Birth date", Description = "Person date of birth", Prompt = "What is the date of your birth?", Type = "date" },new AiExtractStructuredFieldsField(key: "age") { DisplayName = "Age", Description = "Person age", Prompt = "How old are you?", Type = "float" },new AiExtractStructuredFieldsField(key: "hobby") { DisplayName = "Hobby", Description = "Person hobby", Prompt = "What is your hobby?", Type = "multiSelect", Options = Array.AsReadOnly(new [] {new AiExtractStructuredFieldsOptionsField(key: "guitar"),new AiExtractStructuredFieldsOptionsField(key: "books")}) }}) }); Assert.IsTrue(StringUtils.ToStringRepresentation(Utils.GetValueFromObjectRawData(obj: response, key: "firstName")) == "John"); Assert.IsTrue(StringUtils.ToStringRepresentation(Utils.GetValueFromObjectRawData(obj: response, key: "lastName")) == "Doe"); Assert.IsTrue(StringUtils.ToStringRepresentation(Utils.GetValueFromObjectRawData(obj: response, key: "dateOfBirth")) == "1990-07-04"); @@ -87,7 +87,7 @@ public async System.Threading.Tasks.Task TestAiExtractStructuredWithMetadataTemp await Utils.DelayInSecondsAsync(seconds: 5); string templateKey = string.Concat("key", Utils.GetUUID()); MetadataTemplate template = await client.MetadataTemplates.CreateMetadataTemplateAsync(requestBody: new CreateMetadataTemplateRequestBody(scope: "enterprise", displayName: templateKey) { TemplateKey = templateKey, Fields = Array.AsReadOnly(new [] {new CreateMetadataTemplateRequestBodyFieldsField(key: "firstName", displayName: "First name", type: CreateMetadataTemplateRequestBodyFieldsTypeField.String) { Description = "Person first name" },new CreateMetadataTemplateRequestBodyFieldsField(key: "lastName", displayName: "Last name", type: CreateMetadataTemplateRequestBodyFieldsTypeField.String) { Description = "Person last name" },new CreateMetadataTemplateRequestBodyFieldsField(key: "dateOfBirth", displayName: "Birth date", type: CreateMetadataTemplateRequestBodyFieldsTypeField.Date) { Description = "Person date of birth" },new CreateMetadataTemplateRequestBodyFieldsField(key: "age", displayName: "Age", type: CreateMetadataTemplateRequestBodyFieldsTypeField.Float) { Description = "Person age" },new CreateMetadataTemplateRequestBodyFieldsField(key: "hobby", displayName: "Hobby", type: CreateMetadataTemplateRequestBodyFieldsTypeField.MultiSelect) { Description = "Person hobby", Options = Array.AsReadOnly(new [] {new CreateMetadataTemplateRequestBodyFieldsOptionsField(key: "guitar"),new CreateMetadataTemplateRequestBodyFieldsOptionsField(key: "books")}) }}) }); - AiExtractResponse response = await client.Ai.CreateAiExtractStructuredAsync(requestBody: new AiExtractStructured(items: Array.AsReadOnly(new [] {new AiItemBase(id: file.Id)})) { MetadataTemplate = new AiExtractStructuredMetadataTemplateField() { TemplateKey = templateKey, Scope = "enterprise" } }); + AiExtractStructuredResponse response = await client.Ai.CreateAiExtractStructuredAsync(requestBody: new AiExtractStructured(items: Array.AsReadOnly(new [] {new AiItemBase(id: file.Id)})) { MetadataTemplate = new AiExtractStructuredMetadataTemplateField() { TemplateKey = templateKey, Scope = "enterprise" } }); Assert.IsTrue(StringUtils.ToStringRepresentation(Utils.GetValueFromObjectRawData(obj: response, key: "firstName")) == "John"); Assert.IsTrue(StringUtils.ToStringRepresentation(Utils.GetValueFromObjectRawData(obj: response, key: "lastName")) == "Doe"); Assert.IsTrue(StringUtils.ToStringRepresentation(Utils.GetValueFromObjectRawData(obj: response, key: "dateOfBirth")) == "1990-07-04T00:00:00Z"); diff --git a/Box.Sdk.Gen/Managers/Ai/AiManager.cs b/Box.Sdk.Gen/Managers/Ai/AiManager.cs index 2df627ff..f9e70f4f 100644 --- a/Box.Sdk.Gen/Managers/Ai/AiManager.cs +++ b/Box.Sdk.Gen/Managers/Ai/AiManager.cs @@ -108,11 +108,11 @@ public async System.Threading.Tasks.Task CreateAiExtractAsync(AiExtr /// /// Token used for request cancellation. /// - public async System.Threading.Tasks.Task CreateAiExtractStructuredAsync(AiExtractStructured requestBody, CreateAiExtractStructuredHeaders? headers = default, System.Threading.CancellationToken? cancellationToken = null) { + public async System.Threading.Tasks.Task CreateAiExtractStructuredAsync(AiExtractStructured requestBody, CreateAiExtractStructuredHeaders? headers = default, System.Threading.CancellationToken? cancellationToken = null) { headers = headers ?? new CreateAiExtractStructuredHeaders(); Dictionary headersMap = Utils.PrepareParams(map: DictionaryUtils.MergeDictionaries(new Dictionary() { }, headers.ExtraHeaders)); FetchResponse response = await this.NetworkSession.NetworkClient.FetchAsync(options: new FetchOptions(url: string.Concat(this.NetworkSession.BaseUrls.BaseUrl, "/2.0/ai/extract_structured"), method: "POST", contentType: "application/json", responseFormat: Box.Sdk.Gen.ResponseFormat.Json) { Headers = headersMap, Data = SimpleJsonSerializer.Serialize(requestBody), Auth = this.Auth, NetworkSession = this.NetworkSession, CancellationToken = cancellationToken }).ConfigureAwait(false); - return SimpleJsonSerializer.Deserialize(NullableUtils.Unwrap(response.Data)); + return SimpleJsonSerializer.Deserialize(NullableUtils.Unwrap(response.Data)); } } diff --git a/Box.Sdk.Gen/Managers/Ai/IAiManager.cs b/Box.Sdk.Gen/Managers/Ai/IAiManager.cs index 8294487a..9dab3d5e 100644 --- a/Box.Sdk.Gen/Managers/Ai/IAiManager.cs +++ b/Box.Sdk.Gen/Managers/Ai/IAiManager.cs @@ -80,7 +80,7 @@ public interface IAiManager { /// /// Token used for request cancellation. /// - public System.Threading.Tasks.Task CreateAiExtractStructuredAsync(AiExtractStructured requestBody, CreateAiExtractStructuredHeaders? headers = default, System.Threading.CancellationToken? cancellationToken = null) => throw new System.NotImplementedException("This method needs to be implemented by the derived class before calling it."); + public System.Threading.Tasks.Task CreateAiExtractStructuredAsync(AiExtractStructured requestBody, CreateAiExtractStructuredHeaders? headers = default, System.Threading.CancellationToken? cancellationToken = null) => throw new System.NotImplementedException("This method needs to be implemented by the derived class before calling it."); } } \ No newline at end of file diff --git a/Box.Sdk.Gen/Schemas/AiExtractStructuredResponse/AiExtractStructuredResponse.cs b/Box.Sdk.Gen/Schemas/AiExtractStructuredResponse/AiExtractStructuredResponse.cs new file mode 100644 index 00000000..8d85c5f5 --- /dev/null +++ b/Box.Sdk.Gen/Schemas/AiExtractStructuredResponse/AiExtractStructuredResponse.cs @@ -0,0 +1,49 @@ +using Box.Sdk.Gen; +using System.Text.Json.Serialization; +using System.Collections.Generic; +using Box.Sdk.Gen.Internal; +using Box.Sdk.Gen.Schemas; + +namespace Box.Sdk.Gen.Schemas { + public class AiExtractStructuredResponse : ISerializable { + [JsonPropertyName("answer")] + public AiExtractResponse Answer { get; } + + /// + /// The ISO date formatted timestamp of when the answer to the prompt was created. + /// + [JsonPropertyName("created_at")] + public System.DateTimeOffset CreatedAt { get; } + + /// + /// The reason the response finishes. + /// + [JsonPropertyName("completion_reason")] + public string? CompletionReason { get; init; } + + [JsonPropertyName("ai_agent_info")] + public AiAgentInfo? AiAgentInfo { get; init; } + + public AiExtractStructuredResponse(AiExtractResponse answer, System.DateTimeOffset createdAt) { + Answer = answer; + CreatedAt = createdAt; + } + internal string? RawJson { get; set; } = default; + + void ISerializable.SetJson(string json) { + RawJson = json; + } + + string? ISerializable.GetJson() { + return RawJson; + } + + /// + /// Returns raw json response returned from the API. + /// + public Dictionary? GetRawData() { + return SimpleJsonSerializer.GetAllFields(this); + } + + } +} \ No newline at end of file diff --git a/docs/Ai.md b/docs/Ai.md index 0f5dff38..5ad2a895 100644 --- a/docs/Ai.md +++ b/docs/Ai.md @@ -169,7 +169,7 @@ await client.Ai.CreateAiExtractStructuredAsync(requestBody: new AiExtractStructu ### Returns -This function returns a value of type `AiExtractResponse`. +This function returns a value of type `AiExtractStructuredResponse`. A successful response including the answer from the LLM.