MyApp

<back to all web services

ChatCompletion

AI

Chat Completions API (OpenAI-Compatible)

The following routes are available for this service:
POST/v1/chat/completions
#![allow(
    dead_code,
    non_camel_case_types,
    non_snake_case,
    clippy::upper_case_acronyms
)]

use serde::{Deserialize, Serialize};
use serde_json::Value;
use servicestack::*;
use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiContent {
    /// The type of the content part.
    pub r#type: String,
}

/// Annotations for the message, when applicable, as when using the web search tool.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct UrlCitation {
    /// The index of the last character of the URL citation in the message.
    pub end_index: i32,
    /// The index of the first character of the URL citation in the message.
    pub start_index: i32,
    /// The title of the web resource.
    pub title: String,
    /// The URL of the web resource.
    pub url: String,
}

/// Annotations for the message, when applicable, as when using the web search tool.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ChoiceAnnotation {
    /// The type of the URL citation. Always url_citation.
    pub r#type: String,
    /// A URL citation when using web search.
    pub url_citation: UrlCitation,
}

/// If the audio output modality is requested, this object contains data about the audio response from the model.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ChoiceAudio {
    /// Base64 encoded audio bytes generated by the model, in the format specified in the request.
    pub data: String,
    /// The Unix timestamp (in seconds) for when this audio response will no longer be accessible on the server for use in multi-turn conversations.
    pub expires_at: i64,
    /// Unique identifier for this audio response.
    pub id: String,
    /// Transcript of the audio generated by the model.
    pub transcript: String,
}

/// The function that the model called.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ToolFunction {
    /// The name of the function to call.
    pub name: String,
    /// The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function.
    pub arguments: String,
}

/// The tool calls generated by the model, such as function calls.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ToolCall {
    /// The ID of the tool call.
    pub id: String,
    /// The type of the tool. Currently, only `function` is supported.
    pub r#type: String,
    /// The function that the model called.
    pub function: ToolFunction,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ChoiceMessage {
    /// The contents of the message.
    pub content: String,
    /// The refusal message generated by the model.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub refusal: Option<String>,
    /// The reasoning process used by the model.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reasoning: Option<String>,
    /// The reasoning process used by the model, as emitted by Gemini and most OpenAI-compatible providers.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reasoning_content: Option<String>,
    /// The reasoning process used by the model, as emitted by Anthropic.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub thinking: Option<String>,
    /// The role of the author of this message.
    pub role: String,
    /// Unix timestamp (in milliseconds) the message was generated.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub timestamp: Option<i64>,
    /// The tool call this message is responding to, set on `tool` role messages in tool_history.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tool_call_id: Option<String>,
    /// Images generated by the model or produced by a tool call.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub images: Option<Vec<AiContent>>,
    /// Audio generated by the model or produced by a tool call.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub audios: Option<Vec<AiContent>>,
    /// Files produced by a tool call.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub files: Option<Vec<AiContent>>,
    /// Annotations for the message, when applicable, as when using the web search tool.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub annotations: Option<Vec<ChoiceAnnotation>>,
    /// If the audio output modality is requested, this object contains data about the audio response from the model.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub audio: Option<ChoiceAudio>,
    /// The tool calls generated by the model, such as function calls.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tool_calls: Option<Vec<ToolCall>>,
}

/// A list of message content tokens with log probability information.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct LogprobItem {
    /// The token.
    pub token: String,
    /// The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999`.0 is used to signify that the token is very unlikely.
    pub logprob: f64,
    /// A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be `null` if there is no bytes representation for the token.
    pub bytes: Vec<u8>,
    /// List of the most likely tokens and their log probability, at this token position. In rare cases, there may be fewer than the number of requested `top_logprobs` returned.
    pub top_logprobs: Vec<LogprobItem>,
}

/// Log probability information for the choice.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct Logprobs {
    /// A list of message content tokens with log probability information.
    pub content: Vec<LogprobItem>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct Choice {
    /// The reason the model stopped generating tokens. This will be stop if the model hit a natural stop point or a provided stop sequence, length if the maximum number of tokens specified in the request was reached, content_filter if content was omitted due to a flag from our content filters, tool_calls if the model called a tool
    pub finish_reason: String,
    /// The index of the choice in the list of choices.
    pub index: i32,
    /// A chat completion message generated by the model.
    pub message: ChoiceMessage,
    /// Log probability information for the choice.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub logprobs: Option<Logprobs>,
}

/// Usage statistics for the completion request.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiCompletionUsage {
    /// When using Predicted Outputs, the number of tokens in the prediction that appeared in the completion.
    pub accepted_prediction_tokens: i64,
    /// Audio input tokens generated by the model.
    pub audio_tokens: i64,
    /// Tokens generated by the model for reasoning.
    pub reasoning_tokens: i64,
    /// When using Predicted Outputs, the number of tokens in the prediction that did not appear in the completion.
    pub rejected_prediction_tokens: i64,
}

/// Breakdown of tokens used in the prompt.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiPromptUsage {
    /// When using Predicted Outputs, the number of tokens in the prediction that appeared in the completion.
    pub accepted_prediction_tokens: i64,
    /// Audio input tokens present in the prompt.
    pub audio_tokens: i64,
    /// Cached tokens present in the prompt.
    pub cached_tokens: i64,
}

/// Usage statistics for the completion request.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiUsage {
    /// Number of tokens in the generated completion.
    pub completion_tokens: i64,
    /// Number of tokens in the prompt.
    pub prompt_tokens: i64,
    /// Total number of tokens used in the request (prompt + completion).
    pub total_tokens: i64,
    /// Breakdown of tokens used in a completion.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub completion_tokens_details: Option<AiCompletionUsage>,
    /// Breakdown of tokens used in the prompt.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub prompt_tokens_details: Option<AiPromptUsage>,
    /// Seconds spent servicing the completion, including every request in the tool loop.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub duration: Option<i64>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ChatResponse {
    /// A unique identifier for the chat completion.
    pub id: String,
    /// A list of chat completion choices. Can be more than one if n is greater than 1.
    pub choices: Vec<Choice>,
    /// The Unix timestamp (in seconds) of when the chat completion was created.
    pub created: i64,
    /// The model used for the chat completion.
    pub model: String,
    /// This fingerprint represents the backend configuration that the model runs with.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub system_fingerprint: Option<String>,
    /// The object type, which is always chat.completion.
    pub object: String,
    /// Specifies the processing type used for serving the request.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub service_tier: Option<String>,
    /// Usage statistics for the completion request.
    pub usage: AiUsage,
    /// The provider used for the chat completion.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub provider: Option<String>,
    /// Total cost of the completion in USD, accumulated across every request in the tool loop.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cost: Option<f64>,
    /// The assistant and tool messages exchanged during the tool-execution loop, in order.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tool_history: Option<Vec<ChoiceMessage>>,
    /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, String>>,
    #[serde(rename = "responseStatus")]
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub response_status: Option<ResponseStatus>,
}

/// A list of messages comprising the conversation so far.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiMessage {
    /// The contents of the message.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub content: Option<Vec<AiContent>>,
    /// The role of the author of this message. Valid values are `system`, `user`, `assistant` and `tool`.
    pub role: String,
    /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// The tool calls generated by the model, such as function calls.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tool_calls: Option<Vec<ToolCall>>,
    /// Tool call that this message is responding to.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tool_call_id: Option<String>,
    /// The reasoning an assistant message was generated with, normalized per provider when replayed as history.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reasoning: Option<String>,
    /// The reasoning an assistant message was generated with, as emitted by Gemini and most OpenAI-compatible providers.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reasoning_content: Option<String>,
    /// Unix timestamp (in milliseconds) the message was generated.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub timestamp: Option<i64>,
    /// Images attached to the message. Folded into `content` parts before sending to a provider.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub images: Option<Vec<AiContent>>,
}

/// Parameters for audio output. Required when audio output is requested with modalities: [audio]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiChatAudio {
    /// Specifies the output audio format. Must be one of wav, mp3, flac, opus, or pcm16.
    pub format: String,
    /// The voice the model uses to respond. Supported voices are alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, and shimmer.
    pub voice: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum ResponseFormat {
    #[default]
    #[serde(rename = "text")]
    Text,
    #[serde(rename = "json_object")]
    JsonObject,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiResponseFormat {
    /// An object specifying the format that the model must output. Compatible with GPT-4 Turbo and all GPT-3.5 Turbo models newer than gpt-3.5-turbo-1106.
    pub r#type: ResponseFormat,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum ToolType {
    #[default]
    #[serde(rename = "function")]
    Function,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct AiToolFunction {
    /// The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// A description of what the function does, used by the model to choose when and how to call the function.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// The parameters the functions accepts, described as a JSON Schema object. See the guide for examples, and the JSON Schema reference for documentation about the format.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub parameters: Option<HashMap<String, Value>>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct Tool {
    /// The type of the tool. Currently, only function is supported.
    pub r#type: ToolType,
    /// The function definition the model may call.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub function: Option<AiToolFunction>,
}

/// Chat Completions API (OpenAI-Compatible)
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
#[serde(default)]
pub struct ChatCompletion {
    /// The messages to generate chat completions for.
    pub messages: Vec<AiMessage>,
    /// ID of the model to use. See the model endpoint compatibility table for details on which models work with the Chat API
    pub model: String,
    /// Parameters for audio output. Required when audio output is requested with modalities: [audio]
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub audio: Option<AiChatAudio>,
    /// Modify the likelihood of specified tokens appearing in the completion.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub logit_bias: Option<HashMap<i32, i32>>,
    /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, String>>,
    /// Constrains effort on reasoning for reasoning models. Currently supported values are minimal, low, medium, and high (none, default). Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reasoning_effort: Option<String>,
    /// An object specifying the format that the model must output. Compatible with GPT-4 Turbo and all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. Setting Type to ResponseFormat.JsonObject enables JSON mode, which guarantees the message the model generates is valid JSON.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub response_format: Option<AiResponseFormat>,
    /// Specifies the processing type used for serving the request.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub service_tier: Option<String>,
    /// A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely identifies each user.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub safety_identifier: Option<String>,
    /// Up to 4 sequences where the API will stop generating further tokens.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub stop: Option<Vec<String>>,
    /// Output types that you would like the model to generate. Most models are capable of generating text, which is the default:
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub modalities: Option<Vec<String>>,
    /// Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub prompt_cache_key: Option<String>,
    /// A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for. A max of 128 functions are supported.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub tools: Option<Vec<Tool>>,
    /// Constrains the verbosity of the model's response. Lower values will result in more concise responses, while higher values will result in more verbose responses. Currently supported values are low, medium, and high.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub verbosity: Option<String>,
    /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub temperature: Option<f64>,
    /// An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_completion_tokens: Option<i32>,
    /// An integer between 0 and 20 specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub top_logprobs: Option<i32>,
    /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub top_p: Option<f64>,
    /// Number between `-2.0` and `2.0`. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub frequency_penalty: Option<f64>,
    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub presence_penalty: Option<f64>,
    /// This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub seed: Option<i32>,
    /// How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub n: Option<i32>,
    /// Whether or not to store the output of this chat completion request for use in our model distillation or evals products.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub store: Option<bool>,
    /// Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub logprobs: Option<bool>,
    /// Whether to enable parallel function calling during tool use.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub parallel_tool_calls: Option<bool>,
    /// Whether to enable thinking mode for some Qwen models and providers.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub enable_thinking: Option<bool>,
    /// If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a `data: [DONE]` message.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub stream: Option<bool>,
}

Rust ChatCompletion DTOs

To override the Content-type in your clients, use the HTTP Accept Header, append the .other suffix or ?format=other

HTTP + OTHER

The following are sample HTTP requests and responses. The placeholders shown need to be replaced with actual values.

POST /v1/chat/completions HTTP/1.1 
Host: blazor-vue.web-templates.io 
Accept: text/jsonl
Content-Type: text/jsonl
Content-Length: length

{"messages":[{"content":[{}],"role":"String","name":"String","tool_calls":[{"id":"String","type":"String","function":{"name":"String","arguments":"String"}}],"tool_call_id":"String","reasoning":"String","reasoning_content":"String","timestamp":0,"images":[{}]}],"model":"String","audio":{"format":"String","voice":"String"},"logit_bias":{"0":0},"metadata":{"String":"String"},"reasoning_effort":"String","response_format":{"type":"text"},"service_tier":"String","safety_identifier":"String","stop":["String"],"modalities":["String"],"prompt_cache_key":"String","tools":[{"type":"function","function":{"name":"String","description":"String","parameters":{"String":{}}}}],"verbosity":"String","temperature":0,"max_completion_tokens":0,"top_logprobs":0,"top_p":0,"frequency_penalty":0,"presence_penalty":0,"seed":0,"n":0,"store":false,"logprobs":false,"parallel_tool_calls":false,"enable_thinking":false,"stream":false}
HTTP/1.1 200 OK
Content-Type: text/jsonl
Content-Length: length

{"id":"String","choices":[{"finish_reason":"String","index":0,"message":{"content":"String","refusal":"String","reasoning":"String","reasoning_content":"String","thinking":"String","role":"String","timestamp":0,"tool_call_id":"String","images":[{}],"audios":[{}],"files":[{}],"annotations":[{"type":"String","url_citation":{"end_index":0,"start_index":0,"title":"String","url":"String"}}],"audio":{"data":"String","expires_at":0,"id":"String","transcript":"String"},"tool_calls":[{"id":"String","type":"String","function":{"name":"String","arguments":"String"}}]},"logprobs":{"content":[{"token":"String","logprob":0,"bytes":"AA==","top_logprobs":[{"token":"String","logprob":0,"bytes":"AA==","top_logprobs":[{"token":"String","logprob":0,"bytes":"AA=="}]}]}]}}],"created":0,"model":"String","system_fingerprint":"String","object":"String","service_tier":"String","usage":{"completion_tokens":0,"prompt_tokens":0,"total_tokens":0,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"cached_tokens":0},"duration":0},"provider":"String","cost":0,"tool_history":[{"content":"String","refusal":"String","reasoning":"String","reasoning_content":"String","thinking":"String","role":"String","timestamp":0,"tool_call_id":"String","images":[{}],"audios":[{}],"files":[{}],"annotations":[{"type":"String","url_citation":{"end_index":0,"start_index":0,"title":"String","url":"String"}}],"audio":{"data":"String","expires_at":0,"id":"String","transcript":"String"},"tool_calls":[{"id":"String","type":"String","function":{"name":"String","arguments":"String"}}]}],"metadata":{"String":"String"},"responseStatus":{"errorCode":"String","message":"String","stackTrace":"String","errors":[{"errorCode":"String","fieldName":"String","message":"String","meta":{"String":"String"}}],"meta":{"String":"String"}}}