From d4546358326cbadabfa2ed650a7db1bd16684b5c Mon Sep 17 00:00:00 2001 From: Jacob Date: Mon, 28 Sep 2026 00:47:52 -0400 Subject: [PATCH] fix: more --- Cargo.lock | 3 +++ Cargo.toml | 2 +- src/main.rs | 5 +++-- src/server.rs | 51 +++++++++++++++++++++++++++++++-------------------- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12d7ead..5e67885 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -709,6 +709,9 @@ name = "ecow" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dca6141d10838e13f9b166c190254a3f9b5d8379521f9b7510810061cef17a4" +dependencies = [ + "serde", +] [[package]] name = "either" diff --git a/Cargo.toml b/Cargo.toml index 3d6826d..cdb3cb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ async-channel = "2.5.0" axum = { version = "0.8.9", features = ["http2", "macros", "multipart", "ws"] } axum-extra = { version = "0.12.6", features = ["typed-header", "typed-routing"] } 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"] } enumset = { version = "1.1.14", features = ["serde"] } futures = "0.3.34" diff --git a/src/main.rs b/src/main.rs index 26c03d4..78f34ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,10 +12,10 @@ mod server; #[derive(Parser, Debug)] struct AppArgs { - #[arg(long, env)] + #[arg(long, env, default_value_t = [127, 0, 0, 1].into())] ip: IpAddr, - #[arg(long, env)] + #[arg(long, env, default_value_t = 3126)] port: u16, #[arg(long)] @@ -106,6 +106,7 @@ async fn main() { }; join!(stream_responses, async move { + tracing::info!(?addr, "listening"); axum::serve(listener, app).await.expect("TODO"); }); } diff --git a/src/server.rs b/src/server.rs index c791a33..c5958ea 100644 --- a/src/server.rs +++ b/src/server.rs @@ -45,8 +45,8 @@ pub struct AppState { } #[derive(Deserialize, TypedPath)] -#[typed_path("/chat/completions")] -struct ChatCompletionsPath; +#[typed_path("/v1/chat/completions")] +struct V1ChatCompletionsPath; #[derive(Debug, Clone)] enum Provider { @@ -59,6 +59,7 @@ enum Provider { } #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "lowercase")] enum Shortcut { XS, S, @@ -142,8 +143,8 @@ impl Shortcut { } fn take_random_by_swapping(mut vec1: Vec1, mut rng: impl Rng) -> (T, Option>) { - let end = vec1.len().get(); - let index = rng.random_range(0..end); + let end = vec1.len().get() - 1; + let index = rng.random_range(0..=end); vec1.swap(index, end); let (body, element) = vec1.into_rtail_and_head(); @@ -206,7 +207,7 @@ impl IntoResponse for ChatCompletionError { #[axum::debug_handler] #[tracing::instrument(skip(state, request))] async fn create_chat_completion( - _: ChatCompletionsPath, + _: V1ChatCompletionsPath, State(state): State, Json(request): Json>, ) -> Result { @@ -293,6 +294,8 @@ async fn create_chat_completion( model_upstreams.push_back((model.clone(), upstreams)); } + tracing::info!(?model, ?upstream); + let openai::chat::completion::CreateChatCompletionRequest { model: _shortcut, messages, @@ -375,18 +378,25 @@ async fn create_chat_completion( let client = reqwest::Client::new(); - let mut upstream_request = client.post({ - let mut url = upstream.base_url.clone(); + let mut upstream_request = client + .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"); - segments.push("completions"); - } + let s = V1ChatCompletionsPath.to_string(); + let s = s.strip_prefix("/").unwrap_or(&s); + let s = s.strip_suffix("/").unwrap_or(&s); - url - }); + path_segments.extend(s.split("/")); + } + + tracing::info!(?url); + + url + }) + .json(&request); if let Some(api_key) = upstream.api_key { let authorization = @@ -410,12 +420,13 @@ async fn create_chat_completion( } }; - let upstream_response = match upstream_response.error_for_status() { - Ok(upstream_response) => upstream_response, - Err(upstream_error) => { - tracing::error!(?upstream_error); - continue; - } + if let Err(upstream_error) = upstream_response.error_for_status_ref() { + tracing::error!(?upstream_error); + match upstream_response.text().await { + Ok(body) => tracing::error!(?body), + Err(body_error) => tracing::error!(?body_error), + }; + continue; }; if request.stream.unwrap_or(false) {