linger-openai-sdk 0.1.1

Rust-native async SDK for OpenAI APIs with typed requests, streaming, uploads, retries, and pluggable transports.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
use crate::error::LingerError;
use crate::RequestId;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;

/// EN: Request body for `POST /v1/fine_tuning/jobs`.
/// 中文:`POST /v1/fine_tuning/jobs` 的请求体。
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct CreateFineTuningJobRequest {
    /// EN: Base model to fine-tune.
    /// 中文:要微调的基础模型。
    pub model: String,
    /// EN: Uploaded training file id.
    /// 中文:已上传的训练文件 ID。
    pub training_file: String,
    /// EN: Optional uploaded validation file id.
    /// 中文:可选的已上传验证文件 ID。
    #[serde(skip_serializing_if = "Option::is_none")]
    pub validation_file: Option<String>,
    /// EN: Optional suffix for the fine-tuned model name.
    /// 中文:微调后模型名称的可选后缀。
    #[serde(skip_serializing_if = "Option::is_none")]
    pub suffix: Option<String>,
    /// EN: Optional seed for reproducibility.
    /// 中文:用于可复现性的可选 seed。
    #[serde(skip_serializing_if = "Option::is_none")]
    pub seed: Option<u64>,
    /// EN: Optional metadata attached to the job.
    /// 中文:附加到任务的可选元数据。
    #[serde(skip_serializing_if = "BTreeMap::is_empty")]
    pub metadata: BTreeMap<String, String>,
    /// EN: Forward-compatible optional fields not yet covered by handwritten types.
    /// 中文:手写类型尚未覆盖的前向兼容可选字段。
    #[serde(flatten)]
    pub extra: BTreeMap<String, Value>,
}

impl CreateFineTuningJobRequest {
    /// EN: Starts building a fine-tuning job request.
    /// 中文:开始构建 fine-tuning job 请求。
    pub fn builder() -> CreateFineTuningJobRequestBuilder {
        CreateFineTuningJobRequestBuilder::default()
    }
}

/// EN: Builder for create-fine-tuning-job requests.
/// 中文:创建 fine-tuning job 请求的构建器。
#[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 {
    /// EN: Sets the base model id.
    /// 中文:设置基础模型 ID。
    pub fn model(mut self, model: impl Into<String>) -> Self {
        self.model = Some(model.into());
        self
    }

    /// EN: Sets the uploaded training file id.
    /// 中文:设置已上传的训练文件 ID。
    pub fn training_file(mut self, training_file: impl Into<String>) -> Self {
        self.training_file = Some(training_file.into());
        self
    }

    /// EN: Sets the optional validation file id.
    /// 中文:设置可选的验证文件 ID。
    pub fn validation_file(mut self, validation_file: impl Into<String>) -> Self {
        self.validation_file = Some(validation_file.into());
        self
    }

    /// EN: Sets the optional model suffix.
    /// 中文:设置可选的模型后缀。
    pub fn suffix(mut self, suffix: impl Into<String>) -> Self {
        self.suffix = Some(suffix.into());
        self
    }

    /// EN: Sets the optional reproducibility seed.
    /// 中文:设置可选的可复现 seed。
    pub fn seed(mut self, seed: u64) -> Self {
        self.seed = Some(seed);
        self
    }

    /// EN: Adds a metadata entry.
    /// 中文:添加一项元数据。
    pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.metadata.insert(key.into(), value.into());
        self
    }

    /// EN: Adds a forward-compatible JSON field.
    /// 中文:添加前向兼容的 JSON 字段。
    pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
        self.extra.insert(name.into(), value);
        self
    }

    /// EN: Builds and validates the request.
    /// 中文:构建并校验请求。
    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,
        })
    }
}

/// EN: Request body for checkpoint permission creation.
/// 中文:创建 checkpoint permission 的请求体。
#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct CreateFineTuningCheckpointPermissionRequest {
    /// EN: Project ids to grant access to.
    /// 中文:要授予访问权限的项目 ID。
    pub project_ids: Vec<String>,
}

impl CreateFineTuningCheckpointPermissionRequest {
    /// EN: Creates and validates a checkpoint-permission request.
    /// 中文:创建并校验 checkpoint permission 请求。
    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 })
    }
}

/// EN: Request body for `POST /v1/fine_tuning/alpha/graders/validate`.
/// 中文:`POST /v1/fine_tuning/alpha/graders/validate` 的请求体。
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct ValidateFineTuningGraderRequest {
    /// EN: Grader definition to validate.
    /// 中文:要校验的 grader 定义。
    pub grader: Value,
}

impl ValidateFineTuningGraderRequest {
    /// EN: Starts building a grader validation request.
    /// 中文:开始构建 grader 校验请求。
    pub fn builder() -> ValidateFineTuningGraderRequestBuilder {
        ValidateFineTuningGraderRequestBuilder::default()
    }
}

/// EN: Builder for grader validation requests.
/// 中文:grader 校验请求的构建器。
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct ValidateFineTuningGraderRequestBuilder {
    grader: Option<Value>,
}

impl ValidateFineTuningGraderRequestBuilder {
    /// EN: Sets the grader definition to validate.
    /// 中文:设置要校验的 grader 定义。
    pub fn grader(mut self, grader: Value) -> Self {
        self.grader = Some(grader);
        self
    }

    /// EN: Builds and validates the request.
    /// 中文:构建并校验请求。
    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 })
    }
}

/// EN: Response returned after validating a fine-tuning grader.
/// 中文:校验 fine-tuning grader 后返回的响应。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningGraderValidation {
    /// EN: Validated grader definition.
    /// 中文:已校验的 grader 定义。
    pub grader: Value,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: Request body for `POST /v1/fine_tuning/alpha/graders/run`.
/// 中文:`POST /v1/fine_tuning/alpha/graders/run` 的请求体。
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct RunFineTuningGraderRequest {
    /// EN: Grader definition to run.
    /// 中文:要运行的 grader 定义。
    pub grader: Value,
    /// EN: Optional dataset item used to populate the `item` namespace.
    /// 中文:可选的数据集条目,用于填充 `item` 命名空间。
    #[serde(skip_serializing_if = "Option::is_none")]
    pub item: Option<Value>,
    /// EN: Model sample to evaluate.
    /// 中文:要评估的模型样本。
    pub model_sample: String,
}

impl RunFineTuningGraderRequest {
    /// EN: Starts building a grader run request.
    /// 中文:开始构建 grader run 请求。
    pub fn builder() -> RunFineTuningGraderRequestBuilder {
        RunFineTuningGraderRequestBuilder::default()
    }
}

/// EN: Builder for grader run requests.
/// 中文:grader run 请求的构建器。
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct RunFineTuningGraderRequestBuilder {
    grader: Option<Value>,
    item: Option<Value>,
    model_sample: Option<String>,
}

impl RunFineTuningGraderRequestBuilder {
    /// EN: Sets the grader definition to run.
    /// 中文:设置要运行的 grader 定义。
    pub fn grader(mut self, grader: Value) -> Self {
        self.grader = Some(grader);
        self
    }

    /// EN: Sets the optional dataset item.
    /// 中文:设置可选的数据集条目。
    pub fn item(mut self, item: Value) -> Self {
        self.item = Some(item);
        self
    }

    /// EN: Sets the model sample to evaluate.
    /// 中文:设置要评估的模型样本。
    pub fn model_sample(mut self, model_sample: impl Into<String>) -> Self {
        self.model_sample = Some(model_sample.into());
        self
    }

    /// EN: Builds and validates the request.
    /// 中文:构建并校验请求。
    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,
        })
    }
}

/// EN: Response returned after running a fine-tuning grader.
/// 中文:运行 fine-tuning grader 后返回的响应。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningGraderRun {
    /// EN: Numeric reward produced by the grader.
    /// 中文:grader 产生的数值 reward。
    pub reward: f64,
    /// EN: Grader execution metadata.
    /// 中文:grader 执行元数据。
    pub metadata: Value,
    /// EN: Sub-rewards returned by composite graders.
    /// 中文:组合 grader 返回的子 reward。
    pub sub_rewards: Value,
    /// EN: Model grader token usage grouped by model.
    /// 中文:按模型分组的 model grader token 用量。
    pub model_grader_token_usage_per_model: Value,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: Fine-tuning job object returned by the API.
/// 中文:API 返回的 fine-tuning job 对象。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningJob {
    /// EN: Fine-tuning job id.
    /// 中文:fine-tuning job ID。
    pub id: String,
    /// EN: API object type.
    /// 中文:API 对象类型。
    pub object: String,
    /// EN: Base model.
    /// 中文:基础模型。
    pub model: String,
    /// EN: Unix timestamp for creation.
    /// 中文:创建时间的 Unix 时间戳。
    pub created_at: u64,
    /// EN: Fine-tuned model id, when available.
    /// 中文:可用时的微调后模型 ID。
    #[serde(default)]
    pub fine_tuned_model: Option<String>,
    /// EN: Organization id that owns the job.
    /// 中文:拥有该任务的组织 ID。
    #[serde(default)]
    pub organization_id: Option<String>,
    /// EN: Result file ids.
    /// 中文:结果文件 ID。
    #[serde(default)]
    pub result_files: Vec<String>,
    /// EN: Current job status.
    /// 中文:当前任务状态。
    pub status: String,
    /// EN: Validation file id, when present.
    /// 中文:验证文件 ID,如存在。
    #[serde(default)]
    pub validation_file: Option<String>,
    /// EN: Training file id.
    /// 中文:训练文件 ID。
    pub training_file: String,
    /// EN: Hyperparameter details returned by the API.
    /// 中文:API 返回的超参数详情。
    #[serde(default)]
    pub hyperparameters: Value,
    /// EN: Number of trained tokens, when returned.
    /// 中文:训练 token 数,如响应中存在。
    #[serde(default)]
    pub trained_tokens: Option<u64>,
    /// EN: Job error details, when returned.
    /// 中文:任务错误详情,如响应中存在。
    #[serde(default)]
    pub error: Option<Value>,
    /// EN: Estimated finish timestamp, when returned.
    /// 中文:预计完成时间戳,如响应中存在。
    #[serde(default)]
    pub estimated_finish: Option<u64>,
    /// EN: Integration descriptors returned by the API.
    /// 中文:API 返回的集成描述。
    #[serde(default)]
    pub integrations: Vec<Value>,
    /// EN: Seed used for the job, when returned.
    /// 中文:任务使用的 seed,如响应中存在。
    #[serde(default)]
    pub seed: Option<u64>,
    /// EN: Metadata returned with this job.
    /// 中文:此任务返回的元数据。
    #[serde(default, deserialize_with = "deserialize_null_default")]
    pub metadata: BTreeMap<String, String>,
    /// EN: Fine-tuning method details.
    /// 中文:fine-tuning 方法详情。
    #[serde(default)]
    pub method: Value,
    /// EN: Additional fields preserved for forward compatibility.
    /// 中文:为前向兼容保留的额外字段。
    #[serde(flatten)]
    pub extra: BTreeMap<String, Value>,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: Paginated fine-tuning job list.
/// 中文:分页 fine-tuning job 列表。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningJobPage {
    /// EN: API list object type.
    /// 中文:API 列表对象类型。
    pub object: String,
    /// EN: Jobs on this page.
    /// 中文:本页任务。
    #[serde(default)]
    pub data: Vec<FineTuningJob>,
    /// EN: First job id on this page.
    /// 中文:本页第一个任务 ID。
    #[serde(default)]
    pub first_id: Option<String>,
    /// EN: Last job id on this page.
    /// 中文:本页最后一个任务 ID。
    #[serde(default)]
    pub last_id: Option<String>,
    /// EN: Whether more jobs are available.
    /// 中文:是否还有更多任务。
    pub has_more: bool,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: Fine-tuning job event.
/// 中文:fine-tuning job 事件。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningEvent {
    /// EN: Event id.
    /// 中文:事件 ID。
    pub id: String,
    /// EN: API object type.
    /// 中文:API 对象类型。
    pub object: String,
    /// EN: Unix timestamp for event creation.
    /// 中文:事件创建时间的 Unix 时间戳。
    pub created_at: u64,
    /// EN: Event level.
    /// 中文:事件级别。
    pub level: String,
    /// EN: Human-readable event message.
    /// 中文:可读事件消息。
    pub message: String,
    /// EN: Event type, when returned.
    /// 中文:事件类型,如响应中存在。
    #[serde(default)]
    pub r#type: Option<String>,
    /// EN: Additional fields preserved for forward compatibility.
    /// 中文:为前向兼容保留的额外字段。
    #[serde(flatten)]
    pub extra: BTreeMap<String, Value>,
}

/// EN: Paginated fine-tuning event list.
/// 中文:分页 fine-tuning 事件列表。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningEventPage {
    /// EN: API list object type.
    /// 中文:API 列表对象类型。
    pub object: String,
    /// EN: Events on this page.
    /// 中文:本页事件。
    #[serde(default)]
    pub data: Vec<FineTuningEvent>,
    /// EN: First event id on this page.
    /// 中文:本页第一个事件 ID。
    #[serde(default)]
    pub first_id: Option<String>,
    /// EN: Last event id on this page.
    /// 中文:本页最后一个事件 ID。
    #[serde(default)]
    pub last_id: Option<String>,
    /// EN: Whether more events are available.
    /// 中文:是否还有更多事件。
    pub has_more: bool,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: Fine-tuning job checkpoint.
/// 中文:fine-tuning job 检查点。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningCheckpoint {
    /// EN: Checkpoint id.
    /// 中文:检查点 ID。
    pub id: String,
    /// EN: API object type.
    /// 中文:API 对象类型。
    pub object: String,
    /// EN: Unix timestamp for checkpoint creation.
    /// 中文:检查点创建时间的 Unix 时间戳。
    pub created_at: u64,
    /// EN: Fine-tuned checkpoint model id.
    /// 中文:微调检查点模型 ID。
    pub fine_tuned_model_checkpoint: String,
    /// EN: Fine-tuning job id.
    /// 中文:fine-tuning job ID。
    pub fine_tuning_job_id: String,
    /// EN: Step number for this checkpoint.
    /// 中文:此检查点的步数。
    pub step_number: u64,
    /// EN: Metrics returned for this checkpoint.
    /// 中文:此检查点返回的指标。
    #[serde(default)]
    pub metrics: BTreeMap<String, Value>,
    /// EN: Additional fields preserved for forward compatibility.
    /// 中文:为前向兼容保留的额外字段。
    #[serde(flatten)]
    pub extra: BTreeMap<String, Value>,
}

/// EN: Paginated fine-tuning checkpoint list.
/// 中文:分页 fine-tuning 检查点列表。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPage {
    /// EN: API list object type.
    /// 中文:API 列表对象类型。
    pub object: String,
    /// EN: Checkpoints on this page.
    /// 中文:本页检查点。
    #[serde(default)]
    pub data: Vec<FineTuningCheckpoint>,
    /// EN: First checkpoint id on this page.
    /// 中文:本页第一个检查点 ID。
    #[serde(default)]
    pub first_id: Option<String>,
    /// EN: Last checkpoint id on this page.
    /// 中文:本页最后一个检查点 ID。
    #[serde(default)]
    pub last_id: Option<String>,
    /// EN: Whether more checkpoints are available.
    /// 中文:是否还有更多检查点。
    pub has_more: bool,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: A permission for a fine-tuned model checkpoint.
/// 中文:微调模型 checkpoint 的权限对象。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPermission {
    /// EN: Permission id.
    /// 中文:权限 ID。
    pub id: String,
    /// EN: API object type, normally `checkpoint.permission`.
    /// 中文:API 对象类型,通常为 `checkpoint.permission`。
    pub object: String,
    /// EN: Unix timestamp for permission creation.
    /// 中文:权限创建时间的 Unix 时间戳。
    pub created_at: u64,
    /// EN: Project id this permission grants access to.
    /// 中文:此权限授予访问权限的项目 ID。
    pub project_id: String,
}

/// EN: Paginated checkpoint permission list.
/// 中文:分页 checkpoint permission 列表。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPermissionPage {
    /// EN: API list object type.
    /// 中文:API 列表对象类型。
    pub object: String,
    /// EN: Permissions on this page.
    /// 中文:本页权限。
    #[serde(default)]
    pub data: Vec<FineTuningCheckpointPermission>,
    /// EN: First permission id on this page.
    /// 中文:本页第一个权限 ID。
    #[serde(default)]
    pub first_id: Option<String>,
    /// EN: Last permission id on this page.
    /// 中文:本页最后一个权限 ID。
    #[serde(default)]
    pub last_id: Option<String>,
    /// EN: Whether more permissions are available.
    /// 中文:是否还有更多权限。
    pub has_more: bool,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    pub fn request_id(&self) -> Option<&RequestId> {
        self.request_id.as_ref()
    }
}

/// EN: Deletion result returned for checkpoint permissions.
/// 中文:checkpoint permission 的删除结果。
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct FineTuningCheckpointPermissionDeletion {
    /// EN: Deleted permission id.
    /// 中文:已删除的权限 ID。
    pub id: String,
    /// EN: API object type, normally `checkpoint.permission`.
    /// 中文:API 对象类型,通常为 `checkpoint.permission`。
    pub object: String,
    /// EN: Whether the permission was deleted.
    /// 中文:权限是否已删除。
    pub deleted: bool,
    /// EN: OpenAI request id from response headers.
    /// 中文:响应头中的 OpenAI 请求 ID。
    #[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
    }

    /// EN: Returns the OpenAI request id, when present.
    /// 中文:返回 OpenAI 请求 ID,如存在。
    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())
}