| """ |
| π§ Memory & Learning System - Track user progress and mistakes |
| π Remembers mistakes β’ π Tracks progress β’ π― Personalizes learning |
| """ |
| import json |
| import os |
| from datetime import datetime |
| from typing import Dict, List, Optional |
| from collections import defaultdict |
|
|
| class MemorySystem: |
| """π§ Track user interactions, mistakes, and learning progress""" |
| |
| def __init__(self, user_id: str = "default_user"): |
| self.user_id = user_id |
| self.memory_file = f"memory_{user_id}.json" |
| self.load_memory() |
| |
| def load_memory(self): |
| """π Load user memory from file""" |
| if os.path.exists(self.memory_file): |
| with open(self.memory_file, 'r', encoding='utf-8') as f: |
| data = json.load(f) |
| self.conversations = data.get('conversations', []) |
| self.mistakes = data.get('mistakes', []) |
| self.learned_topics = data.get('learned_topics', []) |
| self.weak_areas = data.get('weak_areas', []) |
| self.preferences = data.get('preferences', {}) |
| self.corrections_made = data.get('corrections_made', 0) |
| self.last_interaction = data.get('last_interaction') |
| else: |
| self.conversations = [] |
| self.mistakes = [] |
| self.learned_topics = [] |
| self.weak_areas = [] |
| self.preferences = {} |
| self.corrections_made = 0 |
| self.last_interaction = None |
| |
| def save_memory(self): |
| """πΎ Save user memory to file""" |
| data = { |
| 'user_id': self.user_id, |
| 'conversations': self.conversations[-100:], |
| 'mistakes': self.mistakes, |
| 'learned_topics': self.learned_topics, |
| 'weak_areas': self.weak_areas, |
| 'preferences': self.preferences, |
| 'corrections_made': self.corrections_made, |
| 'last_interaction': self.last_interaction |
| } |
| with open(self.memory_file, 'w', encoding='utf-8') as f: |
| json.dump(data, f, ensure_ascii=False, indent=2) |
| |
| def add_conversation(self, user_input: str, response: str, context: str = ""): |
| """π¬ Add conversation to memory""" |
| self.conversations.append({ |
| 'timestamp': datetime.now().isoformat(), |
| 'user_input': user_input, |
| 'response': response, |
| 'context': context |
| }) |
| self.last_interaction = datetime.now().isoformat() |
| self.save_memory() |
| |
| def add_mistake(self, mistake_text: str, correction: str, mistake_type: str, topic: str): |
| """β Record a mistake made by user""" |
| self.mistakes.append({ |
| 'timestamp': datetime.now().isoformat(), |
| 'mistake': mistake_text, |
| 'correction': correction, |
| 'type': mistake_type, |
| 'topic': topic, |
| 'count': 1 |
| }) |
| self.corrections_made += 1 |
| |
| |
| if topic not in self.weak_areas: |
| self.weak_areas.append(topic) |
| |
| self.save_memory() |
| |
| def mark_topic_learned(self, topic: str): |
| """β
Mark a topic as learned""" |
| if topic not in self.learned_topics: |
| self.learned_topics.append(topic) |
| |
| |
| if topic in self.weak_areas: |
| self.weak_areas.remove(topic) |
| |
| self.save_memory() |
| |
| def get_mistake_history(self, topic: str = None) -> List[Dict]: |
| """π Get mistake history, optionally filtered by topic""" |
| if topic: |
| return [m for m in self.mistakes if m['topic'] == topic] |
| return self.mistakes |
| |
| def get_weak_areas(self) -> List[str]: |
| """π― Get user's weak areas""" |
| return self.weak_areas |
| |
| def get_learned_topics(self) -> List[str]: |
| """π Get topics user has learned""" |
| return self.learned_topics |
| |
| def get_conversation_context(self, last_n: int = 5) -> List[Dict]: |
| """π Get last n conversations for context""" |
| return self.conversations[-last_n:] |
| |
| def get_user_stats(self) -> Dict: |
| """π Get user learning statistics""" |
| return { |
| 'total_conversations': len(self.conversations), |
| 'total_mistakes': len(self.mistakes), |
| 'corrections_made': self.corrections_made, |
| 'topics_learned': len(self.learned_topics), |
| 'weak_areas': len(self.weak_areas), |
| 'last_interaction': self.last_interaction, |
| 'learning_progress': len(self.learned_topics) / max(len(self.weak_areas) + len(self.learned_topics), 1) * 100 |
| } |
| |
| def set_preference(self, key: str, value: any): |
| """π Set user preference""" |
| self.preferences[key] = value |
| self.save_memory() |
| |
| def get_preference(self, key: str, default=None): |
| """π Get user preference""" |
| return self.preferences.get(key, default) |
| |
| def get_common_mistakes(self, topic: str = None, top_n: int = 5) -> List[Dict]: |
| """π Get most common mistakes""" |
| mistakes = self.get_mistake_history(topic) |
| |
| |
| mistake_counts = defaultdict(int) |
| for m in mistakes: |
| mistake_counts[m['mistake']] += 1 |
| |
| |
| sorted_mistakes = sorted(mistake_counts.items(), key=lambda x: x[1], reverse=True) |
| |
| return [ |
| {'mistake': mistake, 'count': count} |
| for mistake, count in sorted_mistakes[:top_n] |
| ] |
| |
| def check_improvement(self, topic: str, recent_mistakes: int = 10) -> Dict: |
| """π Check if user is improving in a topic""" |
| topic_mistakes = self.get_mistake_history(topic) |
| |
| if len(topic_mistakes) < recent_mistakes: |
| return {'improving': None, 'message': 'Not enough data yet'} |
| |
| |
| recent = topic_mistakes[-recent_mistakes:] |
| older = topic_mistakes[:-recent_mistakes] |
| |
| recent_count = len(recent) |
| older_count = len(older) if older else 1 |
| |
| if recent_count < older_count: |
| return { |
| 'improving': True, |
| 'message': 'Great progress! You\'re improving! π', |
| 'progress': (1 - recent_count / older_count) * 100 |
| } |
| else: |
| return { |
| 'improving': False, |
| 'message': 'Keep practicing! You\'ll get better! πͺ', |
| 'progress': 0 |
| } |
|
|
|
|
| class EnglishMistakeDetector: |
| """π Detect and correct English grammar mistakes""" |
| |
| def __init__(self): |
| |
| self.mistake_patterns = { |
| 'tense': [ |
| ('i go yesterday', 'i went yesterday', 'past tense'), |
| ('he go to school', 'he goes to school', 'subject-verb agreement'), |
| ('she don\'t like', 'she doesn\'t like', 'subject-verb agreement'), |
| ('i am knowing', 'i know', 'stative verb'), |
| ], |
| 'article': [ |
| ('i am teacher', 'i am a teacher', 'missing article'), |
| ('the sun is star', 'the sun is a star', 'missing article'), |
| ('i went to the home', 'i went home', 'unnecessary article'), |
| ], |
| 'preposition': [ |
| ('i am good in english', 'i am good at english', 'wrong preposition'), |
| ('afraid from', 'afraid of', 'wrong preposition'), |
| ('different than', 'different from', 'wrong preposition'), |
| ], |
| 'word_order': [ |
| ('you are how', 'how are you', 'question word order'), |
| ('where you are going', 'where are you going', 'question word order'), |
| ], |
| 'spelling': [ |
| ('recieve', 'receive', 'spelling'), |
| ('occured', 'occurred', 'spelling'), |
| ('seperate', 'separate', 'spelling'), |
| ] |
| } |
| |
| |
| self.indian_english_mistakes = [ |
| ('i am having', 'i have', 'possession'), |
| ('i am understanding', 'i understand', 'stative verb'), |
| ('discuss about', 'discuss', 'redundant preposition'), |
| ('return back', 'return', 'redundant word'), |
| ('revert back', 'revert', 'redundant word'), |
| ('cousin brother', 'cousin', 'redundant word'), |
| ('up to mark', 'up to the mark', 'missing article'), |
| ] |
| |
| def detect_mistakes(self, text: str) -> List[Dict]: |
| """π Detect mistakes in text""" |
| text_lower = text.lower() |
| mistakes = [] |
| |
| |
| for category, patterns in self.mistake_patterns.items(): |
| for wrong, correct, mistake_type in patterns: |
| if wrong in text_lower: |
| mistakes.append({ |
| 'original': wrong, |
| 'correction': correct, |
| 'type': mistake_type, |
| 'category': category, |
| 'position': text_lower.find(wrong) |
| }) |
| |
| |
| for wrong, correct, mistake_type in self.indian_english_mistakes: |
| if wrong in text_lower: |
| mistakes.append({ |
| 'original': wrong, |
| 'correction': correct, |
| 'type': mistake_type, |
| 'category': 'indian_english', |
| 'position': text_lower.find(wrong) |
| }) |
| |
| return mistakes |
| |
| def get_corrected_text(self, text: str) -> str: |
| """β
Get corrected version of text""" |
| mistakes = self.detect_mistakes(text) |
| corrected = text |
| |
| |
| for mistake in sorted(mistakes, key=lambda x: x['position'], reverse=True): |
| start = mistake['position'] |
| end = start + len(mistake['original']) |
| corrected = corrected[:start] + mistake['correction'] + corrected[end:] |
| |
| return corrected |
| |
| def get_explanation(self, mistake: Dict) -> str: |
| """π Get explanation for a mistake""" |
| explanations = { |
| 'past tense': 'When talking about the past, use past tense verbs. "go" becomes "went"', |
| 'subject-verb agreement': 'The verb must match the subject. "He/She" takes singular verb form', |
| 'stative verb': 'Stative verbs (know, understand, like) are not used in continuous form', |
| 'missing article': 'Use "a/an" before singular countable nouns when mentioning for the first time', |
| 'unnecessary article': 'Don\'t use "the" with places like home, school, office when going there', |
| 'wrong preposition': 'Different verbs/adjectives take different prepositions. "Good at" not "good in"', |
| 'question word order': 'In questions, use: Question word + auxiliary verb + subject + main verb', |
| 'spelling': 'This is a common spelling mistake', |
| 'possession': 'Use "have" for possession, not "am having"', |
| 'redundant preposition': 'Some verbs don\'t need prepositions after them', |
| 'redundant word': 'Remove unnecessary words that repeat the meaning', |
| 'indian_english': 'This is a common Indian English usage that\'s not standard English' |
| } |
| |
| return explanations.get(mistake['type'], 'Grammar correction needed') |
|
|
|
|
| class ConversationStyle: |
| """π Generate responses in different conversation styles""" |
| |
| def __init__(self, style: str = "friend"): |
| self.style = style |
| self.style_templates = { |
| 'friend': { |
| 'greeting': "Hey! π What's up?", |
| 'encouragement': "You're doing great! Keep it up! π", |
| 'correction': "No worries! Here's a small tip: {correction}", |
| 'explanation': "So basically, {explanation}. Makes sense? π", |
| 'farewell': "Catch you later! π" |
| }, |
| 'teacher': { |
| 'greeting': "Hello! π¨βπ« Ready to learn today?", |
| 'encouragement': "Excellent progress! You're improving well. π", |
| 'correction': "Let me help you with this: {correction}", |
| 'explanation': "The rule is: {explanation}. Do you understand?", |
| 'farewell': "Great session! See you next time. π" |
| }, |
| 'lover': { |
| 'greeting': "Hi sweetheart! π Missed you!", |
| 'encouragement': "You're amazing! I'm so proud of you! π", |
| 'correction': "Don't worry babe, let me help: {correction} π", |
| 'explanation': "Let me explain this for you, my love: {explanation} π", |
| 'farewell': "Bye my love! Take care! π" |
| }, |
| 'mentor': { |
| 'greeting': "Welcome! π Let's make progress today.", |
| 'encouragement': "Your dedication is impressive. Keep going! π", |
| 'correction': "Here's how to improve: {correction}", |
| 'explanation': "The concept is: {explanation}. Clear?", |
| 'farewell': "Good work today. See you soon! π" |
| } |
| } |
| |
| def get_response(self, response_type: str, **kwargs) -> str: |
| """π¬ Get response in the specified style""" |
| template = self.style_templates.get(self.style, self.style_templates['friend']) |
| response = template.get(response_type, "") |
| |
| |
| for key, value in kwargs.items(): |
| response = response.replace(f"{{{key}}}", str(value)) |
| |
| return response |
| |
| def format_correction(self, original: str, correction: str, explanation: str) -> str: |
| """β
Format a correction message""" |
| style = self.style_templates.get(self.style, self.style_templates['friend']) |
| |
| if self.style == 'friend': |
| return f"Oops! You said '{original}', but it should be '{correction}'. {style['explanation'].format(explanation=explanation)}" |
| elif self.style == 'teacher': |
| return f"Correction: '{original}' β '{correction}'\n\n{style['explanation'].format(explanation=explanation)}" |
| elif self.style == 'lover': |
| return f"Babe, you wrote '{original}', but let's make it '{correction}' π {style['explanation'].format(explanation=explanation)}" |
| else: |
| return f"Note: Change '{original}' to '{correction}'\n\n{style['explanation'].format(explanation=explanation)}" |
|
|