use std::collections::HashSet;
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone)]
pub struct Stimulus {
pub id: String,
pub content: String,
pub source: String,
pub urgency: f32, pub relevance: f32, pub timestamp: u64,
pub suppressed: bool,
}
pub struct ImpulseControl {
#[allow(dead_code)]
attention_gates: Arc<RwLock<Vec<String>>>,
suppression_patterns: Arc<RwLock<HashSet<String>>>,
long_term_goals: Vec<String>,
attention_budget: f32, suppression_threshold: f32,
}
impl Default for ImpulseControl {
fn default() -> Self {
Self::new()
}
}
impl ImpulseControl {
pub fn new() -> Self {
Self {
attention_gates: Arc::new(RwLock::new(vec![
"urgent".to_string(),
"important".to_string(),
"goal_aligned".to_string(),
])),
suppression_patterns: Arc::new(RwLock::new(HashSet::new())),
long_term_goals: Vec::new(),
attention_budget: 0.8, suppression_threshold: 0.3,
}
}
pub fn add_goal(&mut self, goal: &str) {
self.long_term_goals.push(goal.to_string());
}
pub fn add_suppression_pattern(&mut self, pattern: &str) {
crate::sync_guard::write_lock(&self.suppression_patterns).insert(pattern.to_lowercase());
}
pub fn filter_stimulus(&mut self, content: &str, source: &str, urgency: f32) -> Stimulus {
let id = format!("stimulus_{}", rand::random::<u32>());
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let mut suppressed = false;
let mut relevance = self.calculate_relevance(content);
let content_lower = content.to_lowercase();
let patterns = crate::sync_guard::read_lock(&self.suppression_patterns);
for pattern in patterns.iter() {
if content_lower.contains(pattern) {
suppressed = true;
relevance = 0.0; break;
}
}
if !suppressed && self.attention_budget < 0.2 {
if relevance < self.suppression_threshold * 2.0 {
suppressed = true;
}
}
let stimulus = Stimulus {
id,
content: content.to_string(),
source: source.to_string(),
urgency,
relevance,
timestamp,
suppressed,
};
if !stimulus.suppressed && stimulus.relevance > 0.5 {
self.attention_budget -= 0.1; self.attention_budget = self.attention_budget.max(0.0);
}
stimulus
}
fn calculate_relevance(&self, content: &str) -> f32 {
if self.long_term_goals.is_empty() {
return 0.5; }
let content_lower = content.to_lowercase();
let mut score = 0.0;
for goal in &self.long_term_goals {
let goal_lower = goal.to_lowercase();
if content_lower.contains(&goal_lower) {
score += 1.0;
}
}
let goal_keywords = ["achieve", "progress", "improve", "develop", "complete"];
for keyword in &goal_keywords {
if content_lower.contains(keyword) {
score += 0.5;
}
}
(score / (self.long_term_goals.len() as f32 + goal_keywords.len() as f32)).min(1.0)
}
pub fn restore_attention(&mut self, amount: f32) {
self.attention_budget += amount;
self.attention_budget = self.attention_budget.min(1.0);
}
pub fn get_stats(&self) -> (f32, usize) {
let patterns = crate::sync_guard::read_lock(&self.suppression_patterns);
(self.attention_budget, patterns.len())
}
pub fn clear_patterns(&mut self) {
crate::sync_guard::write_lock(&self.suppression_patterns).clear();
}
}
pub fn batch_filter_stimuli(
control: &mut ImpulseControl,
stimuli: &[(&str, &str, f32)],
) -> Vec<Stimulus> {
stimuli
.iter()
.map(|(content, source, urgency)| control.filter_stimulus(content, source, *urgency))
.collect()
}