use std::sync::Arc;
use artificial_core::{
generic::{GenericChatCompletionResponse, GenericUsageReport, ResponseContent},
provider::{ChatCompleteParameters, ChatCompletionProvider},
};
use crate::{
OpenAiAdapter,
api_v1::{ChatCompletionMessage, FinishReason},
error::OpenAiError,
};
impl ChatCompletionProvider for OpenAiAdapter {
type Message = ChatCompletionMessage;
fn chat_complete<'s, M>(
&'s self,
params: ChatCompleteParameters<M>,
) -> std::pin::Pin<
Box<
dyn Future<
Output = artificial_core::error::Result<
artificial_core::generic::GenericChatCompletionResponse<
artificial_core::generic::GenericMessage,
>,
>,
> + Send
+ 's,
>,
>
where
M: Into<Self::Message> + Clone + Send + Sync + 's,
{
let client = Arc::clone(&self.client);
Box::pin(async move {
let request = params.try_into()?;
let mut response = client.chat_completion(request).await?;
let usage_report = GenericUsageReport {
prompt_tokens: response.usage.prompt_tokens as i64,
completion_tokens: response.usage.completion_tokens as i64,
total_tokens: response.usage.total_tokens as i64,
};
let Some(first_choice) = response.choices.pop() else {
return Err(OpenAiError::Format("response has no choices".into()).into());
};
match &first_choice.finish_reason {
Some(FinishReason::ToolCalls) => {
let response = GenericChatCompletionResponse {
content: ResponseContent::ToolCalls(first_choice.message.into()),
usage: Some(usage_report),
};
Ok(response)
}
None | Some(FinishReason::Stop) => {
let response = GenericChatCompletionResponse {
content: ResponseContent::Finished(first_choice.message.into()),
usage: Some(usage_report),
};
Ok(response)
}
Some(other) => Err(OpenAiError::Format(format!(
"unhandled finish reason on API: {other:?}"
))
.into()),
}
})
}
}