import 'package:cloud_firestore/cloud_firestore.dart'; /// Model for processed content chunks used in RAG system class ContentChunk { final String id; final String contentId; final String text; final String subject; final String concept; final String? subConcept; final String unit; final double difficulty; final int grade; final List embedding; final String sourceDocument; final Map metadata; final DateTime createdAt; final DateTime? lastUpdated; final bool isActive; final int? pageNumber; final String? section; ContentChunk({ required this.id, required this.contentId, required this.text, required this.subject, required this.concept, this.subConcept, required this.unit, required this.difficulty, required this.grade, required this.embedding, required this.sourceDocument, required this.metadata, required this.createdAt, this.lastUpdated, this.isActive = true, this.pageNumber, this.section, }); /// Create from Firestore document factory ContentChunk.fromFirestore( Map data, String documentId, ) { return ContentChunk( id: documentId, contentId: data['contentId'] ?? '', text: data['text'] ?? '', subject: data['subject'] ?? '', concept: data['concept'] ?? '', subConcept: data['subConcept'], unit: data['unit'] ?? '', difficulty: (data['difficulty'] as num?)?.toDouble() ?? 0.5, grade: data['grade'] ?? 10, embedding: List.from(data['embedding'] ?? []), sourceDocument: data['sourceDocument'] ?? '', metadata: Map.from(data['metadata'] ?? {}), createdAt: (data['createdAt'] as Timestamp?)?.toDate() ?? DateTime.now(), lastUpdated: (data['lastUpdated'] as Timestamp?)?.toDate(), isActive: data['isActive'] ?? true, pageNumber: data['pageNumber'], section: data['section'], ); } /// Convert to Firestore document Map toFirestore() { return { 'contentId': contentId, 'text': text, 'subject': subject, 'concept': concept, if (subConcept != null) 'subConcept': subConcept, 'unit': unit, 'difficulty': difficulty, 'grade': grade, 'embedding': embedding, 'sourceDocument': sourceDocument, 'metadata': metadata, 'createdAt': Timestamp.fromDate(createdAt), if (lastUpdated != null) 'lastUpdated': Timestamp.fromDate(lastUpdated!), 'isActive': isActive, if (pageNumber != null) 'pageNumber': pageNumber, if (section != null) 'section': section, }; } /// Create a copy with updated fields ContentChunk copyWith({ String? id, String? contentId, String? text, String? subject, String? concept, String? subConcept, String? unit, double? difficulty, int? grade, List? embedding, String? sourceDocument, Map? metadata, DateTime? createdAt, DateTime? lastUpdated, bool? isActive, int? pageNumber, String? section, }) { return ContentChunk( id: id ?? this.id, contentId: contentId ?? this.contentId, text: text ?? this.text, subject: subject ?? this.subject, concept: concept ?? this.concept, subConcept: subConcept ?? this.subConcept, unit: unit ?? this.unit, difficulty: difficulty ?? this.difficulty, grade: grade ?? this.grade, embedding: embedding ?? this.embedding, sourceDocument: sourceDocument ?? this.sourceDocument, metadata: metadata ?? this.metadata, createdAt: createdAt ?? this.createdAt, lastUpdated: lastUpdated ?? this.lastUpdated, isActive: isActive ?? this.isActive, pageNumber: pageNumber ?? this.pageNumber, section: section ?? this.section, ); } @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is ContentChunk && other.id == id; } @override int get hashCode => id.hashCode; @override String toString() { return 'ContentChunk(id: $id, subject: $subject, concept: $concept, difficulty: $difficulty)'; } }