use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
use uuid::Uuid;
#[derive(Debug, thiserror::Error)]
pub enum IntentError {
#[error("Classification failed: {0}")]
ClassificationFailed(String),
#[error("Invalid parameter '{parameter}': {message}")]
InvalidParameter { parameter: String, message: String },
#[error("Training failed: {0}")]
TrainingFailed(String),
#[error("Serialization error: {0}")]
SerializationError(#[from] serde_json::Error),
#[error("Invalid confidence value: {0}")]
InvalidConfidence(String),
}
pub type Result<T> = std::result::Result<T, IntentError>;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IntentId(pub String);
impl fmt::Display for IntentId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<String> for IntentId {
fn from(s: String) -> Self {
IntentId(s)
}
}
impl From<&str> for IntentId {
fn from(s: &str) -> Self {
IntentId(s.to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct Confidence(f64);
impl Confidence {
pub fn new(value: f64) -> Result<Self> {
if (0.0..=1.0).contains(&value) {
Ok(Confidence(value))
} else {
Err(IntentError::InvalidParameter {
parameter: "confidence".to_string(),
message: format!("Confidence must be between 0.0 and 1.0, got {}", value),
})
}
}
pub fn value(&self) -> f64 {
self.0
}
pub fn is_high(&self) -> bool {
self.0 >= 0.8
}
pub fn is_medium(&self) -> bool {
self.0 >= 0.5 && self.0 < 0.8
}
pub fn is_low(&self) -> bool {
self.0 < 0.5
}
}
impl Default for Confidence {
fn default() -> Self {
Confidence(1.0)
}
}
impl From<Confidence> for f64 {
fn from(confidence: Confidence) -> Self {
confidence.0
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntentPrediction {
pub intent: IntentId,
pub confidence: Confidence,
pub alternative_intents: Vec<(IntentId, Confidence)>,
pub reasoning: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrainingExample {
pub text: String,
pub intent: IntentId,
pub confidence: f64,
pub source: TrainingSource,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrainingSource {
Bootstrap,
UserFeedback,
Programmatic,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeatureVector {
pub text_features: Vec<f64>,
pub context_features: Vec<f64>,
pub metadata: HashMap<String, f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassifierConfig {
pub feature_dimensions: usize,
pub max_vocabulary_size: usize,
pub min_confidence_threshold: f64,
pub retraining_threshold: usize,
pub debug_mode: bool,
}
impl Default for ClassifierConfig {
fn default() -> Self {
Self {
feature_dimensions: 1000,
max_vocabulary_size: 10000,
min_confidence_threshold: 0.3,
retraining_threshold: 10,
debug_mode: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassifierStats {
pub training_examples: usize,
pub vocabulary_size: usize,
pub intent_count: usize,
pub feedback_examples: usize,
pub last_updated: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntentFeedback {
pub text: String,
pub predicted_intent: IntentId,
pub actual_intent: IntentId,
pub satisfaction_score: f64,
pub notes: Option<String>,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassificationRequest {
pub text: String,
pub context: Option<HashMap<String, String>>,
pub include_alternatives: bool,
pub include_reasoning: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassificationResponse {
pub prediction: IntentPrediction,
pub processing_time_ms: f64,
pub request_id: Uuid,
}