llm_toolkit/intent/
frame.rs1use crate::extract::FlexibleExtractor;
2use crate::extract::core::ContentExtractor;
3use crate::intent::{IntentError, IntentExtractor};
4use std::str::FromStr;
5
6pub struct IntentFrame {
8 input_tag: String,
9 extractor_tag: String,
10}
11
12impl IntentFrame {
13 pub fn new(input_tag: &str, extractor_tag: &str) -> Self {
15 Self {
16 input_tag: input_tag.to_string(),
17 extractor_tag: extractor_tag.to_string(),
18 }
19 }
20
21 pub fn wrap(&self, text: &str) -> String {
23 format!("<{0}>{1}</{0}>", self.input_tag, text)
24 }
25}
26
27impl<T> IntentExtractor<T> for IntentFrame
28where
29 T: FromStr,
30{
31 fn extract_intent(&self, text: &str) -> Result<T, IntentError> {
32 let extractor = FlexibleExtractor::new();
34 let extracted_str = extractor
35 .extract_tagged(text, &self.extractor_tag)
36 .ok_or_else(|| IntentError::TagNotFound {
37 tag: self.extractor_tag.clone(),
38 })?;
39
40 T::from_str(&extracted_str).map_err(|_| IntentError::ParseFailed {
42 value: extracted_str.to_string(),
43 })
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[derive(Debug, PartialEq)]
52 enum TestIntent {
53 Login,
54 Logout,
55 }
56
57 impl FromStr for TestIntent {
58 type Err = String;
59
60 fn from_str(s: &str) -> Result<Self, Self::Err> {
61 match s {
62 "Login" => Ok(TestIntent::Login),
63 "Logout" => Ok(TestIntent::Logout),
64 _ => Err(format!("Unknown intent: {}", s)),
65 }
66 }
67 }
68
69 #[test]
70 fn test_wrap_method() {
71 let frame = IntentFrame::new("input", "output");
72 let wrapped = frame.wrap("test content");
73 assert_eq!(wrapped, "<input>test content</input>");
74 }
75
76 #[test]
77 fn test_extract_intent_success() {
78 let frame = IntentFrame::new("input", "intent");
79 let text = "<intent>Login</intent>";
80 let result: Result<TestIntent, _> = IntentExtractor::extract_intent(&frame, text);
81 assert_eq!(result.unwrap(), TestIntent::Login);
82 }
83
84 #[test]
85 fn test_extract_intent_tag_not_found() {
86 let frame = IntentFrame::new("input", "intent");
87 let text = "No intent tag here";
88 let result: Result<TestIntent, _> = IntentExtractor::extract_intent(&frame, text);
89
90 match result {
91 Err(IntentError::TagNotFound { tag }) => {
92 assert_eq!(tag, "intent");
93 }
94 _ => panic!("Expected TagNotFound error"),
95 }
96 }
97
98 #[test]
99 fn test_extract_intent_parse_failed() {
100 let frame = IntentFrame::new("input", "intent");
101 let text = "<intent>Invalid</intent>";
102 let result: Result<TestIntent, _> = IntentExtractor::extract_intent(&frame, text);
103
104 match result {
105 Err(IntentError::ParseFailed { value }) => {
106 assert_eq!(value, "Invalid");
107 }
108 _ => panic!("Expected ParseFailed error"),
109 }
110 }
111}