use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DetectedPattern {
pub pattern_name: String,
pub confidence: f64,
pub start_index: usize,
pub end_index: usize,
pub pattern_strength: f64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PatternType {
Clarification,
DeepDive,
Exploration,
FeedbackLoop,
StructuredWorkflow,
Frustration,
GoalAchieved,
TopicDrift,
}
impl PatternType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Clarification => "Clarification",
Self::DeepDive => "Deep Dive",
Self::Exploration => "Exploration",
Self::FeedbackLoop => "Feedback Loop",
Self::StructuredWorkflow => "Structured Workflow",
Self::Frustration => "Frustration",
Self::GoalAchieved => "Goal Achieved",
Self::TopicDrift => "Topic Drift",
}
}
}
#[derive(Debug)]
pub struct PatternRecognizer {
min_confidence: f64,
window_size: usize,
}
impl PatternRecognizer {
pub fn new(min_confidence: f64, window_size: usize) -> Self {
Self {
min_confidence,
window_size,
}
}
pub fn detect_patterns(&self, messages: &[String]) -> Vec<DetectedPattern> {
let mut patterns = Vec::new();
if messages.len() < 2 {
return patterns;
}
let len = messages.len();
let window_end = len.min(self.window_size);
let question_count = messages[..window_end]
.iter()
.filter(|m| m.contains('?'))
.count();
if question_count >= 2 {
let confidence = (question_count as f64 / window_end as f64).min(1.0);
if confidence >= self.min_confidence {
patterns.push(DetectedPattern {
pattern_name: PatternType::Clarification.as_str().to_string(),
confidence,
start_index: 0,
end_index: window_end.saturating_sub(1),
pattern_strength: confidence,
});
}
}
let unique_words: std::collections::HashSet<&str> = messages[..window_end]
.iter()
.flat_map(|m| m.split_whitespace())
.collect();
if unique_words.len() > 50 {
let confidence = ((unique_words.len() - 50) as f64 / 100.0).min(1.0);
if confidence >= self.min_confidence {
patterns.push(DetectedPattern {
pattern_name: PatternType::Exploration.as_str().to_string(),
confidence,
start_index: 0,
end_index: window_end.saturating_sub(1),
pattern_strength: confidence,
});
}
}
patterns
}
}
impl Default for PatternRecognizer {
fn default() -> Self {
Self::new(0.5, 20)
}
}