Skip to main content

anno/backends/
gliner_poly.rs

1//! GLiNER poly-encoder (scaffolding).
2//!
3//! This module is intentionally **not implemented**: it exists to keep the wiring points
4//! explicit without returning fake outputs.
5//!
6//! If you want zero-shot custom entity types today, use `GLiNEROnnx`.
7//!
8//! Research pointer (context only): `https://blog.knowledgator.com/meet-the-new-zero-shot-ner-architecture-30ffc2cb1ee0`
9
10use crate::backends::inference::ZeroShotNER;
11use crate::{Entity, EntityType, Error, Model, Result};
12
13/// Poly-Encoder GLiNER backend for zero-shot NER with inter-label interactions.
14///
15/// **Status:** Scaffolding / not implemented yet.
16///
17/// Poly-encoder fusion requires a different ONNX export than the bi-encoder GLiNER models.
18/// We keep the type for forward compatibility, but it returns a clear error if used.
19#[derive(Debug)]
20pub struct GLiNERPoly {
21    _private: (),
22}
23
24impl GLiNERPoly {
25    /// Create a new Poly-Encoder GLiNER model.
26    ///
27    /// # Arguments
28    /// * `model_name` - HuggingFace model ID (e.g., "knowledgator/modern-gliner-poly-large-v1.0")
29    ///
30    /// # Note
31    /// This backend is not implemented yet. Use `GLiNEROnnx` for zero-shot NER today.
32    pub fn new(model_name: &str) -> Result<Self> {
33        let _ = model_name;
34        Err(Error::FeatureNotAvailable(
35            "GLiNERPoly is not implemented yet (poly-encoder fusion ONNX export not supported). \
36             Use GLiNEROnnx instead."
37                .to_string(),
38        ))
39    }
40
41    // NOTE: Poly-encoder fusion would live here once we have compatible exports.
42    // This would allow labels to interact with each other and with text context.
43}
44
45impl Model for GLiNERPoly {
46    fn extract_entities(&self, text: &str, language: Option<&str>) -> Result<Vec<Entity>> {
47        let _ = (text, language);
48        Err(Error::FeatureNotAvailable(
49            "GLiNERPoly is not implemented yet. Use GLiNEROnnx.".to_string(),
50        ))
51    }
52
53    fn supported_types(&self) -> Vec<EntityType> {
54        vec![]
55    }
56
57    fn is_available(&self) -> bool {
58        false
59    }
60
61    fn name(&self) -> &'static str {
62        "gliner_poly"
63    }
64
65    fn description(&self) -> &'static str {
66        "Poly-Encoder GLiNER (scaffolding only; poly-encoder fusion not implemented yet)"
67    }
68}
69
70impl ZeroShotNER for GLiNERPoly {
71    fn extract_with_types(
72        &self,
73        text: &str,
74        entity_types: &[&str],
75        threshold: f32,
76    ) -> Result<Vec<Entity>> {
77        let _ = (text, entity_types, threshold);
78        Err(Error::FeatureNotAvailable(
79            "GLiNERPoly is not implemented yet. Use GLiNEROnnx.".to_string(),
80        ))
81    }
82
83    fn extract_with_descriptions(
84        &self,
85        text: &str,
86        descriptions: &[&str],
87        threshold: f32,
88    ) -> Result<Vec<Entity>> {
89        let _ = (text, descriptions, threshold);
90        Err(Error::FeatureNotAvailable(
91            "GLiNERPoly is not implemented yet. Use GLiNEROnnx.".to_string(),
92        ))
93    }
94
95    fn default_types(&self) -> &[&'static str] {
96        &[]
97    }
98}
99
100// Implement BatchCapable and StreamingCapable for consistency
101impl crate::BatchCapable for GLiNERPoly {
102    fn extract_entities_batch(
103        &self,
104        texts: &[&str],
105        language: Option<&str>,
106    ) -> Result<Vec<Vec<Entity>>> {
107        let _ = (texts, language);
108        Err(Error::FeatureNotAvailable(
109            "GLiNERPoly is not implemented yet. Use GLiNEROnnx.".to_string(),
110        ))
111    }
112}
113
114impl crate::StreamingCapable for GLiNERPoly {
115    fn extract_entities_streaming(&self, chunk: &str, offset: usize) -> Result<Vec<Entity>> {
116        let _ = (chunk, offset);
117        Err(Error::FeatureNotAvailable(
118            "GLiNERPoly is not implemented yet. Use GLiNEROnnx.".to_string(),
119        ))
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    #[test]
128    fn test_gliner_poly_creation() {
129        let err = GLiNERPoly::new("knowledgator/modern-gliner-poly-large-v1.0").unwrap_err();
130        assert!(matches!(err, Error::FeatureNotAvailable(_)));
131    }
132
133    #[test]
134    fn test_gliner_poly_name() {
135        // Name is stable even when backend is unavailable.
136        let model = GLiNERPoly { _private: () };
137        assert_eq!(model.name(), "gliner_poly");
138    }
139}