use crate::error::LingerError;
use crate::RequestId;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct CreateFineTuningJobRequest {
pub model: String,
pub training_file: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub validation_file: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suffix: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub seed: Option<u64>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub metadata: BTreeMap<String, String>,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
}
impl CreateFineTuningJobRequest {
pub fn builder() -> CreateFineTuningJobRequestBuilder {
CreateFineTuningJobRequestBuilder::default()
}
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct CreateFineTuningJobRequestBuilder {
model: Option<String>,
training_file: Option<String>,
validation_file: Option<String>,
suffix: Option<String>,
seed: Option<u64>,
metadata: BTreeMap<String, String>,
extra: BTreeMap<String, Value>,
}
impl CreateFineTuningJobRequestBuilder {
pub fn model(mut self, model: impl Into<String>) -> Self {
self.model = Some(model.into());
self
}
pub fn training_file(mut self, training_file: impl Into<String>) -> Self {
self.training_file = Some(training_file.into());
self
}
pub fn validation_file(mut self, validation_file: impl Into<String>) -> Self {
self.validation_file = Some(validation_file.into());
self
}
pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
self.suffix = Some(suffix.into());
self
}
pub fn seed(mut self, seed: u64) -> Self {
self.seed = Some(seed);
self
}
pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
self.extra.insert(name.into(), value);
self
}
pub fn build(self) -> Result<CreateFineTuningJobRequest, LingerError> {
let model = self
.model
.filter(|value| !value.trim().is_empty())
.ok_or_else(|| LingerError::invalid_config("model is required"))?;
let training_file = self
.training_file
.filter(|value| !value.trim().is_empty())
.ok_or_else(|| LingerError::invalid_config("training_file is required"))?;
if self
.validation_file
.as_ref()
.is_some_and(|value| value.trim().is_empty())
{
return Err(LingerError::invalid_config(
"validation_file must not be empty",
));
}
if self
.suffix
.as_ref()
.is_some_and(|value| value.trim().is_empty())
{
return Err(LingerError::invalid_config("suffix must not be empty"));
}
if self
.metadata
.iter()
.any(|(key, value)| key.trim().is_empty() || value.is_empty())
{
return Err(LingerError::invalid_config(
"metadata keys and values must not be empty",
));
}
Ok(CreateFineTuningJobRequest {
model,
training_file,
validation_file: self.validation_file,
suffix: self.suffix,
seed: self.seed,
metadata: self.metadata,
extra: self.extra,
})
}
}
#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct CreateFineTuningCheckpointPermissionRequest {
pub project_ids: Vec<String>,
}
impl CreateFineTuningCheckpointPermissionRequest {
pub fn new<I, T>(project_ids: I) -> Result<Self, LingerError>
where
I: IntoIterator<Item = T>,
T: Into<String>,
{
let project_ids = project_ids.into_iter().map(Into::into).collect::<Vec<_>>();
if project_ids.is_empty() || project_ids.iter().any(|value| value.trim().is_empty()) {
return Err(LingerError::invalid_config("project_ids is required"));
}
Ok(Self { project_ids })
}
}
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct ValidateFineTuningGraderRequest {
pub grader: Value,
}
impl ValidateFineTuningGraderRequest {
pub fn builder() -> ValidateFineTuningGraderRequestBuilder {
ValidateFineTuningGraderRequestBuilder::default()
}
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct ValidateFineTuningGraderRequestBuilder {
grader: Option<Value>,
}
impl ValidateFineTuningGraderRequestBuilder {
pub fn grader(mut self, grader: Value) -> Self {
self.grader = Some(grader);
self
}
pub fn build(self) -> Result<ValidateFineTuningGraderRequest, LingerError> {
let grader = self
.grader
.filter(|value| !value.is_null())
.ok_or_else(|| LingerError::invalid_config("grader is required"))?;
Ok(ValidateFineTuningGraderRequest { grader })
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningGraderValidation {
pub grader: Value,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningGraderValidation {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct RunFineTuningGraderRequest {
pub grader: Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub item: Option<Value>,
pub model_sample: String,
}
impl RunFineTuningGraderRequest {
pub fn builder() -> RunFineTuningGraderRequestBuilder {
RunFineTuningGraderRequestBuilder::default()
}
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct RunFineTuningGraderRequestBuilder {
grader: Option<Value>,
item: Option<Value>,
model_sample: Option<String>,
}
impl RunFineTuningGraderRequestBuilder {
pub fn grader(mut self, grader: Value) -> Self {
self.grader = Some(grader);
self
}
pub fn item(mut self, item: Value) -> Self {
self.item = Some(item);
self
}
pub fn model_sample(mut self, model_sample: impl Into<String>) -> Self {
self.model_sample = Some(model_sample.into());
self
}
pub fn build(self) -> Result<RunFineTuningGraderRequest, LingerError> {
let grader = self
.grader
.filter(|value| !value.is_null())
.ok_or_else(|| LingerError::invalid_config("grader is required"))?;
let model_sample = self
.model_sample
.filter(|value| !value.trim().is_empty())
.ok_or_else(|| LingerError::invalid_config("model_sample is required"))?;
Ok(RunFineTuningGraderRequest {
grader,
item: self.item,
model_sample,
})
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningGraderRun {
pub reward: f64,
pub metadata: Value,
pub sub_rewards: Value,
pub model_grader_token_usage_per_model: Value,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningGraderRun {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningJob {
pub id: String,
pub object: String,
pub model: String,
pub created_at: u64,
#[serde(default)]
pub fine_tuned_model: Option<String>,
#[serde(default)]
pub organization_id: Option<String>,
#[serde(default)]
pub result_files: Vec<String>,
pub status: String,
#[serde(default)]
pub validation_file: Option<String>,
pub training_file: String,
#[serde(default)]
pub hyperparameters: Value,
#[serde(default)]
pub trained_tokens: Option<u64>,
#[serde(default)]
pub error: Option<Value>,
#[serde(default)]
pub estimated_finish: Option<u64>,
#[serde(default)]
pub integrations: Vec<Value>,
#[serde(default)]
pub seed: Option<u64>,
#[serde(default, deserialize_with = "deserialize_null_default")]
pub metadata: BTreeMap<String, String>,
#[serde(default)]
pub method: Value,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningJob {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningJobPage {
pub object: String,
#[serde(default)]
pub data: Vec<FineTuningJob>,
#[serde(default)]
pub first_id: Option<String>,
#[serde(default)]
pub last_id: Option<String>,
pub has_more: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningJobPage {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningEvent {
pub id: String,
pub object: String,
pub created_at: u64,
pub level: String,
pub message: String,
#[serde(default)]
pub r#type: Option<String>,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningEventPage {
pub object: String,
#[serde(default)]
pub data: Vec<FineTuningEvent>,
#[serde(default)]
pub first_id: Option<String>,
#[serde(default)]
pub last_id: Option<String>,
pub has_more: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningEventPage {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningCheckpoint {
pub id: String,
pub object: String,
pub created_at: u64,
pub fine_tuned_model_checkpoint: String,
pub fine_tuning_job_id: String,
pub step_number: u64,
#[serde(default)]
pub metrics: BTreeMap<String, Value>,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPage {
pub object: String,
#[serde(default)]
pub data: Vec<FineTuningCheckpoint>,
#[serde(default)]
pub first_id: Option<String>,
#[serde(default)]
pub last_id: Option<String>,
pub has_more: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningCheckpointPage {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPermission {
pub id: String,
pub object: String,
pub created_at: u64,
pub project_id: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPermissionPage {
pub object: String,
#[serde(default)]
pub data: Vec<FineTuningCheckpointPermission>,
#[serde(default)]
pub first_id: Option<String>,
#[serde(default)]
pub last_id: Option<String>,
pub has_more: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningCheckpointPermissionPage {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPermissionDeletion {
pub id: String,
pub object: String,
pub deleted: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl FineTuningCheckpointPermissionDeletion {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Default,
{
Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default())
}