import json import hashlib from typing import List, Dict, Any, Optional from pathlib import Path import sqlite3 class KnowledgeBase: """Knowledge base for educational content with fact-grounded explanations.""" def __init__(self, db_path: str = "knowledge_base.sqlite"): self.db_path = db_path self._init_database() self._load_sample_content() def _init_database(self): """Initialize SQLite database for knowledge storage.""" with sqlite3.connect(self.db_path) as conn: conn.execute(""" CREATE TABLE IF NOT EXISTS knowledge_items ( id TEXT PRIMARY KEY, skill TEXT NOT NULL, content TEXT NOT NULL, facts TEXT NOT NULL, difficulty REAL DEFAULT 0.5, prerequisite_skills TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """) conn.execute(""" CREATE INDEX IF NOT EXISTS idx_skill ON knowledge_items(skill) """) def _load_sample_content(self): """Load sample educational content for testing.""" sample_items = [ { "id": "algebra_simplify_001", "skill": "algebra_simplification", "content": "To simplify algebraic expressions, combine like terms by adding or subtracting coefficients of the same variable. For example, 3x + 2x = 5x.", "facts": [ "Like terms have the same variable raised to the same power", "Coefficients of like terms can be combined through addition", "The variable part remains unchanged when combining like terms" ], "difficulty": 0.3, "prerequisite_skills": ["basic_arithmetic", "variables"] }, { "id": "algebra_simplify_002", "skill": "algebra_simplification", "content": "When simplifying expressions with division, first combine like terms in the numerator, then divide by the denominator. Example: (3x + 2x) / 5 = 5x / 5 = x.", "facts": [ "Division applies to the entire expression", "Simplify numerator before dividing", "A term divided by itself equals 1" ], "difficulty": 0.5, "prerequisite_skills": ["algebra_simplification", "division"] }, { "id": "linear_eq_001", "skill": "linear_equations", "content": "To solve linear equations, isolate the variable by performing inverse operations. Add/subtract to isolate the variable term, then multiply/divide to solve for the variable.", "facts": [ "Inverse operations undo each other (addition ↔ subtraction, multiplication ↔ division)", "Apply the same operation to both sides to maintain equality", "Goal is to isolate the variable on one side" ], "difficulty": 0.4, "prerequisite_skills": ["algebra_simplification"] }, { "id": "fraction_div_001", "skill": "fraction_operations", "content": "To divide fractions, multiply by the reciprocal of the second fraction. The reciprocal of a/b is b/a.", "facts": [ "Division is equivalent to multiplication by the reciprocal", "Reciprocal flips numerator and denominator", "Multiply numerators together and denominators together" ], "difficulty": 0.6, "prerequisite_skills": ["fraction_multiplication"] }, { "id": "ratio_001", "skill": "ratios", "content": "Ratios compare quantities. To solve ratio problems, set up proportions and cross-multiply. a:b = c:d means a×d = b×c.", "facts": [ "Ratios show relative sizes of quantities", "Equivalent ratios have the same value when simplified", "Cross-multiplication solves proportion equations" ], "difficulty": 0.5, "prerequisite_skills": ["proportions"] } ] with sqlite3.connect(self.db_path) as conn: for item in sample_items: conn.execute(""" INSERT OR REPLACE INTO knowledge_items (id, skill, content, facts, difficulty, prerequisite_skills) VALUES (?, ?, ?, ?, ?, ?) """, ( item["id"], item["skill"], item["content"], json.dumps(item["facts"]), item["difficulty"], json.dumps(item["prerequisite_skills"]) )) def retrieve_by_skill(self, skill: str, limit: int = 3) -> List[Dict[str, Any]]: """Retrieve knowledge items for a specific skill.""" with sqlite3.connect(self.db_path) as conn: conn.row_factory = sqlite3.Row cursor = conn.execute(""" SELECT * FROM knowledge_items WHERE skill = ? OR skill LIKE ? ORDER BY difficulty ASC LIMIT ? """, (skill, f"%{skill}%", limit)) results = [] for row in cursor.fetchall(): results.append({ "id": row["id"], "skill": row["skill"], "content": row["content"], "facts": json.loads(row["facts"]), "difficulty": row["difficulty"], "prerequisite_skills": json.loads(row["prerequisite_skills"]) }) return results def retrieve_by_query(self, query: str, limit: int = 3) -> List[Dict[str, Any]]: """Retrieve knowledge items based on text search.""" with sqlite3.connect(self.db_path) as conn: conn.row_factory = sqlite3.Row cursor = conn.execute(""" SELECT * FROM knowledge_items WHERE content LIKE ? OR skill LIKE ? ORDER BY difficulty ASC LIMIT ? """, (f"%{query}%", f"%{query}%", limit)) results = [] for row in cursor.fetchall(): results.append({ "id": row["id"], "skill": row["skill"], "content": row["content"], "facts": json.loads(row["facts"]), "difficulty": row["difficulty"], "prerequisite_skills": json.loads(row["prerequisite_skills"]) }) return results def add_knowledge_item(self, item: Dict[str, Any]): """Add a new knowledge item to the database.""" with sqlite3.connect(self.db_path) as conn: conn.execute(""" INSERT OR REPLACE INTO knowledge_items (id, skill, content, facts, difficulty, prerequisite_skills) VALUES (?, ?, ?, ?, ?, ?) """, ( item["id"], item["skill"], item["content"], json.dumps(item["facts"]), item["difficulty"], json.dumps(item.get("prerequisite_skills", [])) ))