kind_openai/endpoints/chat/
standard.rsuse bon::Builder;
use chat_completion_builder::IsComplete;
use kind_openai_schema::OpenAISchema;
use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::{endpoints::OpenAIRequestProvider, OpenAIResult, Usage};
use super::{
structured::{ChatCompletionRequestResponseFormat, StructuredChatCompletion},
FinishReason, Message, Model, UnifiedChatCompletionResponseMessage,
};
#[derive(Serialize, Builder)]
#[builder(start_fn = model, finish_fn = unstructured)]
pub struct ChatCompletion<'a> {
#[builder(start_fn)]
model: Model,
messages: Vec<Message<'a>>,
temperature: Option<f32>,
top_p: Option<f32>,
}
impl OpenAIRequestProvider for ChatCompletion<'_> {
type Response = ChatCompletionResponse;
const METHOD: Method = Method::POST;
fn path_with_leading_slash() -> String {
"/chat/completions".to_string()
}
}
impl super::super::private::Sealed for ChatCompletion<'_> {}
impl<'a, S> ChatCompletionBuilder<'a, S>
where
S: IsComplete,
{
pub fn structured<SS>(self) -> StructuredChatCompletion<'a, SS>
where
SS: OpenAISchema,
{
StructuredChatCompletion {
base_request: self.unstructured(),
response_format: ChatCompletionRequestResponseFormat::JsonSchema(SS::openai_schema()),
_phantom: std::marker::PhantomData,
}
}
}
#[derive(Deserialize)]
pub struct ChatCompletionResponse {
choices: Vec<ChatCompletionResponseChoice>,
usage: Usage,
}
impl ChatCompletionResponse {
pub fn take_first_choice(self) -> Option<ChatCompletionResponseChoice> {
self.choices.into_iter().next()
}
pub fn usage(&self) -> &Usage {
&self.usage
}
}
#[derive(Deserialize)]
pub struct ChatCompletionResponseChoice {
finish_reason: FinishReason,
index: i32,
message: ChatCompletionResponseMessage,
}
impl ChatCompletionResponseChoice {
pub fn message(self) -> OpenAIResult<String> {
Into::<UnifiedChatCompletionResponseMessage<String>>::into(self.message).into()
}
pub fn finish_reason(&self) -> FinishReason {
self.finish_reason
}
pub fn index(&self) -> i32 {
self.index
}
}
#[derive(Deserialize)]
struct ChatCompletionResponseMessage {
content: String,
refusal: Option<String>,
}
impl From<ChatCompletionResponseMessage> for UnifiedChatCompletionResponseMessage<String> {
fn from(value: ChatCompletionResponseMessage) -> Self {
UnifiedChatCompletionResponseMessage {
content: value.content,
refusal: value.refusal,
}
}
}