education-module-ai
Version:
AI Education Module using Agent Framework
434 lines (430 loc) • 16.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EducationModuleAdapter = exports.educationSqliteTables = exports.ResourceType = exports.ModuleAdapter = void 0;
exports.initEducationDatabase = initEducationDatabase;
const uuid_1 = require("uuid");
/**
* Base class for module-specific adapters
* Modules can extend this to create specialized database access
* without creating multiple database connections
*/
class ModuleAdapter {
constructor(databaseAdapter) {
this.databaseAdapter = databaseAdapter;
}
/**
* Get the underlying database instance
*/
getDatabase() {
return this.databaseAdapter['db'];
}
/**
* Get the database adapter this module is using
*/
getDatabaseAdapter() {
return this.databaseAdapter;
}
}
exports.ModuleAdapter = ModuleAdapter;
/**
* Resource type for learning resources
*/
var ResourceType;
(function (ResourceType) {
ResourceType["ARTICLE"] = "article";
ResourceType["VIDEO"] = "video";
ResourceType["EXERCISE"] = "exercise";
ResourceType["BOOK"] = "book";
ResourceType["COURSE"] = "course";
})(ResourceType || (exports.ResourceType = ResourceType = {}));
/**
* SQL schema for education module tables
*/
exports.educationSqliteTables = `
-- Educational Content table
CREATE TABLE IF NOT EXISTS educational_contents (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
type TEXT NOT NULL,
subject TEXT NOT NULL,
level TEXT NOT NULL,
keywords TEXT,
createdAt INTEGER NOT NULL,
updatedAt INTEGER
);
-- Learning Sessions table
CREATE TABLE IF NOT EXISTS learning_sessions (
id TEXT PRIMARY KEY,
userId TEXT NOT NULL,
subject TEXT NOT NULL,
level TEXT NOT NULL,
startTime INTEGER NOT NULL,
endTime INTEGER,
active INTEGER NOT NULL DEFAULT 1,
messages TEXT NOT NULL,
feedback TEXT
);
-- User Profiles table
CREATE TABLE IF NOT EXISTS user_profiles (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
email TEXT,
createdAt INTEGER NOT NULL,
learningStyles TEXT,
subjectProgress TEXT,
recommendations TEXT,
goals TEXT,
streak INTEGER NOT NULL DEFAULT 0,
lastActive INTEGER,
badges TEXT,
totalLearningTime INTEGER NOT NULL DEFAULT 0
);
-- Learning Paths table
CREATE TABLE IF NOT EXISTS learning_paths (
id TEXT PRIMARY KEY,
userId TEXT NOT NULL,
subject TEXT NOT NULL,
topic TEXT NOT NULL,
overview TEXT NOT NULL,
difficultyLevel TEXT NOT NULL,
estimatedCompletionTime TEXT NOT NULL,
prerequisites TEXT,
steps TEXT NOT NULL,
createdAt INTEGER NOT NULL,
updatedAt INTEGER NOT NULL
);
`;
/**
* Initialize the education module database
* @param databaseAdapter The database adapter from the main application
* @returns The education module adapter
*/
async function initEducationDatabase(databaseAdapter) {
// Get the database instance
const db = databaseAdapter['db']; // Access db directly with bracket notation
// Execute the table creation SQL
db.exec(exports.educationSqliteTables);
// Create and return the education module adapter
return new EducationModuleAdapter(databaseAdapter);
}
/**
* Education Module SQLite Database Adapter
* Handles database operations for the education module
*/
class EducationModuleAdapter extends ModuleAdapter {
constructor(databaseAdapter) {
super(databaseAdapter);
}
/**
* Initialize the database tables
*/
init() {
try {
const db = this.getDatabase();
db.exec(exports.educationSqliteTables);
console.log("Education module database tables initialized successfully");
}
catch (error) {
console.error("Failed to initialize education module database tables:", error);
throw error;
}
}
/**
* Get all educational contents
*/
async getEducationalContents() {
const sql = "SELECT * FROM educational_contents";
const rows = this.getDatabase().prepare(sql).all();
return rows.map(row => ({
...row,
keywords: JSON.parse(row.keywords || '[]'),
createdAt: new Date(row.createdAt),
updatedAt: row.updatedAt ? new Date(row.updatedAt) : undefined
}));
}
/**
* Get an educational content by ID
*/
async getEducationalContent(id) {
const sql = "SELECT * FROM educational_contents WHERE id = ?";
const row = this.getDatabase().prepare(sql).get(id);
if (!row)
return null;
return {
...row,
keywords: JSON.parse(row.keywords || '[]'),
createdAt: new Date(row.createdAt),
updatedAt: row.updatedAt ? new Date(row.updatedAt) : undefined
};
}
/**
* Create a new educational content
*/
async createEducationalContent(content) {
try {
console.log("EducationModuleAdapter.createEducationalContent called with:", JSON.stringify({
...content,
content: content.content ? content.content.substring(0, 50) + "..." : undefined
}, null, 2));
const id = content.id || (0, uuid_1.v4)();
// Ensure we're working with timestamps for SQLite
let createdAtTimestamp;
let updatedAtTimestamp = null;
// Handle createdAt - convert any possible format to a timestamp
if (content.createdAt instanceof Date) {
createdAtTimestamp = content.createdAt.getTime();
}
else if (typeof content.createdAt === 'string') {
createdAtTimestamp = new Date(content.createdAt).getTime();
}
else if (typeof content.createdAt === 'number') {
createdAtTimestamp = content.createdAt;
}
else {
createdAtTimestamp = Date.now();
}
// Handle updatedAt - convert any possible format to a timestamp
if (content.updatedAt instanceof Date) {
updatedAtTimestamp = content.updatedAt.getTime();
}
else if (typeof content.updatedAt === 'string') {
updatedAtTimestamp = new Date(content.updatedAt).getTime();
}
else if (typeof content.updatedAt === 'number') {
updatedAtTimestamp = content.updatedAt;
}
// Ensure keywords is an array that can be stringified
const keywords = Array.isArray(content.keywords) ? content.keywords : [];
const sql = `
INSERT INTO educational_contents (
id, title, content, type, subject, level, keywords, createdAt, updatedAt
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
console.log("SQL parameters:", [
id,
content.title,
content.content,
content.type,
content.subject,
content.level,
JSON.stringify(keywords),
createdAtTimestamp,
updatedAtTimestamp
]);
const db = this.getDatabase();
if (!db) {
throw new Error("Database not initialized or not accessible");
}
const stmt = db.prepare(sql);
console.log("Running SQL insertion");
stmt.run(id, content.title, content.content, content.type, content.subject, content.level, JSON.stringify(keywords), createdAtTimestamp, updatedAtTimestamp);
console.log("Content created with ID:", id);
return id;
}
catch (error) {
console.error("Database error creating educational content:", error);
throw new Error(`Failed to create educational content: ${error.message}`);
}
}
/**
* Update an educational content
*/
async updateEducationalContent(content) {
const sql = `
UPDATE educational_contents
SET title = ?, content = ?, type = ?, subject = ?, level = ?,
keywords = ?, updatedAt = ?
WHERE id = ?
`;
const result = this.getDatabase().prepare(sql).run(content.title, content.content, content.type, content.subject, content.level, JSON.stringify(content.keywords || []), Date.now(), content.id);
return result.changes > 0;
}
/**
* Delete an educational content
*/
async deleteEducationalContent(id) {
const sql = "DELETE FROM educational_contents WHERE id = ?";
const result = this.getDatabase().prepare(sql).run(id);
return result.changes > 0;
}
/**
* Get learning sessions for a user
*/
async getLearningSessionsForUser(userId) {
const sql = "SELECT * FROM learning_sessions WHERE userId = ?";
const rows = this.getDatabase().prepare(sql).all(userId);
return rows.map(row => ({
...row,
messages: JSON.parse(row.messages || '[]'),
startTime: new Date(row.startTime),
endTime: row.endTime ? new Date(row.endTime) : undefined,
active: Boolean(row.active)
}));
}
/**
* Get a learning session by ID
*/
async getLearningSession(id) {
const sql = "SELECT * FROM learning_sessions WHERE id = ?";
const row = this.getDatabase().prepare(sql).get(id);
if (!row)
return null;
return {
...row,
messages: JSON.parse(row.messages || '[]'),
startTime: new Date(row.startTime),
endTime: row.endTime ? new Date(row.endTime) : undefined,
active: Boolean(row.active)
};
}
/**
* Create a new learning session
*/
async createLearningSession(session) {
const id = session.id || (0, uuid_1.v4)();
const sql = `
INSERT INTO learning_sessions (
id, userId, subject, level, startTime, endTime, active, messages, feedback
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
this.getDatabase().prepare(sql).run(id, session.userId, session.subject, session.level, session.startTime.getTime(), session.endTime ? session.endTime.getTime() : null, session.active ? 1 : 0, JSON.stringify(session.messages || []), session.feedback || null);
return id;
}
/**
* Update a learning session
*/
async updateLearningSession(session) {
const sql = `
UPDATE learning_sessions
SET subject = ?, level = ?, endTime = ?, active = ?, messages = ?, feedback = ?
WHERE id = ?
`;
const result = this.getDatabase().prepare(sql).run(session.subject, session.level, session.endTime ? session.endTime.getTime() : null, session.active ? 1 : 0, JSON.stringify(session.messages || []), session.feedback || null, session.id);
return result.changes > 0;
}
/**
* Get user profile by ID
*/
async getUserProfile(id) {
const sql = "SELECT * FROM user_profiles WHERE id = ?";
const row = this.getDatabase().prepare(sql).get(id);
if (!row)
return null;
return {
...row,
learningStyles: JSON.parse(row.learningStyles || '[]'),
subjectProgress: JSON.parse(row.subjectProgress || '{}'),
recommendations: JSON.parse(row.recommendations || '[]'),
goals: JSON.parse(row.goals || '[]'),
badges: JSON.parse(row.badges || '[]'),
createdAt: new Date(row.createdAt),
lastActive: row.lastActive ? new Date(row.lastActive) : undefined
};
}
/**
* Get all user profiles
*/
async getAllUserProfiles() {
const sql = "SELECT * FROM user_profiles";
const rows = this.getDatabase().prepare(sql).all();
return rows.map(row => ({
...row,
learningStyles: JSON.parse(row.learningStyles || '[]'),
subjectProgress: JSON.parse(row.subjectProgress || '{}'),
recommendations: JSON.parse(row.recommendations || '[]'),
goals: JSON.parse(row.goals || '[]'),
badges: JSON.parse(row.badges || '[]'),
createdAt: new Date(row.createdAt),
lastActive: row.lastActive ? new Date(row.lastActive) : undefined
}));
}
/**
* Create or update a user profile
*/
async saveUserProfile(profile) {
const id = profile.id || (0, uuid_1.v4)();
// Check if profile exists
const existingProfile = await this.getUserProfile(id);
if (existingProfile) {
// Update existing profile
const sql = `
UPDATE user_profiles
SET name = ?, email = ?, learningStyles = ?, subjectProgress = ?,
recommendations = ?, goals = ?, streak = ?, lastActive = ?,
badges = ?, totalLearningTime = ?
WHERE id = ?
`;
this.getDatabase().prepare(sql).run(profile.name, profile.email || null, JSON.stringify(profile.learningStyles || []), JSON.stringify(profile.subjectProgress || {}), JSON.stringify(profile.recommendations || []), JSON.stringify(profile.goals || []), profile.streak, profile.lastActive ? profile.lastActive.getTime() : null, JSON.stringify(profile.badges || []), profile.totalLearningTime, id);
}
else {
// Create new profile
const sql = `
INSERT INTO user_profiles (
id, name, email, createdAt, learningStyles, subjectProgress,
recommendations, goals, streak, lastActive, badges, totalLearningTime
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
this.getDatabase().prepare(sql).run(id, profile.name, profile.email || null, profile.createdAt.getTime(), JSON.stringify(profile.learningStyles || []), JSON.stringify(profile.subjectProgress || {}), JSON.stringify(profile.recommendations || []), JSON.stringify(profile.goals || []), profile.streak, profile.lastActive ? profile.lastActive.getTime() : null, JSON.stringify(profile.badges || []), profile.totalLearningTime);
}
return id;
}
/**
* Get learning path by ID
*/
async getLearningPath(id) {
const sql = "SELECT * FROM learning_paths WHERE id = ?";
const row = this.getDatabase().prepare(sql).get(id);
if (!row)
return null;
return {
...row,
prerequisites: JSON.parse(row.prerequisites || '[]'),
steps: JSON.parse(row.steps || '[]'),
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt)
};
}
/**
* Get learning paths for a user
*/
async getLearningPathsForUser(userId) {
const sql = "SELECT * FROM learning_paths WHERE userId = ?";
const rows = this.getDatabase().prepare(sql).all(userId);
return rows.map(row => ({
...row,
prerequisites: JSON.parse(row.prerequisites || '[]'),
steps: JSON.parse(row.steps || '[]'),
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt)
}));
}
/**
* Create a new learning path
*/
async createLearningPath(path) {
const id = path.id || (0, uuid_1.v4)();
const sql = `
INSERT INTO learning_paths (
id, userId, subject, topic, overview, difficultyLevel,
estimatedCompletionTime, prerequisites, steps, createdAt, updatedAt
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
this.getDatabase().prepare(sql).run(id, path.userId, path.subject, path.topic, path.overview, path.difficultyLevel, path.estimatedCompletionTime, JSON.stringify(path.prerequisites || []), JSON.stringify(path.steps || []), path.createdAt.getTime(), path.updatedAt.getTime());
return id;
}
/**
* Update a learning path
*/
async updateLearningPath(path) {
const sql = `
UPDATE learning_paths
SET subject = ?, topic = ?, overview = ?, difficultyLevel = ?,
estimatedCompletionTime = ?, prerequisites = ?, steps = ?, updatedAt = ?
WHERE id = ?
`;
const result = this.getDatabase().prepare(sql).run(path.subject, path.topic, path.overview, path.difficultyLevel, path.estimatedCompletionTime, JSON.stringify(path.prerequisites || []), JSON.stringify(path.steps || []), path.updatedAt.getTime(), path.id);
return result.changes > 0;
}
}
exports.EducationModuleAdapter = EducationModuleAdapter;