feat: model dir auto-scan, remote API models, model plaza with HF/ModelScope downloads
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
pub mod error;
|
||||
pub mod manager;
|
||||
pub mod remote;
|
||||
pub mod types;
|
||||
|
||||
pub use error::{EngineError, Result};
|
||||
pub use manager::EngineManager;
|
||||
pub use remote::{stream_chat_remote, RemoteConfig};
|
||||
pub use types::{ChatMessage, ChatRequest, EngineConfig, EngineStatus};
|
||||
|
||||
@@ -203,7 +203,7 @@ fn free_port() -> Result<u16> {
|
||||
}
|
||||
|
||||
/// 把 reqwest 的字节流解析为 SSE 行级文本流(增量 token)。
|
||||
fn sse_text_stream(
|
||||
pub(crate) fn sse_text_stream(
|
||||
bytes: impl Stream<Item = std::result::Result<bytes::Bytes, reqwest::Error>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
use crate::error::{EngineError, Result};
|
||||
use crate::manager::sse_text_stream;
|
||||
use crate::types::ChatRequest;
|
||||
|
||||
/// OpenAI 兼容的远程模型端点配置。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteConfig {
|
||||
pub base_url: String,
|
||||
pub api_key: Option<String>,
|
||||
pub model: String,
|
||||
}
|
||||
|
||||
/// 调用远程 OpenAI 兼容 API 并返回流式增量文本。
|
||||
pub async fn stream_chat_remote(
|
||||
cfg: &RemoteConfig,
|
||||
req: ChatRequest,
|
||||
) -> Result<futures::stream::BoxStream<'static, Result<String>>> {
|
||||
let base = normalize_base(&cfg.base_url);
|
||||
let url = format!("{base}/chat/completions");
|
||||
let client = reqwest::Client::new();
|
||||
let mut builder = client.post(&url).json(&req);
|
||||
if let Some(key) = &cfg.api_key {
|
||||
if !key.trim().is_empty() {
|
||||
builder = builder.bearer_auth(key);
|
||||
}
|
||||
}
|
||||
let response = builder.send().await?;
|
||||
let status = response.status();
|
||||
if !status.is_success() {
|
||||
let body = response.text().await.unwrap_or_default();
|
||||
return Err(EngineError::EngineHttp(status, body));
|
||||
}
|
||||
Ok(sse_text_stream(response.bytes_stream()))
|
||||
}
|
||||
|
||||
/// 把用户填写的 base url 归一化为 `<scheme>://<host>/v1` 形式。
|
||||
fn normalize_base(base: &str) -> String {
|
||||
let mut s = base.trim().trim_end_matches('/').to_string();
|
||||
if !s.ends_with("/v1") {
|
||||
s.push_str("/v1");
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user