From 62468192448654b722584d4e52c54b9e6046d25d Mon Sep 17 00:00:00 2001 From: abhay Date: Thu, 25 Jan 2024 11:07:09 +0700 Subject: [PATCH] Add Support for Azure Content Filter Response --- .../com.aallam.openai.api/chat/ChatChoice.kt | 16 +++- .../com.aallam.openai.api/chat/ChatChunk.kt | 16 +++- .../chat/ChatCompletion.kt | 9 ++- .../chat/ChatCompletionChunk.kt | 9 ++- .../chat/ChatFinishDetails.kt | 33 ++++++++ .../core/ResponseError.kt | 41 ++++++++++ .../core/ResponseInnerError.kt | 24 ++++++ .../ContentFilterBlocklistIdResult.kt | 24 ++++++ .../ContentFilterCitedDetectionResult.kt | 35 +++++++++ .../filtering/ContentFilterDetectionResult.kt | 23 ++++++ .../filtering/ContentFilterResult.kt | 23 ++++++ .../ContentFilterResultDetailsForPrompt.kt | 70 +++++++++++++++++ .../ContentFilterResultsForChoice.kt | 76 +++++++++++++++++++ .../ContentFilterResultsForPrompt.kt | 23 ++++++ .../filtering/ContentFilterSeverity.kt | 44 +++++++++++ 15 files changed, 462 insertions(+), 4 deletions(-) create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/chat/ChatFinishDetails.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseError.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseInnerError.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterBlocklistIdResult.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterCitedDetectionResult.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterDetectionResult.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResult.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultDetailsForPrompt.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForChoice.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForPrompt.kt create mode 100644 openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterSeverity.kt diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChoice.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChoice.kt index 8c78ed23..9e4c0daa 100644 --- a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChoice.kt +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChoice.kt @@ -1,7 +1,8 @@ package com.aallam.openai.api.chat; -import com.aallam.openai.api.BetaOpenAI import com.aallam.openai.api.core.FinishReason +import com.aallam.openai.azure.api.chat.ChatFinishDetails +import com.aallam.openai.azure.api.filtering.ContentFilterResultsForChoice import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -25,4 +26,17 @@ public data class ChatChoice( * The reason why OpenAI stopped generating. */ @SerialName("finish_reason") public val finishReason: FinishReason? = null, + + /** + * Information about the content filtering category (hate, sexual, violence, + * self_harm), if it has been detected, as well as the severity level (very_low, low, medium, high-scale that + * determines the intensity and risk level of harmful content) and if it has been filtered or not. + */ + @SerialName("content_filter_results") public val contentFilterResults: ContentFilterResultsForChoice? = null, + + /** + * The reason the model stopped generating tokens, together with any applicable details. + * This structured representation replaces 'finish_reason' for some models. + */ + @SerialName("finish_details") public val finishDetails: ChatFinishDetails? = null, ) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChunk.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChunk.kt index 6066987c..013cd0e6 100644 --- a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChunk.kt +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatChunk.kt @@ -1,7 +1,8 @@ package com.aallam.openai.api.chat; -import com.aallam.openai.api.BetaOpenAI import com.aallam.openai.api.core.FinishReason +import com.aallam.openai.azure.api.chat.ChatFinishDetails +import com.aallam.openai.azure.api.filtering.ContentFilterResultsForChoice import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -25,4 +26,17 @@ public data class ChatChunk( * The reason why OpenAI stopped generating. */ @SerialName("finish_reason") public val finishReason: FinishReason?, + + /** + * Information about the content filtering category (hate, sexual, violence, + * self_harm), if it has been detected, as well as the severity level (very_low, low, medium, high-scale that + * determines the intensity and risk level of harmful content) and if it has been filtered or not. + */ + @SerialName("content_filter_results") public val contentFilterResults: ContentFilterResultsForChoice? = null, + + /** + * The reason the model stopped generating tokens, together with any applicable details. + * This structured representation replaces 'finish_reason' for some models. + */ + @SerialName("finish_details") public val finishDetails: ChatFinishDetails? = null, ) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletion.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletion.kt index 9f2a87f9..49683c4d 100644 --- a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletion.kt +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletion.kt @@ -1,8 +1,8 @@ package com.aallam.openai.api.chat -import com.aallam.openai.api.BetaOpenAI import com.aallam.openai.api.core.Usage import com.aallam.openai.api.model.ModelId +import com.aallam.openai.azure.api.filtering.ContentFilterResultsForPrompt import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -44,4 +44,11 @@ public data class ChatCompletion( * might impact determinism. */ @SerialName("system_fingerprint") public val systemFingerprint: String? = null, + + /** + * Content filtering results for zero or more prompts in the request. In a streaming request, + * results for different prompts may arrive at different times or in different orders. + */ + @SerialName("prompt_filter_results") + val promptFilterResults: List? = null ) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletionChunk.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletionChunk.kt index 2d0d6aa7..ac13654e 100644 --- a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletionChunk.kt +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/chat/ChatCompletionChunk.kt @@ -1,8 +1,8 @@ package com.aallam.openai.api.chat -import com.aallam.openai.api.BetaOpenAI import com.aallam.openai.api.core.Usage import com.aallam.openai.api.model.ModelId +import com.aallam.openai.azure.api.filtering.ContentFilterResultsForPrompt import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -42,4 +42,11 @@ public data class ChatCompletionChunk( */ @SerialName("usage") public val usage: Usage? = null, + + /** + * Content filtering results for zero or more prompts in the request. In a streaming request, + * results for different prompts may arrive at different times or in different orders. + */ + @SerialName("prompt_filter_results") + val promptFilterResults: List? = null ) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/chat/ChatFinishDetails.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/chat/ChatFinishDetails.kt new file mode 100644 index 00000000..aaa4f54d --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/chat/ChatFinishDetails.kt @@ -0,0 +1,33 @@ +package com.aallam.openai.azure.api.chat + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * An abstract representation of structured information about why a chat completions response terminated. + */ +@Serializable +public sealed class ChatFinishDetails { + + /** + * Represents the "stop" type of ChatFinishDetails. + */ + @Serializable + @SerialName("stop") + public data class StopFinishDetails( + + /** + * The token sequence that the model terminated with. + */ + @SerialName("stop") + val stop: String + ) : ChatFinishDetails() + + /** + * A structured representation of a stop reason that signifies a token limit was reached before the model could + * naturally complete. + */ + @Serializable + @SerialName("max_tokens") + public class MaxTokensFinishDetails : ChatFinishDetails() +} diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseError.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseError.kt new file mode 100644 index 00000000..d4cf459f --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseError.kt @@ -0,0 +1,41 @@ +package com.aallam.openai.azure.api.core + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +/** + * This class represents the error details of an HTTP response. + */ +@Serializable +public data class ResponseError( + + /** + * The error code of this error. + */ + @SerialName("code") + val code: String, + + /** + * The error message of this error. + */ + @SerialName("message") + val message: String, + + /** + * The target of this error. + */ + @SerialName("target") + val target: String? = null, + + /** + * The inner error information for this error. + */ + @SerialName("innererror") + val innerError: ResponseInnerError? = null, + + /** + * A list of details about specific errors that led to this reported error. + */ + @SerialName("details") + val errorDetails: List? = null +) \ No newline at end of file diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseInnerError.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseInnerError.kt new file mode 100644 index 00000000..b1143045 --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/core/ResponseInnerError.kt @@ -0,0 +1,24 @@ +package com.aallam.openai.azure.api.core + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + + +/** + * The inner error of a ResponseError. + */ +@Serializable +public data class ResponseInnerError( + + /** + * The error code of the inner error. + */ + @SerialName("code") + val code: String? = null, + + /** + * The nested inner error for this error. + */ + @SerialName("innererror") + val innerError: ResponseInnerError? = null +) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterBlocklistIdResult.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterBlocklistIdResult.kt new file mode 100644 index 00000000..a119740e --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterBlocklistIdResult.kt @@ -0,0 +1,24 @@ +package com.aallam.openai.azure.api.filtering + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + + +/** + * Represents the outcome of an evaluation against a custom blocklist as performed by content filtering. + */ +@Serializable +public data class ContentFilterBlocklistIdResult( + + /** + * The ID of the custom blocklist evaluated. + */ + @SerialName("id") + val id: String, + + /** + * A value indicating whether the content has been filtered. + */ + @SerialName("filtered") + val filtered: Boolean +) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterCitedDetectionResult.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterCitedDetectionResult.kt new file mode 100644 index 00000000..fecb9352 --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterCitedDetectionResult.kt @@ -0,0 +1,35 @@ +package com.aallam.openai.azure.api.filtering + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Represents the outcome of a detection operation against protected resources as performed by content filtering. + */ +@Serializable +public data class ContentFilterCitedDetectionResult( + + /** + * A value indicating whether or not the content has been filtered. + */ + @SerialName("filtered") + val filtered: Boolean, + + /** + * A value indicating whether detection occurred, irrespective of severity or whether the content was filtered. + */ + @SerialName("detected") + val detected: Boolean, + + /** + * The internet location associated with the detection. + */ + @SerialName("URL") + val url: String, + + /** + * The license description associated with the detection. + */ + @SerialName("license") + val license: String +) \ No newline at end of file diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterDetectionResult.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterDetectionResult.kt new file mode 100644 index 00000000..80ece838 --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterDetectionResult.kt @@ -0,0 +1,23 @@ +package com.aallam.openai.azure.api.filtering + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +/** + * Represents the outcome of a detection operation performed by content filtering. + */ +@Serializable +public data class ContentFilterDetectionResult( + + /** + * A value indicating whether the content has been filtered. + */ + @SerialName("filtered") + val filtered: Boolean, + + /** + * A value indicating whether detection occurred, irrespective of severity or whether the content was filtered. + */ + @SerialName("detected") + val detected: Boolean +) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResult.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResult.kt new file mode 100644 index 00000000..97d99b00 --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResult.kt @@ -0,0 +1,23 @@ +package com.aallam.openai.azure.api.filtering + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Information about filtered content severity level and if it has been filtered or not. + */ +@Serializable +public data class ContentFilterResult( + + /** + * Ratings for the intensity and risk level of filtered content. + */ + @SerialName("severity") + val severity: ContentFilterSeverity, + + /** + * A value indicating whether the content has been filtered. + */ + @SerialName("filtered") + val filtered: Boolean +) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultDetailsForPrompt.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultDetailsForPrompt.kt new file mode 100644 index 00000000..7e59600c --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultDetailsForPrompt.kt @@ -0,0 +1,70 @@ +package com.aallam.openai.azure.api.filtering + +import com.aallam.openai.azure.api.core.ResponseError +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Information about content filtering evaluated against input data to Azure OpenAI. + */ +@Serializable +public data class ContentFilterResultDetailsForPrompt( + + /** + * Describes language related to anatomical organs and genitals, romantic relationships, + * acts portrayed in erotic or affectionate terms, physical sexual acts, including + * those portrayed as an assault or a forced sexual violent act against one’s will, + * prostitution, pornography, and abuse. + */ + @SerialName("sexual") + val sexual: ContentFilterResult? = null, + + /** + * Describes language related to physical actions intended to hurt, injure, damage, or + * kill someone or something; describes weapons, etc. + */ + @SerialName("violence") + val violence: ContentFilterResult? = null, + + /** + * Describes language attacks or uses that include pejorative or discriminatory language + * with reference to a person or identity group on the basis of certain differentiating + * attributes of these groups including but not limited to race, ethnicity, nationality, + * gender identity and expression, sexual orientation, religion, immigration status, ability + * status, personal appearance, and body size. + */ + @SerialName("hate") + val hate: ContentFilterResult? = null, + + /** + * Describes language related to physical actions intended to purposely hurt, injure, + * or damage one’s body, or kill oneself. + */ + @SerialName("self_harm") + val selfHarm: ContentFilterResult? = null, + + /** + * Describes whether profanity was detected. + */ + @SerialName("profanity") + val profanity: ContentFilterDetectionResult? = null, + + /** + * Describes detection results against configured custom blocklists. + */ + @SerialName("custom_blocklists") + val customBlocklists: List? = null, + + /** + * Describes an error returned if the content filtering system is + * down or otherwise unable to complete the operation in time. + */ + @SerialName("error") + val error: ResponseError? = null, + + /** + * Whether a jailbreak attempt was detected in the prompt. + */ + @SerialName("jailbreak") + val jailbreak: ContentFilterDetectionResult? = null +) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForChoice.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForChoice.kt new file mode 100644 index 00000000..81b8655b --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForChoice.kt @@ -0,0 +1,76 @@ +package com.aallam.openai.azure.api.filtering + +import com.aallam.openai.azure.api.core.ResponseError +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Information about content filtering evaluated against generated model output. + */ +@Serializable +public data class ContentFilterResultsForChoice( + + /** + * Describes language related to anatomical organs and genitals, romantic relationships, + * acts portrayed in erotic or affectionate terms, physical sexual acts, including + * those portrayed as an assault or a forced sexual violent act against one’s will, + * prostitution, pornography, and abuse. + */ + @SerialName("sexual") + val sexual: ContentFilterResult? = null, + + /** + * Describes language related to physical actions intended to hurt, injure, damage, or + * kill someone or something; describes weapons, etc. + */ + @SerialName("violence") + val violence: ContentFilterResult? = null, + + /** + * Describes language attacks or uses that include pejorative or discriminatory language + * with reference to a person or identity group on the basis of certain differentiating + * attributes of these groups including but not limited to race, ethnicity, nationality, + * gender identity and expression, sexual orientation, religion, immigration status, ability + * status, personal appearance, and body size. + */ + @SerialName("hate") + val hate: ContentFilterResult? = null, + + /** + * Describes language related to physical actions intended to purposely hurt, injure, + * or damage one’s body, or kill oneself. + */ + @SerialName("self_harm") + val selfHarm: ContentFilterResult? = null, + + /** + * Describes whether profanity was detected. + */ + @SerialName("profanity") + val profanity: ContentFilterDetectionResult? = null, + + /** + * Describes detection results against configured custom blocklists. + */ + @SerialName("custom_blocklists") + val customBlocklists: List? = null, + + /** + * Describes an error returned if the content filtering system is + * down or otherwise unable to complete the operation in time. + */ + @SerialName("error") + val error: ResponseError? = null, + + /** + * Information about detection of protected text material. + */ + @SerialName("protected_material_text") + val protectedMaterialText: ContentFilterDetectionResult? = null, + + /** + * Information about detection of protected code material. + */ + @SerialName("protected_material_code") + val protectedMaterialCode: ContentFilterCitedDetectionResult? = null +) \ No newline at end of file diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForPrompt.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForPrompt.kt new file mode 100644 index 00000000..e1471599 --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterResultsForPrompt.kt @@ -0,0 +1,23 @@ +package com.aallam.openai.azure.api.filtering + +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerialName + +/** + * Content filtering results for a single prompt in the request. + */ +@Serializable +public data class ContentFilterResultsForPrompt( + + /** + * The index of this prompt in the set of prompt results. + */ + @SerialName("prompt_index") + val promptIndex: Int, + + /** + * Content filtering results for this prompt. + */ + @SerialName("content_filter_results") + val contentFilterResults: ContentFilterResultDetailsForPrompt +) diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterSeverity.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterSeverity.kt new file mode 100644 index 00000000..643858cb --- /dev/null +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.azure.api/filtering/ContentFilterSeverity.kt @@ -0,0 +1,44 @@ +package com.aallam.openai.azure.api.filtering + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Ratings for the intensity and risk level of harmful content. + */ +@Serializable +public enum class ContentFilterSeverity(@Serializable public val value: String) { + + /** + * Content may be related to violence, self-harm, sexual, or hate categories but the terms + * are used in general, journalistic, scientific, medical, and similar professional contexts, + * which are appropriate for most audiences. + */ + @SerialName("safe") + SAFE("safe"), + + /** + * Content that expresses prejudiced, judgmental, or opinionated views, includes offensive + * use of language, stereotyping, use cases exploring a fictional world (for example, gaming, + * literature) and depictions at low intensity. + */ + @SerialName("low") + LOW("low"), + + /** + * Content that uses offensive, insulting, mocking, intimidating, or demeaning language + * towards specific identity groups, includes depictions of seeking and executing harmful + * instructions, fantasies, glorification, promotion of harm at medium intensity. + */ + @SerialName("medium") + MEDIUM("medium"), + + /** + * Content that displays explicit and severe harmful instructions, actions, + * damage, or abuse; includes endorsement, glorification, or promotion of severe + * harmful acts, extreme or illegal forms of harm, radicalization, or non-consensual + * power exchange or abuse. + */ + @SerialName("high") + HIGH("high") +}