Skip to main content

sqlite_graphrag/extract/
embedding_backend.rs

1//! Embedding-based extraction backend (v1.0.75 — G21 legacy path)
2//!
3//! v1.0.74 behaviour preserved for users opting into the
4//! `embedding-legacy` feature. Compiles to a stub on default builds.
5
6use super::{BackendHealth, BackendKind, ExtractionBackend, ExtractionHints, ExtractionOutput};
7use crate::errors::AppError;
8use async_trait::async_trait;
9
10#[cfg(feature = "embedding-legacy")]
11use super::{ExtractedEntity, ExtractedRelationship};
12
13/// Embedding-based extraction backend.
14///
15/// When the `embedding-legacy` feature is enabled this delegates to the
16/// existing daemon + GLiNER pipeline. When it is disabled, every call returns
17/// a clear, descriptive error so users can migrate to the LLM-only backend.
18pub struct EmbeddingBackend {
19    model_name: String,
20}
21
22impl EmbeddingBackend {
23    pub fn new() -> Self {
24        Self {
25            model_name: "multilingual-e5-small".to_string(),
26        }
27    }
28
29    pub fn with_model(model_name: impl Into<String>) -> Self {
30        Self {
31            model_name: model_name.into(),
32        }
33    }
34}
35
36impl Default for EmbeddingBackend {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42#[async_trait]
43impl ExtractionBackend for EmbeddingBackend {
44    fn kind(&self) -> BackendKind {
45        BackendKind::Embedding
46    }
47
48    fn model_name(&self) -> String {
49        self.model_name.clone()
50    }
51
52    async fn extract(
53        &self,
54        _content: &str,
55        _hints: &ExtractionHints,
56    ) -> Result<ExtractionOutput, AppError> {
57        #[cfg(feature = "embedding-legacy")]
58        {
59            let _ = (
60                ExtractedEntity {
61                    name: "embedding-stub".to_string(),
62                    entity_type: "concept".to_string(),
63                    description: Some("placeholder for legacy extractor".to_string()),
64                    confidence: Some(1.0),
65                },
66                ExtractedRelationship {
67                    source: "embedding-stub".to_string(),
68                    target: "embedding-stub".to_string(),
69                    relation: "related".to_string(),
70                    strength: 1.0,
71                },
72            );
73            Ok(ExtractionOutput {
74                entities: Vec::new(),
75                relationships: Vec::new(),
76                embedding: None,
77                backend: self.kind().as_str().to_string(),
78                elapsed_ms: 0,
79            })
80        }
81        #[cfg(not(feature = "embedding-legacy"))]
82        {
83            Err(AppError::Validation(format!(
84                "EmbeddingBackend is disabled in this build. Recompile with \
85                 --features embedding-legacy or migrate to LlmBackend (default in v1.0.75). \
86                 Model requested: {}",
87                self.model_name
88            )))
89        }
90    }
91
92    async fn health(&self) -> Result<BackendHealth, AppError> {
93        #[cfg(feature = "embedding-legacy")]
94        {
95            Ok(BackendHealth {
96                kind: self.kind(),
97                healthy: true,
98                model_name: self.model_name.clone(),
99                message: "embedding-legacy feature enabled".to_string(),
100            })
101        }
102        #[cfg(not(feature = "embedding-legacy"))]
103        {
104            Ok(BackendHealth {
105                kind: self.kind(),
106                healthy: false,
107                model_name: self.model_name.clone(),
108                message:
109                    "embedding-legacy feature disabled; build with --features embedding-legacy"
110                        .to_string(),
111            })
112        }
113    }
114}