fix: more
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -709,6 +709,9 @@ name = "ecow"
|
|||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dca6141d10838e13f9b166c190254a3f9b5d8379521f9b7510810061cef17a4"
|
checksum = "2dca6141d10838e13f9b166c190254a3f9b5d8379521f9b7510810061cef17a4"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ async-channel = "2.5.0"
|
|||||||
axum = { version = "0.8.9", features = ["http2", "macros", "multipart", "ws"] }
|
axum = { version = "0.8.9", features = ["http2", "macros", "multipart", "ws"] }
|
||||||
axum-extra = { version = "0.12.6", features = ["typed-header", "typed-routing"] }
|
axum-extra = { version = "0.12.6", features = ["typed-header", "typed-routing"] }
|
||||||
clap = { version = "4.6.7", features = ["derive", "env"] }
|
clap = { version = "4.6.7", features = ["derive", "env"] }
|
||||||
ecow = "0.3.1"
|
ecow = { version = "0.3.1", features = ["serde"] }
|
||||||
enum-map = { version = "3.1.0", features = ["serde"] }
|
enum-map = { version = "3.1.0", features = ["serde"] }
|
||||||
enumset = { version = "1.1.14", features = ["serde"] }
|
enumset = { version = "1.1.14", features = ["serde"] }
|
||||||
futures = "0.3.34"
|
futures = "0.3.34"
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ mod server;
|
|||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct AppArgs {
|
struct AppArgs {
|
||||||
#[arg(long, env)]
|
#[arg(long, env, default_value_t = [127, 0, 0, 1].into())]
|
||||||
ip: IpAddr,
|
ip: IpAddr,
|
||||||
|
|
||||||
#[arg(long, env)]
|
#[arg(long, env, default_value_t = 3126)]
|
||||||
port: u16,
|
port: u16,
|
||||||
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
@@ -106,6 +106,7 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
join!(stream_responses, async move {
|
join!(stream_responses, async move {
|
||||||
|
tracing::info!(?addr, "listening");
|
||||||
axum::serve(listener, app).await.expect("TODO");
|
axum::serve(listener, app).await.expect("TODO");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ pub struct AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, TypedPath)]
|
#[derive(Deserialize, TypedPath)]
|
||||||
#[typed_path("/chat/completions")]
|
#[typed_path("/v1/chat/completions")]
|
||||||
struct ChatCompletionsPath;
|
struct V1ChatCompletionsPath;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Provider {
|
enum Provider {
|
||||||
@@ -59,6 +59,7 @@ enum Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
enum Shortcut {
|
enum Shortcut {
|
||||||
XS,
|
XS,
|
||||||
S,
|
S,
|
||||||
@@ -142,8 +143,8 @@ impl Shortcut {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn take_random_by_swapping<T>(mut vec1: Vec1<T>, mut rng: impl Rng) -> (T, Option<Vec1<T>>) {
|
fn take_random_by_swapping<T>(mut vec1: Vec1<T>, mut rng: impl Rng) -> (T, Option<Vec1<T>>) {
|
||||||
let end = vec1.len().get();
|
let end = vec1.len().get() - 1;
|
||||||
let index = rng.random_range(0..end);
|
let index = rng.random_range(0..=end);
|
||||||
|
|
||||||
vec1.swap(index, end);
|
vec1.swap(index, end);
|
||||||
let (body, element) = vec1.into_rtail_and_head();
|
let (body, element) = vec1.into_rtail_and_head();
|
||||||
@@ -206,7 +207,7 @@ impl IntoResponse for ChatCompletionError {
|
|||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
#[tracing::instrument(skip(state, request))]
|
#[tracing::instrument(skip(state, request))]
|
||||||
async fn create_chat_completion(
|
async fn create_chat_completion(
|
||||||
_: ChatCompletionsPath,
|
_: V1ChatCompletionsPath,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(request): Json<openai::chat::completion::CreateChatCompletionRequest<Shortcut>>,
|
Json(request): Json<openai::chat::completion::CreateChatCompletionRequest<Shortcut>>,
|
||||||
) -> Result<ChatCompletionResponse, ChatCompletionError> {
|
) -> Result<ChatCompletionResponse, ChatCompletionError> {
|
||||||
@@ -293,6 +294,8 @@ async fn create_chat_completion(
|
|||||||
model_upstreams.push_back((model.clone(), upstreams));
|
model_upstreams.push_back((model.clone(), upstreams));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracing::info!(?model, ?upstream);
|
||||||
|
|
||||||
let openai::chat::completion::CreateChatCompletionRequest {
|
let openai::chat::completion::CreateChatCompletionRequest {
|
||||||
model: _shortcut,
|
model: _shortcut,
|
||||||
messages,
|
messages,
|
||||||
@@ -375,18 +378,25 @@ async fn create_chat_completion(
|
|||||||
|
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
let mut upstream_request = client.post({
|
let mut upstream_request = client
|
||||||
let mut url = upstream.base_url.clone();
|
.post({
|
||||||
|
let mut url = upstream.base_url;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut segments = url.path_segments_mut().expect("TODO");
|
let mut path_segments = url.path_segments_mut().expect("TODO");
|
||||||
|
|
||||||
segments.push("chat");
|
let s = V1ChatCompletionsPath.to_string();
|
||||||
segments.push("completions");
|
let s = s.strip_prefix("/").unwrap_or(&s);
|
||||||
|
let s = s.strip_suffix("/").unwrap_or(&s);
|
||||||
|
|
||||||
|
path_segments.extend(s.split("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracing::info!(?url);
|
||||||
|
|
||||||
url
|
url
|
||||||
});
|
})
|
||||||
|
.json(&request);
|
||||||
|
|
||||||
if let Some(api_key) = upstream.api_key {
|
if let Some(api_key) = upstream.api_key {
|
||||||
let authorization =
|
let authorization =
|
||||||
@@ -410,12 +420,13 @@ async fn create_chat_completion(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let upstream_response = match upstream_response.error_for_status() {
|
if let Err(upstream_error) = upstream_response.error_for_status_ref() {
|
||||||
Ok(upstream_response) => upstream_response,
|
|
||||||
Err(upstream_error) => {
|
|
||||||
tracing::error!(?upstream_error);
|
tracing::error!(?upstream_error);
|
||||||
|
match upstream_response.text().await {
|
||||||
|
Ok(body) => tracing::error!(?body),
|
||||||
|
Err(body_error) => tracing::error!(?body_error),
|
||||||
|
};
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if request.stream.unwrap_or(false) {
|
if request.stream.unwrap_or(false) {
|
||||||
|
|||||||
Reference in New Issue
Block a user