File size: 3,718 Bytes
3c2af29 |
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 |
use super::aiserver::v1::ErrorDetails;
use crate::common::model::{ApiStatus, ErrorResponse as CommonErrorResponse};
use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
use prost::Message as _;
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
pub struct ChatError {
error: ErrorBody,
}
#[derive(Deserialize)]
pub struct ErrorBody {
code: String,
// message: String, always: Error
details: Vec<ErrorDetail>,
}
#[derive(Deserialize)]
pub struct ErrorDetail {
// #[serde(rename = "type")]
// error_type: String, always: aiserver.v1.ErrorDetails
// debug: ErrorDebug,
value: String,
}
// #[derive(Deserialize)]
// pub struct ErrorDebug {
// error: String,
// details: ErrorDetails,
// // #[serde(rename = "isExpected")]
// // is_expected: Option<bool>,
// }
// #[derive(Deserialize)]
// pub struct ErrorDetails {
// title: String,
// detail: String,
// // #[serde(rename = "isRetryable")]
// // is_retryable: Option<bool>,
// }
impl ChatError {
pub fn to_error_response(self) -> ErrorResponse {
if self.error.details.is_empty() {
return ErrorResponse {
status: 500,
code: "unknown".to_string(),
error: None,
};
}
let error_details = self.error.details.first().and_then(|detail| {
STANDARD_NO_PAD
.decode(&detail.value)
.ok()
.map(bytes::Bytes::from)
.and_then(|buf| ErrorDetails::decode(buf).ok())
});
let status = error_details
.as_ref()
.map(|details| details.status_code())
.unwrap_or(500);
ErrorResponse {
status,
code: self.error.code,
error: error_details
.and_then(|details| details.details)
.map(|custom_details| Error {
message: custom_details.title,
details: custom_details.detail,
}),
}
}
}
#[derive(Serialize)]
pub struct ErrorResponse {
pub status: u16,
pub code: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<Error>,
}
#[derive(Serialize)]
pub struct Error {
pub message: String,
pub details: String,
// pub value: String,
}
impl ErrorResponse {
// pub fn to_json(&self) -> serde_json::Value {
// serde_json::to_value(self).unwrap()
// }
pub fn status_code(&self) -> StatusCode {
StatusCode::from_u16(self.status).unwrap()
}
pub fn native_code(&self) -> String {
self.error.as_ref().map_or_else(
|| self.code.replace("_", " "),
|error| error.message.clone(),
)
}
pub fn to_common(self) -> CommonErrorResponse {
CommonErrorResponse {
status: ApiStatus::Error,
code: Some(self.status),
error: self
.error
.as_ref()
.map(|error| error.message.clone())
.or(Some(self.code.clone())),
message: self.error.as_ref().map(|error| error.details.clone()),
}
}
}
pub enum StreamError {
ChatError(ChatError),
DataLengthLessThan5,
EmptyStream,
}
impl std::fmt::Display for StreamError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StreamError::ChatError(error) => write!(f, "{}", error.error.code),
StreamError::DataLengthLessThan5 => write!(f, "data length less than 5"),
StreamError::EmptyStream => write!(f, "empty stream"),
}
}
}
|