use llmr::embed::{EmbedRequest, Embedder, Purpose};
use llmr::providers::openai;
use llmr::Ledger;
use std::time::Duration;
const MODEL: &str = "text-embedding-3-small";
#[tokio::main]
async fn main() -> llmr::Result<()> {
let embedder = openai::embed::from_env(Duration::from_secs(30))?;
let documents = vec![
"The harbour gates close an hour before low water.".to_string(),
"Monomorphisation is what makes generic code expensive to compile.".to_string(),
"Poach the eggs for four minutes and no longer.".to_string(),
];
let stored = embedder
.embed(EmbedRequest::new(MODEL.into(), documents.clone()).for_purpose(Purpose::Document))
.await?;
let question = "why is my rust build slow";
let asked = embedder
.embed(EmbedRequest::one(MODEL, question).for_purpose(Purpose::Query))
.await?;
let query = match asked.get(0) {
Some(vector) => vector,
None => return Err(llmr::Error::Unreadable("no vector came back".into())),
};
println!("{question:?}\n");
println!(
"served by {}, {:?} dimensions\n",
stored.model,
stored.dimensions()
);
let mut scored: Vec<(f32, &String)> = Vec::new();
for (position, document) in documents.iter().enumerate() {
match stored.get(position).and_then(|v| query.similarity(v)) {
Some(score) => scored.push((score, document)),
None => println!(" (not comparable: {document})"),
}
}
scored.sort_by(|a, b| b.0.total_cmp(&a.0));
for (score, document) in &scored {
println!(" {score:.3} {document}");
}
let mut ledger = Ledger::new();
ledger.record_unpriced(stored.model.clone(), stored.usage);
ledger.record_unpriced(asked.model.clone(), asked.usage);
let total = match ledger.total() {
Some(total) => total,
None => return Err(llmr::Error::Unreadable("more than one currency".into())),
};
println!(
"\n{} calls, {} of them unpriced. Cost: {total}",
ledger.calls(),
ledger.unpriced()
);
Ok(())
}