#![ allow( clippy::trivially_copy_pass_by_ref, clippy::unused_self, clippy::struct_field_names ) ]
use api_huggingface::
{
Client,
environment::HuggingFaceEnvironmentImpl,
components::
{
input::InferenceParameters,
},
secret::Secret,
};
use std::{ collections::HashMap, time::Instant };
use serde::{ Serialize, Deserialize };
#[ allow( missing_docs ) ]
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub enum ComplexityLevel
{
Elementary,
MiddleSchool,
HighSchool,
University,
Graduate,
}
impl ComplexityLevel
{
#[ must_use ]
pub fn name( &self ) -> &'static str
{
match self
{
ComplexityLevel::Elementary => "Elementary",
ComplexityLevel::MiddleSchool => "Middle School",
ComplexityLevel::HighSchool => "High School",
ComplexityLevel::University => "University",
ComplexityLevel::Graduate => "Graduate",
}
}
#[ must_use ]
pub fn age_range( &self ) -> ( u8, u8 )
{
match self
{
ComplexityLevel::Elementary => ( 5, 11 ),
ComplexityLevel::MiddleSchool => ( 11, 14 ),
ComplexityLevel::HighSchool => ( 14, 18 ),
ComplexityLevel::University => ( 18, 22 ),
ComplexityLevel::Graduate => ( 22, 99 ),
}
}
#[ must_use ]
pub fn vocabulary_complexity( &self ) -> u8
{
match self
{
ComplexityLevel::Elementary => 2,
ComplexityLevel::MiddleSchool => 4,
ComplexityLevel::HighSchool => 6,
ComplexityLevel::University => 8,
ComplexityLevel::Graduate => 10,
}
}
#[ must_use ]
pub fn explanation_length_range( &self ) -> ( usize, usize )
{
match self
{
ComplexityLevel::Elementary => ( 50, 150 ),
ComplexityLevel::MiddleSchool => ( 100, 250 ),
ComplexityLevel::HighSchool => ( 150, 350 ),
ComplexityLevel::University => ( 200, 500 ),
ComplexityLevel::Graduate => ( 300, 800 ),
}
}
#[ must_use ]
pub fn preferred_model( &self ) -> &'static str
{
"meta-llama/Llama-3.3-70B-Instruct"
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub enum LearningStyle
{
Visual,
Auditory,
Kinesthetic,
ReadingWriting,
Multimodal,
}
impl LearningStyle
{
#[ must_use ]
pub fn name( &self ) -> &'static str
{
match self
{
LearningStyle::Visual => "Visual",
LearningStyle::Auditory => "Auditory",
LearningStyle::Kinesthetic => "Kinesthetic",
LearningStyle::ReadingWriting => "Reading/Writing",
LearningStyle::Multimodal => "Multimodal",
}
}
#[ must_use ]
pub fn content_preferences( &self ) -> Vec< &'static str >
{
match self
{
LearningStyle::Visual => vec![ "diagrams", "charts", "mind_maps", "infographics" ],
LearningStyle::Auditory => vec![ "verbal_explanations", "discussions", "recordings", "mnemonics" ],
LearningStyle::Kinesthetic => vec![ "hands_on_activities", "experiments", "simulations", "practice_problems" ],
LearningStyle::ReadingWriting => vec![ "detailed_text", "note_taking", "summaries", "written_exercises" ],
LearningStyle::Multimodal => vec![ "combined_approaches", "varied_formats", "interactive_content", "adaptive_materials" ],
}
}
#[ must_use ]
pub fn engagement_strategies( &self ) -> Vec< &'static str >
{
match self
{
LearningStyle::Visual => vec![ "use_visual_metaphors", "create_concept_maps", "show_step_by_step_visuals" ],
LearningStyle::Auditory => vec![ "explain_aloud", "use_analogies", "encourage_discussion" ],
LearningStyle::Kinesthetic => vec![ "provide_examples", "suggest_practice", "break_into_steps" ],
LearningStyle::ReadingWriting => vec![ "provide_detailed_notes", "suggest_writing_exercises", "offer_additional_reading" ],
LearningStyle::Multimodal => vec![ "combine_multiple_methods", "provide_alternatives", "adapt_to_context" ],
}
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub enum Subject
{
Mathematics,
Science,
History,
LanguageArts,
ComputerScience,
ForeignLanguage,
Arts,
General,
}
impl Subject
{
#[ must_use ]
pub fn name( &self ) -> &'static str
{
match self
{
Subject::Mathematics => "Mathematics",
Subject::Science => "Science",
Subject::History => "History",
Subject::LanguageArts => "Language Arts",
Subject::ComputerScience => "Computer Science",
Subject::ForeignLanguage => "Foreign Language",
Subject::Arts => "Arts",
Subject::General => "General Knowledge",
}
}
#[ must_use ]
pub fn teaching_approaches( &self ) -> Vec< &'static str >
{
match self
{
Subject::Mathematics => vec![ "step_by_step_solutions", "problem_solving", "formula_derivation", "visual_proofs" ],
Subject::Science => vec![ "conceptual_explanations", "real_world_applications", "experimental_design", "cause_and_effect" ],
Subject::History => vec![ "chronological_narrative", "cause_and_effect", "primary_sources", "contextual_analysis" ],
Subject::LanguageArts => vec![ "textual_analysis", "writing_techniques", "grammar_explanation", "literary_devices" ],
Subject::ComputerScience => vec![ "code_examples", "algorithm_explanation", "debugging_techniques", "system_design" ],
Subject::ForeignLanguage => vec![ "conversation_practice", "grammar_rules", "cultural_context", "pronunciation_guides" ],
Subject::Arts => vec![ "technique_demonstration", "historical_context", "creative_inspiration", "skill_building" ],
Subject::General => vec![ "interdisciplinary_connections", "critical_thinking", "research_methods", "synthesis" ],
}
}
}
#[ derive( Debug, Clone ) ]
pub struct StudentProfile
{
pub student_id : String,
pub name : String,
pub complexity_level : ComplexityLevel,
pub learning_style : LearningStyle,
pub strong_subjects : Vec< Subject >,
pub weak_subjects : Vec< Subject >,
pub learning_goals : Vec< String >,
pub learning_pace : f32,
pub preferences : HashMap< String, String >,
}
#[ derive( Debug, Clone ) ]
pub struct ConceptRequest
{
pub concept : String,
pub subject : Subject,
pub complexity_level : ComplexityLevel,
pub learning_style : LearningStyle,
pub context : Option< String >,
pub prerequisites : Vec< String >,
pub focus_areas : Vec< String >,
}
#[ derive( Debug, Clone ) ]
pub struct ConceptExplanation
{
pub concept : String,
pub explanation : String,
pub key_points : Vec< String >,
pub examples : Vec< String >,
pub related_concepts : Vec< String >,
pub practice_suggestions : Vec< String >,
pub effectiveness_score : f32,
pub complexity_score : f32,
pub generation_time_ms : u64,
}
#[ derive( Debug, Clone ) ]
pub struct StudentQuestion
{
pub question_id : String,
pub question_text : String,
pub subject : Option< Subject >,
pub complexity_level : ComplexityLevel,
pub context : Option< String >,
pub understanding_level : Option< f32 >,
}
#[ derive( Debug, Clone ) ]
pub struct TutorResponse
{
pub answer : String,
pub confidence : f32,
pub educational_value : f32,
pub suggests_follow_up : bool,
pub follow_up_suggestions : Vec< String >,
pub understanding_assessment : f32,
pub response_time_ms : u64,
}
#[ derive( Debug, Clone ) ]
pub struct LearningProgress
{
pub subject : Subject,
pub proficiency_level : f32,
pub improvement_rate : f32,
pub concepts_mastered : u32,
pub correct_answers : u32,
pub total_questions : u32,
pub average_response_time : f32,
pub last_updated : String,
}
#[ derive( Debug, Clone ) ]
pub struct Assessment
{
pub assessment_id : String,
pub subject : Subject,
pub questions : Vec< AssessmentQuestion >,
pub total_points : u32,
pub time_limit_minutes : Option< u32 >,
pub difficulty_level : ComplexityLevel,
}
#[ derive( Debug, Clone ) ]
pub struct AssessmentQuestion
{
pub question_id : String,
pub question : String,
pub question_type : QuestionType,
pub correct_answers : Vec< String >,
pub points : u32,
pub explanation : String,
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash ) ]
pub enum QuestionType
{
MultipleChoice,
TrueFalse,
ShortAnswer,
Essay,
FillInTheBlank,
Mathematical,
}
#[ derive( Debug, Clone ) ]
pub struct AssessmentResult
{
pub responses : Vec< String >,
pub score : u32,
pub percentage : f32,
pub time_taken : f32,
pub question_feedback : Vec< QuestionFeedback >,
pub performance_summary : String,
pub improvement_areas : Vec< String >,
pub recommendations : Vec< String >,
}
#[ derive( Debug, Clone ) ]
pub struct QuestionFeedback
{
pub question_id : String,
pub is_correct : bool,
pub points_earned : u32,
pub feedback : String,
pub improvement_hints : Vec< String >,
}
#[ derive( Debug, Clone ) ]
pub struct AITutorPlatform
{
client : Client< HuggingFaceEnvironmentImpl >,
students : HashMap< String, StudentProfile >,
progress_tracking : HashMap< String, HashMap< Subject, LearningProgress > >,
config : TutorConfig,
statistics : TutorStatistics,
}
#[ derive( Debug, Clone ) ]
pub struct TutorConfig
{
pub default_model : String,
pub max_explanation_length : usize,
pub enable_adaptive_difficulty : bool,
pub progress_update_frequency : u32,
pub default_learning_style : LearningStyle,
pub assessment_frequency : u32,
}
impl Default for TutorConfig
{
fn default() -> Self
{
Self
{
default_model : "meta-llama/Llama-3.3-70B-Instruct".to_string(),
max_explanation_length : 1000,
enable_adaptive_difficulty : true,
progress_update_frequency : 5,
default_learning_style : LearningStyle::Multimodal,
assessment_frequency : 10,
}
}
}
#[ derive( Debug, Clone, Default ) ]
pub struct TutorStatistics
{
pub total_explanations : u64,
pub total_questions_answered : u64,
pub average_effectiveness : f32,
pub total_learning_time : u64,
pub students_served : u32,
pub subject_popularity : HashMap< Subject, u32 >,
pub complexity_distribution : HashMap< ComplexityLevel, u32 >,
}
impl AITutorPlatform
{
#[ must_use ]
pub fn new( client : Client< HuggingFaceEnvironmentImpl > ) -> Self
{
Self
{
client,
students : HashMap::new(),
progress_tracking : HashMap::new(),
config : TutorConfig::default(),
statistics : TutorStatistics::default(),
}
}
#[ must_use ]
pub fn with_config( client : Client< HuggingFaceEnvironmentImpl >, config : TutorConfig ) -> Self
{
Self
{
client,
students : HashMap::new(),
progress_tracking : HashMap::new(),
config,
statistics : TutorStatistics::default(),
}
}
pub fn register_student( &mut self, profile : StudentProfile )
{
let student_id = profile.student_id.clone();
self.students.insert( student_id.clone(), profile );
let mut progress = HashMap::new();
for subject in [ Subject::Mathematics, Subject::Science, Subject::History, Subject::LanguageArts,
Subject::ComputerScience, Subject::ForeignLanguage, Subject::Arts, Subject::General ]
{
progress.insert( subject, LearningProgress
{
subject,
proficiency_level : 0.5, improvement_rate : 0.0,
concepts_mastered : 0,
correct_answers : 0,
total_questions : 0,
average_response_time : 0.0,
last_updated : "2023-01-01".to_string(),
} );
}
self.progress_tracking.insert( student_id, progress );
self.statistics.students_served += 1;
}
pub async fn explain_concept( &mut self, request : &ConceptRequest ) -> Result< ConceptExplanation, Box< dyn std::error::Error > >
{
let prompt = self.build_explanation_prompt( request );
let model = request.complexity_level.preferred_model();
let params = InferenceParameters::new()
.with_max_new_tokens( self.calculate_max_tokens( request.complexity_level ) )
.with_temperature( 0.7 ) .with_top_p( 0.9 );
let response = self.client.inference().create_with_parameters( &prompt, model, params ).await?;
let explanation_text = response.extract_text_or_default( "Unable to generate explanation." );
let explanation = self.process_explanation( &explanation_text, request );
self.update_explanation_statistics( request.subject, request.complexity_level );
Ok( explanation )
}
pub async fn answer_question( &mut self, question : &StudentQuestion, student_id : Option< &str > ) -> Result< TutorResponse, Box< dyn std::error::Error > >
{
let start_time = Instant::now();
let prompt = self.build_question_prompt( question, student_id );
let model = question.complexity_level.preferred_model();
let params = InferenceParameters::new()
.with_max_new_tokens( 300 )
.with_temperature( 0.5 ) .with_top_p( 0.8 );
let response = self.client.inference().create_with_parameters( &prompt, model, params ).await?;
let answer_text = response.extract_text_or_default( "I'm not sure how to answer that question." );
let response_time = u64::try_from( start_time.elapsed().as_millis() ).unwrap_or( 0 );
let tutor_response = self.process_answer( &answer_text, question, response_time );
if let Some( id ) = student_id
{
self.update_student_progress( id, question, &tutor_response );
}
self.statistics.total_questions_answered += 1;
Ok( tutor_response )
}
#[ must_use ]
pub fn generate_assessment( &self, subject : Subject, complexity_level : ComplexityLevel, num_questions : usize ) -> Assessment
{
let mut questions = Vec::new();
for i in 0..num_questions
{
let question_type = match i % 4
{
0 => QuestionType::MultipleChoice,
1 => QuestionType::TrueFalse,
2 => QuestionType::ShortAnswer,
_ => QuestionType::FillInTheBlank,
};
questions.push( AssessmentQuestion
{
question_id : format!( "q_{}", i + 1 ),
question : format!( "Sample {} question {} for {complexity_level:?}", subject.name(), i + 1 ),
question_type,
correct_answers : vec![ "Sample correct answer".to_string() ],
points : 10,
explanation : "This is a sample explanation for the correct answer.".to_string(),
} );
}
let total_points = u32::try_from( num_questions * 10 ).unwrap_or( 0 );
let time_limit_minutes = u32::try_from( num_questions ).unwrap_or( 0 ) * 3;
Assessment
{
assessment_id : format!( "assessment_{}_{complexity_level:?}_{}", subject.name(), chrono::Utc::now().timestamp() ),
subject,
questions,
total_points,
time_limit_minutes : Some( time_limit_minutes ), difficulty_level : complexity_level,
}
}
#[ must_use ]
pub fn evaluate_assessment( &self, assessment : &Assessment, responses : Vec< String > ) -> AssessmentResult
{
let mut score = 0;
let mut question_feedback = Vec::new();
let time_taken = 15.5;
for ( i, response ) in responses.iter().enumerate()
{
if let Some( question ) = assessment.questions.get( i )
{
let is_correct = question.correct_answers.contains( response );
let points_earned = if is_correct { question.points } else { 0 };
score += points_earned;
question_feedback.push( QuestionFeedback
{
question_id : question.question_id.clone(),
is_correct,
points_earned,
feedback : if is_correct
{
"Correct! Well done.".to_string()
}
else
{
format!( "Incorrect. The correct answer is : {}", question.correct_answers[ 0 ] )
},
improvement_hints : if is_correct
{
Vec::new()
}
else
{
vec![ "Review the concept explanation and try practice problems.".to_string() ]
},
} );
}
}
let percentage = ( score as f32 / assessment.total_points as f32 ) * 100.0;
AssessmentResult
{
responses,
score,
percentage,
time_taken,
question_feedback,
performance_summary : if percentage >= 90.0 { "Excellent performance!" }
else if percentage >= 80.0 { "Good work with room for improvement." }
else if percentage >= 70.0 { "Satisfactory performance." }
else { "Needs significant improvement." }.to_string(),
improvement_areas : vec![ "Practice more problems".to_string(), "Review key concepts".to_string() ],
recommendations : vec![ "Focus on fundamentals".to_string(), "Seek additional help".to_string() ],
}
}
#[ must_use ]
pub fn get_student_progress( &self, student_id : &str ) -> Option< &HashMap< Subject, LearningProgress > >
{
self.progress_tracking.get( student_id )
}
#[ must_use ]
pub fn get_statistics( &self ) -> &TutorStatistics
{
&self.statistics
}
#[ allow( clippy::unused_self ) ]
fn build_explanation_prompt( &self, request : &ConceptRequest ) -> String
{
let mut prompt = format!(
"Explain the concept of '{}' in {} for {} level students.\n",
request.concept,
request.subject.name(),
request.complexity_level.name()
);
let strategies = request.learning_style.engagement_strategies();
let strategies_joined = strategies.join( ", " );
prompt.push_str( "Use " );
prompt.push_str( &strategies_joined );
prompt.push_str( " teaching strategies. " );
if let Some( ref context ) = request.context
{
prompt.push_str( "Context : " );
prompt.push_str( context );
prompt.push_str( ". " );
}
if !request.prerequisites.is_empty()
{
let prereqs_joined = request.prerequisites.join( ", " );
prompt.push_str( "Assume knowledge of : " );
prompt.push_str( &prereqs_joined );
prompt.push_str( ". " );
}
prompt.push_str( "\n\nExplanation:" );
prompt
}
#[ allow( clippy::unused_self ) ]
fn build_question_prompt( &self, question : &StudentQuestion, student_id : Option< &str > ) -> String
{
let mut prompt = format!(
"A {} level student asks : '{}'\n",
question.complexity_level.name(),
question.question_text
);
if let Some( id ) = student_id
{
if let Some( profile ) = self.students.get( id )
{
let learning_style = profile.learning_style.name();
prompt.push_str( "Student learning style : " );
prompt.push_str( learning_style );
prompt.push_str( ". " );
}
}
if let Some( subject ) = question.subject
{
let subject_name = subject.name();
prompt.push_str( "Subject area : " );
prompt.push_str( subject_name );
prompt.push_str( ". " );
}
prompt.push_str( "\n\nProvide a helpful, educational answer:" );
prompt
}
#[ allow( clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::unused_self ) ]
fn calculate_max_tokens( &self, complexity_level : ComplexityLevel ) -> u32
{
let ( _min_words, max_words ) = complexity_level.explanation_length_range();
( max_words as f32 * 1.3 ) as u32 }
#[ allow( clippy::unused_self ) ]
fn process_explanation( &self, text : &str, request : &ConceptRequest ) -> ConceptExplanation
{
let word_count = text.split_whitespace().count();
let ( min_words, max_words ) = request.complexity_level.explanation_length_range();
let complexity_score = if word_count >= min_words && word_count <= max_words { 1.0 }
else if word_count < min_words { 0.7 }
else { 0.8 };
let effectiveness_score = 0.8;
let key_points = vec![
"Main concept definition".to_string(),
"Key characteristics".to_string(),
"Important relationships".to_string()
];
let examples = vec![
"Practical example 1".to_string(),
"Analogy or metaphor".to_string()
];
let related_concepts = vec![
"Related concept A".to_string(),
"Related concept B".to_string()
];
let practice_suggestions = vec![
"Practice problem 1".to_string(),
"Hands-on activity".to_string()
];
ConceptExplanation
{
concept : request.concept.clone(),
explanation : text.trim().to_string(),
key_points,
examples,
related_concepts,
practice_suggestions,
effectiveness_score,
complexity_score,
generation_time_ms : 150, }
}
#[ allow( clippy::unused_self ) ]
fn process_answer( &self, text : &str, _question : &StudentQuestion, response_time : u64 ) -> TutorResponse
{
let confidence = if text.len() > 50 { 0.8 } else { 0.6 };
let educational_value = 0.75;
let follow_up_suggestions = vec![
"Would you like me to explain this concept in more detail?".to_string(),
"Do you have any related questions?".to_string(),
];
TutorResponse
{
answer : text.trim().to_string(),
confidence,
educational_value,
suggests_follow_up : true,
follow_up_suggestions,
understanding_assessment : 0.7, response_time_ms : response_time,
}
}
fn update_student_progress( &mut self, student_id : &str, question : &StudentQuestion, response : &TutorResponse )
{
if let Some( student_progress ) = self.progress_tracking.get_mut( student_id )
{
if let Some( subject ) = question.subject
{
if let Some( progress ) = student_progress.get_mut( &subject )
{
progress.total_questions += 1;
if response.understanding_assessment > 0.7
{
progress.correct_answers += 1;
}
let accuracy = progress.correct_answers as f32 / progress.total_questions as f32;
progress.proficiency_level = ( progress.proficiency_level + accuracy ) / 2.0;
progress.last_updated = "2023-12-01".to_string(); }
}
}
}
fn update_explanation_statistics( &mut self, subject : Subject, complexity_level : ComplexityLevel )
{
self.statistics.total_explanations += 1;
*self.statistics.subject_popularity.entry( subject ).or_insert( 0 ) += 1;
*self.statistics.complexity_distribution.entry( complexity_level ).or_insert( 0 ) += 1;
}
}
fn create_test_client() -> Option< Client< HuggingFaceEnvironmentImpl > >
{
let api_key = super::get_api_key_for_testing()?;
let secret = Secret::new( api_key );
let env = HuggingFaceEnvironmentImpl::build( secret, None ).ok()?;
Client::build( env ).ok()
}
fn create_sample_student_profile() -> StudentProfile
{
StudentProfile
{
student_id : "student_001".to_string(),
name : "Alice Johnson".to_string(),
complexity_level : ComplexityLevel::HighSchool,
learning_style : LearningStyle::Visual,
strong_subjects : vec![ Subject::Mathematics, Subject::Science ],
weak_subjects : vec![ Subject::History, Subject::LanguageArts ],
learning_goals : vec![
"Improve understanding of calculus".to_string(),
"Master essay writing techniques".to_string()
],
learning_pace : 1.2, preferences : HashMap::new(),
}
}
fn create_sample_concept_requests() -> Vec< ConceptRequest >
{
vec![
ConceptRequest
{
concept : "Photosynthesis".to_string(),
subject : Subject::Science,
complexity_level : ComplexityLevel::MiddleSchool,
learning_style : LearningStyle::Visual,
context : Some( "Plant biology unit".to_string() ),
prerequisites : vec![ "Basic cell structure".to_string(), "Chemical reactions".to_string() ],
focus_areas : vec![ "Process steps".to_string(), "Importance to ecosystems".to_string() ],
},
ConceptRequest
{
concept : "Quadratic equations".to_string(),
subject : Subject::Mathematics,
complexity_level : ComplexityLevel::HighSchool,
learning_style : LearningStyle::Kinesthetic,
context : Some( "Algebra II course".to_string() ),
prerequisites : vec![ "Linear equations".to_string(), "Factoring".to_string() ],
focus_areas : vec![ "Solving methods".to_string(), "Graphing".to_string() ],
},
]
}