use serde_json::Value;
use crate::{LmcppServer, error::LmcppResult, server::ipc::ServerClientExt};
impl LmcppServer {
fn openai_json(
&self,
method: &'static str,
path: &str,
body: Option<&Value>,
) -> LmcppResult<Value> {
match (method, body) {
("GET", _) => self.client.get(path),
("POST", Some(json)) => self.client.post(path, json),
("POST", None) => self.client.post(path, &Value::Null),
_ => unreachable!("unsupported HTTP verb"),
}
.map_err(Into::into)
}
pub fn open_ai_v1_models(&self) -> LmcppResult<Value> {
self.openai_json("GET", "/v1/models", None)
}
pub fn open_ai_v1_completions(&self, body: &Value) -> LmcppResult<Value> {
self.openai_json("POST", "/v1/completions", Some(body))
}
pub fn open_ai_v1_chat_completions(&self, body: &Value) -> LmcppResult<Value> {
self.openai_json("POST", "/v1/chat/completions", Some(body))
}
pub fn open_ai_v1_embeddings(&self, body: &Value) -> LmcppResult<Value> {
self.openai_json("POST", "/v1/embeddings", Some(body))
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use serial_test::serial;
use super::*;
use crate::*;
#[test]
#[ignore]
#[serial]
fn test_v1_models() -> LmcppResult<()> {
let server = LmcppServerLauncher::default().load()?;
let resp = server.open_ai_v1_models()?;
println!("Models: {:#?}", resp);
assert_eq!(resp["object"], "list");
let first_id = &resp["data"][0]["id"];
println!("First model id: {}", first_id);
assert!(first_id.is_string());
Ok(())
}
#[test]
#[ignore]
#[serial]
fn test_v1_completions() -> LmcppResult<()> {
let server = LmcppServerLauncher::default().load()?;
let req = json!({
"prompt": "Rust is…",
"max_tokens": 8
});
let resp = server.open_ai_v1_completions(&req)?;
println!("Completion: {:#?}", resp);
let first = &resp["choices"][0]["text"];
assert!(first.is_string());
println!("Assistant said: {}", first);
Ok(())
}
#[test]
#[ignore]
#[serial]
fn test_v1_chat_completions() -> LmcppResult<()> {
let server = LmcppServerLauncher::default().load()?;
let req = json!({
"messages": [
{"role": "user", "content": "Say hello in French"}
]
});
let resp = server.open_ai_v1_chat_completions(&req)?;
println!("Chat completion: {:#?}", resp);
let first = &resp["choices"][0]["message"]["content"];
assert!(first.is_string());
println!("Assistant said: {}", first);
Ok(())
}
#[test]
#[ignore]
#[serial]
fn test_v1_embeddings() -> LmcppResult<()> {
let server = LmcppServerLauncher::builder()
.server_args(
ServerArgs::builder()
.pooling(Pooling::Cls) .embeddings_only(true)
.default_model()?
.build(),
)
.load()?;
let req = json!({
"input": "LLMs are awesome.",
"encoding_format": "float",
});
let resp = server.open_ai_v1_embeddings(&req)?;
println!("Embedding usage: {:#?}", resp["usage"]);
let data = resp["data"].as_array().unwrap();
println!("Embeddings returned: {:#?}", data.len());
let vec_len = data
.get(0)
.and_then(|e| e["embedding"].as_array())
.map_or(0, |v| v.len());
println!("Length of first embedding vector: {:#?}", vec_len);
Ok(())
}
}