From 462b58c1a8632f7e4985ecdfd81d07b1fc8de01b Mon Sep 17 00:00:00 2001 From: jinlong Date: Wed, 7 May 2025 16:15:34 +0800 Subject: [PATCH] feat(serialization): add two-decimal precision serialization for float fields Added a new `serialize_f32_two_decimals` helper function to serialize Option fields with exactly two decimal places. Applied this serialization to all float fields in ChatBody (temperature, top_p, n, presence_penalty, frequency_penalty) to ensure consistent numeric formatting in API requests. Also improved error handling in requests.rs by: 1. Adding fallback for JSON parsing errors 2. Enhancing error messages with status codes 3. Making error messages more descriptive Signed-off-by: jinlong --- src/apis/chat.rs | 21 ++++++++++++++++----- src/requests.rs | 7 ++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/apis/chat.rs b/src/apis/chat.rs index e4d1e6e..ec7bfcd 100644 --- a/src/apis/chat.rs +++ b/src/apis/chat.rs @@ -7,7 +7,18 @@ use std::collections::HashMap; use crate::requests::Requests; use crate::*; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; + +fn serialize_f32_two_decimals(value: &Option, serializer: S) -> Result +where + S: Serializer, +{ + match value { + Some(v) => serializer.serialize_f64((*v as f64 * 100.0).round() / 100.0), + None => serializer.serialize_none(), + } +} + use super::{completions::Completion, CHAT_COMPLETION_CREATE}; @@ -23,14 +34,14 @@ pub struct ChatBody { /// while lower values like 0.2 will make it more focused and deterministic. /// We generally recommend altering this or top_p but not both. /// Defaults to 1 - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "serialize_f32_two_decimals")] pub temperature: Option, /// An alternative to sampling with temperature, called nucleus sampling, /// where the model considers the results of the tokens with top_p probability mass. /// So 0.1 means only the tokens comprising the top 10% probability mass are considered. /// We generally recommend altering this or temperature but not both. /// Defaults to 1 - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "serialize_f32_two_decimals")] pub top_p: Option, /// How many chat completion choices to generate for each input message. /// Defaults to 1 @@ -55,13 +66,13 @@ pub struct ChatBody { /// Positive values penalize new tokens based on whether they appear in the text so far, /// increasing the model's likelihood to talk about new topics. /// Defaults to 0 - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "serialize_f32_two_decimals")] pub presence_penalty: Option, /// Number between -2.0 and 2.0. /// Positive values penalize new tokens based on their existing frequency in the text so far, /// decreasing the model's likelihood to repeat the same line verbatim. /// Defaults to 0 - #[serde(skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none", serialize_with = "serialize_f32_two_decimals")] pub frequency_penalty: Option, /// Modify the likelihood of specified tokens appearing in the completion. /// Accepts a json object that maps tokens (specified by their token ID in the tokenizer) diff --git a/src/requests.rs b/src/requests.rs index 048edc6..50a4474 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -70,7 +70,12 @@ fn deal_response(response: Result, sub_url: &str) - }, Err(err) => match err { ureq::Error::Status(status, response) => { - let error_msg = response.into_json::().unwrap(); + let mut error_msg = response + .into_json::() + .unwrap_or_else(|x| serde_json::Value::String(x.to_string())); + if let serde_json::Value::String(ref mut s) = error_msg { + *s = format!("status: {}, msg: {}", status, s); + } error!("<== ❌\n\tError api: {sub_url}, status: {status}, error: {error_msg}"); return Err(Error::ApiError(format!("{error_msg}"))); },