| 392 | #[instrument(skip(self, py), fields(batch_size = prompts.len()))] |
| 393 | #[pyo3(signature = (prompts, max_tokens=None, temperature=None, max_concurrency=None))] |
| 394 | fn complete_batch<'a>( |
| 395 | &self, |
| 396 | prompts: Vec<String>, |
| 397 | max_tokens: Option<i64>, |
| 398 | temperature: Option<f64>, |
| 399 | max_concurrency: Option<usize>, |
| 400 | py: Python<'a>, |
| 401 | ) -> PyResult<Bound<'a, PyAny>> { |
| 402 | // Validate batch size |
| 403 | if prompts.is_empty() { |
| 404 | return Err(validation_error( |
| 405 | "prompts", |
| 406 | None, |
| 407 | "Prompts list cannot be empty", |
| 408 | )); |
| 409 | } |
| 410 | |
| 411 | if prompts.len() > 1000 { |
| 412 | return Err(validation_error( |
| 413 | "prompts", |
| 414 | Some(&prompts.len().to_string()), |
| 415 | "Batch size cannot exceed 1000", |
| 416 | )); |
| 417 | } |
| 418 | |
| 419 | // Validate max_tokens |
| 420 | let validated_max_tokens = if let Some(tokens) = max_tokens { |
| 421 | if tokens <= 0 { |
| 422 | return Err(validation_error( |
| 423 | "max_tokens", |
| 424 | Some(&tokens.to_string()), |
| 425 | "max_tokens must be greater than 0", |
| 426 | )); |
| 427 | } |
| 428 | if tokens > u32::MAX as i64 { |
| 429 | return Err(validation_error( |
| 430 | "max_tokens", |
| 431 | Some(&tokens.to_string()), |
| 432 | "max_tokens is too large", |
| 433 | )); |
| 434 | } |
| 435 | Some(tokens as u32) |
| 436 | } else { |
| 437 | None |
| 438 | }; |
| 439 | |
| 440 | // Validate temperature |
| 441 | let validated_temperature = if let Some(temp) = temperature { |
| 442 | if !(0.0..=2.0).contains(&temp) { |
| 443 | return Err(validation_error( |
| 444 | "temperature", |
| 445 | Some(&temp.to_string()), |
| 446 | "temperature must be between 0.0 and 2.0", |
| 447 | )); |
| 448 | } |
| 449 | Some(temp as f32) |
| 450 | } else { |
| 451 | None |