use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UserContext {
pub hour: Option<u8>,
pub day: Option<u8>,
pub device: Option<String>,
pub location: Option<String>,
pub mood: Option<UserMood>,
pub social: SocialContext,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum UserMood {
Relaxed,
Energetic,
Focused,
Social,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SocialContext {
pub watching_alone: bool,
pub group_size: usize,
}
pub struct ContextProcessor {
time_weights: TimeWeights,
}
#[derive(Debug, Clone)]
pub struct TimeWeights {
pub morning: f32,
pub afternoon: f32,
pub evening: f32,
pub night: f32,
}
impl Default for TimeWeights {
fn default() -> Self {
Self {
morning: 1.0,
afternoon: 1.0,
evening: 1.2, night: 0.8,
}
}
}
impl ContextProcessor {
#[must_use]
pub fn new() -> Self {
Self {
time_weights: TimeWeights::default(),
}
}
#[must_use]
pub fn calculate_context_boost(&self, context: &UserContext) -> f32 {
let mut boost = 1.0;
if let Some(hour) = context.hour {
boost *= self.get_time_weight(hour);
}
if let Some(ref device) = context.device {
boost *= self.get_device_weight(device);
}
if !context.social.watching_alone && context.social.group_size > 1 {
boost *= 1.1; }
boost
}
fn get_time_weight(&self, hour: u8) -> f32 {
match hour {
6..=11 => self.time_weights.morning,
12..=17 => self.time_weights.afternoon,
18..=21 => self.time_weights.evening,
_ => self.time_weights.night,
}
}
fn get_device_weight(&self, device: &str) -> f32 {
match device {
"mobile" => 0.9, "tablet" => 1.0,
"tv" => 1.2, "desktop" => 1.1,
_ => 1.0,
}
}
#[must_use]
pub fn detect_intent(&self, context: &UserContext) -> UserIntent {
if let Some(hour) = context.hour {
if (6..12).contains(&hour) {
return UserIntent::QuickView;
} else if (22..24).contains(&hour) || hour < 6 {
return UserIntent::Binge;
}
}
if !context.social.watching_alone {
return UserIntent::Social;
}
UserIntent::Browse
}
}
impl Default for ContextProcessor {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub enum UserIntent {
QuickView,
Binge,
Social,
Browse,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_context_processor() {
let processor = ContextProcessor::new();
let mut context = UserContext::default();
context.hour = Some(20);
let boost = processor.calculate_context_boost(&context);
assert!(boost > 1.0); }
#[test]
fn test_detect_intent() {
let processor = ContextProcessor::new();
let mut context = UserContext::default();
context.hour = Some(8);
let intent = processor.detect_intent(&context);
assert!(matches!(intent, UserIntent::QuickView));
}
}