mirror of
https://github.com/katanemo/plano.git
synced 2026-06-17 15:25:17 +02:00
add support for openwebui
This commit is contained in:
parent
79cbcb5fe1
commit
2ccbcb3ff5
6 changed files with 100 additions and 19 deletions
|
|
@ -728,7 +728,7 @@ static_resources:
|
||||||
- endpoint:
|
- endpoint:
|
||||||
address:
|
address:
|
||||||
socket_address:
|
socket_address:
|
||||||
address: 0.0.0.0
|
address: host.docker.internal
|
||||||
port_value: 9091
|
port_value: 9091
|
||||||
hostname: localhost
|
hostname: localhost
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ def docker_start_archgw_detached(
|
||||||
port_mappings = [
|
port_mappings = [
|
||||||
f"{prompt_gateway_port}:{prompt_gateway_port}",
|
f"{prompt_gateway_port}:{prompt_gateway_port}",
|
||||||
f"{llm_gateway_port}:{llm_gateway_port}",
|
f"{llm_gateway_port}:{llm_gateway_port}",
|
||||||
|
f"{llm_gateway_port+1}:{llm_gateway_port+1}",
|
||||||
"19901:9901",
|
"19901:9901",
|
||||||
]
|
]
|
||||||
port_mappings_args = [item for port in port_mappings for item in ("-p", port)]
|
port_mappings_args = [item for port in port_mappings for item in ("-p", port)]
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
pub mod chat_completions;
|
pub mod chat_completions;
|
||||||
|
pub mod models;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use brightstaff::handlers::chat_completions::chat_completions;
|
use brightstaff::handlers::chat_completions::chat_completions;
|
||||||
|
use brightstaff::handlers::models::list_models;
|
||||||
use brightstaff::router::llm_router::RouterService;
|
use brightstaff::router::llm_router::RouterService;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use common::configuration::Configuration;
|
use common::configuration::Configuration;
|
||||||
|
|
@ -72,6 +73,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
|
||||||
let arch_config = Arc::new(config);
|
let arch_config = Arc::new(config);
|
||||||
|
|
||||||
|
let llm_providers = Arc::new(arch_config.llm_providers.clone());
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"arch_config: {:?}",
|
"arch_config: {:?}",
|
||||||
&serde_json::to_string(arch_config.as_ref()).unwrap()
|
&serde_json::to_string(arch_config.as_ref()).unwrap()
|
||||||
|
|
@ -104,10 +107,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let router_service = Arc::clone(&router_service);
|
let router_service = Arc::clone(&router_service);
|
||||||
let llm_provider_endpoint = llm_provider_endpoint.clone();
|
let llm_provider_endpoint = llm_provider_endpoint.clone();
|
||||||
|
|
||||||
|
let llm_providers = llm_providers.clone();
|
||||||
let service = service_fn(move |req| {
|
let service = service_fn(move |req| {
|
||||||
let router_service = Arc::clone(&router_service);
|
let router_service = Arc::clone(&router_service);
|
||||||
let parent_cx = extract_context_from_request(&req);
|
let parent_cx = extract_context_from_request(&req);
|
||||||
let llm_provider_endpoint = llm_provider_endpoint.clone();
|
let llm_provider_endpoint = llm_provider_endpoint.clone();
|
||||||
|
let llm_providers = llm_providers.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
match (req.method(), req.uri().path()) {
|
match (req.method(), req.uri().path()) {
|
||||||
|
|
@ -116,6 +121,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
.with_context(parent_cx)
|
.with_context(parent_cx)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
(&Method::GET, "/v1/models") => {
|
||||||
|
Ok(list_models(llm_providers).await)
|
||||||
|
}
|
||||||
|
(&Method::OPTIONS, "/v1/models") => {
|
||||||
|
let mut response = Response::new(empty());
|
||||||
|
*response.status_mut() = StatusCode::NO_CONTENT;
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"Allow",
|
||||||
|
"GET, OPTIONS".parse().unwrap(),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"Access-Control-Allow-Origin",
|
||||||
|
"*".parse().unwrap(),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"Access-Control-Allow-Headers",
|
||||||
|
"Authorization, Content-Type".parse().unwrap(),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"Access-Control-Allow-Methods",
|
||||||
|
"GET, POST, OPTIONS".parse().unwrap(),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"Content-Type",
|
||||||
|
"application/json".parse().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut not_found = Response::new(empty());
|
let mut not_found = Response::new(empty());
|
||||||
*not_found.status_mut() = StatusCode::NOT_FOUND;
|
*not_found.status_mut() = StatusCode::NOT_FOUND;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
use crate::consts::{ARCH_FC_MODEL_NAME, ASSISTANT_ROLE};
|
use crate::{
|
||||||
|
configuration::LlmProvider,
|
||||||
|
consts::{ARCH_FC_MODEL_NAME, ASSISTANT_ROLE},
|
||||||
|
};
|
||||||
|
use core::{panic, str};
|
||||||
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
||||||
use serde_yaml::Value;
|
use serde_yaml::Value;
|
||||||
use core::panic;
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
|
|
@ -420,6 +423,45 @@ pub fn to_server_events(chunks: Vec<ChatCompletionStreamResponse>) -> String {
|
||||||
response_str
|
response_str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ModelDetail {
|
||||||
|
pub id: String,
|
||||||
|
pub object: String,
|
||||||
|
pub created: usize,
|
||||||
|
pub owned_by: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum ModelObject {
|
||||||
|
#[serde(rename = "list")]
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Models {
|
||||||
|
pub object: ModelObject,
|
||||||
|
pub data: Vec<ModelDetail>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<LlmProvider>> for Models {
|
||||||
|
fn from(llm_providers: Vec<LlmProvider>) -> Self {
|
||||||
|
let data = llm_providers
|
||||||
|
.iter()
|
||||||
|
.map(|provider| ModelDetail {
|
||||||
|
id: provider.model.as_ref().unwrap().clone(),
|
||||||
|
object: "model".to_string(),
|
||||||
|
created: 1721172741,
|
||||||
|
owned_by: "system".to_string(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Models {
|
||||||
|
object: ModelObject::List,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::api::open_ai::{ChatCompletionsRequest, ContentType, MultiPartContentType};
|
use crate::api::open_ai::{ChatCompletionsRequest, ContentType, MultiPartContentType};
|
||||||
|
|
@ -775,7 +817,10 @@ data: [DONE]
|
||||||
if let Some(ContentType::MultiPart(multi_part_content)) =
|
if let Some(ContentType::MultiPart(multi_part_content)) =
|
||||||
chat_completions_request.messages[0].content.as_ref()
|
chat_completions_request.messages[0].content.as_ref()
|
||||||
{
|
{
|
||||||
assert_eq!(multi_part_content[0].content_type, MultiPartContentType::Text);
|
assert_eq!(
|
||||||
|
multi_part_content[0].content_type,
|
||||||
|
MultiPartContentType::Text
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
multi_part_content[0].text,
|
multi_part_content[0].text,
|
||||||
Some("What city do you want to know the weather for?".to_string())
|
Some("What city do you want to know the weather for?".to_string())
|
||||||
|
|
@ -815,22 +860,24 @@ data: [DONE]
|
||||||
chat_completions_request.messages[0].content.as_ref()
|
chat_completions_request.messages[0].content.as_ref()
|
||||||
{
|
{
|
||||||
assert_eq!(multi_part_content.len(), 2);
|
assert_eq!(multi_part_content.len(), 2);
|
||||||
assert_eq!(multi_part_content[0].content_type, MultiPartContentType::Text);
|
assert_eq!(
|
||||||
|
multi_part_content[0].content_type,
|
||||||
|
MultiPartContentType::Text
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
multi_part_content[0].text,
|
multi_part_content[0].text,
|
||||||
Some("What city do you want to know the weather for?".to_string())
|
Some("What city do you want to know the weather for?".to_string())
|
||||||
);
|
);
|
||||||
assert_eq!(multi_part_content[1].content_type, MultiPartContentType::Text);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
multi_part_content[1].text,
|
multi_part_content[1].content_type,
|
||||||
Some("hello world".to_string())
|
MultiPartContentType::Text
|
||||||
);
|
);
|
||||||
|
assert_eq!(multi_part_content[1].text, Some("hello world".to_string()));
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected MultiPartContent");
|
panic!("Expected MultiPartContent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stream_chunk_parse_claude() {
|
fn stream_chunk_parse_claude() {
|
||||||
const CHUNK_RESPONSE: &str = r#"data: {"id":"msg_01DZDMxYSgq8aPQxMQoBv6Kb","choices":[{"index":0,"delta":{"role":"assistant"}}],"created":1747685264,"model":"claude-3-7-sonnet-latest","object":"chat.completion.chunk"}
|
const CHUNK_RESPONSE: &str = r#"data: {"id":"msg_01DZDMxYSgq8aPQxMQoBv6Kb","choices":[{"index":0,"delta":{"role":"assistant"}}],"created":1747685264,"model":"claude-3-7-sonnet-latest","object":"chat.completion.chunk"}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
services:
|
services:
|
||||||
|
|
||||||
chatbot_ui:
|
|
||||||
build:
|
open-web-ui:
|
||||||
context: ../../shared/chatbot_ui
|
image: ghcr.io/open-webui/open-webui:main
|
||||||
dockerfile: Dockerfile
|
container_name: open-webui
|
||||||
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "18080:8080"
|
- "8080:8080"
|
||||||
environment:
|
environment:
|
||||||
- CHAT_COMPLETION_ENDPOINT=http://host.docker.internal:12000/v1
|
- DEFAULT_MODEL=gpt-4o-mini
|
||||||
extra_hosts:
|
- OPENAI_API_KEY=your_secret_key
|
||||||
- "host.docker.internal:host-gateway"
|
|
||||||
volumes:
|
|
||||||
- ./arch_config.yaml:/app/arch_config.yaml
|
|
||||||
|
|
||||||
jaeger:
|
jaeger:
|
||||||
build:
|
build:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue