1use crate::{LanguageCode, Result};
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct SemanticContext {
10 pub topics: HashMap<String, f32>,
12 pub sentiment_polarity: f32,
14 pub formality_level: f32,
16 pub technical_complexity: f32,
18 pub domain: Option<String>,
20 pub emotion_indicators: Vec<String>,
22 pub register: String,
24}
25
26impl Default for SemanticContext {
27 fn default() -> Self {
28 Self {
29 topics: HashMap::new(),
30 sentiment_polarity: 0.0,
31 formality_level: 0.5,
32 technical_complexity: 0.0,
33 domain: None,
34 emotion_indicators: Vec::new(),
35 register: "neutral".to_string(),
36 }
37 }
38}
39
40pub trait SemanticAnalysis: Send + Sync {
42 fn analyze_context(&self, text: &str) -> Result<SemanticContext>;
44
45 fn detect_topics(&self, text: &str) -> Result<HashMap<String, f32>>;
47
48 fn analyze_sentiment(&self, text: &str) -> Result<f32>;
50
51 fn assess_formality(&self, text: &str) -> Result<f32>;
53
54 fn supported_languages(&self) -> Vec<LanguageCode>;
56}
57
58#[derive(Debug, Clone)]
60pub struct BasicSemanticAnalyzer {
61 pub topic_models: HashMap<String, TopicModel>,
63 pub sentiment_lexicons: HashMap<LanguageCode, SentimentLexicon>,
65 pub formality_indicators: HashMap<LanguageCode, FormalityIndicators>,
67}
68
69#[derive(Debug, Clone)]
71pub struct TopicModel {
72 pub keywords: HashMap<String, f32>,
74 pub name: String,
76 pub threshold: f32,
78}
79
80#[derive(Debug, Clone)]
82pub struct SentimentLexicon {
83 pub word_scores: HashMap<String, f32>,
85 pub negation_patterns: Vec<String>,
87 pub intensifier_patterns: Vec<(String, f32)>,
89}
90
91#[derive(Debug, Clone)]
93pub struct FormalityIndicators {
94 pub formal_indicators: HashMap<String, f32>,
96 pub informal_indicators: HashMap<String, f32>,
98 pub technical_terms: HashSet<String>,
100}
101
102impl SemanticAnalysis for BasicSemanticAnalyzer {
103 fn analyze_context(&self, text: &str) -> Result<SemanticContext> {
104 let words: Vec<&str> = text.split_whitespace().collect();
105
106 let topics = self.detect_topics(text)?;
108
109 let sentiment_polarity = self.analyze_sentiment(text)?;
111
112 let formality_level = self.assess_formality(text)?;
114
115 let technical_complexity = self.assess_technical_complexity(&words);
117
118 let domain = self.classify_domain(&topics);
120
121 let emotion_indicators = self.detect_emotion_indicators(&words);
123
124 let register = self.determine_register(formality_level, technical_complexity);
126
127 Ok(SemanticContext {
128 topics,
129 sentiment_polarity,
130 formality_level,
131 technical_complexity,
132 domain,
133 emotion_indicators,
134 register,
135 })
136 }
137
138 fn detect_topics(&self, text: &str) -> Result<HashMap<String, f32>> {
139 let words: Vec<&str> = text.split_whitespace().collect();
140 let mut topic_scores = HashMap::new();
141
142 for (topic_name, topic_model) in &self.topic_models {
143 let mut score = 0.0;
144 let mut word_count = 0;
145
146 for word in &words {
147 if let Some(word_score) = topic_model.keywords.get(&word.to_lowercase()) {
148 score += word_score;
149 word_count += 1;
150 }
151 }
152
153 if word_count > 0 {
154 let normalized_score = score / words.len() as f32;
155 if normalized_score >= topic_model.threshold {
156 topic_scores.insert(topic_name.clone(), normalized_score);
157 }
158 }
159 }
160
161 Ok(topic_scores)
162 }
163
164 fn analyze_sentiment(&self, text: &str) -> Result<f32> {
165 let words: Vec<&str> = text.split_whitespace().collect();
166
167 let lexicon = self.sentiment_lexicons.get(&LanguageCode::EnUs);
169
170 if let Some(lexicon) = lexicon {
171 let mut total_score = 0.0;
172 let mut scored_words = 0;
173 let mut negation_active = false;
174
175 for word in &words {
176 let word_lower = word.to_lowercase();
177
178 if lexicon
180 .negation_patterns
181 .iter()
182 .any(|pattern| word_lower.contains(pattern))
183 {
184 negation_active = true;
185 continue;
186 }
187
188 if let Some(score) = lexicon.word_scores.get(&word_lower) {
190 let final_score = if negation_active { -score } else { *score };
191 total_score += final_score;
192 scored_words += 1;
193 negation_active = false; }
195 }
196
197 if scored_words > 0 {
198 Ok(total_score / scored_words as f32)
199 } else {
200 Ok(0.0)
201 }
202 } else {
203 Ok(0.0) }
205 }
206
207 fn assess_formality(&self, text: &str) -> Result<f32> {
208 let words: Vec<&str> = text.split_whitespace().collect();
209
210 let indicators = self.formality_indicators.get(&LanguageCode::EnUs);
212
213 if let Some(indicators) = indicators {
214 let mut formal_score = 0.0;
215 let mut informal_score = 0.0;
216
217 for word in &words {
218 let word_lower = word.to_lowercase();
219
220 if let Some(score) = indicators.formal_indicators.get(&word_lower) {
221 formal_score += score;
222 }
223
224 if let Some(score) = indicators.informal_indicators.get(&word_lower) {
225 informal_score += score;
226 }
227 }
228
229 let total_score = formal_score + informal_score;
230 if total_score > 0.0 {
231 Ok(formal_score / total_score)
232 } else {
233 Ok(0.5) }
235 } else {
236 Ok(0.5) }
238 }
239
240 fn supported_languages(&self) -> Vec<LanguageCode> {
241 self.sentiment_lexicons.keys().copied().collect()
242 }
243}
244
245impl BasicSemanticAnalyzer {
246 pub fn new() -> Self {
248 let mut analyzer = Self {
249 topic_models: HashMap::new(),
250 sentiment_lexicons: HashMap::new(),
251 formality_indicators: HashMap::new(),
252 };
253
254 analyzer.initialize_default_topic_models();
256 analyzer.initialize_default_sentiment_lexicons();
257 analyzer.initialize_default_formality_indicators();
258
259 analyzer
260 }
261
262 pub fn add_topic_model(&mut self, name: String, model: TopicModel) {
264 self.topic_models.insert(name, model);
265 }
266
267 pub fn add_sentiment_lexicon(&mut self, language: LanguageCode, lexicon: SentimentLexicon) {
269 self.sentiment_lexicons.insert(language, lexicon);
270 }
271
272 pub fn add_formality_indicators(
274 &mut self,
275 language: LanguageCode,
276 indicators: FormalityIndicators,
277 ) {
278 self.formality_indicators.insert(language, indicators);
279 }
280
281 fn initialize_default_topic_models(&mut self) {
283 let mut tech_model = TopicModel::new("technology".to_string(), 0.1);
285 let tech_keywords = vec![
286 ("computer", 0.9),
287 ("software", 0.8),
288 ("algorithm", 0.8),
289 ("programming", 0.9),
290 ("code", 0.7),
291 ("development", 0.7),
292 ("system", 0.6),
293 ("network", 0.7),
294 ("database", 0.8),
295 ("server", 0.7),
296 ("application", 0.6),
297 ("digital", 0.6),
298 ("internet", 0.7),
299 ("web", 0.6),
300 ("mobile", 0.6),
301 ("cloud", 0.7),
302 ("artificial", 0.8),
303 ("intelligence", 0.8),
304 ("machine", 0.7),
305 ("learning", 0.8),
306 ("data", 0.6),
307 ("analytics", 0.7),
308 ("security", 0.7),
309 ("encryption", 0.8),
310 ];
311 for (word, weight) in tech_keywords {
312 tech_model.add_keyword(word.to_string(), weight);
313 }
314 self.add_topic_model("technology".to_string(), tech_model);
315
316 let mut business_model = TopicModel::new("business".to_string(), 0.1);
318 let business_keywords = vec![
319 ("company", 0.8),
320 ("market", 0.8),
321 ("customer", 0.7),
322 ("sales", 0.8),
323 ("revenue", 0.9),
324 ("profit", 0.9),
325 ("investment", 0.8),
326 ("strategy", 0.7),
327 ("management", 0.7),
328 ("finance", 0.8),
329 ("marketing", 0.8),
330 ("brand", 0.7),
331 ("product", 0.6),
332 ("service", 0.6),
333 ("business", 0.9),
334 ("enterprise", 0.8),
335 ("corporate", 0.8),
336 ("commercial", 0.7),
337 ("economic", 0.7),
338 ("financial", 0.8),
339 ("industry", 0.7),
340 ("sector", 0.7),
341 ("competition", 0.7),
342 ("growth", 0.7),
343 ];
344 for (word, weight) in business_keywords {
345 business_model.add_keyword(word.to_string(), weight);
346 }
347 self.add_topic_model("business".to_string(), business_model);
348
349 let mut health_model = TopicModel::new("health".to_string(), 0.1);
351 let health_keywords = vec![
352 ("medical", 0.9),
353 ("health", 0.9),
354 ("doctor", 0.8),
355 ("patient", 0.8),
356 ("treatment", 0.8),
357 ("medicine", 0.8),
358 ("hospital", 0.8),
359 ("clinic", 0.7),
360 ("diagnosis", 0.8),
361 ("therapy", 0.7),
362 ("surgery", 0.8),
363 ("disease", 0.7),
364 ("symptoms", 0.7),
365 ("prevention", 0.7),
366 ("wellness", 0.7),
367 ("fitness", 0.6),
368 ("nutrition", 0.7),
369 ("pharmaceutical", 0.8),
370 ("research", 0.6),
371 ("clinical", 0.8),
372 ("healthcare", 0.9),
373 ("nursing", 0.7),
374 ("emergency", 0.7),
375 ("recovery", 0.6),
376 ];
377 for (word, weight) in health_keywords {
378 health_model.add_keyword(word.to_string(), weight);
379 }
380 self.add_topic_model("health".to_string(), health_model);
381
382 let mut education_model = TopicModel::new("education".to_string(), 0.1);
384 let education_keywords = vec![
385 ("school", 0.8),
386 ("university", 0.8),
387 ("student", 0.8),
388 ("teacher", 0.8),
389 ("learning", 0.9),
390 ("education", 0.9),
391 ("academic", 0.8),
392 ("study", 0.7),
393 ("research", 0.7),
394 ("curriculum", 0.8),
395 ("course", 0.7),
396 ("degree", 0.7),
397 ("knowledge", 0.7),
398 ("scholarship", 0.8),
399 ("tuition", 0.7),
400 ("exam", 0.6),
401 ("grade", 0.6),
402 ("class", 0.6),
403 ("lecture", 0.7),
404 ("professor", 0.8),
405 ("college", 0.8),
406 ("training", 0.7),
407 ("skill", 0.6),
408 ("instruction", 0.7),
409 ];
410 for (word, weight) in education_keywords {
411 education_model.add_keyword(word.to_string(), weight);
412 }
413 self.add_topic_model("education".to_string(), education_model);
414
415 let mut science_model = TopicModel::new("science".to_string(), 0.1);
417 let science_keywords = vec![
418 ("science", 0.9),
419 ("research", 0.8),
420 ("experiment", 0.8),
421 ("theory", 0.7),
422 ("hypothesis", 0.8),
423 ("analysis", 0.7),
424 ("method", 0.6),
425 ("result", 0.6),
426 ("conclusion", 0.7),
427 ("discovery", 0.8),
428 ("innovation", 0.7),
429 ("laboratory", 0.8),
430 ("physics", 0.8),
431 ("chemistry", 0.8),
432 ("biology", 0.8),
433 ("mathematics", 0.8),
434 ("engineering", 0.8),
435 ("technology", 0.7),
436 ("scientific", 0.8),
437 ("academic", 0.7),
438 ("publication", 0.7),
439 ("journal", 0.7),
440 ("peer", 0.6),
441 ("review", 0.6),
442 ];
443 for (word, weight) in science_keywords {
444 science_model.add_keyword(word.to_string(), weight);
445 }
446 self.add_topic_model("science".to_string(), science_model);
447 }
448
449 fn initialize_default_sentiment_lexicons(&mut self) {
451 let mut en_lexicon = SentimentLexicon::new();
453
454 let positive_words = vec![
456 ("excellent", 0.9),
457 ("amazing", 0.9),
458 ("wonderful", 0.8),
459 ("fantastic", 0.9),
460 ("great", 0.7),
461 ("good", 0.6),
462 ("nice", 0.5),
463 ("beautiful", 0.7),
464 ("perfect", 0.9),
465 ("outstanding", 0.9),
466 ("superb", 0.8),
467 ("brilliant", 0.8),
468 ("awesome", 0.8),
469 ("terrific", 0.8),
470 ("marvelous", 0.8),
471 ("spectacular", 0.8),
472 ("love", 0.8),
473 ("like", 0.4),
474 ("enjoy", 0.6),
475 ("happy", 0.7),
476 ("pleased", 0.6),
477 ("satisfied", 0.6),
478 ("delighted", 0.8),
479 ("thrilled", 0.8),
480 ("excited", 0.7),
481 ("positive", 0.6),
482 ("successful", 0.7),
483 ("effective", 0.5),
484 ("impressive", 0.7),
485 ("remarkable", 0.7),
486 ("exceptional", 0.8),
487 ("superior", 0.7),
488 ];
489 for (word, score) in positive_words {
490 en_lexicon.add_word(word.to_string(), score);
491 }
492
493 let negative_words = vec![
495 ("terrible", -0.9),
496 ("awful", -0.9),
497 ("horrible", -0.9),
498 ("disgusting", -0.9),
499 ("bad", -0.6),
500 ("poor", -0.5),
501 ("worst", -0.9),
502 ("hate", -0.8),
503 ("dislike", -0.5),
504 ("disappointing", -0.7),
505 ("frustrated", -0.7),
506 ("angry", -0.7),
507 ("sad", -0.6),
508 ("upset", -0.6),
509 ("annoyed", -0.5),
510 ("irritated", -0.5),
511 ("terrible", -0.9),
512 ("dreadful", -0.8),
513 ("appalling", -0.9),
514 ("shocking", -0.7),
515 ("unacceptable", -0.8),
516 ("inadequate", -0.6),
517 ("insufficient", -0.5),
518 ("useless", -0.8),
519 ("worthless", -0.8),
520 ("pathetic", -0.8),
521 ("ridiculous", -0.6),
522 ("absurd", -0.6),
523 ("stupid", -0.7),
524 ("foolish", -0.6),
525 ("nonsense", -0.6),
526 ("wrong", -0.4),
527 ];
528 for (word, score) in negative_words {
529 en_lexicon.add_word(word.to_string(), score);
530 }
531
532 self.add_sentiment_lexicon(LanguageCode::EnUs, en_lexicon);
533 }
534
535 fn initialize_default_formality_indicators(&mut self) {
537 let mut en_indicators = FormalityIndicators::new();
539
540 let formal_words = vec![
542 ("therefore", 0.9),
543 ("furthermore", 0.9),
544 ("however", 0.8),
545 ("nevertheless", 0.9),
546 ("consequently", 0.9),
547 ("accordingly", 0.8),
548 ("subsequently", 0.8),
549 ("moreover", 0.8),
550 ("additionally", 0.8),
551 ("likewise", 0.7),
552 ("nonetheless", 0.8),
553 ("whereas", 0.8),
554 ("regarding", 0.7),
555 ("concerning", 0.7),
556 ("pursuant", 0.9),
557 ("henceforth", 0.9),
558 ("heretofore", 0.9),
559 ("notwithstanding", 0.9),
560 ("aforementioned", 0.9),
561 ("herewith", 0.8),
562 ("kindly", 0.7),
563 ("please", 0.5),
564 ("respectfully", 0.8),
565 ("sincerely", 0.8),
566 ("cordially", 0.8),
567 ("gratefully", 0.7),
568 ("appreciate", 0.6),
569 ("acknowledge", 0.7),
570 ("endeavor", 0.8),
571 ("utilize", 0.7),
572 ("implement", 0.6),
573 ("establish", 0.6),
574 ];
575 for (word, score) in formal_words {
576 en_indicators.add_formal_indicator(word.to_string(), score);
577 }
578
579 let informal_words = vec![
581 ("yeah", 0.9),
582 ("yep", 0.8),
583 ("nope", 0.8),
584 ("gonna", 0.9),
585 ("wanna", 0.9),
586 ("gotta", 0.9),
587 ("kinda", 0.8),
588 ("sorta", 0.8),
589 ("dunno", 0.9),
590 ("ain't", 0.9),
591 ("can't", 0.4),
592 ("won't", 0.4),
593 ("don't", 0.4),
594 ("isn't", 0.4),
595 ("wasn't", 0.4),
596 ("weren't", 0.4),
597 ("cool", 0.6),
598 ("awesome", 0.6),
599 ("sweet", 0.7),
600 ("neat", 0.6),
601 ("stuff", 0.6),
602 ("things", 0.4),
603 ("guys", 0.7),
604 ("folks", 0.6),
605 ("ok", 0.7),
606 ("okay", 0.6),
607 ("alright", 0.7),
608 ("sure", 0.5),
609 ("totally", 0.7),
610 ("really", 0.4),
611 ("pretty", 0.4),
612 ("super", 0.6),
613 ];
614 for (word, score) in informal_words {
615 en_indicators.add_informal_indicator(word.to_string(), score);
616 }
617
618 let technical_terms = vec![
620 "algorithm",
621 "methodology",
622 "implementation",
623 "optimization",
624 "configuration",
625 "specification",
626 "architecture",
627 "framework",
628 "paradigm",
629 "protocol",
630 "interface",
631 "abstraction",
632 "encapsulation",
633 "polymorphism",
634 "inheritance",
635 "instantiation",
636 "initialization",
637 "synchronization",
638 "asynchronous",
639 "concurrent",
640 "distributed",
641 "scalable",
642 "modular",
643 "extensible",
644 "maintainable",
645 ];
646 for term in technical_terms {
647 en_indicators.add_technical_term(term.to_string());
648 }
649
650 self.add_formality_indicators(LanguageCode::EnUs, en_indicators);
651 }
652
653 fn assess_technical_complexity(&self, words: &[&str]) -> f32 {
655 let mut _technical_count = 0;
656 let mut total_complexity = 0.0;
657
658 for word in words {
659 let word_len = word.len();
660
661 if word_len > 10 {
663 _technical_count += 1;
664 total_complexity += 0.3;
665 }
666
667 if word.contains('_') || word.contains('-') {
668 _technical_count += 1;
669 total_complexity += 0.2;
670 }
671
672 if word.chars().any(|c| c.is_uppercase()) && word.len() > 3 {
673 _technical_count += 1;
674 total_complexity += 0.1;
675 }
676 }
677
678 if words.is_empty() {
679 0.0
680 } else {
681 total_complexity / words.len() as f32
682 }
683 }
684
685 fn classify_domain(&self, topics: &HashMap<String, f32>) -> Option<String> {
687 topics
688 .iter()
689 .max_by(|a, b| a.1.partial_cmp(b.1).unwrap_or(std::cmp::Ordering::Equal))
690 .map(|(domain, _)| domain.clone())
691 }
692
693 fn detect_emotion_indicators(&self, words: &[&str]) -> Vec<String> {
695 let emotion_words = [
696 "happy",
697 "sad",
698 "angry",
699 "excited",
700 "worried",
701 "surprised",
702 "disappointed",
703 "frustrated",
704 "delighted",
705 "anxious",
706 ];
707
708 words
709 .iter()
710 .filter_map(|word| {
711 let word_lower = word.to_lowercase();
712 if emotion_words.contains(&word_lower.as_str()) {
713 Some(word_lower)
714 } else {
715 None
716 }
717 })
718 .collect()
719 }
720
721 fn determine_register(&self, formality_level: f32, technical_complexity: f32) -> String {
723 match (formality_level, technical_complexity) {
724 (f, t) if f > 0.7 && t > 0.5 => "academic".to_string(),
725 (f, _) if f > 0.7 => "formal".to_string(),
726 (f, _) if f < 0.3 => "informal".to_string(),
727 (_, t) if t > 0.6 => "technical".to_string(),
728 _ => "neutral".to_string(),
729 }
730 }
731}
732
733impl Default for BasicSemanticAnalyzer {
734 fn default() -> Self {
735 Self::new()
736 }
737}
738
739impl TopicModel {
740 pub fn new(name: String, threshold: f32) -> Self {
742 Self {
743 keywords: HashMap::new(),
744 name,
745 threshold,
746 }
747 }
748
749 pub fn add_keyword(&mut self, keyword: String, weight: f32) {
751 self.keywords.insert(keyword, weight);
752 }
753}
754
755impl SentimentLexicon {
756 pub fn new() -> Self {
758 Self {
759 word_scores: HashMap::new(),
760 negation_patterns: vec!["not".to_string(), "no".to_string(), "never".to_string()],
761 intensifier_patterns: vec![
762 ("very".to_string(), 1.5),
763 ("extremely".to_string(), 2.0),
764 ("quite".to_string(), 1.2),
765 ],
766 }
767 }
768
769 pub fn add_word(&mut self, word: String, score: f32) {
771 self.word_scores.insert(word, score.clamp(-1.0, 1.0));
772 }
773}
774
775impl Default for SentimentLexicon {
776 fn default() -> Self {
777 Self::new()
778 }
779}
780
781impl FormalityIndicators {
782 pub fn new() -> Self {
784 Self {
785 formal_indicators: HashMap::new(),
786 informal_indicators: HashMap::new(),
787 technical_terms: HashSet::new(),
788 }
789 }
790
791 pub fn add_formal_indicator(&mut self, word: String, score: f32) {
793 self.formal_indicators.insert(word, score);
794 }
795
796 pub fn add_informal_indicator(&mut self, word: String, score: f32) {
798 self.informal_indicators.insert(word, score);
799 }
800
801 pub fn add_technical_term(&mut self, term: String) {
803 self.technical_terms.insert(term);
804 }
805}
806
807impl Default for FormalityIndicators {
808 fn default() -> Self {
809 Self::new()
810 }
811}
812
813#[cfg(test)]
814mod tests {
815 use super::*;
816
817 #[test]
818 fn test_semantic_context_default() {
819 let context = SemanticContext::default();
820 assert_eq!(context.sentiment_polarity, 0.0);
821 assert_eq!(context.formality_level, 0.5);
822 assert_eq!(context.technical_complexity, 0.0);
823 assert_eq!(context.register, "neutral");
824 }
825
826 #[test]
827 fn test_topic_model() {
828 let mut model = TopicModel::new("technology".to_string(), 0.1);
829 model.add_keyword("computer".to_string(), 0.8);
830 model.add_keyword("software".to_string(), 0.7);
831
832 assert_eq!(model.keywords.len(), 2);
833 assert_eq!(model.keywords.get("computer"), Some(&0.8));
834 }
835
836 #[test]
837 fn test_sentiment_lexicon() {
838 let mut lexicon = SentimentLexicon::new();
839 lexicon.add_word("happy".to_string(), 0.8);
840 lexicon.add_word("sad".to_string(), -0.6);
841
842 assert_eq!(lexicon.word_scores.get("happy"), Some(&0.8));
843 assert_eq!(lexicon.word_scores.get("sad"), Some(&-0.6));
844 }
845
846 #[test]
847 fn test_formality_indicators() {
848 let mut indicators = FormalityIndicators::new();
849 indicators.add_formal_indicator("therefore".to_string(), 0.8);
850 indicators.add_informal_indicator("yeah".to_string(), 0.9);
851 indicators.add_technical_term("algorithm".to_string());
852
853 assert_eq!(indicators.formal_indicators.len(), 1);
854 assert_eq!(indicators.informal_indicators.len(), 1);
855 assert!(indicators.technical_terms.contains("algorithm"));
856 }
857
858 #[test]
859 fn test_basic_semantic_analyzer() {
860 let analyzer = BasicSemanticAnalyzer::new();
861
862 let context = analyzer.analyze_context("").unwrap();
864 assert_eq!(context.topics.len(), 0);
865 assert_eq!(context.sentiment_polarity, 0.0);
866 }
867
868 #[test]
869 fn test_technical_complexity() {
870 let analyzer = BasicSemanticAnalyzer::new();
871 let words = vec!["very_complex_function", "algorithm", "data"];
872 let complexity = analyzer.assess_technical_complexity(&words);
873 assert!(complexity > 0.0);
874 }
875
876 #[test]
877 fn test_emotion_indicators() {
878 let analyzer = BasicSemanticAnalyzer::new();
879 let words = vec!["I", "am", "very", "happy", "today"];
880 let emotions = analyzer.detect_emotion_indicators(&words);
881 assert!(emotions.contains(&"happy".to_string()));
882 }
883
884 #[test]
885 fn test_register_determination() {
886 let analyzer = BasicSemanticAnalyzer::new();
887
888 assert_eq!(analyzer.determine_register(0.8, 0.6), "academic");
889 assert_eq!(analyzer.determine_register(0.8, 0.2), "formal");
890 assert_eq!(analyzer.determine_register(0.2, 0.1), "informal");
891 assert_eq!(analyzer.determine_register(0.5, 0.7), "technical");
892 assert_eq!(analyzer.determine_register(0.5, 0.3), "neutral");
893 }
894}