alith_client/components/grammar/
exact_string.rs1use super::{Grammar, GrammarError, GrammarSetterTrait};
2use std::cell::RefCell;
3
4#[derive(Clone, Default, PartialEq)]
5pub struct ExactStringGrammar {
6 pub exact_strings: Vec<String>,
7 pub stop_word_done: Option<String>,
8 pub stop_word_no_result: Option<String>,
9 grammar_string: RefCell<Option<String>>,
10}
11
12impl ExactStringGrammar {
13 #[inline]
14 pub fn wrap(self) -> Grammar {
15 Grammar::ExactString(self)
16 }
17
18 pub fn add_exact_strings<T: AsRef<str>>(mut self, exact_strings: &[T]) -> Self {
19 for incoming_string in exact_strings {
20 if !self.exact_strings.is_empty()
21 && self
22 .exact_strings
23 .iter()
24 .any(|s| s == incoming_string.as_ref())
25 {
26 continue;
27 }
28 self.exact_strings.push(incoming_string.as_ref().to_owned());
29 }
30 self
31 }
32
33 #[inline]
34 pub fn add_exact_string<T: AsRef<str>>(self, exact_string: T) -> Self {
35 self.add_exact_strings(&[exact_string])
36 }
37
38 pub fn grammar_string(&self) -> String {
39 if self.exact_strings.is_empty() {
40 panic!("ExactStringGrammar must have at least one exact string");
41 }
42 let mut grammar_string = self.grammar_string.borrow_mut();
43 if grammar_string.is_none() {
44 *grammar_string = Some(exact_string_grammar(
45 &self.exact_strings,
46 &self.stop_word_done,
47 &self.stop_word_no_result,
48 ));
49 }
50 grammar_string.as_ref().unwrap().clone()
51 }
52
53 #[inline]
54 pub fn validate_clean(&self, content: &str) -> Result<String, GrammarError> {
55 exact_string_validate_clean(content, &self.exact_strings)
56 }
57
58 #[inline]
59 pub fn grammar_parse(&self, content: &str) -> Result<String, GrammarError> {
60 exact_string_parse(content, &self.exact_strings)
61 }
62}
63
64impl GrammarSetterTrait for ExactStringGrammar {
65 fn stop_word_done_mut(&mut self) -> &mut Option<String> {
66 &mut self.stop_word_done
67 }
68
69 fn stop_word_no_result_mut(&mut self) -> &mut Option<String> {
70 &mut self.stop_word_no_result
71 }
72}
73
74pub fn exact_string_grammar<T: AsRef<str>>(
75 exact_strings: &[String],
76 stop_word_done: &Option<T>,
77 stop_word_no_result: &Option<T>,
78) -> String {
79 let mut pattern = String::new();
80 for text in exact_strings {
81 if pattern.is_empty() {
82 pattern.push('(');
83 } else {
84 pattern.push('|');
85 }
86 pattern.push_str(&format!(" \"{}\" ", text));
87 }
88 pattern.push(')');
89 match (stop_word_done, stop_word_no_result) {
90 (Some(stop_word_done), Some(stop_word_no_result)) => format!(
91 "root ::= ( {pattern} | \"{}\" ) \" {}\"",
92 stop_word_no_result.as_ref(),
93 stop_word_done.as_ref()
94 ),
95 (None, Some(stop_word_no_result)) => {
96 format!(
97 "root ::= ( {pattern} | \"{}\" )",
98 stop_word_no_result.as_ref()
99 )
100 }
101 (Some(stop_word_done), None) => {
102 format!("root ::= {pattern} \" {}\"", stop_word_done.as_ref())
103 }
104 (None, None) => format!("root ::= {pattern}"),
105 }
106}
107
108pub fn exact_string_validate_clean(
109 content: &str,
110 exact_strings: &[String],
111) -> Result<String, GrammarError> {
112 let content = content.trim();
113 if exact_string_parse(content, exact_strings).is_ok() {
114 Ok(content.to_string())
115 } else {
116 Err(GrammarError::ParseValueError {
117 content: content.to_string(),
118 parse_type: "exact_string".to_string(),
119 })
120 }
121}
122
123pub fn exact_string_parse(content: &str, exact_strings: &[String]) -> Result<String, GrammarError> {
124 exact_strings
125 .iter()
126 .find(|&text| content.contains(text))
127 .map(|text| text.to_string())
128 .ok_or_else(|| GrammarError::ParseValueError {
129 content: format!("Content: {}, Exact Strings: {:?}", content, exact_strings),
130 parse_type: "exact_string".to_string(),
131 })
132}