sc/embeddings/
provider.rs1use crate::error::Result;
7use super::types::ProviderInfo;
8
9pub trait EmbeddingProvider: Send + Sync {
14 fn info(&self) -> ProviderInfo;
16
17 fn is_available(&self) -> impl std::future::Future<Output = bool> + Send;
22
23 fn generate_embedding(&self, text: &str) -> impl std::future::Future<Output = Result<Vec<f32>>> + Send;
25
26 fn generate_embeddings(&self, texts: &[&str]) -> impl std::future::Future<Output = Result<Vec<Vec<f32>>>> + Send {
30 async move {
31 let mut results = Vec::with_capacity(texts.len());
32 for text in texts {
33 results.push(self.generate_embedding(text).await?);
34 }
35 Ok(results)
36 }
37 }
38}
39
40pub struct BoxedProvider {
45 inner: Box<dyn EmbeddingProviderBoxed + Send + Sync>,
46}
47
48pub trait EmbeddingProviderBoxed: Send + Sync {
50 fn info(&self) -> ProviderInfo;
51 fn is_available_boxed(&self) -> std::pin::Pin<Box<dyn std::future::Future<Output = bool> + Send + '_>>;
52 fn generate_embedding_boxed(&self, text: &str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Vec<f32>>> + Send + '_>>;
53 fn generate_embeddings_boxed(&self, texts: &[&str]) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Vec<Vec<f32>>>> + Send + '_>>;
54}
55
56impl BoxedProvider {
57 pub fn new<P: EmbeddingProvider + 'static>(provider: P) -> Self {
59 Self {
60 inner: Box::new(BoxedProviderWrapper(provider)),
61 }
62 }
63
64 pub fn info(&self) -> ProviderInfo {
66 self.inner.info()
67 }
68
69 pub async fn is_available(&self) -> bool {
71 self.inner.is_available_boxed().await
72 }
73
74 pub async fn generate_embedding(&self, text: &str) -> Result<Vec<f32>> {
76 self.inner.generate_embedding_boxed(text).await
77 }
78
79 pub async fn generate_embeddings(&self, texts: &[&str]) -> Result<Vec<Vec<f32>>> {
81 self.inner.generate_embeddings_boxed(texts).await
82 }
83}
84
85struct BoxedProviderWrapper<P: EmbeddingProvider + 'static>(P);
87
88impl<P: EmbeddingProvider + 'static> EmbeddingProviderBoxed for BoxedProviderWrapper<P> {
89 fn info(&self) -> ProviderInfo {
90 self.0.info()
91 }
92
93 fn is_available_boxed(&self) -> std::pin::Pin<Box<dyn std::future::Future<Output = bool> + Send + '_>> {
94 Box::pin(self.0.is_available())
95 }
96
97 fn generate_embedding_boxed(&self, text: &str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Vec<f32>>> + Send + '_>> {
98 let text_owned = text.to_string();
102 Box::pin(async move {
103 self.0.generate_embedding(&text_owned).await
105 })
106 }
107
108 fn generate_embeddings_boxed(&self, texts: &[&str]) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Vec<Vec<f32>>>> + Send + '_>> {
109 let texts_owned: Vec<String> = texts.iter().map(|s| (*s).to_string()).collect();
111 Box::pin(async move {
112 let refs: Vec<&str> = texts_owned.iter().map(String::as_str).collect();
114 self.0.generate_embeddings(&refs).await
115 })
116 }
117}