use std::collections::HashMap;
use anyhow::Result;
use crate::llm::LLM;
use crate::prompt::PromptTemplate;
use crate::cache::Cache;
use crate::memory::Memory;
use std::sync::Arc;
#[derive(Clone)]
pub struct LLMChain {
prompt: PromptTemplate,
llm: Arc<dyn LLM>,
cache: Option<Arc<dyn Cache>>,
memory: Option<Arc<dyn Memory>>,
}
impl LLMChain {
pub fn new(prompt: PromptTemplate, llm: Arc<dyn LLM>) -> Self {
Self {
prompt,
llm,
cache: None, memory: None, }
}
pub fn with_cache(mut self, cache: Arc<dyn Cache>) -> Self {
self.cache = Some(cache);
self
}
pub fn with_memory(mut self, memory: Arc<dyn Memory>) -> Self {
self.memory = Some(memory);
self
}
pub async fn call(&self, mut inputs: HashMap<String, String>) -> Result<String> {
if let Some(memory) = &self.memory {
let mem_vars = memory.load_memory_variables(&inputs).await?;
inputs.extend(mem_vars);
}
let formatted = self.prompt.format(&inputs)?;
let minified = self.prompt.minify(&formatted);
if let Some(cache) = &self.cache {
if let Some(cached_response) = cache.get(&minified).await {
return Ok(cached_response);
}
}
let result = self.llm.generate(&minified).await?;
if let Some(cache) = &self.cache {
cache.set(&minified, &result).await;
}
if let Some(cache) = &self.cache {
cache.set(&minified, &result).await;
}
if let Some(memory) = &self.memory {
let mut outputs = HashMap::new();
outputs.insert("output".to_string(), result.clone());
memory.save_context(&inputs, &outputs).await?;
}
Ok(result)
}
}