fix: more

This commit is contained in:
2026-09-28 00:47:52 -04:00
parent c233fcda38
commit d454635832
4 changed files with 38 additions and 23 deletions

3
Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -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");
}); });
} }

View File

@@ -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);
url path_segments.extend(s.split("/"));
}); }
tracing::info!(?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, tracing::error!(?upstream_error);
Err(upstream_error) => { match upstream_response.text().await {
tracing::error!(?upstream_error); Ok(body) => tracing::error!(?body),
continue; Err(body_error) => tracing::error!(?body_error),
} };
continue;
}; };
if request.stream.unwrap_or(false) { if request.stream.unwrap_or(false) {