feat: add embedding and rerank support

This commit is contained in:
Kayphoon
2026-05-03 17:32:41 +08:00
parent 3e2eca4fd0
commit 5abe664d65
87 changed files with 5520 additions and 184 deletions

View File

@@ -0,0 +1,13 @@
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"doubao:embedding" => Some("doubao:embedding"),
_ => None,
}
}
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"doubao:embedding" => Some("/v1/embeddings"),
_ => None,
}
}

View File

@@ -1,6 +1,7 @@
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"gemini:generate_content" => Some("gemini:generate_content"),
"gemini:embedding" => Some("gemini:embedding"),
"gemini:video" => Some("gemini:video"),
"gemini:files" => Some("gemini:files"),
_ => None,
@@ -10,6 +11,7 @@ pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"gemini" | "gemini:generate_content" => Some("/v1beta/models/{model}:{action}"),
"gemini:embedding" => Some("/v1/embeddings"),
"gemini:video" => Some("/v1beta/models/{model}:predictLongRunning"),
"gemini:files" => Some("/v1beta/files"),
_ => None,

View File

@@ -0,0 +1,15 @@
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"jina:embedding" => Some("jina:embedding"),
"jina:rerank" => Some("jina:rerank"),
_ => None,
}
}
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"jina:embedding" => Some("/v1/embeddings"),
"jina:rerank" => Some("/v1/rerank"),
_ => None,
}
}

View File

@@ -1,5 +1,7 @@
mod claude;
mod doubao;
mod gemini;
mod jina;
mod openai;
mod registry;

View File

@@ -1,6 +1,8 @@
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"openai:chat" => Some("openai:chat"),
"openai:embedding" => Some("openai:embedding"),
"openai:rerank" => Some("openai:rerank"),
"openai:responses" => Some("openai:responses"),
"openai:responses:compact" => Some("openai:responses:compact"),
"openai:image" => Some("openai:image"),
@@ -12,6 +14,8 @@ pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
match crate::ai_serving::normalize_api_format_alias(api_format).as_str() {
"openai" | "openai:chat" => Some("/v1/chat/completions"),
"openai:embedding" => Some("/v1/embeddings"),
"openai:rerank" => Some("/v1/rerank"),
"openai:responses" => Some("/v1/responses"),
"openai:responses:compact" => Some("/v1/responses/compact"),
"openai:image" => Some("/v1/images/generations"),

View File

@@ -1,7 +1,7 @@
use axum::routing::{any, post};
use axum::Router;
use super::{claude, gemini, openai};
use super::{claude, doubao, gemini, jina, openai};
use crate::{handlers::proxy::proxy_request, state::AppState};
// Router registration patterns live here so AI public ingress has a single mount registry.
@@ -9,6 +9,8 @@ use crate::{handlers::proxy::proxy_request, state::AppState};
// which describe operational compatibility surfaces rather than the concrete axum mount list.
const AI_POST_ROUTE_PATTERNS: &[&str] = &[
"/v1/chat/completions",
"/v1/embeddings",
"/v1/rerank",
"/v1/messages",
"/v1/messages/count_tokens",
"/v1/responses",
@@ -45,6 +47,8 @@ pub(crate) fn public_api_format_local_path(api_format: &str) -> &'static str {
openai::local_path(&normalized)
.or_else(|| claude::local_path(&normalized))
.or_else(|| gemini::local_path(&normalized))
.or_else(|| jina::local_path(&normalized))
.or_else(|| doubao::local_path(&normalized))
.unwrap_or("/")
}
@@ -53,6 +57,8 @@ pub(crate) fn normalize_admin_endpoint_signature(api_format: &str) -> Option<&'s
openai::normalized_signature(&normalized)
.or_else(|| claude::normalized_signature(&normalized))
.or_else(|| gemini::normalized_signature(&normalized))
.or_else(|| jina::normalized_signature(&normalized))
.or_else(|| doubao::normalized_signature(&normalized))
}
pub(crate) fn admin_endpoint_signature_parts(
@@ -71,3 +77,26 @@ pub(crate) fn admin_default_body_rules_for_signature(
let _ = provider_type;
Some((normalized_api_format, Vec::new()))
}
#[cfg(test)]
mod tests {
use super::{admin_endpoint_signature_parts, public_api_format_local_path};
#[test]
fn supports_data_api_endpoint_signatures_and_public_paths() {
for (api_format, family, kind, path) in [
("openai:embedding", "openai", "embedding", "/v1/embeddings"),
("gemini:embedding", "gemini", "embedding", "/v1/embeddings"),
("jina:embedding", "jina", "embedding", "/v1/embeddings"),
("doubao:embedding", "doubao", "embedding", "/v1/embeddings"),
("openai:rerank", "openai", "rerank", "/v1/rerank"),
("jina:rerank", "jina", "rerank", "/v1/rerank"),
] {
assert_eq!(
admin_endpoint_signature_parts(api_format),
Some((api_format, family, kind))
);
assert_eq!(public_api_format_local_path(api_format), path);
}
}
}