#[cfg(feature = "ort-backend")]
use crate::config::{MAX_BATCH_SIZE, MAX_ENTITY_LABEL_CHARS, MAX_ENTITY_LABELS};
#[cfg(feature = "ort-backend")]
use crate::{GlinerError, Result};
#[cfg(feature = "ort-backend")]
const ENTITY_TOKEN: &str = "<<ENT>>";
#[cfg(feature = "ort-backend")]
const SEP_TOKEN: &str = "<<SEP>>";
#[cfg(feature = "ort-backend")]
#[derive(Debug, Clone)]
pub struct TextInput {
pub(crate) texts: Vec<String>,
pub(crate) entities: Vec<String>,
}
#[cfg(feature = "ort-backend")]
impl TextInput {
pub fn new(texts: Vec<String>, entities: Vec<String>) -> Result<Self> {
if texts.is_empty() {
return Err(GlinerError::InvalidInput("texts must not be empty".to_string()));
}
if entities.is_empty() {
return Err(GlinerError::InvalidInput("entity labels must not be empty".to_string()));
}
if texts.len() > MAX_BATCH_SIZE {
return Err(GlinerError::InvalidInput(format!(
"batch size must be at most {MAX_BATCH_SIZE}, got {}",
texts.len()
)));
}
if entities.len() > MAX_ENTITY_LABELS {
return Err(GlinerError::InvalidInput(format!(
"entity label count must be at most {MAX_ENTITY_LABELS}, got {}",
entities.len()
)));
}
if let Some(index) = texts.iter().position(|text| text.trim().is_empty()) {
return Err(GlinerError::InvalidInput(format!("texts[{index}] must not be empty")));
}
if let Some(index) = entities.iter().position(|label| label.trim().is_empty()) {
return Err(GlinerError::InvalidInput(format!(
"entity labels[{index}] must not be empty"
)));
}
if let Some((index, label)) = entities
.iter()
.enumerate()
.find(|(_, label)| label.chars().count() > MAX_ENTITY_LABEL_CHARS)
{
return Err(GlinerError::InvalidInput(format!(
"entity labels[{index}] must be at most {MAX_ENTITY_LABEL_CHARS} characters, got {}",
label.chars().count()
)));
}
if let Some(index) = entities
.iter()
.position(|label| label.contains(ENTITY_TOKEN) || label.contains(SEP_TOKEN))
{
return Err(GlinerError::InvalidInput(format!(
"entity labels[{index}] must not contain reserved GLiNER prompt markers"
)));
}
Ok(Self { texts, entities })
}
pub fn from_str(texts: &[&str], entities: &[&str]) -> Result<Self> {
Self::new(
texts.iter().map(|text| (*text).to_string()).collect(),
entities.iter().map(|entity| (*entity).to_string()).collect(),
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Token {
start: usize,
end: usize,
text: String,
}
impl Token {
pub fn new(start: usize, end: usize, text: &str) -> Self {
Self {
start,
end,
text: text.to_string(),
}
}
pub fn start(&self) -> usize {
self.start
}
pub fn end(&self) -> usize {
self.end
}
pub fn text(&self) -> &str {
&self.text
}
}