| POST | /v1/chat/completions |
|---|
# frozen_string_literal: true
# encoding: utf-8
require 'json'
require 'servicestack'
module ResponseFormat
TEXT = 'Text'
JSON_OBJECT = 'JsonObject'
end
module ToolType
FUNCTION = 'Function'
end
# @DataContract
class AiContent
include ServiceStack::DTO
# @DataMember(Name="type")
# @return [String]
attr_accessor :type
def self.properties
{
type: { name: 'type' },
}
end
end
#
# Annotations for the message, when applicable, as when using the web search tool.
#
# @DataContract
class UrlCitation
include ServiceStack::DTO
# @DataMember(Name="end_index")
# @return [Integer]
attr_accessor :end_index
# @DataMember(Name="start_index")
# @return [Integer]
attr_accessor :start_index
# @DataMember(Name="title")
# @return [String]
attr_accessor :title
# @DataMember(Name="url")
# @return [String]
attr_accessor :url
def self.properties
{
end_index: { name: 'end_index' },
start_index: { name: 'start_index' },
title: { name: 'title' },
url: { name: 'url' },
}
end
end
#
# Annotations for the message, when applicable, as when using the web search tool.
#
# @DataContract
class ChoiceAnnotation
include ServiceStack::DTO
# @DataMember(Name="type")
# @return [String]
attr_accessor :type
# @DataMember(Name="url_citation")
# @return [UrlCitation]
attr_accessor :url_citation
def self.properties
{
type: { name: 'type' },
url_citation: { name: 'url_citation', type: UrlCitation },
}
end
end
#
# If the audio output modality is requested, this object contains data about the audio response from the model.
#
# @DataContract
class ChoiceAudio
include ServiceStack::DTO
# @DataMember(Name="data")
# @return [String]
attr_accessor :data
# @DataMember(Name="expires_at")
# @return [Integer]
attr_accessor :expires_at
# @DataMember(Name="id")
# @return [String]
attr_accessor :id
# @DataMember(Name="transcript")
# @return [String]
attr_accessor :transcript
def self.properties
{
data: { name: 'data' },
expires_at: { name: 'expires_at' },
id: { name: 'id' },
transcript: { name: 'transcript' },
}
end
end
#
# The function that the model called.
#
# @DataContract
class ToolFunction
include ServiceStack::DTO
# @DataMember(Name="name")
# @return [String]
attr_accessor :name
# @DataMember(Name="arguments")
# @return [String]
attr_accessor :arguments
def self.properties
{
name: { name: 'name' },
arguments: { name: 'arguments' },
}
end
end
#
# The tool calls generated by the model, such as function calls.
#
# @DataContract
class ToolCall
include ServiceStack::DTO
# @DataMember(Name="id")
# @return [String]
attr_accessor :id
# @DataMember(Name="type")
# @return [String]
attr_accessor :type
# @DataMember(Name="function")
# @return [ToolFunction]
attr_accessor :function
def self.properties
{
id: { name: 'id' },
type: { name: 'type' },
function: { name: 'function', type: ToolFunction },
}
end
end
# @DataContract
class ChoiceMessage
include ServiceStack::DTO
# @DataMember(Name="content")
# @return [String]
attr_accessor :content
# @DataMember(Name="refusal")
# @return [String]
attr_accessor :refusal
# @DataMember(Name="reasoning")
# @return [String]
attr_accessor :reasoning
# @DataMember(Name="reasoning_content")
# @return [String]
attr_accessor :reasoning_content
# @DataMember(Name="thinking")
# @return [String]
attr_accessor :thinking
# @DataMember(Name="role")
# @return [String]
attr_accessor :role
# @DataMember(Name="timestamp")
# @return [Integer]
attr_accessor :timestamp
# @DataMember(Name="tool_call_id")
# @return [String]
attr_accessor :tool_call_id
# @DataMember(Name="images")
# @return [List]
attr_accessor :images
# @DataMember(Name="audios")
# @return [List]
attr_accessor :audios
# @DataMember(Name="files")
# @return [List]
attr_accessor :files
# @DataMember(Name="annotations")
# @return [List]
attr_accessor :annotations
# @DataMember(Name="audio")
# @return [ChoiceAudio]
attr_accessor :audio
# @DataMember(Name="tool_calls")
# @return [List]
attr_accessor :tool_calls
def self.properties
{
content: { name: 'content' },
refusal: { name: 'refusal' },
reasoning: { name: 'reasoning' },
reasoning_content: { name: 'reasoning_content' },
thinking: { name: 'thinking' },
role: { name: 'role' },
timestamp: { name: 'timestamp' },
tool_call_id: { name: 'tool_call_id' },
images: { name: 'images', type: [AiContent] },
audios: { name: 'audios', type: [AiContent] },
files: { name: 'files', type: [AiContent] },
annotations: { name: 'annotations', type: [ChoiceAnnotation] },
audio: { name: 'audio', type: ChoiceAudio },
tool_calls: { name: 'tool_calls', type: [ToolCall] },
}
end
end
#
# A list of message content tokens with log probability information.
#
# @DataContract
class LogprobItem
include ServiceStack::DTO
# @DataMember(Name="token")
# @return [String]
attr_accessor :token
# @DataMember(Name="logprob")
# @return [Float]
attr_accessor :logprob
# @DataMember(Name="bytes")
# @return [String]
attr_accessor :bytes
# @DataMember(Name="top_logprobs")
# @return [List]
attr_accessor :top_logprobs
def self.properties
{
token: { name: 'token' },
logprob: { name: 'logprob' },
bytes: { name: 'bytes' },
top_logprobs: { name: 'top_logprobs', type: [LogprobItem] },
}
end
end
#
# Log probability information for the choice.
#
# @DataContract
class Logprobs
include ServiceStack::DTO
# @DataMember(Name="content")
# @return [List]
attr_accessor :content
def self.properties
{
content: { name: 'content', type: [LogprobItem] },
}
end
end
# @DataContract
class Choice
include ServiceStack::DTO
# @DataMember(Name="finish_reason")
# @return [String]
attr_accessor :finish_reason
# @DataMember(Name="index")
# @return [Integer]
attr_accessor :index
# @DataMember(Name="message")
# @return [ChoiceMessage]
attr_accessor :message
# @DataMember(Name="logprobs")
# @return [Logprobs]
attr_accessor :logprobs
def self.properties
{
finish_reason: { name: 'finish_reason' },
index: { name: 'index' },
message: { name: 'message', type: ChoiceMessage },
logprobs: { name: 'logprobs', type: Logprobs },
}
end
end
#
# Usage statistics for the completion request.
#
# @DataContract
class AiCompletionUsage
include ServiceStack::DTO
# @DataMember(Name="accepted_prediction_tokens")
# @return [Integer]
attr_accessor :accepted_prediction_tokens
# @DataMember(Name="audio_tokens")
# @return [Integer]
attr_accessor :audio_tokens
# @DataMember(Name="reasoning_tokens")
# @return [Integer]
attr_accessor :reasoning_tokens
# @DataMember(Name="rejected_prediction_tokens")
# @return [Integer]
attr_accessor :rejected_prediction_tokens
def self.properties
{
accepted_prediction_tokens: { name: 'accepted_prediction_tokens' },
audio_tokens: { name: 'audio_tokens' },
reasoning_tokens: { name: 'reasoning_tokens' },
rejected_prediction_tokens: { name: 'rejected_prediction_tokens' },
}
end
end
#
# Breakdown of tokens used in the prompt.
#
# @DataContract
class AiPromptUsage
include ServiceStack::DTO
# @DataMember(Name="accepted_prediction_tokens")
# @return [Integer]
attr_accessor :accepted_prediction_tokens
# @DataMember(Name="audio_tokens")
# @return [Integer]
attr_accessor :audio_tokens
# @DataMember(Name="cached_tokens")
# @return [Integer]
attr_accessor :cached_tokens
def self.properties
{
accepted_prediction_tokens: { name: 'accepted_prediction_tokens' },
audio_tokens: { name: 'audio_tokens' },
cached_tokens: { name: 'cached_tokens' },
}
end
end
#
# Usage statistics for the completion request.
#
# @DataContract
class AiUsage
include ServiceStack::DTO
# @DataMember(Name="completion_tokens")
# @return [Integer]
attr_accessor :completion_tokens
# @DataMember(Name="prompt_tokens")
# @return [Integer]
attr_accessor :prompt_tokens
# @DataMember(Name="total_tokens")
# @return [Integer]
attr_accessor :total_tokens
# @DataMember(Name="completion_tokens_details")
# @return [AiCompletionUsage]
attr_accessor :completion_tokens_details
# @DataMember(Name="prompt_tokens_details")
# @return [AiPromptUsage]
attr_accessor :prompt_tokens_details
# @DataMember(Name="duration")
# @return [Integer]
attr_accessor :duration
def self.properties
{
completion_tokens: { name: 'completion_tokens' },
prompt_tokens: { name: 'prompt_tokens' },
total_tokens: { name: 'total_tokens' },
completion_tokens_details: { name: 'completion_tokens_details', type: AiCompletionUsage },
prompt_tokens_details: { name: 'prompt_tokens_details', type: AiPromptUsage },
duration: { name: 'duration' },
}
end
end
# @DataContract
class ChatResponse
include ServiceStack::DTO
# @DataMember(Name="id")
# @return [String]
attr_accessor :id
# @DataMember(Name="choices")
# @return [List]
attr_accessor :choices
# @DataMember(Name="created")
# @return [Integer]
attr_accessor :created
# @DataMember(Name="model")
# @return [String]
attr_accessor :model
# @DataMember(Name="system_fingerprint")
# @return [String]
attr_accessor :system_fingerprint
# @DataMember(Name="object")
# @return [String]
attr_accessor :object
# @DataMember(Name="service_tier")
# @return [String]
attr_accessor :service_tier
# @DataMember(Name="usage")
# @return [AiUsage]
attr_accessor :usage
# @DataMember(Name="provider")
# @return [String]
attr_accessor :provider
# @DataMember(Name="cost")
# @return [Float]
attr_accessor :cost
# @DataMember(Name="tool_history")
# @return [List]
attr_accessor :tool_history
# @DataMember(Name="metadata")
# @return [Dictionary]
attr_accessor :metadata
# @DataMember(Name="responseStatus")
# @return [ServiceStack::ResponseStatus]
attr_accessor :response_status
def self.properties
{
id: { name: 'id' },
choices: { name: 'choices', type: [Choice] },
created: { name: 'created' },
model: { name: 'model' },
system_fingerprint: { name: 'system_fingerprint' },
object: { name: 'object' },
service_tier: { name: 'service_tier' },
usage: { name: 'usage', type: AiUsage },
provider: { name: 'provider' },
cost: { name: 'cost' },
tool_history: { name: 'tool_history', type: [ChoiceMessage] },
metadata: { name: 'metadata' },
response_status: { name: 'responseStatus', type: ServiceStack::ResponseStatus },
}
end
end
#
# A list of messages comprising the conversation so far.
#
# @DataContract
class AiMessage
include ServiceStack::DTO
# @DataMember(Name="content")
# @return [List]
attr_accessor :content
# @DataMember(Name="role")
# @return [String]
attr_accessor :role
# @DataMember(Name="name")
# @return [String]
attr_accessor :name
# @DataMember(Name="tool_calls")
# @return [List]
attr_accessor :tool_calls
# @DataMember(Name="tool_call_id")
# @return [String]
attr_accessor :tool_call_id
# @DataMember(Name="reasoning")
# @return [String]
attr_accessor :reasoning
# @DataMember(Name="reasoning_content")
# @return [String]
attr_accessor :reasoning_content
# @DataMember(Name="timestamp")
# @return [Integer]
attr_accessor :timestamp
# @DataMember(Name="images")
# @return [List]
attr_accessor :images
def self.properties
{
content: { name: 'content', type: [AiContent] },
role: { name: 'role' },
name: { name: 'name' },
tool_calls: { name: 'tool_calls', type: [ToolCall] },
tool_call_id: { name: 'tool_call_id' },
reasoning: { name: 'reasoning' },
reasoning_content: { name: 'reasoning_content' },
timestamp: { name: 'timestamp' },
images: { name: 'images', type: [AiContent] },
}
end
end
#
# Parameters for audio output. Required when audio output is requested with modalities: [audio]
#
# @DataContract
class AiChatAudio
include ServiceStack::DTO
# @DataMember(Name="format")
# @return [String]
attr_accessor :format
# @DataMember(Name="voice")
# @return [String]
attr_accessor :voice
def self.properties
{
format: { name: 'format' },
voice: { name: 'voice' },
}
end
end
# @DataContract
class AiResponseFormat
include ServiceStack::DTO
# @DataMember(Name="type")
# @return [ResponseFormat]
attr_accessor :type
def self.properties
{
type: { name: 'type' },
}
end
end
# @DataContract
class AiToolFunction
include ServiceStack::DTO
# @DataMember(Name="name")
# @return [String]
attr_accessor :name
# @DataMember(Name="description")
# @return [String]
attr_accessor :description
# @DataMember(Name="parameters")
# @return [Dictionary]
attr_accessor :parameters
def self.properties
{
name: { name: 'name' },
description: { name: 'description' },
parameters: { name: 'parameters' },
}
end
end
# @DataContract
class Tool
include ServiceStack::DTO
# @DataMember(Name="type")
# @return [ToolType]
attr_accessor :type
# @DataMember(Name="function")
# @return [AiToolFunction]
attr_accessor :function
def self.properties
{
type: { name: 'type' },
function: { name: 'function', type: AiToolFunction },
}
end
end
#
# Chat Completions API (OpenAI-Compatible)
#
# @DataContract
class ChatCompletion
include ServiceStack::DTO
# @DataMember(Name="messages")
# @return [List]
attr_accessor :messages
# @DataMember(Name="model")
# @return [String]
attr_accessor :model
# @DataMember(Name="audio")
# @return [AiChatAudio]
attr_accessor :audio
# @DataMember(Name="logit_bias")
# @return [Dictionary]
attr_accessor :logit_bias
# @DataMember(Name="metadata")
# @return [Dictionary]
attr_accessor :metadata
# @DataMember(Name="reasoning_effort")
# @return [String]
attr_accessor :reasoning_effort
# @DataMember(Name="response_format")
# @return [AiResponseFormat]
attr_accessor :response_format
# @DataMember(Name="service_tier")
# @return [String]
attr_accessor :service_tier
# @DataMember(Name="safety_identifier")
# @return [String]
attr_accessor :safety_identifier
# @DataMember(Name="stop")
# @return [List]
attr_accessor :stop
# @DataMember(Name="modalities")
# @return [List]
attr_accessor :modalities
# @DataMember(Name="prompt_cache_key")
# @return [String]
attr_accessor :prompt_cache_key
# @DataMember(Name="tools")
# @return [List]
attr_accessor :tools
# @DataMember(Name="verbosity")
# @return [String]
attr_accessor :verbosity
# @DataMember(Name="temperature")
# @return [Float]
attr_accessor :temperature
# @DataMember(Name="max_completion_tokens")
# @return [Integer]
attr_accessor :max_completion_tokens
# @DataMember(Name="top_logprobs")
# @return [Integer]
attr_accessor :top_logprobs
# @DataMember(Name="top_p")
# @return [Float]
attr_accessor :top_p
# @DataMember(Name="frequency_penalty")
# @return [Float]
attr_accessor :frequency_penalty
# @DataMember(Name="presence_penalty")
# @return [Float]
attr_accessor :presence_penalty
# @DataMember(Name="seed")
# @return [Integer]
attr_accessor :seed
# @DataMember(Name="n")
# @return [Integer]
attr_accessor :n
# @DataMember(Name="store")
# @return [TrueClass]
attr_accessor :store
# @DataMember(Name="logprobs")
# @return [TrueClass]
attr_accessor :logprobs
# @DataMember(Name="parallel_tool_calls")
# @return [TrueClass]
attr_accessor :parallel_tool_calls
# @DataMember(Name="enable_thinking")
# @return [TrueClass]
attr_accessor :enable_thinking
# @DataMember(Name="stream")
# @return [TrueClass]
attr_accessor :stream
def self.properties
{
messages: { name: 'messages', type: [AiMessage] },
model: { name: 'model' },
audio: { name: 'audio', type: AiChatAudio },
logit_bias: { name: 'logit_bias' },
metadata: { name: 'metadata' },
reasoning_effort: { name: 'reasoning_effort' },
response_format: { name: 'response_format', type: AiResponseFormat },
service_tier: { name: 'service_tier' },
safety_identifier: { name: 'safety_identifier' },
stop: { name: 'stop' },
modalities: { name: 'modalities' },
prompt_cache_key: { name: 'prompt_cache_key' },
tools: { name: 'tools', type: [Tool] },
verbosity: { name: 'verbosity' },
temperature: { name: 'temperature' },
max_completion_tokens: { name: 'max_completion_tokens' },
top_logprobs: { name: 'top_logprobs' },
top_p: { name: 'top_p' },
frequency_penalty: { name: 'frequency_penalty' },
presence_penalty: { name: 'presence_penalty' },
seed: { name: 'seed' },
n: { name: 'n' },
store: { name: 'store' },
logprobs: { name: 'logprobs' },
parallel_tool_calls: { name: 'parallel_tool_calls' },
enable_thinking: { name: 'enable_thinking' },
stream: { name: 'stream' },
}
end
def response_type() = ChatResponse
def get_type_name() = 'ChatCompletion'
end
To override the Content-type in your clients, use the HTTP Accept Header, append the .csv suffix or ?format=csv
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/csv
Content-Type: text/csv
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/csv
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"}}}