feat(server): add /v1/models endpoint for OpenAI-compatible model discovery
Open WebUI and other OpenAI-compatible clients call GET /v1/models to discover available models. Lists all models from enabled providers via the model registry, respects disabled models, and handles Ollama models from TOML config.
This commit is contained in:
@@ -3,7 +3,7 @@ use axum::{
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
response::sse::{Event, Sse},
|
||||
routing::post,
|
||||
routing::{get, post},
|
||||
};
|
||||
use futures::stream::StreamExt;
|
||||
use std::sync::Arc;
|
||||
@@ -24,6 +24,7 @@ use crate::{
|
||||
pub fn router(state: AppState) -> Router {
|
||||
Router::new()
|
||||
.route("/v1/chat/completions", post(chat_completions))
|
||||
.route("/v1/models", get(list_models))
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
rate_limiting::middleware::rate_limit_middleware,
|
||||
@@ -31,6 +32,60 @@ pub fn router(state: AppState) -> Router {
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
/// GET /v1/models — OpenAI-compatible model listing.
|
||||
/// Returns all models from enabled providers so clients like Open WebUI can
|
||||
/// discover which models are available through the proxy.
|
||||
async fn list_models(
|
||||
State(state): State<AppState>,
|
||||
_auth: AuthenticatedClient,
|
||||
) -> Result<Json<serde_json::Value>, AppError> {
|
||||
let registry = &state.model_registry;
|
||||
let providers = state.provider_manager.get_all_providers().await;
|
||||
|
||||
let mut models = Vec::new();
|
||||
|
||||
for provider in &providers {
|
||||
let provider_name = provider.name();
|
||||
|
||||
// Find this provider's models in the registry
|
||||
if let Some(provider_info) = registry.providers.get(provider_name) {
|
||||
for (model_id, meta) in &provider_info.models {
|
||||
// Skip disabled models via the config cache
|
||||
if let Some(cfg) = state.model_config_cache.get(model_id).await {
|
||||
if !cfg.enabled {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
models.push(serde_json::json!({
|
||||
"id": model_id,
|
||||
"object": "model",
|
||||
"created": 0,
|
||||
"owned_by": provider_name,
|
||||
"name": meta.name,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// For Ollama, models are configured in the TOML, not the registry
|
||||
if provider_name == "ollama" {
|
||||
for model_id in &state.config.providers.ollama.models {
|
||||
models.push(serde_json::json!({
|
||||
"id": model_id,
|
||||
"object": "model",
|
||||
"created": 0,
|
||||
"owned_by": "ollama",
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Json(serde_json::json!({
|
||||
"object": "list",
|
||||
"data": models
|
||||
})))
|
||||
}
|
||||
|
||||
async fn get_model_cost(
|
||||
model: &str,
|
||||
prompt_tokens: u32,
|
||||
|
||||
Reference in New Issue
Block a user