1use crate::error::LingerError;
2use crate::RequestId;
3use serde::{Deserialize, Deserializer, Serialize};
4use serde_json::Value;
5use std::collections::BTreeMap;
6
7#[derive(Clone, Debug, Serialize, PartialEq)]
10#[non_exhaustive]
11pub struct CreateFineTuningJobRequest {
12 pub model: String,
15 pub training_file: String,
18 #[serde(skip_serializing_if = "Option::is_none")]
21 pub validation_file: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
25 pub suffix: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
29 pub seed: Option<u64>,
30 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
33 pub metadata: BTreeMap<String, String>,
34 #[serde(flatten)]
37 pub extra: BTreeMap<String, Value>,
38}
39
40impl CreateFineTuningJobRequest {
41 pub fn builder() -> CreateFineTuningJobRequestBuilder {
44 CreateFineTuningJobRequestBuilder::default()
45 }
46}
47
48#[derive(Clone, Debug, Default)]
51#[non_exhaustive]
52pub struct CreateFineTuningJobRequestBuilder {
53 model: Option<String>,
54 training_file: Option<String>,
55 validation_file: Option<String>,
56 suffix: Option<String>,
57 seed: Option<u64>,
58 metadata: BTreeMap<String, String>,
59 extra: BTreeMap<String, Value>,
60}
61
62impl CreateFineTuningJobRequestBuilder {
63 pub fn model(mut self, model: impl Into<String>) -> Self {
66 self.model = Some(model.into());
67 self
68 }
69
70 pub fn training_file(mut self, training_file: impl Into<String>) -> Self {
73 self.training_file = Some(training_file.into());
74 self
75 }
76
77 pub fn validation_file(mut self, validation_file: impl Into<String>) -> Self {
80 self.validation_file = Some(validation_file.into());
81 self
82 }
83
84 pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
87 self.suffix = Some(suffix.into());
88 self
89 }
90
91 pub fn seed(mut self, seed: u64) -> Self {
94 self.seed = Some(seed);
95 self
96 }
97
98 pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
101 self.metadata.insert(key.into(), value.into());
102 self
103 }
104
105 pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
108 self.extra.insert(name.into(), value);
109 self
110 }
111
112 pub fn build(self) -> Result<CreateFineTuningJobRequest, LingerError> {
115 let model = self
116 .model
117 .filter(|value| !value.trim().is_empty())
118 .ok_or_else(|| LingerError::invalid_config("model is required"))?;
119 let training_file = self
120 .training_file
121 .filter(|value| !value.trim().is_empty())
122 .ok_or_else(|| LingerError::invalid_config("training_file is required"))?;
123 if self
124 .validation_file
125 .as_ref()
126 .is_some_and(|value| value.trim().is_empty())
127 {
128 return Err(LingerError::invalid_config(
129 "validation_file must not be empty",
130 ));
131 }
132 if self
133 .suffix
134 .as_ref()
135 .is_some_and(|value| value.trim().is_empty())
136 {
137 return Err(LingerError::invalid_config("suffix must not be empty"));
138 }
139 if self
140 .metadata
141 .iter()
142 .any(|(key, value)| key.trim().is_empty() || value.is_empty())
143 {
144 return Err(LingerError::invalid_config(
145 "metadata keys and values must not be empty",
146 ));
147 }
148 Ok(CreateFineTuningJobRequest {
149 model,
150 training_file,
151 validation_file: self.validation_file,
152 suffix: self.suffix,
153 seed: self.seed,
154 metadata: self.metadata,
155 extra: self.extra,
156 })
157 }
158}
159
160#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
163#[non_exhaustive]
164pub struct CreateFineTuningCheckpointPermissionRequest {
165 pub project_ids: Vec<String>,
168}
169
170impl CreateFineTuningCheckpointPermissionRequest {
171 pub fn new<I, T>(project_ids: I) -> Result<Self, LingerError>
174 where
175 I: IntoIterator<Item = T>,
176 T: Into<String>,
177 {
178 let project_ids = project_ids.into_iter().map(Into::into).collect::<Vec<_>>();
179 if project_ids.is_empty() || project_ids.iter().any(|value| value.trim().is_empty()) {
180 return Err(LingerError::invalid_config("project_ids is required"));
181 }
182 Ok(Self { project_ids })
183 }
184}
185
186#[derive(Clone, Debug, Serialize, PartialEq)]
189#[non_exhaustive]
190pub struct ValidateFineTuningGraderRequest {
191 pub grader: Value,
194}
195
196impl ValidateFineTuningGraderRequest {
197 pub fn builder() -> ValidateFineTuningGraderRequestBuilder {
200 ValidateFineTuningGraderRequestBuilder::default()
201 }
202}
203
204#[derive(Clone, Debug, Default)]
207#[non_exhaustive]
208pub struct ValidateFineTuningGraderRequestBuilder {
209 grader: Option<Value>,
210}
211
212impl ValidateFineTuningGraderRequestBuilder {
213 pub fn grader(mut self, grader: Value) -> Self {
216 self.grader = Some(grader);
217 self
218 }
219
220 pub fn build(self) -> Result<ValidateFineTuningGraderRequest, LingerError> {
223 let grader = self
224 .grader
225 .filter(|value| !value.is_null())
226 .ok_or_else(|| LingerError::invalid_config("grader is required"))?;
227 Ok(ValidateFineTuningGraderRequest { grader })
228 }
229}
230
231#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
234#[non_exhaustive]
235pub struct FineTuningGraderValidation {
236 pub grader: Value,
239 #[serde(skip)]
242 request_id: Option<RequestId>,
243}
244
245impl FineTuningGraderValidation {
246 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
247 self.request_id = request_id;
248 self
249 }
250
251 pub fn request_id(&self) -> Option<&RequestId> {
254 self.request_id.as_ref()
255 }
256}
257
258#[derive(Clone, Debug, Serialize, PartialEq)]
261#[non_exhaustive]
262pub struct RunFineTuningGraderRequest {
263 pub grader: Value,
266 #[serde(skip_serializing_if = "Option::is_none")]
269 pub item: Option<Value>,
270 pub model_sample: String,
273}
274
275impl RunFineTuningGraderRequest {
276 pub fn builder() -> RunFineTuningGraderRequestBuilder {
279 RunFineTuningGraderRequestBuilder::default()
280 }
281}
282
283#[derive(Clone, Debug, Default)]
286#[non_exhaustive]
287pub struct RunFineTuningGraderRequestBuilder {
288 grader: Option<Value>,
289 item: Option<Value>,
290 model_sample: Option<String>,
291}
292
293impl RunFineTuningGraderRequestBuilder {
294 pub fn grader(mut self, grader: Value) -> Self {
297 self.grader = Some(grader);
298 self
299 }
300
301 pub fn item(mut self, item: Value) -> Self {
304 self.item = Some(item);
305 self
306 }
307
308 pub fn model_sample(mut self, model_sample: impl Into<String>) -> Self {
311 self.model_sample = Some(model_sample.into());
312 self
313 }
314
315 pub fn build(self) -> Result<RunFineTuningGraderRequest, LingerError> {
318 let grader = self
319 .grader
320 .filter(|value| !value.is_null())
321 .ok_or_else(|| LingerError::invalid_config("grader is required"))?;
322 let model_sample = self
323 .model_sample
324 .filter(|value| !value.trim().is_empty())
325 .ok_or_else(|| LingerError::invalid_config("model_sample is required"))?;
326 Ok(RunFineTuningGraderRequest {
327 grader,
328 item: self.item,
329 model_sample,
330 })
331 }
332}
333
334#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
337#[non_exhaustive]
338pub struct FineTuningGraderRun {
339 pub reward: f64,
342 pub metadata: Value,
345 pub sub_rewards: Value,
348 pub model_grader_token_usage_per_model: Value,
351 #[serde(skip)]
354 request_id: Option<RequestId>,
355}
356
357impl FineTuningGraderRun {
358 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
359 self.request_id = request_id;
360 self
361 }
362
363 pub fn request_id(&self) -> Option<&RequestId> {
366 self.request_id.as_ref()
367 }
368}
369
370#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
373#[non_exhaustive]
374pub struct FineTuningJob {
375 pub id: String,
378 pub object: String,
381 pub model: String,
384 pub created_at: u64,
387 #[serde(default)]
390 pub fine_tuned_model: Option<String>,
391 #[serde(default)]
394 pub organization_id: Option<String>,
395 #[serde(default)]
398 pub result_files: Vec<String>,
399 pub status: String,
402 #[serde(default)]
405 pub validation_file: Option<String>,
406 pub training_file: String,
409 #[serde(default)]
412 pub hyperparameters: Value,
413 #[serde(default)]
416 pub trained_tokens: Option<u64>,
417 #[serde(default)]
420 pub error: Option<Value>,
421 #[serde(default)]
424 pub estimated_finish: Option<u64>,
425 #[serde(default)]
428 pub integrations: Vec<Value>,
429 #[serde(default)]
432 pub seed: Option<u64>,
433 #[serde(default, deserialize_with = "deserialize_null_default")]
436 pub metadata: BTreeMap<String, String>,
437 #[serde(default)]
440 pub method: Value,
441 #[serde(flatten)]
444 pub extra: BTreeMap<String, Value>,
445 #[serde(skip)]
448 request_id: Option<RequestId>,
449}
450
451impl FineTuningJob {
452 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
453 self.request_id = request_id;
454 self
455 }
456
457 pub fn request_id(&self) -> Option<&RequestId> {
460 self.request_id.as_ref()
461 }
462}
463
464#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
467#[non_exhaustive]
468pub struct FineTuningJobPage {
469 pub object: String,
472 #[serde(default)]
475 pub data: Vec<FineTuningJob>,
476 #[serde(default)]
479 pub first_id: Option<String>,
480 #[serde(default)]
483 pub last_id: Option<String>,
484 pub has_more: bool,
487 #[serde(skip)]
490 request_id: Option<RequestId>,
491}
492
493impl FineTuningJobPage {
494 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
495 self.request_id = request_id;
496 self
497 }
498
499 pub fn request_id(&self) -> Option<&RequestId> {
502 self.request_id.as_ref()
503 }
504}
505
506#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
509#[non_exhaustive]
510pub struct FineTuningEvent {
511 pub id: String,
514 pub object: String,
517 pub created_at: u64,
520 pub level: String,
523 pub message: String,
526 #[serde(default)]
529 pub r#type: Option<String>,
530 #[serde(flatten)]
533 pub extra: BTreeMap<String, Value>,
534}
535
536#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
539#[non_exhaustive]
540pub struct FineTuningEventPage {
541 pub object: String,
544 #[serde(default)]
547 pub data: Vec<FineTuningEvent>,
548 #[serde(default)]
551 pub first_id: Option<String>,
552 #[serde(default)]
555 pub last_id: Option<String>,
556 pub has_more: bool,
559 #[serde(skip)]
562 request_id: Option<RequestId>,
563}
564
565impl FineTuningEventPage {
566 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
567 self.request_id = request_id;
568 self
569 }
570
571 pub fn request_id(&self) -> Option<&RequestId> {
574 self.request_id.as_ref()
575 }
576}
577
578#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
581#[non_exhaustive]
582pub struct FineTuningCheckpoint {
583 pub id: String,
586 pub object: String,
589 pub created_at: u64,
592 pub fine_tuned_model_checkpoint: String,
595 pub fine_tuning_job_id: String,
598 pub step_number: u64,
601 #[serde(default)]
604 pub metrics: BTreeMap<String, Value>,
605 #[serde(flatten)]
608 pub extra: BTreeMap<String, Value>,
609}
610
611#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
614#[non_exhaustive]
615pub struct FineTuningCheckpointPage {
616 pub object: String,
619 #[serde(default)]
622 pub data: Vec<FineTuningCheckpoint>,
623 #[serde(default)]
626 pub first_id: Option<String>,
627 #[serde(default)]
630 pub last_id: Option<String>,
631 pub has_more: bool,
634 #[serde(skip)]
637 request_id: Option<RequestId>,
638}
639
640impl FineTuningCheckpointPage {
641 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
642 self.request_id = request_id;
643 self
644 }
645
646 pub fn request_id(&self) -> Option<&RequestId> {
649 self.request_id.as_ref()
650 }
651}
652
653#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
656#[non_exhaustive]
657pub struct FineTuningCheckpointPermission {
658 pub id: String,
661 pub object: String,
664 pub created_at: u64,
667 pub project_id: String,
670}
671
672#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
675#[non_exhaustive]
676pub struct FineTuningCheckpointPermissionPage {
677 pub object: String,
680 #[serde(default)]
683 pub data: Vec<FineTuningCheckpointPermission>,
684 #[serde(default)]
687 pub first_id: Option<String>,
688 #[serde(default)]
691 pub last_id: Option<String>,
692 pub has_more: bool,
695 #[serde(skip)]
698 request_id: Option<RequestId>,
699}
700
701impl FineTuningCheckpointPermissionPage {
702 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
703 self.request_id = request_id;
704 self
705 }
706
707 pub fn request_id(&self) -> Option<&RequestId> {
710 self.request_id.as_ref()
711 }
712}
713
714#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
717#[non_exhaustive]
718pub struct FineTuningCheckpointPermissionDeletion {
719 pub id: String,
722 pub object: String,
725 pub deleted: bool,
728 #[serde(skip)]
731 request_id: Option<RequestId>,
732}
733
734impl FineTuningCheckpointPermissionDeletion {
735 pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
736 self.request_id = request_id;
737 self
738 }
739
740 pub fn request_id(&self) -> Option<&RequestId> {
743 self.request_id.as_ref()
744 }
745}
746
747fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
748where
749 D: Deserializer<'de>,
750 T: Deserialize<'de> + Default,
751{
752 Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default())
753}