use super::{openai_post, ApiResponseOrError, OpenAiError, Usage};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Clone)]
pub struct Edit {
pub created: u32,
#[serde(skip_deserializing)]
pub choices: Vec<String>,
pub usage: Usage,
#[serde(rename = "choices")]
choices_bad: Vec<EditChoice>,
}
#[derive(Deserialize, Clone)]
struct EditChoice {
text: String,
}
#[derive(Serialize, Builder, Debug, Clone)]
#[builder(pattern = "owned")]
#[builder(name = "EditBuilder")]
#[builder(setter(strip_option, into))]
pub struct EditRequest {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub input: Option<String>,
pub instruction: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(setter(into = false), default)]
pub n: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub temperature: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub top_p: Option<f32>,
}
impl Edit {
async fn create(request: &EditRequest) -> ApiResponseOrError<Self> {
let response: Result<Self, OpenAiError> = openai_post("edits", request).await?;
match response {
Ok(mut edit) => {
for choice in &edit.choices_bad {
edit.choices.push(choice.text.clone());
}
Ok(edit)
}
Err(_) => response,
}
}
pub fn builder(model: &str, instruction: impl Into<String>) -> EditBuilder {
EditBuilder::create_empty()
.model(model)
.instruction(instruction)
}
}
impl EditBuilder {
pub async fn create(self) -> ApiResponseOrError<Edit> {
Edit::create(&self.build().unwrap()).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::set_key;
use dotenvy::dotenv;
use std::env;
#[tokio::test]
#[ignore]
async fn edit() {
dotenv().ok();
set_key(env::var("OPENAI_KEY").unwrap());
let edit = Edit::builder("text-davinci-edit-001", "Fix the spelling mistakes")
.input("What day of the wek is it?")
.temperature(0.0)
.create()
.await
.unwrap();
assert_eq!(
edit.choices.first().unwrap(),
"What day of the week is it?\n"
);
}
}