diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9183c1774..7553ced81 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.47.0" + ".": "4.48.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 039bcd9c9..284e122e6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 277 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-44d4add500460ed21ac9ae1d6dd4047a32a79d3b4c3a9d9754f6ecf8cbdb9eec.yml -openapi_spec_hash: 8a34ba094583f56e975067493574fa69 -config_hash: ca12d10f1dbe101a81cd0376f868c674 +configured_endpoints: 278 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-31fcc3c97e5c432754bf0b72c5d5abbe1493573f0ca888af914baf81188b453e.yml +openapi_spec_hash: f867849a0c2a9c9b838d21f1c720a9e3 +config_hash: fce3820c4f95b555e486349bc7d297d8 diff --git a/CHANGELOG.md b/CHANGELOG.md index 79c6fc25e..e600865db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 4.48.0 (2026-07-31) + +Full Changelog: [v4.47.0...v4.48.0](https://github.com/openai/openai-java/compare/v4.47.0...v4.48.0) + +### Features + +* **api:** content provenance checks ([b89a308](https://github.com/openai/openai-java/commit/b89a3082b84d68cd7003f53397fb56cdd3062bd6)) +* **api:** support the fast service tier for response compaction ([b89a308](https://github.com/openai/openai-java/commit/b89a3082b84d68cd7003f53397fb56cdd3062bd6)) + ## 4.47.0 (2026-07-30) Full Changelog: [v4.46.0...v4.47.0](https://github.com/openai/openai-java/compare/v4.46.0...v4.47.0) diff --git a/README.md b/README.md index 64144dbfc..b6788a580 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.openai/openai-java)](https://central.sonatype.com/artifact/com.openai/openai-java/4.47.0) -[![javadoc](https://javadoc.io/badge2/com.openai/openai-java/4.47.0/javadoc.svg)](https://javadoc.io/doc/com.openai/openai-java/4.47.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.openai/openai-java)](https://central.sonatype.com/artifact/com.openai/openai-java/4.48.0) +[![javadoc](https://javadoc.io/badge2/com.openai/openai-java/4.48.0/javadoc.svg)](https://javadoc.io/doc/com.openai/openai-java/4.48.0) @@ -11,7 +11,7 @@ The OpenAI Java SDK provides convenient access to the [OpenAI REST API](https:// -The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.openai/openai-java/4.47.0). +The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.openai/openai-java/4.48.0). @@ -22,7 +22,7 @@ The REST API documentation can be found on [platform.openai.com](https://platfor ### Gradle ```kotlin -implementation("com.openai:openai-java:4.47.0") +implementation("com.openai:openai-java:4.48.0") ``` ### Maven @@ -31,7 +31,7 @@ implementation("com.openai:openai-java:4.47.0") com.openai openai-java - 4.47.0 + 4.48.0 ``` @@ -94,7 +94,7 @@ with normal AWS credentials: ```kotlin -implementation("com.openai:openai-java-bedrock:4.47.0") +implementation("com.openai:openai-java-bedrock:4.48.0") ``` diff --git a/bedrock.md b/bedrock.md index 670a7a4cc..d0490289d 100644 --- a/bedrock.md +++ b/bedrock.md @@ -11,14 +11,14 @@ Use this artifact instead of adding AWS dependencies to the base OpenAI package ```kotlin -implementation("com.openai:openai-java-bedrock:4.47.0") +implementation("com.openai:openai-java-bedrock:4.48.0") ``` ```xml com.openai openai-java-bedrock - 4.47.0 + 4.48.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 0333e52a0..f8aa6e1b8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ repositories { allprojects { group = "com.openai" - version = "4.47.0" // x-release-please-version + version = "4.48.0" // x-release-please-version // Dokka 2.1.0 depends on Jackson 2.15.3. Keep its isolated build-tool classpaths on a // secure, internally aligned Jackson release without changing the SDK's published or diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt index efc707c8e..f97b5f8ac 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt @@ -10,6 +10,7 @@ import com.openai.services.blocking.BetaService import com.openai.services.blocking.ChatService import com.openai.services.blocking.CompletionService import com.openai.services.blocking.ContainerService +import com.openai.services.blocking.ContentProvenanceCheckService import com.openai.services.blocking.ConversationService import com.openai.services.blocking.EmbeddingService import com.openai.services.blocking.EvalService @@ -87,6 +88,8 @@ interface OpenAIClient { /** Given a prompt and/or an input image, the model will generate a new image. */ fun images(): ImageService + fun contentProvenanceChecks(): ContentProvenanceCheckService + fun audio(): AudioService /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ @@ -175,6 +178,8 @@ interface OpenAIClient { /** Given a prompt and/or an input image, the model will generate a new image. */ fun images(): ImageService.WithRawResponse + fun contentProvenanceChecks(): ContentProvenanceCheckService.WithRawResponse + fun audio(): AudioService.WithRawResponse /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt index 7c32392eb..cd53ee594 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt @@ -10,6 +10,7 @@ import com.openai.services.async.BetaServiceAsync import com.openai.services.async.ChatServiceAsync import com.openai.services.async.CompletionServiceAsync import com.openai.services.async.ContainerServiceAsync +import com.openai.services.async.ContentProvenanceCheckServiceAsync import com.openai.services.async.ConversationServiceAsync import com.openai.services.async.EmbeddingServiceAsync import com.openai.services.async.EvalServiceAsync @@ -87,6 +88,8 @@ interface OpenAIClientAsync { /** Given a prompt and/or an input image, the model will generate a new image. */ fun images(): ImageServiceAsync + fun contentProvenanceChecks(): ContentProvenanceCheckServiceAsync + fun audio(): AudioServiceAsync /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ @@ -177,6 +180,8 @@ interface OpenAIClientAsync { /** Given a prompt and/or an input image, the model will generate a new image. */ fun images(): ImageServiceAsync.WithRawResponse + fun contentProvenanceChecks(): ContentProvenanceCheckServiceAsync.WithRawResponse + fun audio(): AudioServiceAsync.WithRawResponse /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt index 188ab8314..78c78f6aa 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt @@ -18,6 +18,8 @@ import com.openai.services.async.CompletionServiceAsync import com.openai.services.async.CompletionServiceAsyncImpl import com.openai.services.async.ContainerServiceAsync import com.openai.services.async.ContainerServiceAsyncImpl +import com.openai.services.async.ContentProvenanceCheckServiceAsync +import com.openai.services.async.ContentProvenanceCheckServiceAsyncImpl import com.openai.services.async.ConversationServiceAsync import com.openai.services.async.ConversationServiceAsyncImpl import com.openai.services.async.EmbeddingServiceAsync @@ -85,6 +87,10 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl ImageServiceAsyncImpl(clientOptionsWithUserAgent) } + private val contentProvenanceChecks: ContentProvenanceCheckServiceAsync by lazy { + ContentProvenanceCheckServiceAsyncImpl(clientOptionsWithUserAgent) + } + private val audio: AudioServiceAsync by lazy { AudioServiceAsyncImpl(clientOptionsWithUserAgent) } @@ -183,6 +189,9 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl /** Given a prompt and/or an input image, the model will generate a new image. */ override fun images(): ImageServiceAsync = images + override fun contentProvenanceChecks(): ContentProvenanceCheckServiceAsync = + contentProvenanceChecks + override fun audio(): AudioServiceAsync = audio /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ @@ -250,6 +259,11 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl ImageServiceAsyncImpl.WithRawResponseImpl(clientOptions) } + private val contentProvenanceChecks: + ContentProvenanceCheckServiceAsync.WithRawResponse by lazy { + ContentProvenanceCheckServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + private val audio: AudioServiceAsync.WithRawResponse by lazy { AudioServiceAsyncImpl.WithRawResponseImpl(clientOptions) } @@ -352,6 +366,9 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl /** Given a prompt and/or an input image, the model will generate a new image. */ override fun images(): ImageServiceAsync.WithRawResponse = images + override fun contentProvenanceChecks(): ContentProvenanceCheckServiceAsync.WithRawResponse = + contentProvenanceChecks + override fun audio(): AudioServiceAsync.WithRawResponse = audio /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt index 0f7b0dcc1..52f28f315 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt @@ -18,6 +18,8 @@ import com.openai.services.blocking.CompletionService import com.openai.services.blocking.CompletionServiceImpl import com.openai.services.blocking.ContainerService import com.openai.services.blocking.ContainerServiceImpl +import com.openai.services.blocking.ContentProvenanceCheckService +import com.openai.services.blocking.ContentProvenanceCheckServiceImpl import com.openai.services.blocking.ConversationService import com.openai.services.blocking.ConversationServiceImpl import com.openai.services.blocking.EmbeddingService @@ -83,6 +85,10 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient private val images: ImageService by lazy { ImageServiceImpl(clientOptionsWithUserAgent) } + private val contentProvenanceChecks: ContentProvenanceCheckService by lazy { + ContentProvenanceCheckServiceImpl(clientOptionsWithUserAgent) + } + private val audio: AudioService by lazy { AudioServiceImpl(clientOptionsWithUserAgent) } private val moderations: ModerationService by lazy { @@ -163,6 +169,8 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient /** Given a prompt and/or an input image, the model will generate a new image. */ override fun images(): ImageService = images + override fun contentProvenanceChecks(): ContentProvenanceCheckService = contentProvenanceChecks + override fun audio(): AudioService = audio /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ @@ -230,6 +238,10 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient ImageServiceImpl.WithRawResponseImpl(clientOptions) } + private val contentProvenanceChecks: ContentProvenanceCheckService.WithRawResponse by lazy { + ContentProvenanceCheckServiceImpl.WithRawResponseImpl(clientOptions) + } + private val audio: AudioService.WithRawResponse by lazy { AudioServiceImpl.WithRawResponseImpl(clientOptions) } @@ -332,6 +344,9 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient /** Given a prompt and/or an input image, the model will generate a new image. */ override fun images(): ImageService.WithRawResponse = images + override fun contentProvenanceChecks(): ContentProvenanceCheckService.WithRawResponse = + contentProvenanceChecks + override fun audio(): AudioService.WithRawResponse = audio /** Given text and/or image inputs, classifies if those inputs are potentially harmful. */ diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/ResponseCompactParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/ResponseCompactParams.kt index 1974fb8e5..7f906e18a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/ResponseCompactParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/responses/ResponseCompactParams.kt @@ -125,7 +125,19 @@ private constructor( fun promptCacheRetention(): Optional = body.promptCacheRetention() /** - * The service tier to use for this request. + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. Unless + * otherwise configured, the Project will use 'default'. - If set to 'default', then the request + * will be processed with the standard pricing and performance for the selected model. - If set + * to '[flex](https://platform.openai.com/docs/guides/flex-processing)', then the request will + * be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the `service_tier=fast` + * or `service_tier=priority` parameter for Responses or Chat Completions. The response will + * show `service_tier=priority` regardless of if you specify `service_tier=fast` or `priority` + * in your request. - When not set, the default behavior is 'auto'. When the `service_tier` + * parameter is set, the response body will include the `service_tier` value based on the + * processing mode actually used to serve the request. This response value may be different from + * the value set in the parameter. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -434,7 +446,21 @@ private constructor( body.promptCacheRetention(promptCacheRetention) } - /** The service tier to use for this request. */ + /** + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. + * Unless otherwise configured, the Project will use 'default'. - If set to 'default', then + * the request will be processed with the standard pricing and performance for the selected + * model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)', + * then the request will be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the + * `service_tier=fast` or `service_tier=priority` parameter for Responses or Chat + * Completions. The response will show `service_tier=priority` regardless of if you specify + * `service_tier=fast` or `priority` in your request. - When not set, the default behavior + * is 'auto'. When the `service_tier` parameter is set, the response body will include the + * `service_tier` value based on the processing mode actually used to serve the request. + * This response value may be different from the value set in the parameter. + */ fun serviceTier(serviceTier: ServiceTier?) = apply { body.serviceTier(serviceTier) } /** Alias for calling [Builder.serviceTier] with `serviceTier.orElse(null)`. */ @@ -727,7 +753,19 @@ private constructor( promptCacheRetention.getOptional("prompt_cache_retention") /** - * The service tier to use for this request. + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. + * Unless otherwise configured, the Project will use 'default'. - If set to 'default', then + * the request will be processed with the standard pricing and performance for the selected + * model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)', + * then the request will be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the + * `service_tier=fast` or `service_tier=priority` parameter for Responses or Chat + * Completions. The response will show `service_tier=priority` regardless of if you specify + * `service_tier=fast` or `priority` in your request. - When not set, the default behavior + * is 'auto'. When the `service_tier` parameter is set, the response body will include the + * `service_tier` value based on the processing mode actually used to serve the request. + * This response value may be different from the value set in the parameter. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -1041,7 +1079,23 @@ private constructor( this.promptCacheRetention = promptCacheRetention } - /** The service tier to use for this request. */ + /** + * Specifies the processing type used for serving the request. - If set to 'auto', then + * the request will be processed with the service tier configured in the Project + * settings. Unless otherwise configured, the Project will use 'default'. - If set to + * 'default', then the request will be processed with the standard pricing and + * performance for the selected model. - If set to + * '[flex](https://platform.openai.com/docs/guides/flex-processing)', then the request + * will be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the + * `service_tier=fast` or `service_tier=priority` parameter for Responses or Chat + * Completions. The response will show `service_tier=priority` regardless of if you + * specify `service_tier=fast` or `priority` in your request. - When not set, the + * default behavior is 'auto'. When the `service_tier` parameter is set, the response + * body will include the `service_tier` value based on the processing mode actually used + * to serve the request. This response value may be different from the value set in the + * parameter. + */ fun serviceTier(serviceTier: ServiceTier?) = serviceTier(JsonField.ofNullable(serviceTier)) @@ -2762,7 +2816,21 @@ private constructor( override fun toString() = value.toString() } - /** The service tier to use for this request. */ + /** + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. Unless + * otherwise configured, the Project will use 'default'. - If set to 'default', then the request + * will be processed with the standard pricing and performance for the selected model. - If set + * to '[flex](https://platform.openai.com/docs/guides/flex-processing)', then the request will + * be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the `service_tier=fast` + * or `service_tier=priority` parameter for Responses or Chat Completions. The response will + * show `service_tier=priority` regardless of if you specify `service_tier=fast` or `priority` + * in your request. - When not set, the default behavior is 'auto'. When the `service_tier` + * parameter is set, the response body will include the `service_tier` value based on the + * processing mode actually used to serve the request. This response value may be different from + * the value set in the parameter. + */ class ServiceTier @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -2782,6 +2850,8 @@ private constructor( @JvmField val DEFAULT = of("default") + @JvmField val FAST = of("fast") + @JvmField val FLEX = of("flex") @JvmField val PRIORITY = of("priority") @@ -2793,6 +2863,7 @@ private constructor( enum class Known { AUTO, DEFAULT, + FAST, FLEX, PRIORITY, } @@ -2809,6 +2880,7 @@ private constructor( enum class Value { AUTO, DEFAULT, + FAST, FLEX, PRIORITY, /** @@ -2828,6 +2900,7 @@ private constructor( when (this) { AUTO -> Value.AUTO DEFAULT -> Value.DEFAULT + FAST -> Value.FAST FLEX -> Value.FLEX PRIORITY -> Value.PRIORITY else -> Value._UNKNOWN @@ -2846,6 +2919,7 @@ private constructor( when (this) { AUTO -> Known.AUTO DEFAULT -> Known.DEFAULT + FAST -> Known.FAST FLEX -> Known.FLEX PRIORITY -> Known.PRIORITY else -> throw OpenAIInvalidDataException("Unknown ServiceTier: $value") diff --git a/openai-java-core/src/main/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheck.kt b/openai-java-core/src/main/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheck.kt new file mode 100644 index 000000000..04b1a7fa7 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheck.kt @@ -0,0 +1,1827 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.contentprovenancechecks + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.Enum +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.checkKnown +import com.openai.core.checkRequired +import com.openai.core.getOrThrow +import com.openai.core.toImmutable +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class ContentProvenanceCheck +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val createdAt: JsonField, + private val object_: JsonField, + private val results: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("created_at") @ExcludeMissing createdAt: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonField = JsonMissing.of(), + @JsonProperty("results") @ExcludeMissing results: JsonField> = JsonMissing.of(), + ) : this(createdAt, object_, results, mutableMapOf()) + + /** + * The Unix timestamp, in seconds, when the provenance check was created. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun createdAt(): Long = createdAt.getRequired("created_at") + + /** + * The object type. Always `content_provenance_check` for this endpoint. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun object_(): Object = object_.getRequired("object") + + /** + * The provenance results that apply to the uploaded file. Image results include C2PA and + * SynthID; audio results include SynthID. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun results(): List = results.getRequired("results") + + /** + * Returns the raw JSON value of [createdAt]. + * + * Unlike [createdAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("created_at") @ExcludeMissing fun _createdAt(): JsonField = createdAt + + /** + * Returns the raw JSON value of [object_]. + * + * Unlike [object_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonField = object_ + + /** + * Returns the raw JSON value of [results]. + * + * Unlike [results], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("results") @ExcludeMissing fun _results(): JsonField> = results + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ContentProvenanceCheck]. + * + * The following fields are required: + * ```java + * .createdAt() + * .object_() + * .results() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ContentProvenanceCheck]. */ + class Builder internal constructor() { + + private var createdAt: JsonField? = null + private var object_: JsonField? = null + private var results: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(contentProvenanceCheck: ContentProvenanceCheck) = apply { + createdAt = contentProvenanceCheck.createdAt + object_ = contentProvenanceCheck.object_ + results = contentProvenanceCheck.results.map { it.toMutableList() } + additionalProperties = contentProvenanceCheck.additionalProperties.toMutableMap() + } + + /** The Unix timestamp, in seconds, when the provenance check was created. */ + fun createdAt(createdAt: Long) = createdAt(JsonField.of(createdAt)) + + /** + * Sets [Builder.createdAt] to an arbitrary JSON value. + * + * You should usually call [Builder.createdAt] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } + + /** The object type. Always `content_provenance_check` for this endpoint. */ + fun object_(object_: Object) = object_(JsonField.of(object_)) + + /** + * Sets [Builder.object_] to an arbitrary JSON value. + * + * You should usually call [Builder.object_] with a well-typed [Object] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun object_(object_: JsonField) = apply { this.object_ = object_ } + + /** + * The provenance results that apply to the uploaded file. Image results include C2PA and + * SynthID; audio results include SynthID. + */ + fun results(results: List) = results(JsonField.of(results)) + + /** + * Sets [Builder.results] to an arbitrary JSON value. + * + * You should usually call [Builder.results] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun results(results: JsonField>) = apply { + this.results = results.map { it.toMutableList() } + } + + /** + * Adds a single [Result] to [results]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addResult(result: Result) = apply { + results = + (results ?: JsonField.of(mutableListOf())).also { + checkKnown("results", it).add(result) + } + } + + /** Alias for calling [addResult] with `Result.ofC2pa(c2pa)`. */ + fun addResult(c2pa: Result.C2pa) = addResult(Result.ofC2pa(c2pa)) + + /** Alias for calling [addResult] with `Result.ofSynthID(synthID)`. */ + fun addResult(synthID: Result.SynthID) = addResult(Result.ofSynthID(synthID)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ContentProvenanceCheck]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .createdAt() + * .object_() + * .results() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ContentProvenanceCheck = + ContentProvenanceCheck( + checkRequired("createdAt", createdAt), + checkRequired("object_", object_), + checkRequired("results", results).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): ContentProvenanceCheck = apply { + if (validated) { + return@apply + } + + createdAt() + object_().validate() + results().forEach { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (createdAt.asKnown().isPresent) 1 else 0) + + (object_.asKnown().getOrNull()?.validity() ?: 0) + + (results.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + /** The object type. Always `content_provenance_check` for this endpoint. */ + class Object @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val CONTENT_PROVENANCE_CHECK = of("content_provenance_check") + + @JvmStatic fun of(value: String) = Object(JsonField.of(value)) + } + + /** An enum containing [Object]'s known values. */ + enum class Known { + CONTENT_PROVENANCE_CHECK + } + + /** + * An enum containing [Object]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Object] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + CONTENT_PROVENANCE_CHECK, + /** An enum member indicating that [Object] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + CONTENT_PROVENANCE_CHECK -> Value.CONTENT_PROVENANCE_CHECK + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + CONTENT_PROVENANCE_CHECK -> Known.CONTENT_PROVENANCE_CHECK + else -> throw OpenAIInvalidDataException("Unknown Object: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { OpenAIInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): Object = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Object && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + @JsonDeserialize(using = Result.Deserializer::class) + @JsonSerialize(using = Result.Serializer::class) + class Result + private constructor( + private val c2pa: C2pa? = null, + private val synthID: SynthID? = null, + private val _json: JsonValue? = null, + ) { + + fun c2pa(): Optional = Optional.ofNullable(c2pa) + + fun synthID(): Optional = Optional.ofNullable(synthID) + + fun isC2pa(): Boolean = c2pa != null + + fun isSynthID(): Boolean = synthID != null + + fun asC2pa(): C2pa = c2pa.getOrThrow("c2pa") + + fun asSynthID(): SynthID = synthID.getOrThrow("synthID") + + fun _json(): Optional = Optional.ofNullable(_json) + + /** + * Maps this instance's current variant to a value of type [T] using the given [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, unless + * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of + * the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.openai.core.JsonValue; + * import java.util.Optional; + * + * Optional result = result.accept(new Result.Visitor>() { + * @Override + * public Optional visitC2pa(C2pa c2pa) { + * return Optional.of(c2pa.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws OpenAIInvalidDataException if [Visitor.unknown] is not overridden in [visitor] + * and the current variant is unknown. + */ + fun accept(visitor: Visitor): T = + when { + c2pa != null -> visitor.visitC2pa(c2pa) + synthID != null -> visitor.visitSynthID(synthID) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): Result = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitC2pa(c2pa: C2pa) { + c2pa.validate() + } + + override fun visitSynthID(synthID: SynthID) { + synthID.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitC2pa(c2pa: C2pa) = c2pa.validity() + + override fun visitSynthID(synthID: SynthID) = synthID.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Result && c2pa == other.c2pa && synthID == other.synthID + } + + override fun hashCode(): Int = Objects.hash(c2pa, synthID) + + override fun toString(): String = + when { + c2pa != null -> "Result{c2pa=$c2pa}" + synthID != null -> "Result{synthID=$synthID}" + _json != null -> "Result{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Result") + } + + companion object { + + @JvmStatic fun ofC2pa(c2pa: C2pa) = Result(c2pa = c2pa) + + @JvmStatic fun ofSynthID(synthID: SynthID) = Result(synthID = synthID) + } + + /** An interface that defines how to map each variant of [Result] to a value of type [T]. */ + interface Visitor { + + fun visitC2pa(c2pa: C2pa): T + + fun visitSynthID(synthID: SynthID): T + + /** + * Maps an unknown variant of [Result] to a value of type [T]. + * + * An instance of [Result] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Result: $json") + } + } + + internal class Deserializer : BaseDeserializer(Result::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Result { + val json = JsonValue.fromJsonNode(node) + val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() + + when (type) { + "c2pa" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Result(c2pa = it, _json = json) + } ?: Result(_json = json) + } + "synthid" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Result(synthID = it, _json = json) + } ?: Result(_json = json) + } + } + + return Result(_json = json) + } + } + + internal class Serializer : BaseSerializer(Result::class) { + + override fun serialize( + value: Result, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.c2pa != null -> generator.writeObject(value.c2pa) + value.synthID != null -> generator.writeObject(value.synthID) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Result") + } + } + } + + class C2pa + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val generatedAt: JsonField, + private val issuer: JsonField, + private val model: JsonField, + private val outcome: JsonField, + private val type: JsonValue, + private val validationState: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("generated_at") + @ExcludeMissing + generatedAt: JsonField = JsonMissing.of(), + @JsonProperty("issuer") + @ExcludeMissing + issuer: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("outcome") + @ExcludeMissing + outcome: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("validation_state") + @ExcludeMissing + validationState: JsonField = JsonMissing.of(), + ) : this(generatedAt, issuer, model, outcome, type, validationState, mutableMapOf()) + + /** + * The UTC RFC 3339 timestamp recorded by the provenance signal for when the asset was + * generated, when available. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun generatedAt(): Optional = generatedAt.getOptional("generated_at") + + /** + * The C2PA manifest issuer, when available. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun issuer(): Optional = issuer.getOptional("issuer") + + /** + * The OpenAI model recorded by the provenance signal, when available. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Whether a supported OpenAI C2PA provenance signal was detected. If `not_detected`, it + * means the tool did not find supported signals in the uploaded file. The content could + * still have been generated by OpenAI if the metadata was stripped or has evidence of + * tampering, the watermark was degraded, it comes from a legacy generation model, or it + * was created before provenance signals were available. Content could also still be + * AI-generated by another company's model, which the tool currently does not detect. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun outcome(): Outcome = outcome.getRequired("outcome") + + /** + * The provenance signal type. Always `c2pa`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("c2pa") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The validation status of the C2PA manifest in the uploaded image. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun validationState(): ValidationState = validationState.getRequired("validation_state") + + /** + * Returns the raw JSON value of [generatedAt]. + * + * Unlike [generatedAt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("generated_at") + @ExcludeMissing + fun _generatedAt(): JsonField = generatedAt + + /** + * Returns the raw JSON value of [issuer]. + * + * Unlike [issuer], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("issuer") @ExcludeMissing fun _issuer(): JsonField = issuer + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [outcome]. + * + * Unlike [outcome], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("outcome") @ExcludeMissing fun _outcome(): JsonField = outcome + + /** + * Returns the raw JSON value of [validationState]. + * + * Unlike [validationState], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("validation_state") + @ExcludeMissing + fun _validationState(): JsonField = validationState + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [C2pa]. + * + * The following fields are required: + * ```java + * .generatedAt() + * .issuer() + * .model() + * .outcome() + * .validationState() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [C2pa]. */ + class Builder internal constructor() { + + private var generatedAt: JsonField? = null + private var issuer: JsonField? = null + private var model: JsonField? = null + private var outcome: JsonField? = null + private var type: JsonValue = JsonValue.from("c2pa") + private var validationState: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(c2pa: C2pa) = apply { + generatedAt = c2pa.generatedAt + issuer = c2pa.issuer + model = c2pa.model + outcome = c2pa.outcome + type = c2pa.type + validationState = c2pa.validationState + additionalProperties = c2pa.additionalProperties.toMutableMap() + } + + /** + * The UTC RFC 3339 timestamp recorded by the provenance signal for when the asset + * was generated, when available. + */ + fun generatedAt(generatedAt: String?) = + generatedAt(JsonField.ofNullable(generatedAt)) + + /** Alias for calling [Builder.generatedAt] with `generatedAt.orElse(null)`. */ + fun generatedAt(generatedAt: Optional) = + generatedAt(generatedAt.getOrNull()) + + /** + * Sets [Builder.generatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.generatedAt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun generatedAt(generatedAt: JsonField) = apply { + this.generatedAt = generatedAt + } + + /** The C2PA manifest issuer, when available. */ + fun issuer(issuer: String?) = issuer(JsonField.ofNullable(issuer)) + + /** Alias for calling [Builder.issuer] with `issuer.orElse(null)`. */ + fun issuer(issuer: Optional) = issuer(issuer.getOrNull()) + + /** + * Sets [Builder.issuer] to an arbitrary JSON value. + * + * You should usually call [Builder.issuer] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun issuer(issuer: JsonField) = apply { this.issuer = issuer } + + /** The OpenAI model recorded by the provenance signal, when available. */ + fun model(model: String?) = model(JsonField.ofNullable(model)) + + /** Alias for calling [Builder.model] with `model.orElse(null)`. */ + fun model(model: Optional) = model(model.getOrNull()) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** + * Whether a supported OpenAI C2PA provenance signal was detected. If + * `not_detected`, it means the tool did not find supported signals in the uploaded + * file. The content could still have been generated by OpenAI if the metadata was + * stripped or has evidence of tampering, the watermark was degraded, it comes from + * a legacy generation model, or it was created before provenance signals were + * available. Content could also still be AI-generated by another company's model, + * which the tool currently does not detect. + */ + fun outcome(outcome: Outcome) = outcome(JsonField.of(outcome)) + + /** + * Sets [Builder.outcome] to an arbitrary JSON value. + * + * You should usually call [Builder.outcome] with a well-typed [Outcome] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun outcome(outcome: JsonField) = apply { this.outcome = outcome } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("c2pa") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The validation status of the C2PA manifest in the uploaded image. */ + fun validationState(validationState: ValidationState) = + validationState(JsonField.of(validationState)) + + /** + * Sets [Builder.validationState] to an arbitrary JSON value. + * + * You should usually call [Builder.validationState] with a well-typed + * [ValidationState] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun validationState(validationState: JsonField) = apply { + this.validationState = validationState + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [C2pa]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .generatedAt() + * .issuer() + * .model() + * .outcome() + * .validationState() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): C2pa = + C2pa( + checkRequired("generatedAt", generatedAt), + checkRequired("issuer", issuer), + checkRequired("model", model), + checkRequired("outcome", outcome), + type, + checkRequired("validationState", validationState), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): C2pa = apply { + if (validated) { + return@apply + } + + generatedAt() + issuer() + model() + outcome().validate() + _type().let { + if (it != JsonValue.from("c2pa")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + validationState().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (generatedAt.asKnown().isPresent) 1 else 0) + + (if (issuer.asKnown().isPresent) 1 else 0) + + (if (model.asKnown().isPresent) 1 else 0) + + (outcome.asKnown().getOrNull()?.validity() ?: 0) + + type.let { if (it == JsonValue.from("c2pa")) 1 else 0 } + + (validationState.asKnown().getOrNull()?.validity() ?: 0) + + /** + * Whether a supported OpenAI C2PA provenance signal was detected. If `not_detected`, it + * means the tool did not find supported signals in the uploaded file. The content could + * still have been generated by OpenAI if the metadata was stripped or has evidence of + * tampering, the watermark was degraded, it comes from a legacy generation model, or it + * was created before provenance signals were available. Content could also still be + * AI-generated by another company's model, which the tool currently does not detect. + */ + class Outcome @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val DETECTED = of("detected") + + @JvmField val NOT_DETECTED = of("not_detected") + + @JvmStatic fun of(value: String) = Outcome(JsonField.of(value)) + } + + /** An enum containing [Outcome]'s known values. */ + enum class Known { + DETECTED, + NOT_DETECTED, + } + + /** + * An enum containing [Outcome]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Outcome] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + DETECTED, + NOT_DETECTED, + /** + * An enum member indicating that [Outcome] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + DETECTED -> Value.DETECTED + NOT_DETECTED -> Value.NOT_DETECTED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + DETECTED -> Known.DETECTED + NOT_DETECTED -> Known.NOT_DETECTED + else -> throw OpenAIInvalidDataException("Unknown Outcome: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + OpenAIInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): Outcome = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Outcome && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** The validation status of the C2PA manifest in the uploaded image. */ + class ValidationState + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUSTED = of("trusted") + + @JvmField val VALID = of("valid") + + @JvmField val INVALID = of("invalid") + + @JvmField val NOT_PRESENT = of("not_present") + + @JvmStatic fun of(value: String) = ValidationState(JsonField.of(value)) + } + + /** An enum containing [ValidationState]'s known values. */ + enum class Known { + TRUSTED, + VALID, + INVALID, + NOT_PRESENT, + } + + /** + * An enum containing [ValidationState]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [ValidationState] can contain an unknown value in a couple of + * cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUSTED, + VALID, + INVALID, + NOT_PRESENT, + /** + * An enum member indicating that [ValidationState] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUSTED -> Value.TRUSTED + VALID -> Value.VALID + INVALID -> Value.INVALID + NOT_PRESENT -> Value.NOT_PRESENT + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + TRUSTED -> Known.TRUSTED + VALID -> Known.VALID + INVALID -> Known.INVALID + NOT_PRESENT -> Known.NOT_PRESENT + else -> throw OpenAIInvalidDataException("Unknown ValidationState: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + OpenAIInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): ValidationState = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ValidationState && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is C2pa && + generatedAt == other.generatedAt && + issuer == other.issuer && + model == other.model && + outcome == other.outcome && + type == other.type && + validationState == other.validationState && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + generatedAt, + issuer, + model, + outcome, + type, + validationState, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "C2pa{generatedAt=$generatedAt, issuer=$issuer, model=$model, outcome=$outcome, type=$type, validationState=$validationState, additionalProperties=$additionalProperties}" + } + + class SynthID + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val generatedAt: JsonField, + private val model: JsonField, + private val outcome: JsonField, + private val type: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("generated_at") + @ExcludeMissing + generatedAt: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("outcome") + @ExcludeMissing + outcome: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + ) : this(generatedAt, model, outcome, type, mutableMapOf()) + + /** + * The UTC RFC 3339 timestamp recorded by the provenance signal for when the asset was + * generated, when available. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun generatedAt(): Optional = generatedAt.getOptional("generated_at") + + /** + * The OpenAI model recorded by the provenance signal, when available. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Whether a supported OpenAI SynthID watermark was detected. If `not_detected`, it + * means the tool did not find supported signals in the uploaded file. The content could + * still have been generated by OpenAI if the metadata was stripped or has evidence of + * tampering, the watermark was degraded, it comes from a legacy generation model, or it + * was created before provenance signals were available. Content could also still be + * AI-generated by another company's model, which the tool currently does not detect. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun outcome(): Outcome = outcome.getRequired("outcome") + + /** + * The provenance signal type. Always `synthid`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("synthid") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * Returns the raw JSON value of [generatedAt]. + * + * Unlike [generatedAt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("generated_at") + @ExcludeMissing + fun _generatedAt(): JsonField = generatedAt + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [outcome]. + * + * Unlike [outcome], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("outcome") @ExcludeMissing fun _outcome(): JsonField = outcome + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SynthID]. + * + * The following fields are required: + * ```java + * .generatedAt() + * .model() + * .outcome() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SynthID]. */ + class Builder internal constructor() { + + private var generatedAt: JsonField? = null + private var model: JsonField? = null + private var outcome: JsonField? = null + private var type: JsonValue = JsonValue.from("synthid") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(synthID: SynthID) = apply { + generatedAt = synthID.generatedAt + model = synthID.model + outcome = synthID.outcome + type = synthID.type + additionalProperties = synthID.additionalProperties.toMutableMap() + } + + /** + * The UTC RFC 3339 timestamp recorded by the provenance signal for when the asset + * was generated, when available. + */ + fun generatedAt(generatedAt: String?) = + generatedAt(JsonField.ofNullable(generatedAt)) + + /** Alias for calling [Builder.generatedAt] with `generatedAt.orElse(null)`. */ + fun generatedAt(generatedAt: Optional) = + generatedAt(generatedAt.getOrNull()) + + /** + * Sets [Builder.generatedAt] to an arbitrary JSON value. + * + * You should usually call [Builder.generatedAt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun generatedAt(generatedAt: JsonField) = apply { + this.generatedAt = generatedAt + } + + /** The OpenAI model recorded by the provenance signal, when available. */ + fun model(model: String?) = model(JsonField.ofNullable(model)) + + /** Alias for calling [Builder.model] with `model.orElse(null)`. */ + fun model(model: Optional) = model(model.getOrNull()) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** + * Whether a supported OpenAI SynthID watermark was detected. If `not_detected`, it + * means the tool did not find supported signals in the uploaded file. The content + * could still have been generated by OpenAI if the metadata was stripped or has + * evidence of tampering, the watermark was degraded, it comes from a legacy + * generation model, or it was created before provenance signals were available. + * Content could also still be AI-generated by another company's model, which the + * tool currently does not detect. + */ + fun outcome(outcome: Outcome) = outcome(JsonField.of(outcome)) + + /** + * Sets [Builder.outcome] to an arbitrary JSON value. + * + * You should usually call [Builder.outcome] with a well-typed [Outcome] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun outcome(outcome: JsonField) = apply { this.outcome = outcome } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("synthid") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SynthID]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .generatedAt() + * .model() + * .outcome() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SynthID = + SynthID( + checkRequired("generatedAt", generatedAt), + checkRequired("model", model), + checkRequired("outcome", outcome), + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): SynthID = apply { + if (validated) { + return@apply + } + + generatedAt() + model() + outcome().validate() + _type().let { + if (it != JsonValue.from("synthid")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (generatedAt.asKnown().isPresent) 1 else 0) + + (if (model.asKnown().isPresent) 1 else 0) + + (outcome.asKnown().getOrNull()?.validity() ?: 0) + + type.let { if (it == JsonValue.from("synthid")) 1 else 0 } + + /** + * Whether a supported OpenAI SynthID watermark was detected. If `not_detected`, it + * means the tool did not find supported signals in the uploaded file. The content could + * still have been generated by OpenAI if the metadata was stripped or has evidence of + * tampering, the watermark was degraded, it comes from a legacy generation model, or it + * was created before provenance signals were available. Content could also still be + * AI-generated by another company's model, which the tool currently does not detect. + */ + class Outcome @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val DETECTED = of("detected") + + @JvmField val NOT_DETECTED = of("not_detected") + + @JvmStatic fun of(value: String) = Outcome(JsonField.of(value)) + } + + /** An enum containing [Outcome]'s known values. */ + enum class Known { + DETECTED, + NOT_DETECTED, + } + + /** + * An enum containing [Outcome]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Outcome] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + DETECTED, + NOT_DETECTED, + /** + * An enum member indicating that [Outcome] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + DETECTED -> Value.DETECTED + NOT_DETECTED -> Value.NOT_DETECTED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + DETECTED -> Known.DETECTED + NOT_DETECTED -> Known.NOT_DETECTED + else -> throw OpenAIInvalidDataException("Unknown Outcome: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + OpenAIInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): Outcome = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Outcome && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SynthID && + generatedAt == other.generatedAt && + model == other.model && + outcome == other.outcome && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(generatedAt, model, outcome, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SynthID{generatedAt=$generatedAt, model=$model, outcome=$outcome, type=$type, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ContentProvenanceCheck && + createdAt == other.createdAt && + object_ == other.object_ && + results == other.results && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(createdAt, object_, results, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ContentProvenanceCheck{createdAt=$createdAt, object_=$object_, results=$results, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckCreateParams.kt new file mode 100644 index 000000000..8367384ea --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckCreateParams.kt @@ -0,0 +1,446 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.contentprovenancechecks + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonProperty +import com.openai.core.ExcludeMissing +import com.openai.core.JsonValue +import com.openai.core.MultipartField +import com.openai.core.Params +import com.openai.core.checkRequired +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.toImmutable +import com.openai.errors.OpenAIInvalidDataException +import java.io.InputStream +import java.nio.file.Path +import java.util.Collections +import java.util.Objects +import kotlin.io.path.inputStream +import kotlin.io.path.name + +/** + * Check whether an image or audio file contains known OpenAI provenance signals. + * [Learn more about content provenance](/api/docs/guides/content-provenance). + * + * If `not_detected`, it means the tool did not find supported signals in the uploaded file. The + * content could still have been generated by OpenAI if the metadata was stripped or has evidence of + * tampering, the watermark was degraded, it comes from a legacy generation model, or it was created + * before provenance signals were available. Content could also still be AI-generated by another + * company's model, which the tool currently does not detect. + */ +class ContentProvenanceCheckCreateParams +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * The image or audio file to check for supported OpenAI provenance signals. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun file(): InputStream = body.file() + + /** + * Returns the raw multipart value of [file]. + * + * Unlike [file], this method doesn't throw if the multipart field has an unexpected type. + */ + fun _file(): MultipartField = body._file() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [ContentProvenanceCheckCreateParams]. + * + * The following fields are required: + * ```java + * .file() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ContentProvenanceCheckCreateParams]. */ + class Builder internal constructor() { + + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(contentProvenanceCheckCreateParams: ContentProvenanceCheckCreateParams) = + apply { + body = contentProvenanceCheckCreateParams.body.toBuilder() + additionalHeaders = contentProvenanceCheckCreateParams.additionalHeaders.toBuilder() + additionalQueryParams = + contentProvenanceCheckCreateParams.additionalQueryParams.toBuilder() + } + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [file] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** The image or audio file to check for supported OpenAI provenance signals. */ + fun file(file: InputStream) = apply { body.file(file) } + + /** + * Sets [Builder.file] to an arbitrary multipart value. + * + * You should usually call [Builder.file] with a well-typed [InputStream] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun file(file: MultipartField) = apply { body.file(file) } + + /** The image or audio file to check for supported OpenAI provenance signals. */ + fun file(file: ByteArray) = apply { body.file(file) } + + /** The image or audio file to check for supported OpenAI provenance signals. */ + fun file(path: Path) = apply { body.file(path) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [ContentProvenanceCheckCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .file() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ContentProvenanceCheckCreateParams = + ContentProvenanceCheckCreateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Map> = + (mapOf("file" to _file()) + + _additionalBodyProperties().mapValues { (_, value) -> MultipartField.of(value) }) + .toImmutable() + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + private constructor( + private val file: MultipartField, + private val additionalProperties: MutableMap, + ) { + + /** + * The image or audio file to check for supported OpenAI provenance signals. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun file(): InputStream = file.value.getRequired("file") + + /** + * Returns the raw multipart value of [file]. + * + * Unlike [file], this method doesn't throw if the multipart field has an unexpected type. + */ + @JsonProperty("file") @ExcludeMissing fun _file(): MultipartField = file + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .file() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var file: MultipartField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + file = body.file + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The image or audio file to check for supported OpenAI provenance signals. */ + fun file(file: InputStream) = file(MultipartField.of(file)) + + /** + * Sets [Builder.file] to an arbitrary multipart value. + * + * You should usually call [Builder.file] with a well-typed [InputStream] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun file(file: MultipartField) = apply { this.file = file } + + /** The image or audio file to check for supported OpenAI provenance signals. */ + fun file(file: ByteArray) = file(file.inputStream()) + + /** The image or audio file to check for supported OpenAI provenance signals. */ + fun file(path: Path) = + file( + MultipartField.builder() + .value(path.inputStream()) + .filename(path.name) + .build() + ) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .file() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("file", file), additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws OpenAIInvalidDataException if any value type in this object doesn't match its + * expected type. + */ + fun validate(): Body = apply { + if (validated) { + return@apply + } + + file() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + file == other.file && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(file, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Body{file=$file, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ContentProvenanceCheckCreateParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "ContentProvenanceCheckCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCompactParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCompactParams.kt index 4d1ca3761..08171a5ae 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCompactParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCompactParams.kt @@ -122,7 +122,19 @@ private constructor( fun promptCacheRetention(): Optional = body.promptCacheRetention() /** - * The service tier to use for this request. + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. Unless + * otherwise configured, the Project will use 'default'. - If set to 'default', then the request + * will be processed with the standard pricing and performance for the selected model. - If set + * to '[flex](https://platform.openai.com/docs/guides/flex-processing)', then the request will + * be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the `service_tier=fast` + * or `service_tier=priority` parameter for Responses or Chat Completions. The response will + * show `service_tier=priority` regardless of if you specify `service_tier=fast` or `priority` + * in your request. - When not set, the default behavior is 'auto'. When the `service_tier` + * parameter is set, the response body will include the `service_tier` value based on the + * processing mode actually used to serve the request. This response value may be different from + * the value set in the parameter. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -414,7 +426,21 @@ private constructor( body.promptCacheRetention(promptCacheRetention) } - /** The service tier to use for this request. */ + /** + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. + * Unless otherwise configured, the Project will use 'default'. - If set to 'default', then + * the request will be processed with the standard pricing and performance for the selected + * model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)', + * then the request will be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the + * `service_tier=fast` or `service_tier=priority` parameter for Responses or Chat + * Completions. The response will show `service_tier=priority` regardless of if you specify + * `service_tier=fast` or `priority` in your request. - When not set, the default behavior + * is 'auto'. When the `service_tier` parameter is set, the response body will include the + * `service_tier` value based on the processing mode actually used to serve the request. + * This response value may be different from the value set in the parameter. + */ fun serviceTier(serviceTier: ServiceTier?) = apply { body.serviceTier(serviceTier) } /** Alias for calling [Builder.serviceTier] with `serviceTier.orElse(null)`. */ @@ -700,7 +726,19 @@ private constructor( promptCacheRetention.getOptional("prompt_cache_retention") /** - * The service tier to use for this request. + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. + * Unless otherwise configured, the Project will use 'default'. - If set to 'default', then + * the request will be processed with the standard pricing and performance for the selected + * model. - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)', + * then the request will be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the + * `service_tier=fast` or `service_tier=priority` parameter for Responses or Chat + * Completions. The response will show `service_tier=priority` regardless of if you specify + * `service_tier=fast` or `priority` in your request. - When not set, the default behavior + * is 'auto'. When the `service_tier` parameter is set, the response body will include the + * `service_tier` value based on the processing mode actually used to serve the request. + * This response value may be different from the value set in the parameter. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -1011,7 +1049,23 @@ private constructor( this.promptCacheRetention = promptCacheRetention } - /** The service tier to use for this request. */ + /** + * Specifies the processing type used for serving the request. - If set to 'auto', then + * the request will be processed with the service tier configured in the Project + * settings. Unless otherwise configured, the Project will use 'default'. - If set to + * 'default', then the request will be processed with the standard pricing and + * performance for the selected model. - If set to + * '[flex](https://platform.openai.com/docs/guides/flex-processing)', then the request + * will be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the + * `service_tier=fast` or `service_tier=priority` parameter for Responses or Chat + * Completions. The response will show `service_tier=priority` regardless of if you + * specify `service_tier=fast` or `priority` in your request. - When not set, the + * default behavior is 'auto'. When the `service_tier` parameter is set, the response + * body will include the `service_tier` value based on the processing mode actually used + * to serve the request. This response value may be different from the value set in the + * parameter. + */ fun serviceTier(serviceTier: ServiceTier?) = serviceTier(JsonField.ofNullable(serviceTier)) @@ -2731,7 +2785,21 @@ private constructor( override fun toString() = value.toString() } - /** The service tier to use for this request. */ + /** + * Specifies the processing type used for serving the request. - If set to 'auto', then the + * request will be processed with the service tier configured in the Project settings. Unless + * otherwise configured, the Project will use 'default'. - If set to 'default', then the request + * will be processed with the standard pricing and performance for the selected model. - If set + * to '[flex](https://platform.openai.com/docs/guides/flex-processing)', then the request will + * be processed with the Flex Processing service tier. - To opt-in to + * [Fast mode](/api/docs/guides/fast-mode) at the request level, include the `service_tier=fast` + * or `service_tier=priority` parameter for Responses or Chat Completions. The response will + * show `service_tier=priority` regardless of if you specify `service_tier=fast` or `priority` + * in your request. - When not set, the default behavior is 'auto'. When the `service_tier` + * parameter is set, the response body will include the `service_tier` value based on the + * processing mode actually used to serve the request. This response value may be different from + * the value set in the parameter. + */ class ServiceTier @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -2751,6 +2819,8 @@ private constructor( @JvmField val DEFAULT = of("default") + @JvmField val FAST = of("fast") + @JvmField val FLEX = of("flex") @JvmField val PRIORITY = of("priority") @@ -2762,6 +2832,7 @@ private constructor( enum class Known { AUTO, DEFAULT, + FAST, FLEX, PRIORITY, } @@ -2778,6 +2849,7 @@ private constructor( enum class Value { AUTO, DEFAULT, + FAST, FLEX, PRIORITY, /** @@ -2797,6 +2869,7 @@ private constructor( when (this) { AUTO -> Value.AUTO DEFAULT -> Value.DEFAULT + FAST -> Value.FAST FLEX -> Value.FLEX PRIORITY -> Value.PRIORITY else -> Value._UNKNOWN @@ -2815,6 +2888,7 @@ private constructor( when (this) { AUTO -> Known.AUTO DEFAULT -> Known.DEFAULT + FAST -> Known.FAST FLEX -> Known.FLEX PRIORITY -> Known.PRIORITY else -> throw OpenAIInvalidDataException("Unknown ServiceTier: $value") diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsync.kt new file mode 100644 index 000000000..4431d7e66 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsync.kt @@ -0,0 +1,77 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async + +import com.openai.core.ClientOptions +import com.openai.core.RequestOptions +import com.openai.core.http.HttpResponseFor +import com.openai.models.contentprovenancechecks.ContentProvenanceCheck +import com.openai.models.contentprovenancechecks.ContentProvenanceCheckCreateParams +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer + +interface ContentProvenanceCheckServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): ContentProvenanceCheckServiceAsync + + /** + * Check whether an image or audio file contains known OpenAI provenance signals. + * [Learn more about content provenance](/api/docs/guides/content-provenance). + * + * If `not_detected`, it means the tool did not find supported signals in the uploaded file. The + * content could still have been generated by OpenAI if the metadata was stripped or has + * evidence of tampering, the watermark was degraded, it comes from a legacy generation model, + * or it was created before provenance signals were available. Content could also still be + * AI-generated by another company's model, which the tool currently does not detect. + */ + fun create( + params: ContentProvenanceCheckCreateParams + ): CompletableFuture = create(params, RequestOptions.none()) + + /** @see create */ + fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** + * A view of [ContentProvenanceCheckServiceAsync] that provides access to raw HTTP responses for + * each method. + */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions( + modifier: Consumer + ): ContentProvenanceCheckServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /content_provenance_checks`, but is otherwise the + * same as [ContentProvenanceCheckServiceAsync.create]. + */ + fun create( + params: ContentProvenanceCheckCreateParams + ): CompletableFuture> = + create(params, RequestOptions.none()) + + /** @see create */ + fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsyncImpl.kt new file mode 100644 index 000000000..5985d0eb7 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsyncImpl.kt @@ -0,0 +1,97 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async + +import com.openai.core.ClientOptions +import com.openai.core.RequestOptions +import com.openai.core.SecurityOptions +import com.openai.core.handlers.errorBodyHandler +import com.openai.core.handlers.errorHandler +import com.openai.core.handlers.jsonHandler +import com.openai.core.http.HttpMethod +import com.openai.core.http.HttpRequest +import com.openai.core.http.HttpResponse +import com.openai.core.http.HttpResponse.Handler +import com.openai.core.http.HttpResponseFor +import com.openai.core.http.multipartFormData +import com.openai.core.http.parseable +import com.openai.core.prepareAsync +import com.openai.models.contentprovenancechecks.ContentProvenanceCheck +import com.openai.models.contentprovenancechecks.ContentProvenanceCheckCreateParams +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer + +class ContentProvenanceCheckServiceAsyncImpl +internal constructor(private val clientOptions: ClientOptions) : + ContentProvenanceCheckServiceAsync { + + private val withRawResponse: ContentProvenanceCheckServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ContentProvenanceCheckServiceAsync.WithRawResponse = + withRawResponse + + override fun withOptions( + modifier: Consumer + ): ContentProvenanceCheckServiceAsync = + ContentProvenanceCheckServiceAsyncImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + override fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /content_provenance_checks + withRawResponse().create(params, requestOptions).thenApply { it.parse() } + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ContentProvenanceCheckServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: Consumer + ): ContentProvenanceCheckServiceAsync.WithRawResponse = + ContentProvenanceCheckServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("content_provenance_checks") + .body(multipartFormData(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync( + clientOptions, + params, + SecurityOptions.builder().bearerAuth(true).build(), + ) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContentProvenanceCheckService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContentProvenanceCheckService.kt new file mode 100644 index 000000000..7781bd53b --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContentProvenanceCheckService.kt @@ -0,0 +1,77 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking + +import com.google.errorprone.annotations.MustBeClosed +import com.openai.core.ClientOptions +import com.openai.core.RequestOptions +import com.openai.core.http.HttpResponseFor +import com.openai.models.contentprovenancechecks.ContentProvenanceCheck +import com.openai.models.contentprovenancechecks.ContentProvenanceCheckCreateParams +import java.util.function.Consumer + +interface ContentProvenanceCheckService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): ContentProvenanceCheckService + + /** + * Check whether an image or audio file contains known OpenAI provenance signals. + * [Learn more about content provenance](/api/docs/guides/content-provenance). + * + * If `not_detected`, it means the tool did not find supported signals in the uploaded file. The + * content could still have been generated by OpenAI if the metadata was stripped or has + * evidence of tampering, the watermark was degraded, it comes from a legacy generation model, + * or it was created before provenance signals were available. Content could also still be + * AI-generated by another company's model, which the tool currently does not detect. + */ + fun create(params: ContentProvenanceCheckCreateParams): ContentProvenanceCheck = + create(params, RequestOptions.none()) + + /** @see create */ + fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): ContentProvenanceCheck + + /** + * A view of [ContentProvenanceCheckService] that provides access to raw HTTP responses for each + * method. + */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions( + modifier: Consumer + ): ContentProvenanceCheckService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /content_provenance_checks`, but is otherwise the + * same as [ContentProvenanceCheckService.create]. + */ + @MustBeClosed + fun create( + params: ContentProvenanceCheckCreateParams + ): HttpResponseFor = create(params, RequestOptions.none()) + + /** @see create */ + @MustBeClosed + fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContentProvenanceCheckServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContentProvenanceCheckServiceImpl.kt new file mode 100644 index 000000000..93363bc1d --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContentProvenanceCheckServiceImpl.kt @@ -0,0 +1,89 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking + +import com.openai.core.ClientOptions +import com.openai.core.RequestOptions +import com.openai.core.SecurityOptions +import com.openai.core.handlers.errorBodyHandler +import com.openai.core.handlers.errorHandler +import com.openai.core.handlers.jsonHandler +import com.openai.core.http.HttpMethod +import com.openai.core.http.HttpRequest +import com.openai.core.http.HttpResponse +import com.openai.core.http.HttpResponse.Handler +import com.openai.core.http.HttpResponseFor +import com.openai.core.http.multipartFormData +import com.openai.core.http.parseable +import com.openai.core.prepare +import com.openai.models.contentprovenancechecks.ContentProvenanceCheck +import com.openai.models.contentprovenancechecks.ContentProvenanceCheckCreateParams +import java.util.function.Consumer + +class ContentProvenanceCheckServiceImpl +internal constructor(private val clientOptions: ClientOptions) : ContentProvenanceCheckService { + + private val withRawResponse: ContentProvenanceCheckService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): ContentProvenanceCheckService.WithRawResponse = withRawResponse + + override fun withOptions( + modifier: Consumer + ): ContentProvenanceCheckService = + ContentProvenanceCheckServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + + override fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions, + ): ContentProvenanceCheck = + // post /content_provenance_checks + withRawResponse().create(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + ContentProvenanceCheckService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: Consumer + ): ContentProvenanceCheckService.WithRawResponse = + ContentProvenanceCheckServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + private val createHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun create( + params: ContentProvenanceCheckCreateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("content_provenance_checks") + .body(multipartFormData(clientOptions.jsonMapper, params._body())) + .build() + .prepare( + clientOptions, + params, + SecurityOptions.builder().bearerAuth(true).build(), + ) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { createHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckCreateParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckCreateParamsTest.kt new file mode 100644 index 000000000..e4e98420c --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckCreateParamsTest.kt @@ -0,0 +1,41 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.contentprovenancechecks + +import com.openai.core.MultipartField +import java.io.InputStream +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ContentProvenanceCheckCreateParamsTest { + + @Test + fun create() { + ContentProvenanceCheckCreateParams.builder().file("Example data".byteInputStream()).build() + } + + @Test + fun body() { + val params = + ContentProvenanceCheckCreateParams.builder() + .file("Example data".byteInputStream()) + .build() + + val body = params._body() + + assertThat(body.filterValues { !it.value.isNull() }) + .usingRecursiveComparison() + // TODO(AssertJ): Replace this and the `mapValues` below with: + // https://github.com/assertj/assertj/issues/3165 + .withEqualsForType( + { a, b -> a.readBytes() contentEquals b.readBytes() }, + InputStream::class.java, + ) + .isEqualTo( + mapOf("file" to MultipartField.of("Example data".byteInputStream())).mapValues { + (_, field) -> + field.map { (it as? ByteArray)?.inputStream() ?: it } + } + ) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckTest.kt new file mode 100644 index 000000000..97ecce7c3 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/contentprovenancechecks/ContentProvenanceCheckTest.kt @@ -0,0 +1,72 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.contentprovenancechecks + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ContentProvenanceCheckTest { + + @Test + fun create() { + val contentProvenanceCheck = + ContentProvenanceCheck.builder() + .createdAt(0L) + .object_(ContentProvenanceCheck.Object.CONTENT_PROVENANCE_CHECK) + .addResult( + ContentProvenanceCheck.Result.C2pa.builder() + .generatedAt("generated_at") + .issuer("issuer") + .model("model") + .outcome(ContentProvenanceCheck.Result.C2pa.Outcome.DETECTED) + .validationState(ContentProvenanceCheck.Result.C2pa.ValidationState.TRUSTED) + .build() + ) + .build() + + assertThat(contentProvenanceCheck.createdAt()).isEqualTo(0L) + assertThat(contentProvenanceCheck.object_()) + .isEqualTo(ContentProvenanceCheck.Object.CONTENT_PROVENANCE_CHECK) + assertThat(contentProvenanceCheck.results()) + .containsExactly( + ContentProvenanceCheck.Result.ofC2pa( + ContentProvenanceCheck.Result.C2pa.builder() + .generatedAt("generated_at") + .issuer("issuer") + .model("model") + .outcome(ContentProvenanceCheck.Result.C2pa.Outcome.DETECTED) + .validationState(ContentProvenanceCheck.Result.C2pa.ValidationState.TRUSTED) + .build() + ) + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val contentProvenanceCheck = + ContentProvenanceCheck.builder() + .createdAt(0L) + .object_(ContentProvenanceCheck.Object.CONTENT_PROVENANCE_CHECK) + .addResult( + ContentProvenanceCheck.Result.C2pa.builder() + .generatedAt("generated_at") + .issuer("issuer") + .model("model") + .outcome(ContentProvenanceCheck.Result.C2pa.Outcome.DETECTED) + .validationState(ContentProvenanceCheck.Result.C2pa.ValidationState.TRUSTED) + .build() + ) + .build() + + val roundtrippedContentProvenanceCheck = + jsonMapper.readValue( + jsonMapper.writeValueAsString(contentProvenanceCheck), + jacksonTypeRef(), + ) + + assertThat(roundtrippedContentProvenanceCheck).isEqualTo(contentProvenanceCheck) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsyncTest.kt new file mode 100644 index 000000000..40077ea6d --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/ContentProvenanceCheckServiceAsyncTest.kt @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async + +import com.openai.TestServerExtension +import com.openai.client.okhttp.OpenAIOkHttpClientAsync +import com.openai.models.contentprovenancechecks.ContentProvenanceCheckCreateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ContentProvenanceCheckServiceAsyncTest { + + @Test + fun create() { + val client = + OpenAIOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .adminApiKey("My Admin API Key") + .build() + val contentProvenanceCheckServiceAsync = client.contentProvenanceChecks() + + val contentProvenanceCheckFuture = + contentProvenanceCheckServiceAsync.create( + ContentProvenanceCheckCreateParams.builder() + .file("Example data".byteInputStream()) + .build() + ) + + val contentProvenanceCheck = contentProvenanceCheckFuture.get() + contentProvenanceCheck.validate() + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/ContentProvenanceCheckServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/ContentProvenanceCheckServiceTest.kt new file mode 100644 index 000000000..5f5ebfa7a --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/ContentProvenanceCheckServiceTest.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking + +import com.openai.TestServerExtension +import com.openai.client.okhttp.OpenAIOkHttpClient +import com.openai.models.contentprovenancechecks.ContentProvenanceCheckCreateParams +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class ContentProvenanceCheckServiceTest { + + @Test + fun create() { + val client = + OpenAIOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .adminApiKey("My Admin API Key") + .build() + val contentProvenanceCheckService = client.contentProvenanceChecks() + + val contentProvenanceCheck = + contentProvenanceCheckService.create( + ContentProvenanceCheckCreateParams.builder() + .file("Example data".byteInputStream()) + .build() + ) + + contentProvenanceCheck.validate() + } +} diff --git a/openai-java-proguard-test/src/test/kotlin/com/openai/proguard/ProGuardCompatibilityTest.kt b/openai-java-proguard-test/src/test/kotlin/com/openai/proguard/ProGuardCompatibilityTest.kt index 15c8026c0..a704fa7df 100644 --- a/openai-java-proguard-test/src/test/kotlin/com/openai/proguard/ProGuardCompatibilityTest.kt +++ b/openai-java-proguard-test/src/test/kotlin/com/openai/proguard/ProGuardCompatibilityTest.kt @@ -65,6 +65,7 @@ internal class ProGuardCompatibilityTest { assertThat(client.embeddings()).isNotNull() assertThat(client.files()).isNotNull() assertThat(client.images()).isNotNull() + assertThat(client.contentProvenanceChecks()).isNotNull() assertThat(client.audio()).isNotNull() assertThat(client.moderations()).isNotNull() assertThat(client.models()).isNotNull()