Repository: satvik314/educhain (language: python)

Issue:
Dev


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

## Release Notes

- **New Features**
	- Introduced a method to generate multiple-choice questions specifically for math topics.
	- Enhanced lesson planning capabilities with a new parameter for grade level and improved structure.
	- Added new classes to support various question types and activities in lesson plans.

- **Bug Fixes**
	- Improved error handling and logging in question generation and lesson planning methods.

- **Documentation**
	- Updated Jupyter notebook for clarity and improved formatting of generated questions.

- **Tests**
	- Added new test scripts to validate lesson plan and math question generation functionalities.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Discussion / hints:

Fix patch:
diff --git a/archive/content_engine_converter.py b/archive/content_engine_converter.py
new file mode 100644
index 0000000..55ac58a
--- /dev/null
+++ b/archive/content_engine_converter.py
@@ -0,0 +1,220 @@
+from typing import Optional, Any
+import json
+import csv
+from datetime import datetime
+from reportlab.lib.pagesizes import letter
+from reportlab.lib import colors
+from reportlab.lib.styles import getSampleStyleSheet
+from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
+
+
+class ContentExporter:
+    def export_lesson_plan_to_pdf(self, lesson_plan: Any, output_path: Optional[str] = None) -> str:
+        """Export lesson plan to PDF format using ReportLab"""
+        if output_path is None:
+            output_path = f"lesson_plan_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
+        
+        # Create PDF document
+        doc = SimpleDocTemplate(output_path, pagesize=letter)
+        story = []
+        styles = getSampleStyleSheet()
+        
+        # Title
+        title = getattr(lesson_plan, 'title', 'Untitled Lesson Plan')
+        story.append(Paragraph(f"Lesson Plan: {title}", styles['Title']))
+        story.append(Spacer(1, 12))
+        
+        # Subject Area
+        subject = getattr(lesson_plan, 'subject', 'N/A')
+        story.append(Paragraph(f"Subject Area: {subject}", styles['Heading2']))
+        story.append(Spacer(1, 12))
+        
+        # Learning Objectives
+        learning_objectives = getattr(lesson_plan, 'learning_objectives', [])
+        story.append(Paragraph("Learning Objectives:", styles['Heading2']))
+        for obj in learning_objectives:
+            story.append(Paragraph(f"- {obj}", styles['Normal']))
+        story.append(Spacer(1, 12))
+        
+        # Main Topics
+        for topic in getattr(lesson_plan, 'main_topics', []):
+            topic_title = getattr(topic, 'title', 'Untitled Topic')
+            story.append(Paragraph(f"Topic: {topic_title}", styles['Heading2']))
+            story.append(Spacer(1, 12))
+            
+            for subtopic in getattr(topic, 'subtopics', []):
+                subtopic_title = getattr(subtopic, 'title', 'Untitled Subtopic')
+                story.append(Paragraph(f"Subtopic: {subtopic_title}", styles['Heading3']))
+                story.append(Spacer(1, 12))
+                
+                # Add Key Concepts, Discussion Questions, and Activities
+                story.append(Paragraph(f"Key Concepts: {getattr(subtopic, 'key_concepts', 'N/A')}", styles['Normal']))
+                discussion_questions = getattr(subtopic, 'discussion_questions', [])
+                story.append(Paragraph(f"Discussion Questions: {', '.join(str(q) for q in discussion_questions)}", styles['Normal']))
+                story.append(Paragraph(f"Activities: {getattr(subtopic, 'activities', 'N/A')}", styles['Normal']))
+                story.append(Spacer(1, 12))
+        
+        # Build the PDF
+        doc.build(story)
+        print(f"PDF generated successfully: {output_path}")  # Debugging output
+        return output_path
+
+    def export_lesson_plan_to_csv(self, lesson_plan: Any, output_path: Optional[str] = None) -> str:
+        """Export lesson plan to CSV format."""
+        if output_path is None:
+            output_path = f"lesson_plan_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
+
+        with open(output_path, 'w', newline='', encoding='utf-8') as file:
+            writer = csv.writer(file)
+            writer.writerow(['Section', 'Content'])
+
+            writer.writerow(['Title', getattr(lesson_plan, 'title', 'Untitled Lesson Plan')])
+            writer.writerow(['Subject', getattr(lesson_plan, 'subject', 'N/A')])
+            learning_objectives = getattr(lesson_plan, 'learning_objectives', [])
+            writer.writerow(['Learning Objectives', '\n'.join(learning_objectives) if learning_objectives else 'N/A'])
+
+            for topic in getattr(lesson_plan, 'main_topics', []):
+                writer.writerow(['Topic', getattr(topic, 'title', 'Untitled Topic')])
+                for subtopic in getattr(topic, 'subtopics', []):
+                    writer.writerow(['Subtopic', getattr(subtopic, 'title', 'Untitled Subtopic')])
+                    writer.writerow(['Key Concepts', getattr(subtopic, 'key_concepts', 'N/A')])
+                    discussion_questions = getattr(subtopic, 'discussion_questions', [])
+                    writer.writerow(['Discussion Questions', '\n'.join(str(q) for q in discussion_questions)])  # Convert to string
+                    writer.writerow(['Activities', getattr(subtopic, 'activities', 'N/A')])
+
+        return output_path
+
+    def export_study_guide_to_pdf(self, study_guide: Any, output_path: Optional[str] = None) -> str:
+        """Export study guide to PDF format using ReportLab."""
+        if output_path is None:
+            output_path = f"study_guide_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
+
+        # Create PDF document
+        doc = SimpleDocTemplate(output_path, pagesize=letter)
+        story = []
+        styles = getSampleStyleSheet()
+        
+        # Title
+        topic = getattr(study_guide, 'topic', 'N/A')
+        story.append(Paragraph(f"Study Guide: {topic}", styles['Title']))
+        story.append(Spacer(1, 12))
+
+        # Overview
+        overview = getattr(study_guide, 'overview', 'N/A')
+        story.append(Paragraph("Overview", styles['Heading2']))
+        story.append(Paragraph(overview, styles['Normal']))
+        story.append(Spacer(1, 12))
+
+        # Key Concepts
+        story.append(Paragraph("Key Concepts", styles['Heading2']))
+        for concept, description in getattr(study_guide, 'key_concepts', {}).items():
+            story.append(Paragraph(f"{concept}: {description}", styles['Normal']))
+        
+        # Practice Exercises
+        story.append(Paragraph("Practice Exercises", styles['Heading2']))
+        for exercise in getattr(study_guide, 'practice_exercises', []):
+            title = getattr(exercise, 'title', 'N/A')
+            difficulty = getattr(exercise, 'difficulty', 'N/A')
+            problem = getattr(exercise, 'problem', 'N/A')
+            solution = getattr(exercise, 'solution', 'N/A')
+            story.append(Paragraph(f"Exercise: {title} (Difficulty: {difficulty})", styles['Normal']))
+            story.append(Paragraph(f"Problem: {problem}", styles['Normal']))
+            story.append(Paragraph(f"Solution: {solution}", styles['Normal']))
+            story.append(Spacer(1, 12))
+
+        # Case Studies
+        story.append(Paragraph("Case Studies", styles['Heading2']))
+        for case in getattr(study_guide, 'case_studies', []):
+            case_title = getattr(case, 'title', 'N/A')
+            scenario = getattr(case, 'scenario', 'N/A')
+            challenge = getattr(case, 'challenge', 'N/A')
+            story.append(Paragraph(f"Case Study: {case_title}", styles['Normal']))
+            story.append(Paragraph(f"Scenario: {scenario}", styles['Normal']))
+            story.append(Paragraph(f"Challenge: {challenge}", styles['Normal']))
+            story.append(Spacer(1, 12))
+
+        # Build the PDF
+        doc.build(story)
+        print(f"PDF generated successfully: {output_path}")  # Debugging output
+        return output_path
+
+    def export_study_guide_to_csv(self, study_guide: Any, output_path: Optional[str] = None) -> str:
+        """Export study guide to CSV format."""
+        if output_path is None:
+            output_path = f"study_guide_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
+
+        with open(output_path, 'w', newline='', encoding='utf-8') as file:
+            writer = csv.writer(file)
+            writer.writerow(['Section', 'Content'])
+
+            writer.writerow(['Topic', getattr(study_guide, 'topic', 'N/A')])
+            writer.writerow(['Overview', getattr(study_guide, 'overview', 'N/A')])
+
+            for concept, description in getattr(study_guide, 'key_concepts', {}).items():
+                writer.writerow(['Key Concept', f"{concept}: {description}"])
+            for exercise in getattr(study_guide, 'practice_exercises', []):
+                writer.writerow(['Practice Exercise', f"{getattr(exercise, 'title', 'N/A')}: {getattr(exercise, 'problem', 'N/A')}"])
+
+            for case in getattr(study_guide, 'case_studies', []):
+                writer.writerow(['Case Study', f"{getattr(case, 'title', 'N/A')}: {getattr(case, 'scenario', 'N/A')}"])
+
+        return output_path
+
+    def export_career_connections_to_pdf(self, career_connections: Any, output_path: Optional[str] = None) -> str:
+        """Export career connections to PDF format using ReportLab."""
+        if output_path is None:
+            output_path = f"career_connections_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
+
+        # Create PDF document
+        doc = SimpleDocTemplate(output_path, pagesize=letter)
+        story = []
+        styles = getSampleStyleSheet()
+        
+        # Title
+        career_field = getattr(career_connections, 'career_field', 'N/A')
+        story.append(Paragraph(f"Career Connections: {career_field}", styles['Title']))
+        story.append(Spacer(1, 12))
+
+        # Description
+        description = getattr(career_connections, 'description', 'N/A')
+        story.append(Paragraph("Description", styles['Heading2']))
+        story.append(Paragraph(description, styles['Normal']))
+        story.append(Spacer(1, 12))
+
+        # Required Skills
+        story.append(Paragraph("Required Skills", styles['Heading2']))
+        for skill in getattr(career_connections, 'required_skills', []):
+            story.append(Paragraph(f"- {skill}", styles['Normal']))
+        
+        # Career Pathways
+        story.append(Paragraph("Career Pathways", styles['Heading2']))
+        for pathway in getattr(career_connections, 'career_pathways', []):
+            pathway_name = getattr(pathway, 'name', 'N/A')
+            pathway_description = getattr(pathway, 'description', 'N/A')
+            story.append(Paragraph(f"Pathway: {pathway_name}", styles['Normal']))
+            story.append(Paragraph(f"Description: {pathway_description}", styles['Normal']))
+            story.append(Spacer(1, 12))
+
+        # Build the PDF
+        doc.build(story)
+        print(f"PDF generated successfully: {output_path}")  # Debugging output
+        return output_path
+
+    def export_career_connections_to_csv(self, career_connections: Any, output_path: Optional[str] = None) -> str:
+        """Export career connections to CSV format."""
+        if output_path is None:
+            output_path = f"career_connections_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
+
+        with open(output_path, 'w', newline='', encoding='utf-8') as file:
+            writer = csv.writer(file)
+            writer.writerow(['Section', 'Content'])
+
+            writer.writerow(['Career Field', getattr(career_connections, 'career_field', 'N/A')])
+            writer.writerow(['Description', getattr(career_connections, 'description', 'N/A')])
+
+            for skill in getattr(career_connections, 'required_skills', []):
+                writer.writerow(['Required Skill', skill])
+            for pathway in getattr(career_connections, 'career_pathways', []):
+                writer.writerow(['Career Pathway', f"{getattr(pathway, 'name', 'N/A')}: {getattr(pathway, 'description', 'N/A')}"])
+
+        return output_path
diff --git a/cookbook/educhain_career_connection.ipynb b/cookbook/educhain_career_connection.ipynb
new file mode 100644
index 0000000..f630ef1
--- /dev/null
+++ b/cookbook/educhain_career_connection.ipynb
@@ -0,0 +1,706 @@
+{
+  "nbformat": 4,
+  "nbformat_minor": 0,
+  "metadata": {
+    "colab": {
+      "provenance": []
+    },
+    "kernelspec": {
+      "name": "python3",
+      "display_name": "Python 3"
+    },
+    "language_info": {
+      "name": "python"
+    }
+  },
+  "cells": [
+    {
+      "cell_type": "markdown",
+      "source": [
+        "## Generate Study Guide using [Educhain](https://github.com/satvik314/educhain)"
+      ],
+      "metadata": {
+        "id": "WSqlGy_wSmwu"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "Explore the power of AI-driven education with Educhain! This notebook demonstrates how to view carrer connection of various subjects/topics using the Educhain package.\n",
+        "\n",
+        "Key Features:\n",
+        "- Customize output according to the Industry you are focusing on\n",
+        "- Leverage advanced language models for carrer connection generation\n",
+        "\n",
+        "Perfect for educators, students, and e-learning developers looking for the possibility of jobs/internship in their field/subject and enhance their career plan. Dive in to revolutionize your approach to educational content generation!"
+      ],
+      "metadata": {
+        "id": "-hL4ioiWSrDH"
+      }
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 1,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "6sTmhfmySfQO",
+        "outputId": "3f6b72b4-43cd-4108-b21c-d035d642334b"
+      },
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stdout",
+          "text": [
+            "Collecting git+https://github.com/lunatic-7/educhain.git@main\n",
+            "  Cloning https://github.com/lunatic-7/educhain.git (to revision main) to /tmp/pip-req-build-l9molyzi\n",
+            "  Running command git clone --filter=blob:none --quiet https://github.com/lunatic-7/educhain.git /tmp/pip-req-build-l9molyzi\n",
+            "  Resolved https://github.com/lunatic-7/educhain.git to commit 39fec93ecaf5c4ebe78a391840f6e7e98645db6c\n",
+            "  Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+            "Collecting langchain (from educhain==0.3.2)\n",
+            "  Downloading langchain-0.3.4-py3-none-any.whl.metadata (7.1 kB)\n",
+            "Collecting langchain-community (from educhain==0.3.2)\n",
+            "  Downloading langchain_community-0.3.3-py3-none-any.whl.metadata (2.8 kB)\n",
+            "Collecting langchain-openai (from educhain==0.3.2)\n",
+            "  Downloading langchain_openai-0.2.3-py3-none-any.whl.metadata (2.6 kB)\n",
+            "Collecting openai (from educhain==0.3.2)\n",
+            "  Downloading openai-1.52.2-py3-none-any.whl.metadata (24 kB)\n",
+            "Collecting python-dotenv (from educhain==0.3.2)\n",
+            "  Downloading python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)\n",
+            "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (2.2.2)\n",
+            "Collecting reportlab (from educhain==0.3.2)\n",
+            "  Downloading reportlab-4.2.5-py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting PyPDF2 (from educhain==0.3.2)\n",
+            "  Downloading pypdf2-3.0.1-py3-none-any.whl.metadata (6.8 kB)\n",
+            "Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (4.12.3)\n",
+            "Collecting youtube_transcript_api (from educhain==0.3.2)\n",
+            "  Downloading youtube_transcript_api-0.6.2-py3-none-any.whl.metadata (15 kB)\n",
+            "Requirement already satisfied: pydantic in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (2.9.2)\n",
+            "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (2.32.3)\n",
+            "Collecting chromadb (from educhain==0.3.2)\n",
+            "  Downloading chromadb-0.5.15-py3-none-any.whl.metadata (6.8 kB)\n",
+            "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4->educhain==0.3.2) (2.6)\n",
+            "Collecting build>=1.0.3 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading build-1.2.2.post1-py3-none-any.whl.metadata (6.5 kB)\n",
+            "Collecting chroma-hnswlib==0.7.6 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading chroma_hnswlib-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (252 bytes)\n",
+            "Collecting fastapi>=0.95.2 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading fastapi-0.115.3-py3-none-any.whl.metadata (27 kB)\n",
+            "Collecting uvicorn>=0.18.3 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading uvicorn-0.32.0-py3-none-any.whl.metadata (6.6 kB)\n",
+            "Requirement already satisfied: numpy>=1.22.5 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.26.4)\n",
+            "Collecting posthog>=2.4.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading posthog-3.7.0-py2.py3-none-any.whl.metadata (2.0 kB)\n",
+            "Requirement already satisfied: typing-extensions>=4.5.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (4.12.2)\n",
+            "Collecting onnxruntime>=1.14.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading onnxruntime-1.19.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (4.5 kB)\n",
+            "Requirement already satisfied: opentelemetry-api>=1.2.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Collecting opentelemetry-exporter-otlp-proto-grpc>=1.2.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl.metadata (2.3 kB)\n",
+            "Collecting opentelemetry-instrumentation-fastapi>=0.41b0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_instrumentation_fastapi-0.48b0-py3-none-any.whl.metadata (2.1 kB)\n",
+            "Requirement already satisfied: opentelemetry-sdk>=1.2.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Requirement already satisfied: tokenizers>=0.13.2 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (0.19.1)\n",
+            "Collecting pypika>=0.48.9 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading PyPika-0.48.9.tar.gz (67 kB)\n",
+            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m67.3/67.3 kB\u001b[0m \u001b[31m3.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25h  Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n",
+            "  Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n",
+            "  Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
+            "Requirement already satisfied: tqdm>=4.65.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (4.66.5)\n",
+            "Collecting overrides>=7.3.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading overrides-7.7.0-py3-none-any.whl.metadata (5.8 kB)\n",
+            "Requirement already satisfied: importlib-resources in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (6.4.5)\n",
+            "Requirement already satisfied: grpcio>=1.58.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.64.1)\n",
+            "Collecting bcrypt>=4.0.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl.metadata (9.6 kB)\n",
+            "Requirement already satisfied: typer>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (0.12.5)\n",
+            "Collecting kubernetes>=28.1.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading kubernetes-31.0.0-py2.py3-none-any.whl.metadata (1.5 kB)\n",
+            "Requirement already satisfied: tenacity>=8.2.3 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (9.0.0)\n",
+            "Requirement already satisfied: PyYAML>=6.0.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (6.0.2)\n",
+            "Collecting mmh3>=4.0.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading mmh3-5.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (14 kB)\n",
+            "Collecting orjson>=3.9.12 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (50 kB)\n",
+            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.6/50.6 kB\u001b[0m \u001b[31m1.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hCollecting httpx>=0.27.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading httpx-0.27.2-py3-none-any.whl.metadata (7.1 kB)\n",
+            "Requirement already satisfied: rich>=10.11.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (13.9.3)\n",
+            "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.10/dist-packages (from pydantic->educhain==0.3.2) (0.7.0)\n",
+            "Requirement already satisfied: pydantic-core==2.23.4 in /usr/local/lib/python3.10/dist-packages (from pydantic->educhain==0.3.2) (2.23.4)\n",
+            "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.10/dist-packages (from langchain->educhain==0.3.2) (2.0.36)\n",
+            "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.10/dist-packages (from langchain->educhain==0.3.2) (3.10.10)\n",
+            "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain->educhain==0.3.2) (4.0.3)\n",
+            "Collecting langchain-core<0.4.0,>=0.3.12 (from langchain->educhain==0.3.2)\n",
+            "  Downloading langchain_core-0.3.13-py3-none-any.whl.metadata (6.3 kB)\n",
+            "Collecting langchain-text-splitters<0.4.0,>=0.3.0 (from langchain->educhain==0.3.2)\n",
+            "  Downloading langchain_text_splitters-0.3.0-py3-none-any.whl.metadata (2.3 kB)\n",
+            "Collecting langsmith<0.2.0,>=0.1.17 (from langchain->educhain==0.3.2)\n",
+            "  Downloading langsmith-0.1.137-py3-none-any.whl.metadata (13 kB)\n",
+            "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (3.4.0)\n",
+            "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (3.10)\n",
+            "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (2.2.3)\n",
+            "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (2024.8.30)\n",
+            "Collecting dataclasses-json<0.7,>=0.5.7 (from langchain-community->educhain==0.3.2)\n",
+            "  Downloading dataclasses_json-0.6.7-py3-none-any.whl.metadata (25 kB)\n",
+            "Collecting pydantic-settings<3.0.0,>=2.4.0 (from langchain-community->educhain==0.3.2)\n",
+            "  Downloading pydantic_settings-2.6.0-py3-none-any.whl.metadata (3.5 kB)\n",
+            "Collecting tiktoken<1,>=0.7 (from langchain-openai->educhain==0.3.2)\n",
+            "  Downloading tiktoken-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)\n",
+            "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from openai->educhain==0.3.2) (3.7.1)\n",
+            "Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from openai->educhain==0.3.2) (1.7.0)\n",
+            "Collecting jiter<1,>=0.4.0 (from openai->educhain==0.3.2)\n",
+            "  Downloading jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.2 kB)\n",
+            "Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from openai->educhain==0.3.2) (1.3.1)\n",
+            "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas->educhain==0.3.2) (2.8.2)\n",
+            "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->educhain==0.3.2) (2024.2)\n",
+            "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas->educhain==0.3.2) (2024.2)\n",
+            "Requirement already satisfied: pillow>=9.0.0 in /usr/local/lib/python3.10/dist-packages (from reportlab->educhain==0.3.2) (10.4.0)\n",
+            "Requirement already satisfied: chardet in /usr/local/lib/python3.10/dist-packages (from reportlab->educhain==0.3.2) (5.2.0)\n",
+            "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (2.4.3)\n",
+            "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (1.3.1)\n",
+            "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (24.2.0)\n",
+            "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (1.4.1)\n",
+            "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (6.1.0)\n",
+            "Requirement already satisfied: yarl<2.0,>=1.12.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (1.16.0)\n",
+            "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->openai->educhain==0.3.2) (1.2.2)\n",
+            "Requirement already satisfied: packaging>=19.1 in /usr/local/lib/python3.10/dist-packages (from build>=1.0.3->chromadb->educhain==0.3.2) (24.1)\n",
+            "Collecting pyproject_hooks (from build>=1.0.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading pyproject_hooks-1.2.0-py3-none-any.whl.metadata (1.3 kB)\n",
+            "Requirement already satisfied: tomli>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from build>=1.0.3->chromadb->educhain==0.3.2) (2.0.2)\n",
+            "Collecting marshmallow<4.0.0,>=3.18.0 (from dataclasses-json<0.7,>=0.5.7->langchain-community->educhain==0.3.2)\n",
+            "  Downloading marshmallow-3.23.0-py3-none-any.whl.metadata (7.6 kB)\n",
+            "Collecting typing-inspect<1,>=0.4.0 (from dataclasses-json<0.7,>=0.5.7->langchain-community->educhain==0.3.2)\n",
+            "  Downloading typing_inspect-0.9.0-py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting starlette<0.42.0,>=0.40.0 (from fastapi>=0.95.2->chromadb->educhain==0.3.2)\n",
+            "  Downloading starlette-0.41.2-py3-none-any.whl.metadata (6.0 kB)\n",
+            "Collecting httpcore==1.* (from httpx>=0.27.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading httpcore-1.0.6-py3-none-any.whl.metadata (21 kB)\n",
+            "Collecting h11<0.15,>=0.13 (from httpcore==1.*->httpx>=0.27.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)\n",
+            "Requirement already satisfied: six>=1.9.0 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Requirement already satisfied: google-auth>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (2.27.0)\n",
+            "Requirement already satisfied: websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (1.8.0)\n",
+            "Requirement already satisfied: requests-oauthlib in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (1.3.1)\n",
+            "Requirement already satisfied: oauthlib>=3.2.2 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (3.2.2)\n",
+            "Collecting durationpy>=0.7 (from kubernetes>=28.1.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading durationpy-0.9-py3-none-any.whl.metadata (338 bytes)\n",
+            "Collecting jsonpatch<2.0,>=1.33 (from langchain-core<0.4.0,>=0.3.12->langchain->educhain==0.3.2)\n",
+            "  Downloading jsonpatch-1.33-py2.py3-none-any.whl.metadata (3.0 kB)\n",
+            "Collecting requests-toolbelt<2.0.0,>=1.0.0 (from langsmith<0.2.0,>=0.1.17->langchain->educhain==0.3.2)\n",
+            "  Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl.metadata (14 kB)\n",
+            "Collecting coloredlogs (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2)\n",
+            "  Downloading coloredlogs-15.0.1-py2.py3-none-any.whl.metadata (12 kB)\n",
+            "Requirement already satisfied: flatbuffers in /usr/local/lib/python3.10/dist-packages (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (24.3.25)\n",
+            "Requirement already satisfied: protobuf in /usr/local/lib/python3.10/dist-packages (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (3.20.3)\n",
+            "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (1.13.1)\n",
+            "Requirement already satisfied: deprecated>=1.2.6 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2) (1.2.14)\n",
+            "Requirement already satisfied: setuptools>=16.0 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2) (75.1.0)\n",
+            "Requirement already satisfied: googleapis-common-protos~=1.52 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb->educhain==0.3.2) (1.65.0)\n",
+            "Collecting opentelemetry-exporter-otlp-proto-common==1.27.0 (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl.metadata (1.8 kB)\n",
+            "Collecting opentelemetry-proto==1.27.0 (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_proto-1.27.0-py3-none-any.whl.metadata (2.3 kB)\n",
+            "Collecting opentelemetry-sdk>=1.2.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_sdk-1.27.0-py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting opentelemetry-instrumentation-asgi==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_instrumentation_asgi-0.48b0-py3-none-any.whl.metadata (2.0 kB)\n",
+            "Collecting opentelemetry-instrumentation==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_instrumentation-0.48b0-py3-none-any.whl.metadata (6.1 kB)\n",
+            "Collecting opentelemetry-semantic-conventions==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl.metadata (2.4 kB)\n",
+            "Collecting opentelemetry-util-http==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_util_http-0.48b0-py3-none-any.whl.metadata (2.5 kB)\n",
+            "Requirement already satisfied: wrapt<2.0.0,>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-instrumentation==0.48b0->opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Collecting asgiref~=3.0 (from opentelemetry-instrumentation-asgi==0.48b0->opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading asgiref-3.8.1-py3-none-any.whl.metadata (9.3 kB)\n",
+            "Collecting opentelemetry-api>=1.2.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_api-1.27.0-py3-none-any.whl.metadata (1.4 kB)\n",
+            "Collecting importlib-metadata<=8.4.0,>=6.0 (from opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading importlib_metadata-8.4.0-py3-none-any.whl.metadata (4.7 kB)\n",
+            "Collecting monotonic>=1.5 (from posthog>=2.4.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading monotonic-1.6-py2.py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting backoff>=1.10.0 (from posthog>=2.4.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading backoff-2.2.1-py3-none-any.whl.metadata (14 kB)\n",
+            "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich>=10.11.0->chromadb->educhain==0.3.2) (3.0.0)\n",
+            "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich>=10.11.0->chromadb->educhain==0.3.2) (2.18.0)\n",
+            "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy<3,>=1.4->langchain->educhain==0.3.2) (3.1.1)\n",
+            "Requirement already satisfied: regex>=2022.1.18 in /usr/local/lib/python3.10/dist-packages (from tiktoken<1,>=0.7->langchain-openai->educhain==0.3.2) (2024.9.11)\n",
+            "Requirement already satisfied: huggingface-hub<1.0,>=0.16.4 in /usr/local/lib/python3.10/dist-packages (from tokenizers>=0.13.2->chromadb->educhain==0.3.2) (0.24.7)\n",
+            "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer>=0.9.0->chromadb->educhain==0.3.2) (8.1.7)\n",
+            "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer>=0.9.0->chromadb->educhain==0.3.2) (1.5.4)\n",
+            "Collecting httptools>=0.5.0 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.6 kB)\n",
+            "Collecting uvloop!=0.15.0,!=0.15.1,>=0.14.0 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.9 kB)\n",
+            "Collecting watchfiles>=0.13 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.9 kB)\n",
+            "Collecting websockets>=10.4 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.8 kB)\n",
+            "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (5.5.0)\n",
+            "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (0.4.1)\n",
+            "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.10/dist-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (4.9)\n",
+            "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.13.2->chromadb->educhain==0.3.2) (3.16.1)\n",
+            "Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.10/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.13.2->chromadb->educhain==0.3.2) (2024.6.1)\n",
+            "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.10/dist-packages (from importlib-metadata<=8.4.0,>=6.0->opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2) (3.20.2)\n",
+            "Collecting jsonpointer>=1.9 (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.12->langchain->educhain==0.3.2)\n",
+            "  Downloading jsonpointer-3.0.0-py2.py3-none-any.whl.metadata (2.3 kB)\n",
+            "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich>=10.11.0->chromadb->educhain==0.3.2) (0.1.2)\n",
+            "Collecting mypy-extensions>=0.3.0 (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain-community->educhain==0.3.2)\n",
+            "  Downloading mypy_extensions-1.0.0-py3-none-any.whl.metadata (1.1 kB)\n",
+            "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from yarl<2.0,>=1.12.0->aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (0.2.0)\n",
+            "Collecting humanfriendly>=9.1 (from coloredlogs->onnxruntime>=1.14.1->chromadb->educhain==0.3.2)\n",
+            "  Downloading humanfriendly-10.0-py2.py3-none-any.whl.metadata (9.2 kB)\n",
+            "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy->onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (1.3.0)\n",
+            "Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /usr/local/lib/python3.10/dist-packages (from pyasn1-modules>=0.2.1->google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (0.6.1)\n",
+            "Downloading chromadb-0.5.15-py3-none-any.whl (607 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m607.0/607.0 kB\u001b[0m \u001b[31m14.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading chroma_hnswlib-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m51.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain-0.3.4-py3-none-any.whl (1.0 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.0/1.0 MB\u001b[0m \u001b[31m56.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_community-0.3.3-py3-none-any.whl (2.4 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m82.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_openai-0.2.3-py3-none-any.whl (49 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.9/49.9 kB\u001b[0m \u001b[31m5.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading openai-1.52.2-py3-none-any.whl (386 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m386.9/386.9 kB\u001b[0m \u001b[31m27.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading pypdf2-3.0.1-py3-none-any.whl (232 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m232.6/232.6 kB\u001b[0m \u001b[31m20.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)\n",
+            "Downloading reportlab-4.2.5-py3-none-any.whl (1.9 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m66.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading youtube_transcript_api-0.6.2-py3-none-any.whl (24 kB)\n",
+            "Downloading bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl (273 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m273.8/273.8 kB\u001b[0m \u001b[31m26.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading build-1.2.2.post1-py3-none-any.whl (22 kB)\n",
+            "Downloading dataclasses_json-0.6.7-py3-none-any.whl (28 kB)\n",
+            "Downloading fastapi-0.115.3-py3-none-any.whl (94 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m94.6/94.6 kB\u001b[0m \u001b[31m9.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading httpx-0.27.2-py3-none-any.whl (76 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.4/76.4 kB\u001b[0m \u001b[31m8.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading httpcore-1.0.6-py3-none-any.whl (78 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m78.0/78.0 kB\u001b[0m \u001b[31m8.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (325 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m325.2/325.2 kB\u001b[0m \u001b[31m28.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading kubernetes-31.0.0-py2.py3-none-any.whl (1.9 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m76.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_core-0.3.13-py3-none-any.whl (408 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m408.0/408.0 kB\u001b[0m \u001b[31m32.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_text_splitters-0.3.0-py3-none-any.whl (25 kB)\n",
+            "Downloading langsmith-0.1.137-py3-none-any.whl (296 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m296.9/296.9 kB\u001b[0m \u001b[31m23.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading mmh3-5.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (93 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m93.2/93.2 kB\u001b[0m \u001b[31m8.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading onnxruntime-1.19.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (13.2 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m13.2/13.2 MB\u001b[0m \u001b[31m88.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl (18 kB)\n",
+            "Downloading opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl (17 kB)\n",
+            "Downloading opentelemetry_proto-1.27.0-py3-none-any.whl (52 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m52.5/52.5 kB\u001b[0m \u001b[31m4.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_instrumentation_fastapi-0.48b0-py3-none-any.whl (11 kB)\n",
+            "Downloading opentelemetry_instrumentation-0.48b0-py3-none-any.whl (29 kB)\n",
+            "Downloading opentelemetry_instrumentation_asgi-0.48b0-py3-none-any.whl (15 kB)\n",
+            "Downloading opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl (149 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m149.7/149.7 kB\u001b[0m \u001b[31m15.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_api-1.27.0-py3-none-any.whl (63 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m64.0/64.0 kB\u001b[0m \u001b[31m7.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_util_http-0.48b0-py3-none-any.whl (6.9 kB)\n",
+            "Downloading opentelemetry_sdk-1.27.0-py3-none-any.whl (110 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m110.5/110.5 kB\u001b[0m \u001b[31m11.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (144 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m144.5/144.5 kB\u001b[0m \u001b[31m15.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading overrides-7.7.0-py3-none-any.whl (17 kB)\n",
+            "Downloading posthog-3.7.0-py2.py3-none-any.whl (54 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.4/54.4 kB\u001b[0m \u001b[31m5.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading pydantic_settings-2.6.0-py3-none-any.whl (28 kB)\n",
+            "Downloading tiktoken-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.2/1.2 MB\u001b[0m \u001b[31m58.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading uvicorn-0.32.0-py3-none-any.whl (63 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m63.7/63.7 kB\u001b[0m \u001b[31m6.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading backoff-2.2.1-py3-none-any.whl (15 kB)\n",
+            "Downloading durationpy-0.9-py3-none-any.whl (3.5 kB)\n",
+            "Downloading h11-0.14.0-py3-none-any.whl (58 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (442 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m442.1/442.1 kB\u001b[0m \u001b[31m36.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading importlib_metadata-8.4.0-py3-none-any.whl (26 kB)\n",
+            "Downloading jsonpatch-1.33-py2.py3-none-any.whl (12 kB)\n",
+            "Downloading marshmallow-3.23.0-py3-none-any.whl (49 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.5/49.5 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading monotonic-1.6-py2.py3-none-any.whl (8.2 kB)\n",
+            "Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl (54 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.5/54.5 kB\u001b[0m \u001b[31m5.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading starlette-0.41.2-py3-none-any.whl (73 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m73.3/73.3 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading typing_inspect-0.9.0-py3-none-any.whl (8.8 kB)\n",
+            "Downloading uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.8/3.8 MB\u001b[0m \u001b[31m67.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (425 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m425.7/425.7 kB\u001b[0m \u001b[31m34.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (164 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m164.1/164.1 kB\u001b[0m \u001b[31m15.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading coloredlogs-15.0.1-py2.py3-none-any.whl (46 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m46.0/46.0 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading pyproject_hooks-1.2.0-py3-none-any.whl (10 kB)\n",
+            "Downloading asgiref-3.8.1-py3-none-any.whl (23 kB)\n",
+            "Downloading humanfriendly-10.0-py2.py3-none-any.whl (86 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m86.8/86.8 kB\u001b[0m \u001b[31m8.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading jsonpointer-3.0.0-py2.py3-none-any.whl (7.6 kB)\n",
+            "Downloading mypy_extensions-1.0.0-py3-none-any.whl (4.7 kB)\n",
+            "Building wheels for collected packages: educhain, pypika\n",
+            "  Building wheel for educhain (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+            "  Created wheel for educhain: filename=educhain-0.3.2-py3-none-any.whl size=20719 sha256=0bf5ea4fcfe437b0a6dcec0002590d476d304ac11b78b48c28f974366a8240da\n",
+            "  Stored in directory: /tmp/pip-ephem-wheel-cache-7nu1wrn_/wheels/cf/37/1a/d1708e678c8679ecce8ee35b17f42fc00df5e425b1ef60b913\n",
+            "  Building wheel for pypika (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
+            "  Created wheel for pypika: filename=PyPika-0.48.9-py2.py3-none-any.whl size=53725 sha256=c62ff4cb1da83c72e6d3e285f45c6976b7867f93d68a9ce6261bc7c5292dc475\n",
+            "  Stored in directory: /root/.cache/pip/wheels/e1/26/51/d0bffb3d2fd82256676d7ad3003faea3bd6dddc9577af665f4\n",
+            "Successfully built educhain pypika\n",
+            "Installing collected packages: pypika, monotonic, durationpy, websockets, uvloop, reportlab, python-dotenv, pyproject_hooks, PyPDF2, overrides, orjson, opentelemetry-util-http, opentelemetry-proto, mypy-extensions, mmh3, marshmallow, jsonpointer, jiter, importlib-metadata, humanfriendly, httptools, h11, chroma-hnswlib, bcrypt, backoff, asgiref, youtube_transcript_api, watchfiles, uvicorn, typing-inspect, tiktoken, starlette, requests-toolbelt, posthog, opentelemetry-exporter-otlp-proto-common, opentelemetry-api, jsonpatch, httpcore, coloredlogs, build, pydantic-settings, opentelemetry-semantic-conventions, opentelemetry-instrumentation, onnxruntime, kubernetes, httpx, fastapi, dataclasses-json, opentelemetry-sdk, opentelemetry-instrumentation-asgi, openai, langsmith, opentelemetry-instrumentation-fastapi, opentelemetry-exporter-otlp-proto-grpc, langchain-core, langchain-text-splitters, langchain-openai, chromadb, langchain, langchain-community, educhain\n",
+            "  Attempting uninstall: importlib-metadata\n",
+            "    Found existing installation: importlib_metadata 8.5.0\n",
+            "    Uninstalling importlib_metadata-8.5.0:\n",
+            "      Successfully uninstalled importlib_metadata-8.5.0\n",
+            "  Attempting uninstall: opentelemetry-api\n",
+            "    Found existing installation: opentelemetry-api 1.16.0\n",
+            "    Uninstalling opentelemetry-api-1.16.0:\n",
+            "      Successfully uninstalled opentelemetry-api-1.16.0\n",
+            "  Attempting uninstall: opentelemetry-semantic-conventions\n",
+            "    Found existing installation: opentelemetry-semantic-conventions 0.37b0\n",
+            "    Uninstalling opentelemetry-semantic-conventions-0.37b0:\n",
+            "      Successfully uninstalled opentelemetry-semantic-conventions-0.37b0\n",
+            "  Attempting uninstall: opentelemetry-sdk\n",
+            "    Found existing installation: opentelemetry-sdk 1.16.0\n",
+            "    Uninstalling opentelemetry-sdk-1.16.0:\n",
+            "      Successfully uninstalled opentelemetry-sdk-1.16.0\n",
+            "Successfully installed PyPDF2-3.0.1 asgiref-3.8.1 backoff-2.2.1 bcrypt-4.2.0 build-1.2.2.post1 chroma-hnswlib-0.7.6 chromadb-0.5.15 coloredlogs-15.0.1 dataclasses-json-0.6.7 durationpy-0.9 educhain-0.3.2 fastapi-0.115.3 h11-0.14.0 httpcore-1.0.6 httptools-0.6.4 httpx-0.27.2 humanfriendly-10.0 importlib-metadata-8.4.0 jiter-0.6.1 jsonpatch-1.33 jsonpointer-3.0.0 kubernetes-31.0.0 langchain-0.3.4 langchain-community-0.3.3 langchain-core-0.3.13 langchain-openai-0.2.3 langchain-text-splitters-0.3.0 langsmith-0.1.137 marshmallow-3.23.0 mmh3-5.0.1 monotonic-1.6 mypy-extensions-1.0.0 onnxruntime-1.19.2 openai-1.52.2 opentelemetry-api-1.27.0 opentelemetry-exporter-otlp-proto-common-1.27.0 opentelemetry-exporter-otlp-proto-grpc-1.27.0 opentelemetry-instrumentation-0.48b0 opentelemetry-instrumentation-asgi-0.48b0 opentelemetry-instrumentation-fastapi-0.48b0 opentelemetry-proto-1.27.0 opentelemetry-sdk-1.27.0 opentelemetry-semantic-conventions-0.48b0 opentelemetry-util-http-0.48b0 orjson-3.10.10 overrides-7.7.0 posthog-3.7.0 pydantic-settings-2.6.0 pypika-0.48.9 pyproject_hooks-1.2.0 python-dotenv-1.0.1 reportlab-4.2.5 requests-toolbelt-1.0.0 starlette-0.41.2 tiktoken-0.8.0 typing-inspect-0.9.0 uvicorn-0.32.0 uvloop-0.21.0 watchfiles-0.24.0 websockets-13.1 youtube_transcript_api-0.6.2\n"
+          ]
+        }
+      ],
+      "source": [
+        "!pip install git+https://github.com/lunatic-7/educhain.git@main"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "# Set up your OpenAI API key\n",
+        "import os\n",
+        "from google.colab import userdata\n",
+        "\n",
+        "os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY')"
+      ],
+      "metadata": {
+        "id": "9oFbWTb5TXNe"
+      },
+      "execution_count": 6,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "### Generate Career Connection\n",
+        "\n",
+        "**NOTE** - \"Using better models is important here, models like *gpt-4o* will work fine, small models like *gpt-4o-mini* might give parsing errors...\""
+      ],
+      "metadata": {
+        "id": "-q2Y-XKdTehw"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "from langchain_openai import ChatOpenAI\n",
+        "from educhain import Educhain, LLMConfig\n",
+        "\n",
+        "openai_4o = ChatOpenAI(\n",
+        "    model=\"gpt-4o\",\n",
+        "    openai_api_key=userdata.get(\"OPENAI_API_KEY\"))\n",
+        "\n",
+        "openai_config = LLMConfig(custom_model=openai_4o)\n",
+        "\n",
+        "client = Educhain(openai_config) #using better model\n",
+        "\n",
+        "plan = client.content_engine.generate_career_connections(\n",
+        "    topic = \"Data Science\"\n",
+        "    )\n",
+        "\n",
+        "plan.show()"
+      ],
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "WDrG2lTOTZ0v",
+        "outputId": "50776c36-d399-4069-c25f-6095ae5bbe7c"
+      },
+      "execution_count": 20,
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stdout",
+          "text": [
+            "================================================================================\n",
+            "Career Connections: Data Science\n",
+            "================================================================================\n",
+            "\n",
+            "Industry Overview:\n",
+            "The data science industry is experiencing rapid growth as organizations across all sectors seek to leverage data-driven insights to drive decision-making and innovation. Current advancements in machine learning, artificial intelligence, and big data analytics are propelling the industry forward. The future outlook is promising, with an increasing demand for skilled professionals who can harness data to solve complex problems. Key trends include the rise of automated machine learning (AutoML), the integration of AI in data analytics, and the growing importance of data ethics and governance.\n",
+            "\n",
+            "Career Paths:\n",
+            "\n",
+            "1. Data Scientist\n",
+            "   Description: Data Scientists analyze and interpret complex data to help organizations make informed decisions.\n",
+            "   Responsibilities:\n",
+            "   - Developing algorithms and models to extract insights from data\n",
+            "   - Collaborating with cross-functional teams to implement data-driven solutions\n",
+            "   - Communicating findings to stakeholders through reports and visualizations\n",
+            "   Education: Bachelor's degree in Computer Science, Statistics, or a related field; Master's or PhD preferred\n",
+            "   Salary Range: $80,000 - $150,000\n",
+            "   Growth Potential: High; opportunities to advance to senior roles or specialized fields like AI or machine learning\n",
+            "   Required Skills:\n",
+            "   - Statistical Analysis (Essential)\n",
+            "   - Programming (Essential)\n",
+            "\n",
+            "2. Data Analyst\n",
+            "   Description: Data Analysts collect, process, and perform statistical analyses on data sets.\n",
+            "   Responsibilities:\n",
+            "   - Interpreting data and analyzing results\n",
+            "   - Developing data collection systems and strategies\n",
+            "   - Creating data visualizations to present findings\n",
+            "   Education: Bachelor's degree in Mathematics, Economics, Computer Science, or related field\n",
+            "   Salary Range: $60,000 - $90,000\n",
+            "   Growth Potential: Moderate; potential to transition into data science or business intelligence roles\n",
+            "   Required Skills:\n",
+            "   - Data Visualization (Important)\n",
+            "   - Data Cleaning (Essential)\n",
+            "\n",
+            "Industry Trends:\n",
+            "\n",
+            "- Automated Machine Learning (AutoML)\n",
+            "  Impact: Increases efficiency and accessibility of machine learning applications.\n",
+            "  Timeframe: Current and ongoing\n",
+            "\n",
+            "- Data Ethics and Governance\n",
+            "  Impact: Shapes policies and practices for responsible data management.\n",
+            "  Timeframe: Current and increasing in importance\n",
+            "\n",
+            "Professional Insights:\n",
+            "\n",
+            "From Senior Data Scientist (10 years)\n",
+            "Key Insights:\n",
+            "- Data science is a collaborative field that requires effective communication.\n",
+            "- Continuous learning is crucial due to rapid technological advancements.\n",
+            "Advice for Students:\n",
+            "- Develop strong foundational skills in mathematics and programming.\n",
+            "- Engage in projects and internships to gain practical experience.\n",
+            "\n",
+            "Preparation Paths:\n",
+            "\n",
+            "Education\n",
+            "Requirements:\n",
+            "- Pursue a degree in a relevant field (e.g., Computer Science, Statistics)\n",
+            "- Take courses in machine learning, data analysis, and statistics\n",
+            "Duration: 4-6 years\n",
+            "\n",
+            "Early Career\n",
+            "Requirements:\n",
+            "- Gain experience through entry-level roles such as data analyst\n",
+            "- Develop a portfolio of data projects\n",
+            "Duration: 2-4 years\n",
+            "\n",
+            "Resources:\n",
+            "\n",
+            "- Kaggle (Platform)\n",
+            "  Description: An online community for data scientists to collaborate and compete on data science challenges.\n",
+            "  URL: https://www.kaggle.com\n",
+            "  Cost: Free\n",
+            "\n",
+            "- Coursera (Platform)\n",
+            "  Description: Provides a wide range of data science courses and certifications.\n",
+            "  URL: https://www.coursera.org\n",
+            "  Cost: Varies; some courses free or with financial aid\n",
+            "\n",
+            "- Data Science Association (Organization)\n",
+            "  Description: A professional organization that provides resources and networking opportunities for data scientists.\n",
+            "  URL: http://datascienceassn.org\n",
+            "  Cost: Membership fees vary\n",
+            "\n",
+            "Skill Categories:\n",
+            "\n",
+            "Technical Skills:\n",
+            "- Machine Learning: Ability to design and implement machine learning algorithms\n",
+            "- Data Visualization Tools: Proficiency in tools like Tableau, Power BI, or D3.js\n",
+            "\n",
+            "Soft Skills:\n",
+            "- Communication: Ability to effectively convey complex information to non-technical stakeholders\n",
+            "- Problem Solving: Strong analytical and critical thinking skills to tackle challenging data problems\n",
+            "\n",
+            "Industry-specific Skills:\n",
+            "- Data Governance: Knowledge of policies and procedures for managing data assets\n",
+            "\n",
+            "Future Skills Needed:\n",
+            "- AI Ethics: Understanding of ethical implications in AI and machine learning\n"
+          ]
+        }
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "### Generate Study Guide with **Industry you are focusing on**"
+      ],
+      "metadata": {
+        "id": "L1VZaA7NUNQF"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "from langchain_openai import ChatOpenAI\n",
+        "from educhain import Educhain, LLMConfig\n",
+        "\n",
+        "openai_4o = ChatOpenAI(\n",
+        "    model=\"gpt-4o\",\n",
+        "    openai_api_key=userdata.get(\"OPENAI_API_KEY\"))\n",
+        "\n",
+        "openai_config = LLMConfig(custom_model=openai_4o)\n",
+        "\n",
+        "client = Educhain(openai_config) #using better model\n",
+        "\n",
+        "plan = client.content_engine.generate_career_connections(\n",
+        "    topic = \"Data Science\",\n",
+        "    industry_focus = \"Finance\"\n",
+        "    )\n",
+        "\n",
+        "plan.show()"
+      ],
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "z06-wGHET09G",
+        "outputId": "bf9fe930-b40e-4b89-c7e4-43bc08f53aed"
+      },
+      "execution_count": 21,
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stdout",
+          "text": [
+            "================================================================================\n",
+            "Career Connections: Data Science\n",
+            "================================================================================\n",
+            "\n",
+            "Industry Overview:\n",
+            "The finance industry is undergoing a significant transformation driven by advancements in data science. With the proliferation of big data, financial institutions are leveraging data science to gain insights, improve decision-making, and enhance customer experiences. The integration of machine learning, artificial intelligence, and predictive analytics is becoming commonplace. The future outlook for data science in finance is promising, with increased demand for skilled professionals who can navigate complex data landscapes and drive innovation. Key trends include the rise of fintech, the adoption of blockchain, and the use of AI for risk management and fraud detection.\n",
+            "\n",
+            "Career Paths:\n",
+            "\n",
+            "1. Financial Data Scientist\n",
+            "   Description: A Financial Data Scientist analyzes complex financial data to identify trends, forecast future outcomes, and make data-driven decisions.\n",
+            "   Responsibilities:\n",
+            "   - Analyze financial datasets to identify trends and patterns.\n",
+            "   - Develop predictive models for financial forecasting.\n",
+            "   - Collaborate with stakeholders to optimize financial strategies.\n",
+            "   Education: Bachelor's degree in Data Science, Finance, or related field; Master's preferred.\n",
+            "   Salary Range: $90,000 - $130,000\n",
+            "   Growth Potential: High growth potential with opportunities to advance to senior data scientist or managerial roles.\n",
+            "   Required Skills:\n",
+            "   - Statistical Analysis (Essential)\n",
+            "   - Machine Learning (Essential)\n",
+            "\n",
+            "2. Quantitative Analyst\n",
+            "   Description: Quantitative Analysts use mathematical models to evaluate financial securities and manage risk.\n",
+            "   Responsibilities:\n",
+            "   - Develop quantitative models for pricing and risk assessment.\n",
+            "   - Analyze market trends to inform trading strategies.\n",
+            "   - Collaborate with traders and risk managers.\n",
+            "   Education: Bachelor's degree in Mathematics, Finance, or related field; PhD preferred.\n",
+            "   Salary Range: $100,000 - $150,000\n",
+            "   Growth Potential: Strong demand in investment banks, hedge funds, and asset management firms.\n",
+            "   Required Skills:\n",
+            "   - Mathematical Modeling (Essential)\n",
+            "   - Programming (Important)\n",
+            "\n",
+            "Industry Trends:\n",
+            "\n",
+            "- Rise of Fintech\n",
+            "  Impact: Increased demand for data-driven solutions and adaptable financial strategies.\n",
+            "  Timeframe: Current and ongoing\n",
+            "\n",
+            "- AI in Risk Management\n",
+            "  Impact: Improved accuracy in risk assessment and fraud detection.\n",
+            "  Timeframe: Next 5-10 years\n",
+            "\n",
+            "Professional Insights:\n",
+            "\n",
+            "From Senior Data Scientist (10 years)\n",
+            "Key Insights:\n",
+            "- Data science is integral to strategic decision-making in finance.\n",
+            "- Continuous learning and adaptation are crucial due to rapid technological advancements.\n",
+            "Advice for Students:\n",
+            "- Build a strong foundation in both finance and data science.\n",
+            "- Gain practical experience through internships and projects.\n",
+            "\n",
+            "Preparation Paths:\n",
+            "\n",
+            "Education\n",
+            "Requirements:\n",
+            "- Bachelor's degree in Data Science, Finance, or related field\n",
+            "Duration: 4 years\n",
+            "\n",
+            "Early Career\n",
+            "Requirements:\n",
+            "- Entry-level data analyst or financial analyst position\n",
+            "Duration: 2-3 years\n",
+            "\n",
+            "Resources:\n",
+            "\n",
+            "- Kaggle (Platform)\n",
+            "  Description: An online community for data scientists and machine learning enthusiasts.\n",
+            "  URL: https://www.kaggle.com\n",
+            "\n",
+            "- Financial Data Professional Institute (Organization)\n",
+            "  Description: Offers certifications and resources for finance professionals specializing in data science.\n",
+            "  URL: https://fdpinstitute.org\n",
+            "  Cost: Certification fees apply\n",
+            "\n",
+            "- Journal of Financial Data Science (Publication)\n",
+            "  Description: Provides insights and research on data science applications in finance.\n",
+            "  Cost: Subscription fees apply\n",
+            "\n",
+            "Skill Categories:\n",
+            "\n",
+            "Technical Skills:\n",
+            "- Statistical Analysis: Ability to analyze data using statistical methods.\n",
+            "- Machine Learning: Knowledge of machine learning techniques and algorithms.\n",
+            "\n",
+            "Soft Skills:\n",
+            "- Communication: Effective communication of complex data insights to non-technical stakeholders.\n",
+            "- Problem-Solving: Ability to address complex financial challenges using data-driven approaches.\n",
+            "\n",
+            "Industry-Specific Skills:\n",
+            "- Financial Modeling: Creation of mathematical models to represent financial scenarios.\n",
+            "- Risk Management: Understanding of risk assessment and mitigation strategies.\n",
+            "\n",
+            "Future Skills Needed:\n",
+            "- Blockchain Technology: Understanding of blockchain and its applications in finance.\n",
+            "- AI Development: Ability to develop AI-driven solutions for financial applications.\n"
+          ]
+        }
+      ]
+    },
+    {
+      "cell_type": "code",
+      "source": [],
+      "metadata": {
+        "id": "lUo6MIabVY27"
+      },
+      "execution_count": null,
+      "outputs": []
+    }
+  ]
+}
\ No newline at end of file
diff --git a/cookbook/educhain_generate_study_guide.ipynb b/cookbook/educhain_generate_study_guide.ipynb
new file mode 100644
index 0000000..454a872
--- /dev/null
+++ b/cookbook/educhain_generate_study_guide.ipynb
@@ -0,0 +1,663 @@
+{
+  "nbformat": 4,
+  "nbformat_minor": 0,
+  "metadata": {
+    "colab": {
+      "provenance": []
+    },
+    "kernelspec": {
+      "name": "python3",
+      "display_name": "Python 3"
+    },
+    "language_info": {
+      "name": "python"
+    }
+  },
+  "cells": [
+    {
+      "cell_type": "markdown",
+      "source": [
+        "## Generate Study Guide using [Educhain](https://github.com/satvik314/educhain)"
+      ],
+      "metadata": {
+        "id": "2yuOXx718YJT"
+      }
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "Explore the power of AI-driven education with Educhain! This notebook demonstrates how to create high-quality Study Guide of various topics using the Educhain package.\n",
+        "\n",
+        "Key Features:\n",
+        "- Customize difficulty level according to you\n",
+        "- Leverage advanced language models for study guide generation\n",
+        "\n",
+        "Perfect for educators, students, and e-learning developers looking to automate and enhance their study guide plan. Dive in to revolutionize your approach to educational content generation!"
+      ],
+      "metadata": {
+        "id": "Vdyr-nkg8fBI"
+      }
+    },
+    {
+      "cell_type": "code",
+      "execution_count": 1,
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "IM2f9yVg73iO",
+        "outputId": "b8a060a2-792d-4b03-9d6c-c8cf18625f8b"
+      },
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stdout",
+          "text": [
+            "Collecting git+https://github.com/lunatic-7/educhain.git@main\n",
+            "  Cloning https://github.com/lunatic-7/educhain.git (to revision main) to /tmp/pip-req-build-6bihe9wx\n",
+            "  Running command git clone --filter=blob:none --quiet https://github.com/lunatic-7/educhain.git /tmp/pip-req-build-6bihe9wx\n",
+            "  Resolved https://github.com/lunatic-7/educhain.git to commit 2d0d94a5ac83c31075a08ad220e11a892b0edbe2\n",
+            "  Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+            "Collecting langchain (from educhain==0.3.2)\n",
+            "  Downloading langchain-0.3.4-py3-none-any.whl.metadata (7.1 kB)\n",
+            "Collecting langchain-community (from educhain==0.3.2)\n",
+            "  Downloading langchain_community-0.3.3-py3-none-any.whl.metadata (2.8 kB)\n",
+            "Collecting langchain-openai (from educhain==0.3.2)\n",
+            "  Downloading langchain_openai-0.2.3-py3-none-any.whl.metadata (2.6 kB)\n",
+            "Collecting openai (from educhain==0.3.2)\n",
+            "  Downloading openai-1.52.2-py3-none-any.whl.metadata (24 kB)\n",
+            "Collecting python-dotenv (from educhain==0.3.2)\n",
+            "  Downloading python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)\n",
+            "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (2.2.2)\n",
+            "Collecting reportlab (from educhain==0.3.2)\n",
+            "  Downloading reportlab-4.2.5-py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting PyPDF2 (from educhain==0.3.2)\n",
+            "  Downloading pypdf2-3.0.1-py3-none-any.whl.metadata (6.8 kB)\n",
+            "Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (4.12.3)\n",
+            "Collecting youtube_transcript_api (from educhain==0.3.2)\n",
+            "  Downloading youtube_transcript_api-0.6.2-py3-none-any.whl.metadata (15 kB)\n",
+            "Requirement already satisfied: pydantic in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (2.9.2)\n",
+            "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from educhain==0.3.2) (2.32.3)\n",
+            "Collecting chromadb (from educhain==0.3.2)\n",
+            "  Downloading chromadb-0.5.15-py3-none-any.whl.metadata (6.8 kB)\n",
+            "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4->educhain==0.3.2) (2.6)\n",
+            "Collecting build>=1.0.3 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading build-1.2.2.post1-py3-none-any.whl.metadata (6.5 kB)\n",
+            "Collecting chroma-hnswlib==0.7.6 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading chroma_hnswlib-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (252 bytes)\n",
+            "Collecting fastapi>=0.95.2 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading fastapi-0.115.3-py3-none-any.whl.metadata (27 kB)\n",
+            "Collecting uvicorn>=0.18.3 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading uvicorn-0.32.0-py3-none-any.whl.metadata (6.6 kB)\n",
+            "Requirement already satisfied: numpy>=1.22.5 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.26.4)\n",
+            "Collecting posthog>=2.4.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading posthog-3.7.0-py2.py3-none-any.whl.metadata (2.0 kB)\n",
+            "Requirement already satisfied: typing-extensions>=4.5.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (4.12.2)\n",
+            "Collecting onnxruntime>=1.14.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading onnxruntime-1.19.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.metadata (4.5 kB)\n",
+            "Requirement already satisfied: opentelemetry-api>=1.2.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Collecting opentelemetry-exporter-otlp-proto-grpc>=1.2.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl.metadata (2.3 kB)\n",
+            "Collecting opentelemetry-instrumentation-fastapi>=0.41b0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_instrumentation_fastapi-0.48b0-py3-none-any.whl.metadata (2.1 kB)\n",
+            "Requirement already satisfied: opentelemetry-sdk>=1.2.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Requirement already satisfied: tokenizers>=0.13.2 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (0.19.1)\n",
+            "Collecting pypika>=0.48.9 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading PyPika-0.48.9.tar.gz (67 kB)\n",
+            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m67.3/67.3 kB\u001b[0m \u001b[31m3.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25h  Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n",
+            "  Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n",
+            "  Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
+            "Requirement already satisfied: tqdm>=4.65.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (4.66.5)\n",
+            "Collecting overrides>=7.3.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading overrides-7.7.0-py3-none-any.whl.metadata (5.8 kB)\n",
+            "Requirement already satisfied: importlib-resources in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (6.4.5)\n",
+            "Requirement already satisfied: grpcio>=1.58.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (1.64.1)\n",
+            "Collecting bcrypt>=4.0.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl.metadata (9.6 kB)\n",
+            "Requirement already satisfied: typer>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (0.12.5)\n",
+            "Collecting kubernetes>=28.1.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading kubernetes-31.0.0-py2.py3-none-any.whl.metadata (1.5 kB)\n",
+            "Requirement already satisfied: tenacity>=8.2.3 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (9.0.0)\n",
+            "Requirement already satisfied: PyYAML>=6.0.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (6.0.2)\n",
+            "Collecting mmh3>=4.0.1 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading mmh3-5.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (14 kB)\n",
+            "Collecting orjson>=3.9.12 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (50 kB)\n",
+            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.6/50.6 kB\u001b[0m \u001b[31m3.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hCollecting httpx>=0.27.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading httpx-0.27.2-py3-none-any.whl.metadata (7.1 kB)\n",
+            "Requirement already satisfied: rich>=10.11.0 in /usr/local/lib/python3.10/dist-packages (from chromadb->educhain==0.3.2) (13.9.3)\n",
+            "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.10/dist-packages (from pydantic->educhain==0.3.2) (0.7.0)\n",
+            "Requirement already satisfied: pydantic-core==2.23.4 in /usr/local/lib/python3.10/dist-packages (from pydantic->educhain==0.3.2) (2.23.4)\n",
+            "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.10/dist-packages (from langchain->educhain==0.3.2) (2.0.36)\n",
+            "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.10/dist-packages (from langchain->educhain==0.3.2) (3.10.10)\n",
+            "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain->educhain==0.3.2) (4.0.3)\n",
+            "Collecting langchain-core<0.4.0,>=0.3.12 (from langchain->educhain==0.3.2)\n",
+            "  Downloading langchain_core-0.3.12-py3-none-any.whl.metadata (6.3 kB)\n",
+            "Collecting langchain-text-splitters<0.4.0,>=0.3.0 (from langchain->educhain==0.3.2)\n",
+            "  Downloading langchain_text_splitters-0.3.0-py3-none-any.whl.metadata (2.3 kB)\n",
+            "Collecting langsmith<0.2.0,>=0.1.17 (from langchain->educhain==0.3.2)\n",
+            "  Downloading langsmith-0.1.137-py3-none-any.whl.metadata (13 kB)\n",
+            "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (3.4.0)\n",
+            "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (3.10)\n",
+            "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (2.2.3)\n",
+            "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->educhain==0.3.2) (2024.8.30)\n",
+            "Collecting dataclasses-json<0.7,>=0.5.7 (from langchain-community->educhain==0.3.2)\n",
+            "  Downloading dataclasses_json-0.6.7-py3-none-any.whl.metadata (25 kB)\n",
+            "Collecting pydantic-settings<3.0.0,>=2.4.0 (from langchain-community->educhain==0.3.2)\n",
+            "  Downloading pydantic_settings-2.6.0-py3-none-any.whl.metadata (3.5 kB)\n",
+            "Collecting tiktoken<1,>=0.7 (from langchain-openai->educhain==0.3.2)\n",
+            "  Downloading tiktoken-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)\n",
+            "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from openai->educhain==0.3.2) (3.7.1)\n",
+            "Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from openai->educhain==0.3.2) (1.7.0)\n",
+            "Collecting jiter<1,>=0.4.0 (from openai->educhain==0.3.2)\n",
+            "  Downloading jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.2 kB)\n",
+            "Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from openai->educhain==0.3.2) (1.3.1)\n",
+            "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas->educhain==0.3.2) (2.8.2)\n",
+            "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->educhain==0.3.2) (2024.2)\n",
+            "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas->educhain==0.3.2) (2024.2)\n",
+            "Requirement already satisfied: pillow>=9.0.0 in /usr/local/lib/python3.10/dist-packages (from reportlab->educhain==0.3.2) (10.4.0)\n",
+            "Requirement already satisfied: chardet in /usr/local/lib/python3.10/dist-packages (from reportlab->educhain==0.3.2) (5.2.0)\n",
+            "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (2.4.3)\n",
+            "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (1.3.1)\n",
+            "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (24.2.0)\n",
+            "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (1.4.1)\n",
+            "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (6.1.0)\n",
+            "Requirement already satisfied: yarl<2.0,>=1.12.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (1.16.0)\n",
+            "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->openai->educhain==0.3.2) (1.2.2)\n",
+            "Requirement already satisfied: packaging>=19.1 in /usr/local/lib/python3.10/dist-packages (from build>=1.0.3->chromadb->educhain==0.3.2) (24.1)\n",
+            "Collecting pyproject_hooks (from build>=1.0.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading pyproject_hooks-1.2.0-py3-none-any.whl.metadata (1.3 kB)\n",
+            "Requirement already satisfied: tomli>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from build>=1.0.3->chromadb->educhain==0.3.2) (2.0.2)\n",
+            "Collecting marshmallow<4.0.0,>=3.18.0 (from dataclasses-json<0.7,>=0.5.7->langchain-community->educhain==0.3.2)\n",
+            "  Downloading marshmallow-3.23.0-py3-none-any.whl.metadata (7.6 kB)\n",
+            "Collecting typing-inspect<1,>=0.4.0 (from dataclasses-json<0.7,>=0.5.7->langchain-community->educhain==0.3.2)\n",
+            "  Downloading typing_inspect-0.9.0-py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting starlette<0.42.0,>=0.40.0 (from fastapi>=0.95.2->chromadb->educhain==0.3.2)\n",
+            "  Downloading starlette-0.41.0-py3-none-any.whl.metadata (6.0 kB)\n",
+            "Collecting httpcore==1.* (from httpx>=0.27.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading httpcore-1.0.6-py3-none-any.whl.metadata (21 kB)\n",
+            "Collecting h11<0.15,>=0.13 (from httpcore==1.*->httpx>=0.27.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)\n",
+            "Requirement already satisfied: six>=1.9.0 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Requirement already satisfied: google-auth>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (2.27.0)\n",
+            "Requirement already satisfied: websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (1.8.0)\n",
+            "Requirement already satisfied: requests-oauthlib in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (1.3.1)\n",
+            "Requirement already satisfied: oauthlib>=3.2.2 in /usr/local/lib/python3.10/dist-packages (from kubernetes>=28.1.0->chromadb->educhain==0.3.2) (3.2.2)\n",
+            "Collecting durationpy>=0.7 (from kubernetes>=28.1.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading durationpy-0.9-py3-none-any.whl.metadata (338 bytes)\n",
+            "Collecting jsonpatch<2.0,>=1.33 (from langchain-core<0.4.0,>=0.3.12->langchain->educhain==0.3.2)\n",
+            "  Downloading jsonpatch-1.33-py2.py3-none-any.whl.metadata (3.0 kB)\n",
+            "Collecting requests-toolbelt<2.0.0,>=1.0.0 (from langsmith<0.2.0,>=0.1.17->langchain->educhain==0.3.2)\n",
+            "  Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl.metadata (14 kB)\n",
+            "Collecting coloredlogs (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2)\n",
+            "  Downloading coloredlogs-15.0.1-py2.py3-none-any.whl.metadata (12 kB)\n",
+            "Requirement already satisfied: flatbuffers in /usr/local/lib/python3.10/dist-packages (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (24.3.25)\n",
+            "Requirement already satisfied: protobuf in /usr/local/lib/python3.10/dist-packages (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (3.20.3)\n",
+            "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (1.13.1)\n",
+            "Requirement already satisfied: deprecated>=1.2.6 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2) (1.2.14)\n",
+            "Requirement already satisfied: setuptools>=16.0 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2) (75.1.0)\n",
+            "Requirement already satisfied: googleapis-common-protos~=1.52 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb->educhain==0.3.2) (1.65.0)\n",
+            "Collecting opentelemetry-exporter-otlp-proto-common==1.27.0 (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl.metadata (1.8 kB)\n",
+            "Collecting opentelemetry-proto==1.27.0 (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_proto-1.27.0-py3-none-any.whl.metadata (2.3 kB)\n",
+            "Collecting opentelemetry-sdk>=1.2.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_sdk-1.27.0-py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting opentelemetry-instrumentation-asgi==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_instrumentation_asgi-0.48b0-py3-none-any.whl.metadata (2.0 kB)\n",
+            "Collecting opentelemetry-instrumentation==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_instrumentation-0.48b0-py3-none-any.whl.metadata (6.1 kB)\n",
+            "Collecting opentelemetry-semantic-conventions==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl.metadata (2.4 kB)\n",
+            "Collecting opentelemetry-util-http==0.48b0 (from opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_util_http-0.48b0-py3-none-any.whl.metadata (2.5 kB)\n",
+            "Requirement already satisfied: wrapt<2.0.0,>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from opentelemetry-instrumentation==0.48b0->opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2) (1.16.0)\n",
+            "Collecting asgiref~=3.0 (from opentelemetry-instrumentation-asgi==0.48b0->opentelemetry-instrumentation-fastapi>=0.41b0->chromadb->educhain==0.3.2)\n",
+            "  Downloading asgiref-3.8.1-py3-none-any.whl.metadata (9.3 kB)\n",
+            "Collecting opentelemetry-api>=1.2.0 (from chromadb->educhain==0.3.2)\n",
+            "  Downloading opentelemetry_api-1.27.0-py3-none-any.whl.metadata (1.4 kB)\n",
+            "Collecting importlib-metadata<=8.4.0,>=6.0 (from opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading importlib_metadata-8.4.0-py3-none-any.whl.metadata (4.7 kB)\n",
+            "Collecting monotonic>=1.5 (from posthog>=2.4.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading monotonic-1.6-py2.py3-none-any.whl.metadata (1.5 kB)\n",
+            "Collecting backoff>=1.10.0 (from posthog>=2.4.0->chromadb->educhain==0.3.2)\n",
+            "  Downloading backoff-2.2.1-py3-none-any.whl.metadata (14 kB)\n",
+            "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich>=10.11.0->chromadb->educhain==0.3.2) (3.0.0)\n",
+            "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich>=10.11.0->chromadb->educhain==0.3.2) (2.18.0)\n",
+            "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy<3,>=1.4->langchain->educhain==0.3.2) (3.1.1)\n",
+            "Requirement already satisfied: regex>=2022.1.18 in /usr/local/lib/python3.10/dist-packages (from tiktoken<1,>=0.7->langchain-openai->educhain==0.3.2) (2024.9.11)\n",
+            "Requirement already satisfied: huggingface-hub<1.0,>=0.16.4 in /usr/local/lib/python3.10/dist-packages (from tokenizers>=0.13.2->chromadb->educhain==0.3.2) (0.24.7)\n",
+            "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer>=0.9.0->chromadb->educhain==0.3.2) (8.1.7)\n",
+            "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer>=0.9.0->chromadb->educhain==0.3.2) (1.5.4)\n",
+            "Collecting httptools>=0.5.0 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.6 kB)\n",
+            "Collecting uvloop!=0.15.0,!=0.15.1,>=0.14.0 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.9 kB)\n",
+            "Collecting watchfiles>=0.13 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.9 kB)\n",
+            "Collecting websockets>=10.4 (from uvicorn[standard]>=0.18.3->chromadb->educhain==0.3.2)\n",
+            "  Downloading websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.8 kB)\n",
+            "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (5.5.0)\n",
+            "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (0.4.1)\n",
+            "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.10/dist-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (4.9)\n",
+            "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.13.2->chromadb->educhain==0.3.2) (3.16.1)\n",
+            "Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.10/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.13.2->chromadb->educhain==0.3.2) (2024.6.1)\n",
+            "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.10/dist-packages (from importlib-metadata<=8.4.0,>=6.0->opentelemetry-api>=1.2.0->chromadb->educhain==0.3.2) (3.20.2)\n",
+            "Collecting jsonpointer>=1.9 (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.12->langchain->educhain==0.3.2)\n",
+            "  Downloading jsonpointer-3.0.0-py2.py3-none-any.whl.metadata (2.3 kB)\n",
+            "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich>=10.11.0->chromadb->educhain==0.3.2) (0.1.2)\n",
+            "Collecting mypy-extensions>=0.3.0 (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain-community->educhain==0.3.2)\n",
+            "  Downloading mypy_extensions-1.0.0-py3-none-any.whl.metadata (1.1 kB)\n",
+            "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from yarl<2.0,>=1.12.0->aiohttp<4.0.0,>=3.8.3->langchain->educhain==0.3.2) (0.2.0)\n",
+            "Collecting humanfriendly>=9.1 (from coloredlogs->onnxruntime>=1.14.1->chromadb->educhain==0.3.2)\n",
+            "  Downloading humanfriendly-10.0-py2.py3-none-any.whl.metadata (9.2 kB)\n",
+            "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy->onnxruntime>=1.14.1->chromadb->educhain==0.3.2) (1.3.0)\n",
+            "Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /usr/local/lib/python3.10/dist-packages (from pyasn1-modules>=0.2.1->google-auth>=1.0.1->kubernetes>=28.1.0->chromadb->educhain==0.3.2) (0.6.1)\n",
+            "Downloading chromadb-0.5.15-py3-none-any.whl (607 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m607.0/607.0 kB\u001b[0m \u001b[31m24.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading chroma_hnswlib-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m25.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain-0.3.4-py3-none-any.whl (1.0 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.0/1.0 MB\u001b[0m \u001b[31m32.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_community-0.3.3-py3-none-any.whl (2.4 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m60.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_openai-0.2.3-py3-none-any.whl (49 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.9/49.9 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading openai-1.52.2-py3-none-any.whl (386 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m386.9/386.9 kB\u001b[0m \u001b[31m20.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading pypdf2-3.0.1-py3-none-any.whl (232 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m232.6/232.6 kB\u001b[0m \u001b[31m15.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)\n",
+            "Downloading reportlab-4.2.5-py3-none-any.whl (1.9 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m57.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading youtube_transcript_api-0.6.2-py3-none-any.whl (24 kB)\n",
+            "Downloading bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl (273 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m273.8/273.8 kB\u001b[0m \u001b[31m20.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading build-1.2.2.post1-py3-none-any.whl (22 kB)\n",
+            "Downloading dataclasses_json-0.6.7-py3-none-any.whl (28 kB)\n",
+            "Downloading fastapi-0.115.3-py3-none-any.whl (94 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m94.6/94.6 kB\u001b[0m \u001b[31m7.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading httpx-0.27.2-py3-none-any.whl (76 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.4/76.4 kB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading httpcore-1.0.6-py3-none-any.whl (78 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m78.0/78.0 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (325 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m325.2/325.2 kB\u001b[0m \u001b[31m20.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading kubernetes-31.0.0-py2.py3-none-any.whl (1.9 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m69.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_core-0.3.12-py3-none-any.whl (407 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m407.7/407.7 kB\u001b[0m \u001b[31m29.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading langchain_text_splitters-0.3.0-py3-none-any.whl (25 kB)\n",
+            "Downloading langsmith-0.1.137-py3-none-any.whl (296 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m296.9/296.9 kB\u001b[0m \u001b[31m18.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading mmh3-5.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (93 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m93.2/93.2 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading onnxruntime-1.19.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (13.2 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m13.2/13.2 MB\u001b[0m \u001b[31m85.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl (18 kB)\n",
+            "Downloading opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl (17 kB)\n",
+            "Downloading opentelemetry_proto-1.27.0-py3-none-any.whl (52 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m52.5/52.5 kB\u001b[0m \u001b[31m3.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_instrumentation_fastapi-0.48b0-py3-none-any.whl (11 kB)\n",
+            "Downloading opentelemetry_instrumentation-0.48b0-py3-none-any.whl (29 kB)\n",
+            "Downloading opentelemetry_instrumentation_asgi-0.48b0-py3-none-any.whl (15 kB)\n",
+            "Downloading opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl (149 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m149.7/149.7 kB\u001b[0m \u001b[31m10.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_api-1.27.0-py3-none-any.whl (63 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m64.0/64.0 kB\u001b[0m \u001b[31m4.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading opentelemetry_util_http-0.48b0-py3-none-any.whl (6.9 kB)\n",
+            "Downloading opentelemetry_sdk-1.27.0-py3-none-any.whl (110 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m110.5/110.5 kB\u001b[0m \u001b[31m8.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (144 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m144.5/144.5 kB\u001b[0m \u001b[31m11.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading overrides-7.7.0-py3-none-any.whl (17 kB)\n",
+            "Downloading posthog-3.7.0-py2.py3-none-any.whl (54 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.4/54.4 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading pydantic_settings-2.6.0-py3-none-any.whl (28 kB)\n",
+            "Downloading tiktoken-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.2/1.2 MB\u001b[0m \u001b[31m53.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading uvicorn-0.32.0-py3-none-any.whl (63 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m63.7/63.7 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading backoff-2.2.1-py3-none-any.whl (15 kB)\n",
+            "Downloading durationpy-0.9-py3-none-any.whl (3.5 kB)\n",
+            "Downloading h11-0.14.0-py3-none-any.whl (58 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m4.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (442 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m442.1/442.1 kB\u001b[0m \u001b[31m24.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading importlib_metadata-8.4.0-py3-none-any.whl (26 kB)\n",
+            "Downloading jsonpatch-1.33-py2.py3-none-any.whl (12 kB)\n",
+            "Downloading marshmallow-3.23.0-py3-none-any.whl (49 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.5/49.5 kB\u001b[0m \u001b[31m3.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading monotonic-1.6-py2.py3-none-any.whl (8.2 kB)\n",
+            "Downloading requests_toolbelt-1.0.0-py2.py3-none-any.whl (54 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.5/54.5 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading starlette-0.41.0-py3-none-any.whl (73 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m73.2/73.2 kB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading typing_inspect-0.9.0-py3-none-any.whl (8.8 kB)\n",
+            "Downloading uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.8/3.8 MB\u001b[0m \u001b[31m76.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (425 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m425.7/425.7 kB\u001b[0m \u001b[31m26.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (164 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m164.1/164.1 kB\u001b[0m \u001b[31m12.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading coloredlogs-15.0.1-py2.py3-none-any.whl (46 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m46.0/46.0 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading pyproject_hooks-1.2.0-py3-none-any.whl (10 kB)\n",
+            "Downloading asgiref-3.8.1-py3-none-any.whl (23 kB)\n",
+            "Downloading humanfriendly-10.0-py2.py3-none-any.whl (86 kB)\n",
+            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m86.8/86.8 kB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+            "\u001b[?25hDownloading jsonpointer-3.0.0-py2.py3-none-any.whl (7.6 kB)\n",
+            "Downloading mypy_extensions-1.0.0-py3-none-any.whl (4.7 kB)\n",
+            "Building wheels for collected packages: educhain, pypika\n",
+            "  Building wheel for educhain (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
+            "  Created wheel for educhain: filename=educhain-0.3.2-py3-none-any.whl size=18549 sha256=6ef98ea713c3b172d8589cc51e183acad5ceb623eaf8d2c1bda7e9b7f9b2bffa\n",
+            "  Stored in directory: /tmp/pip-ephem-wheel-cache-b9ci1szg/wheels/cf/37/1a/d1708e678c8679ecce8ee35b17f42fc00df5e425b1ef60b913\n",
+            "  Building wheel for pypika (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
+            "  Created wheel for pypika: filename=PyPika-0.48.9-py2.py3-none-any.whl size=53725 sha256=75dad2077afcd19b316b0c1cd2860f38a33cb75c2e95acae38cefe9d9cfab164\n",
+            "  Stored in directory: /root/.cache/pip/wheels/e1/26/51/d0bffb3d2fd82256676d7ad3003faea3bd6dddc9577af665f4\n",
+            "Successfully built educhain pypika\n",
+            "Installing collected packages: pypika, monotonic, durationpy, websockets, uvloop, reportlab, python-dotenv, pyproject_hooks, PyPDF2, overrides, orjson, opentelemetry-util-http, opentelemetry-proto, mypy-extensions, mmh3, marshmallow, jsonpointer, jiter, importlib-metadata, humanfriendly, httptools, h11, chroma-hnswlib, bcrypt, backoff, asgiref, youtube_transcript_api, watchfiles, uvicorn, typing-inspect, tiktoken, starlette, requests-toolbelt, posthog, opentelemetry-exporter-otlp-proto-common, opentelemetry-api, jsonpatch, httpcore, coloredlogs, build, pydantic-settings, opentelemetry-semantic-conventions, opentelemetry-instrumentation, onnxruntime, kubernetes, httpx, fastapi, dataclasses-json, opentelemetry-sdk, opentelemetry-instrumentation-asgi, openai, langsmith, opentelemetry-instrumentation-fastapi, opentelemetry-exporter-otlp-proto-grpc, langchain-core, langchain-text-splitters, langchain-openai, chromadb, langchain, langchain-community, educhain\n",
+            "  Attempting uninstall: importlib-metadata\n",
+            "    Found existing installation: importlib_metadata 8.5.0\n",
+            "    Uninstalling importlib_metadata-8.5.0:\n",
+            "      Successfully uninstalled importlib_metadata-8.5.0\n",
+            "  Attempting uninstall: opentelemetry-api\n",
+            "    Found existing installation: opentelemetry-api 1.16.0\n",
+            "    Uninstalling opentelemetry-api-1.16.0:\n",
+            "      Successfully uninstalled opentelemetry-api-1.16.0\n",
+            "  Attempting uninstall: opentelemetry-semantic-conventions\n",
+            "    Found existing installation: opentelemetry-semantic-conventions 0.37b0\n",
+            "    Uninstalling opentelemetry-semantic-conventions-0.37b0:\n",
+            "      Successfully uninstalled opentelemetry-semantic-conventions-0.37b0\n",
+            "  Attempting uninstall: opentelemetry-sdk\n",
+            "    Found existing installation: opentelemetry-sdk 1.16.0\n",
+            "    Uninstalling opentelemetry-sdk-1.16.0:\n",
+            "      Successfully uninstalled opentelemetry-sdk-1.16.0\n",
+            "Successfully installed PyPDF2-3.0.1 asgiref-3.8.1 backoff-2.2.1 bcrypt-4.2.0 build-1.2.2.post1 chroma-hnswlib-0.7.6 chromadb-0.5.15 coloredlogs-15.0.1 dataclasses-json-0.6.7 durationpy-0.9 educhain-0.3.2 fastapi-0.115.3 h11-0.14.0 httpcore-1.0.6 httptools-0.6.4 httpx-0.27.2 humanfriendly-10.0 importlib-metadata-8.4.0 jiter-0.6.1 jsonpatch-1.33 jsonpointer-3.0.0 kubernetes-31.0.0 langchain-0.3.4 langchain-community-0.3.3 langchain-core-0.3.12 langchain-openai-0.2.3 langchain-text-splitters-0.3.0 langsmith-0.1.137 marshmallow-3.23.0 mmh3-5.0.1 monotonic-1.6 mypy-extensions-1.0.0 onnxruntime-1.19.2 openai-1.52.2 opentelemetry-api-1.27.0 opentelemetry-exporter-otlp-proto-common-1.27.0 opentelemetry-exporter-otlp-proto-grpc-1.27.0 opentelemetry-instrumentation-0.48b0 opentelemetry-instrumentation-asgi-0.48b0 opentelemetry-instrumentation-fastapi-0.48b0 opentelemetry-proto-1.27.0 opentelemetry-sdk-1.27.0 opentelemetry-semantic-conventions-0.48b0 opentelemetry-util-http-0.48b0 orjson-3.10.10 overrides-7.7.0 posthog-3.7.0 pydantic-settings-2.6.0 pypika-0.48.9 pyproject_hooks-1.2.0 python-dotenv-1.0.1 reportlab-4.2.5 requests-toolbelt-1.0.0 starlette-0.41.0 tiktoken-0.8.0 typing-inspect-0.9.0 uvicorn-0.32.0 uvloop-0.21.0 watchfiles-0.24.0 websockets-13.1 youtube_transcript_api-0.6.2\n"
+          ]
+        }
+      ],
+      "source": [
+        "!pip install git+https://github.com/lunatic-7/educhain.git@main"
+      ]
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "# Set up your OpenAI API key\n",
+        "import os\n",
+        "from google.colab import userdata\n",
+        "\n",
+        "os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY')"
+      ],
+      "metadata": {
+        "id": "PVFWI_hi89i-"
+      },
+      "execution_count": 4,
+      "outputs": []
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "### Generate Study guide"
+      ],
+      "metadata": {
+        "id": "jZRJaa2p9Evq"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "from educhain import Educhain\n",
+        "\n",
+        "client = Educhain()\n",
+        "\n",
+        "plan = client.content_engine.generate_study_guide(\n",
+        "    topic = \"Ethical Hacking\",\n",
+        "    difficulty_level = \"Beginner\",\n",
+        "    )\n",
+        "\n",
+        "plan.show(format=\"text\")"
+      ],
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "SYibPQr1-JOd",
+        "outputId": "b82ff18d-fb7e-4851-a7b6-053599facdd0"
+      },
+      "execution_count": 5,
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stdout",
+          "text": [
+            "=== Study Guide: Ethical Hacking ===\n",
+            "\n",
+            "Difficulty Level: Beginner\n",
+            "Estimated Study Time: 10 hours\n",
+            "\n",
+            "Prerequisites:\n",
+            "- Basic understanding of computer networks\n",
+            "- Familiarity with operating systems (especially Linux)\n",
+            "- Basic programming skills (Python or similar recommended)\n",
+            "\n",
+            "Learning Objectives:\n",
+            "- Define ethical hacking and its importance in cybersecurity.\n",
+            "- Identify different types of hackers and their motivations.\n",
+            "- Describe the ethical hacking process and methodologies.\n",
+            "- Recognize the legal implications and ethical considerations in hacking.\n",
+            "- Conduct basic penetration testing using common tools.\n",
+            "\n",
+            "Overview:\n",
+            "Ethical hacking involves legally breaking into systems to identify vulnerabilities. Unlike malicious hackers, ethical hackers work to improve security systems. This field is crucial for protecting sensitive information and maintaining trust in technology.\n",
+            "\n",
+            "Key Concepts:\n",
+            "\n",
+            "Ethical Hacking:\n",
+            "The practice of deliberately probing systems for vulnerabilities in order to improve security. Ethical hackers obtain permission to test systems legally.\n",
+            "\n",
+            "Types of Hackers:\n",
+            "Hackers can be categorized as white hat (ethical hackers), black hat (malicious hackers), and gray hat (mixed intentions). Understanding these types helps in identifying motivations behind hacking activities.\n",
+            "\n",
+            "Penetration Testing:\n",
+            "A simulated cyber attack against a system, conducted to evaluate its security. This process involves planning, scanning, gaining access, maintaining access, and analysis.\n",
+            "\n",
+            "Legal Aspects:\n",
+            "Ethical hackers must understand laws such as the Computer Fraud and Abuse Act (CFAA) and the importance of obtaining proper authorization before testing systems.\n",
+            "\n",
+            "Common Tools:\n",
+            "Tools like Metasploit, Nmap, Wireshark, and Burp Suite are essential for ethical hacking as they assist in scanning, exploiting vulnerabilities, and analyzing traffic.\n",
+            "\n",
+            "Important Dates:\n",
+            "- 1996: The formation of the first hacking ethics organization, which established guidelines for ethical hacking.\n",
+            "- 2000: The release of the first version of the Certified Ethical Hacker (CEH) certification.\n",
+            "\n",
+            "Practice Exercises:\n",
+            "\n",
+            "Exercise 1:\n",
+            "Problem: List and describe at least three types of hackers and their motivations.\n",
+            "Solution: 1. White Hat: Ethical hackers who find vulnerabilities to protect systems. 2. Black Hat: Malicious hackers who exploit vulnerabilities for personal gain. 3. Gray Hat: Individuals who may violate ethical standards but do not have malicious intent.\n",
+            "\n",
+            "Exercise 2:\n",
+            "Problem: Outline the five main steps in the penetration testing process.\n",
+            "Solution: 1. Planning: Define the scope and objectives. 2. Scanning: Identify open ports and services. 3. Gaining Access: Exploit identified vulnerabilities. 4. Maintaining Access: Ensure continued access for further testing. 5. Analysis: Document findings and provide recommendations.\n",
+            "\n",
+            "Real-World Case Studies:\n",
+            "\n",
+            "Case Study 1: Target Data Breach (2013)\n",
+            "Scenario: Target Corporation suffered a massive data breach affecting millions of customer credit and debit card accounts.\n",
+            "Challenge: The attackers gained access through a third-party vendor, highlighting the importance of supply chain security.\n",
+            "Solution: After the breach, Target implemented strict security measures, including enhanced monitoring and segmentation of networks to prevent unauthorized access.\n",
+            "Outcome: The breach resulted in significant financial loss and reputational damage, leading to a reevaluation of their cybersecurity practices.\n",
+            "\n",
+            "Key Lessons Learned:\n",
+            "- The importance of securing third-party vendors.\n",
+            "- Continuous monitoring and assessment of security protocols are essential.\n",
+            "\n",
+            "Related Concepts:\n",
+            "- Penetration Testing\n",
+            "- Legal Aspects of Ethical Hacking\n",
+            "--------------------------------------------------\n",
+            "\n",
+            "Study Tips:\n",
+            "- Use hands-on tools to practice ethical hacking techniques in a safe and legal environment.\n",
+            "- Join online forums or groups to discuss and learn from other aspiring ethical hackers.\n",
+            "- Take online courses that offer practical labs and exercises.\n",
+            "- Stay updated with the latest cybersecurity news and trends.\n",
+            "\n",
+            "Additional Resources:\n",
+            "- OWASP: The Open Web Application Security Project provides free tools and resources for web application security.\n",
+            "- Cybrary: An online platform offering courses in ethical hacking and cybersecurity.\n",
+            "- Kali Linux: A widely used Linux distribution for penetration testing and ethical hacking.\n",
+            "\n",
+            "Summary:\n",
+            "Ethical hacking is a vital field that helps organizations protect their systems from malicious attacks. By understanding the types of hackers, the ethical hacking process, and the legal implications, beginners can start their journey in cybersecurity, armed with the knowledge of essential tools and practices.\n"
+          ]
+        }
+      ]
+    },
+    {
+      "cell_type": "markdown",
+      "source": [
+        "### Generate Study Guide with **custom instructions**"
+      ],
+      "metadata": {
+        "id": "EXAn-gUs-NEV"
+      }
+    },
+    {
+      "cell_type": "code",
+      "source": [
+        "from educhain import Educhain\n",
+        "\n",
+        "client = Educhain()\n",
+        "\n",
+        "plan = client.content_engine.generate_study_guide(\n",
+        "    topic = \"Ethical Hacking\",\n",
+        "    difficulty_level = \"Beginner\",\n",
+        "    # Optional\n",
+        "    custom_instructions = \"\"\"\n",
+        "        Include hands-on examples and some real-world techniques.\n",
+        "        Focus on practical applications and security best practices.\n",
+        "        \"\"\"\n",
+        "    )\n",
+        "\n",
+        "plan.show(format=\"text\")"
+      ],
+      "metadata": {
+        "colab": {
+          "base_uri": "https://localhost:8080/"
+        },
+        "id": "9Nocv5yN9FSf",
+        "outputId": "b9cc93b8-c824-43e3-e78b-71db159f3c18"
+      },
+      "execution_count": 6,
+      "outputs": [
+        {
+          "output_type": "stream",
+          "name": "stdout",
+          "text": [
+            "=== Study Guide: Ethical Hacking ===\n",
+            "\n",
+            "Difficulty Level: Beginner\n",
+            "Estimated Study Time: 10-15 hours\n",
+            "\n",
+            "Prerequisites:\n",
+            "- Basic understanding of computer networks\n",
+            "- Familiarity with operating systems (Windows, Linux)\n",
+            "- Basic programming knowledge (Python or similar)\n",
+            "\n",
+            "Learning Objectives:\n",
+            "- Understand the role and importance of ethical hacking in cybersecurity.\n",
+            "- Identify common types of cyber attacks and their mechanisms.\n",
+            "- Learn the ethical and legal considerations in ethical hacking.\n",
+            "- Gain hands-on experience with basic tools and techniques used in ethical hacking.\n",
+            "- Develop problem-solving skills to address security vulnerabilities.\n",
+            "\n",
+            "Overview:\n",
+            "Ethical hacking involves legally breaking into computers and devices to test an organization's defenses. Unlike malicious hackers, ethical hackers have permission to access systems to identify vulnerabilities and strengthen security measures. This study guide covers essential concepts, practices, and tools necessary for aspiring ethical hackers.\n",
+            "\n",
+            "Key Concepts:\n",
+            "\n",
+            "Ethical Hacking:\n",
+            "Ethical hacking refers to the practice of intentionally probing systems for vulnerabilities in order to fix them before they can be exploited by malicious hackers.\n",
+            "\n",
+            "Types of Hackers:\n",
+            "Hackers are typically categorized into three groups: White Hat (ethical hackers), Black Hat (malicious hackers), and Gray Hat (who may violate laws but without malicious intent).\n",
+            "\n",
+            "Penetration Testing:\n",
+            "A method of evaluating the security of a system by simulating an attack from malicious outsiders and insiders. It helps to identify vulnerabilities.\n",
+            "\n",
+            "Social Engineering:\n",
+            "A tactic used by hackers to manipulate individuals into divulging confidential information, often by exploiting human psychology.\n",
+            "\n",
+            "Common Attacks:\n",
+            "Examples include phishing, malware, denial-of-service (DoS) attacks, and SQL injection.\n",
+            "\n",
+            "Important Dates:\n",
+            "- 1970: The term 'hacker' is first used in the context of computing.\n",
+            "- 1996: The Computer Fraud and Abuse Act (CFAA) becomes law in the U.S., defining illegal hacking.\n",
+            "- 2010: The first known use of ethical hacking certifications begins to gain traction.\n",
+            "\n",
+            "Practice Exercises:\n",
+            "\n",
+            "Exercise 1:\n",
+            "Problem: Using online tools, gather information about a target website (e.g., domain name, IP address, and hosting information).\n",
+            "Solution: Use tools like WHOIS, nslookup, and online services like DNSstuff to collect data on the target website.\n",
+            "\n",
+            "Exercise 2:\n",
+            "Problem: Use a port scanning tool (like Nmap) to identify open ports on a local machine.\n",
+            "Solution: 1. Install Nmap. 2. Run the command 'nmap <target_ip>' to scan for open ports. 3. Analyze the results.\n",
+            "\n",
+            "Exercise 3:\n",
+            "Problem: Create a basic SQL injection to manipulate a sample database query.\n",
+            "Solution: 1. Set up a vulnerable web application (e.g., DVWA). 2. Input a common SQL injection payload (like ' OR '1'='1') into a form field to bypass authentication. 3. Observe the results.\n",
+            "\n",
+            "Real-World Case Studies:\n",
+            "\n",
+            "Case Study 1: Target Data Breach (2013)\n",
+            "Scenario: Target suffered a massive data breach that exposed customer credit card information.\n",
+            "Challenge: The breach occurred due to inadequate security measures and failure to monitor third-party vendors.\n",
+            "Solution: Target implemented stronger network segmentation, improved monitoring of third-party vendors, and conducted comprehensive security assessments.\n",
+            "Outcome: The company faced significant financial losses and damage to reputation, leading to increased focus on cybersecurity.\n",
+            "\n",
+            "Key Lessons Learned:\n",
+            "- Never underestimate the security of third-party vendors.\n",
+            "- Continuous monitoring and assessment of security measures are crucial.\n",
+            "\n",
+            "Related Concepts:\n",
+            "- Penetration Testing\n",
+            "- Social Engineering\n",
+            "--------------------------------------------------\n",
+            "\n",
+            "Study Tips:\n",
+            "- Practice using ethical hacking tools in a controlled environment (e.g., virtual machines).\n",
+            "- Engage in Capture The Flag (CTF) exercises to apply your knowledge practically.\n",
+            "- Stay updated with the latest cybersecurity news and trends.\n",
+            "- Join online forums or communities focused on ethical hacking for shared learning.\n",
+            "\n",
+            "Additional Resources:\n",
+            "- Cybrary: An online platform offering free courses on ethical hacking and cybersecurity.\n",
+            "- OWASP: The Open Web Application Security Project provides comprehensive resources on web application security.\n",
+            "- Kali Linux Documentation: Official documentation for Kali Linux, a popular operating system for penetration testing.\n",
+            "\n",
+            "Summary:\n",
+            "Ethical hacking is a vital field within cybersecurity, focusing on identifying and addressing vulnerabilities before they can be exploited. By understanding the various types of hackers, learning common attack methods, and utilizing key tools and techniques, aspiring ethical hackers can contribute significantly to organizational security.\n"
+          ]
+        }
+      ]
+    },
+    {
+      "cell_type": "code",
+      "source": [],
+      "metadata": {
+        "id": "BhCpfDm2-uHb"
+      },
+      "execution_count": null,
+      "outputs": []
+    }
+  ]
+}
\ No newline at end of file
diff --git a/educhain/engines/content_engine.py b/educhain/engines/content_engine.py
index a5a4ca4..de4ca0a 100644
--- a/educhain/engines/content_engine.py
+++ b/educhain/engines/content_engine.py
@@ -5,6 +5,9 @@
 from langchain.chains import LLMChain
 from langchain.output_parsers import PydanticOutputParser
 from educhain.core.config import LLMConfig
+
+from educhain.models.content_models import StudyGuide, CareerConnections
+import json
 from educhain.models.content_models import LessonPlan
 from educhain.models.content_models import FlashcardSet 
 
@@ -28,6 +31,7 @@ def _initialize_llm(self, llm_config: LLMConfig):
                 default_headers=llm_config.default_headers
             )
 
+    # Lesson Plan
     def generate_lesson_plan(
         self,
         topic: str,
@@ -36,6 +40,7 @@ def generate_lesson_plan(
         custom_instructions: Optional[str] = None,
         response_model: Optional[Type[Any]] = None,
         llm: Optional[Any] = None,
+        output_format: Optional[str] = None,
         **kwargs
     ) -> Any:
         if response_model is None:
@@ -105,11 +110,307 @@ def generate_lesson_plan(
         try:
             # Parse results to match the new LessonPlan structure
             structured_output = parser.parse(results)
+
+            return structured_output
+        except Exception as e:
+            print(f"Error parsing output: {e}")
+            print("Raw output:")
+            print(results)
+            return response_model()
+        
+    # Study Guide
+    def generate_study_guide(
+        self,
+        topic: str,
+        difficulty_level: Optional[str] = None,
+        prompt_template: Optional[str] = None,
+        custom_instructions: Optional[str] = None,
+        response_model: Optional[Type[Any]] = None,
+        llm: Optional[Any] = None,
+        output_format: Optional[str] = None,
+        **kwargs
+    ) -> Any:
+        if response_model is None:
+            response_model = StudyGuide
+
+        parser = PydanticOutputParser(pydantic_object=response_model)
+        format_instructions = parser.get_format_instructions()
+
+        if prompt_template is None:
+            prompt_template = """
+            Create a comprehensive study guide for the following topic:
+            Topic: {topic}
+            Difficulty Level: {difficulty_level}
+
+            The study guide should be engaging, well-structured, and suitable for self-study or classroom use.
+            Include the following elements in your response:
+
+            1. Difficulty level and estimated study time
+            2. Prerequisites (if any)
+            3. Clear learning objectives (3-5 specific, measurable objectives)
+            4. Comprehensive overview of the topic
+            5. Key concepts with detailed explanations
+            6. Important dates and events (if applicable)
+            8. Practice exercises formatted as:
+            "practice_exercises": [
+                {{
+                    "title": "Exercise Title",
+                    "problem": "Detailed problem description",
+                    "solution": "Step-by-step solution",
+                    "difficulty": "beginner|intermediate|advanced"
+                }}
+            ]
+            9. Real-world case studies formatted as:
+            "case_studies": [
+                {{
+                    "title": "Case Study Title",
+                    "scenario": "Description of the real-world situation",
+                    "challenge": "Specific problems or challenges faced",
+                    "solution": "How the challenges were addressed",
+                    "outcome": "Results and impact",
+                    "lessons_learned": ["Key lesson 1", "Key lesson 2"],
+                    "related_concepts": ["Concept 1", "Concept 2"]
+                }}
+            ]
+            10. Study tips and strategies specific to the topic
+            11. Additional resources for deeper learning
+            12. Brief summary of key takeaways
+
+            For the case studies:
+            - Include at least one detailed real-world example
+            - Focus on recent and relevant scenarios
+            - Highlight practical applications of the concepts
+            - Connect the case study to specific learning objectives
+            - Emphasize problem-solving approaches
+            - Include both successes and lessons learned
+            - Make sure the examples are appropriate for the difficulty level
+
+            Make sure all content is hands-on and directly related to real-world applications of {topic}.
+            The study guide should accommodate different learning styles and include various types of learning activities.
+            """
+
+        if custom_instructions:
+            prompt_template += f"\n\nAdditional Instructions:\n{custom_instructions}"
+
+        prompt_template += "\n\nThe response should be in JSON format.\n{format_instructions}"
+
+        study_guide_prompt = PromptTemplate(
+            input_variables=["topic", "difficulty_level"],
+            template=prompt_template,
+            partial_variables={"format_instructions": format_instructions}
+        )
+
+        llm_to_use = llm if llm is not None else self.llm
+
+        study_guide_chain = study_guide_prompt | llm_to_use
+        results = study_guide_chain.invoke(
+            {
+                "topic": topic,
+                "difficulty_level": difficulty_level or "Intermediate",
+                **kwargs
+            },
+        )
+        results = results.content
+
+        try:
+            # Handle empty practice exercises
+            if '"practice_exercises": []' in results or '"practice_exercises":[]' in results:
+                results = results.replace(
+                    '"practice_exercises": []',
+                    '"practice_exercises": [{"title": "Basic Exercise", "problem": "No exercises provided", "solution": "N/A", "difficulty": "beginner"}]'
+                )
+                
+            # Handle empty case studies
+            if '"case_studies": []' in results or '"case_studies":[]' in results:
+                results = results.replace(
+                    '"case_studies": []',
+                    '"case_studies": [{"title": "Sample Case", "scenario": "No case studies provided", "challenge": "N/A", "solution": "N/A", "outcome": "N/A", "lessons_learned": ["N/A"], "related_concepts": ["N/A"]}]'
+                )
+
+            # Parse results to match the new LessonPlan structure
+            structured_output = parser.parse(results)
+
+            return structured_output
+        except Exception as e:
+            print(f"Error parsing output: {e}")
+            print("Raw output:")
+            print(results)
+            # Return an instance with default values including case studies
+            return response_model(
+                topic=topic,
+                overview="Error generating content",
+                key_concepts={"Basic Concept": "Error generating concepts"},
+                example_questions=[{"question": "Error generating questions", "answer": "N/A", "difficulty": "beginner"}],
+                practice_exercises=[{
+                    "title": "Basic Exercise",
+                    "problem": "Error generating exercises",
+                    "solution": "N/A",
+                    "difficulty": "beginner"
+                }],
+                case_studies=[{
+                    "title": "Sample Case",
+                    "scenario": "Error generating case studies",
+                    "challenge": "N/A",
+                    "solution": "N/A",
+                    "outcome": "N/A",
+                    "lessons_learned": ["N/A"],
+                    "related_concepts": ["N/A"]
+                }]
+            )
+        
+    # Carrer connections
+    def generate_career_connections(
+        self,
+        topic: str,
+        industry_focus: Optional[str] = None,
+        prompt_template: Optional[str] = None,
+        custom_instructions: Optional[str] = None,
+        response_model: Optional[Type[Any]] = None,
+        llm: Optional[Any] = None,
+        output_format: Optional[str] = None,
+        **kwargs
+    ) -> Any:
+        """
+        Generates connections between academic topics and real-world careers,
+        including insights from professionals in the field.
+        """
+        if response_model is None:
+            response_model = CareerConnections
+
+        parser = PydanticOutputParser(pydantic_object=response_model)
+        format_instructions = parser.get_format_instructions()
+
+        if prompt_template is None:
+            prompt_template = """
+            Create comprehensive career connections for the following academic topic:
+            Topic: {topic}
+            Industry Focus: {industry_focus}
+
+            Generate detailed information about how this topic connects to real-world careers and professional opportunities.
+            Include:
+
+            1. Industry Overview
+            - Current state of the industry
+            - Future outlook
+            - Key trends and developments
+
+            2. Career Paths formatted as:
+            "career_paths": [
+                {{
+                    "title": "Job Title",
+                    "description": "Role description",
+                    "typical_responsibilities": ["responsibility1", "responsibility2"],
+                    "required_education": "Education requirements",
+                    "salary_range": "Typical salary range",
+                    "growth_potential": "Career growth opportunities",
+                    "topic_application": "How this topic is used in the role"
+                }}
+            ]
+
+            3. Professional Insights formatted as:
+            "professional_insights": [
+                {{
+                    "role": "Professional's role",
+                    "experience_level": "Years of experience",
+                    "key_insights": ["insight1", "insight2"],
+                    "daily_applications": ["application1", "application2"],
+                    "advice_for_students": ["advice1", "advice2"]
+                }}
+            ]
+
+            4. Required Skills
+            - Technical skills
+            - Soft skills
+            - Industry-specific skills
+            - Future skills needed
+
+            5. Preparation Steps
+            - Educational pathways
+            - Certifications
+            - Experience building
+            - Networking opportunities
+
+            6. Resources
+            - Professional organizations
+            - Learning platforms
+            - Industry publications
+            - Networking opportunities
+
+            Make sure to:
+            - Focus on current and emerging career opportunities
+            - Include both traditional and non-traditional career paths
+            - Highlight the practical applications of the topic
+            - Provide actionable steps for students
+            - Include diverse perspectives and roles
+
+            Response format:
+            {format_instructions}
+            """
+
+        if custom_instructions:
+            prompt_template += f"\n\nAdditional Instructions:\n{custom_instructions}"
+
+        prompt = PromptTemplate(
+            input_variables=["topic", "industry_focus"],
+            template=prompt_template,
+            partial_variables={"format_instructions": format_instructions}
+        )
+
+        llm_to_use = llm if llm is not None else self.llm
+        
+        career_chain = prompt | llm_to_use
+        results = career_chain.invoke(
+            {
+                "topic": topic,
+                "industry_focus": industry_focus or "General",
+                **kwargs
+            },
+        )
+        results = results.content
+
+        try:
+            # Parse results to match the new LessonPlan structure
+            structured_output = parser.parse(results)
+            
             return structured_output
         except Exception as e:
             print(f"Error parsing output: {e}")
             print("Raw output:")
             print(results)
+            return response_model(
+                topic=topic,
+                industry_overview="Error generating content",
+                career_paths=[{
+                    "title": "Sample Career",
+                    "description": "Error generating career paths",
+                    "typical_responsibilities": ["N/A"],
+                    "required_education": "N/A",
+                    "salary_range": "N/A",
+                    "growth_potential": "N/A",
+                    "topic_application": "N/A"
+                }],
+                required_skills={
+                    "technical": ["Error generating skills"],
+                    "soft": ["Error generating skills"]
+                },
+                industry_trends=["Error generating trends"],
+                professional_insights=[{
+                    "role": "Sample Professional",
+                    "experience_level": "N/A",
+                    "key_insights": ["Error generating insights"],
+                    "daily_applications": ["N/A"],
+                    "advice_for_students": ["N/A"]
+                }],
+                preparation_steps={
+                    "education": ["Error generating steps"],
+                    "experience": ["Error generating steps"]
+                },
+                resources=[{
+                    "name": "Sample Resource",
+                    "url": "N/A"
+                }]
+            )
+          
             return response_model()
     
     def generate_flashcards(
diff --git a/educhain/engines/qna_engine.py b/educhain/engines/qna_engine.py
index 8ddaf21..e578515 100644
--- a/educhain/engines/qna_engine.py
+++ b/educhain/engines/qna_engine.py
@@ -1,6 +1,6 @@
 # educhain/engines/qna_engine.py
 
-from typing import Optional, Type, Any, List, Literal
+from typing import Optional, Type, Any, List, Literal, Union, Tuple
 from pydantic import BaseModel
 from langchain_openai import ChatOpenAI, OpenAIEmbeddings
 from langchain.prompts import PromptTemplate
@@ -16,10 +16,14 @@
     FillInBlankQuestionList, MCQListMath, Option
 )
 from educhain.utils.loaders import PdfFileLoader, UrlLoader
+from educhain.utils.output_formatter import OutputFormatter
+
+# Update the QuestionType definition
 
 import random
 
 QuestionType = Literal["Multiple Choice", "Short Answer", "True/False", "Fill in the Blank"]
+OutputFormatType = Literal["pdf", "csv"]
 
 class QnAEngine:
     def __init__(self, llm_config: Optional[LLMConfig] = None):
@@ -111,6 +115,21 @@ def _load_data(self, source: str, source_type: str) -> str:
             return source
         else:
             raise ValueError("Unsupported source type. Please use 'pdf', 'url', or 'text'.")
+        
+    def _handle_output_format(self, data: Any, output_format: Optional[OutputFormatType]) -> Union[Any, Tuple[Any, str]]:
+        """Handle output format conversion if specified"""
+        if output_format is None:
+            return data
+            
+        formatter = OutputFormatter()
+        if output_format == "pdf":
+            output_file = formatter.to_pdf(data)
+        elif output_format == "csv":
+            output_file = formatter.to_csv(data)
+        else:
+            raise ValueError(f"Unsupported output format: {output_format}")
+            
+        return data, output_file
 
     def generate_questions(
         self,
@@ -120,6 +139,7 @@ def generate_questions(
         prompt_template: Optional[str] = None,
         custom_instructions: Optional[str] = None,
         response_model: Optional[Type[Any]] = None,
+        output_format: Optional[OutputFormatType] = None,
         **kwargs
     ) -> Any:
         parser, model = self._get_parser_and_model(question_type, response_model)
@@ -157,6 +177,10 @@ def generate_questions(
 
         try:
             structured_output = parser.parse(results)
+
+            if output_format:
+                self._handle_output_format(structured_output, output_format)
+                
             return structured_output
         except Exception as e:
             print(f"Error parsing output: {e}")
@@ -173,6 +197,7 @@ def generate_questions_from_data(
         prompt_template: Optional[str] = None,
         custom_instructions: Optional[str] = None,
         response_model: Optional[Type[Any]] = None,
+        output_format: Optional[OutputFormatType] = None,
         **kwargs
     ) -> Any:
         content = self._load_data(source, source_type)
@@ -197,6 +222,7 @@ def generate_questions_with_rag(
         response_model: Optional[Type[Any]] = None,
         learning_objective: str = "",
         difficulty_level: str = "",
+        output_format: Optional[OutputFormatType] = None,
         **kwargs
     ) -> Any:
         # Initialize embeddings only when this method is called
@@ -244,7 +270,12 @@ def generate_questions_with_rag(
         results = qa_chain.invoke({"query": query, "n_results": 3})
 
         try:
-            return parser.parse(results["result"])
+            structured_output = parser.parse(results["result"])
+
+            if output_format:
+                self._handle_output_format(structured_output, output_format)
+            
+            return structured_output
         except Exception as e:
             print(f"Error parsing output: {e}")
             print("Raw output:", results)
@@ -264,6 +295,7 @@ def generate_mcq_math(
         prompt_template: Optional[str] = None,
         custom_instructions: Optional[str] = None,
         response_model: Optional[Type[Any]] = None,
+        output_format: Optional[OutputFormatType] = None,
         **kwargs
     ) -> Any:
 
@@ -333,4 +365,7 @@ def generate_mcq_math(
                 except Exception as e:
                     print(f"LLMMathChain failed to answer: {str(e)}")
 
+        if output_format:
+                self._handle_output_format(structured_output, output_format)
+
         return structured_output
\ No newline at end of file
diff --git a/educhain/models/content_models.py b/educhain/models/content_models.py
index cb6aa2b..600b13e 100644
--- a/educhain/models/content_models.py
+++ b/educhain/models/content_models.py
@@ -1,5 +1,7 @@
-from typing import Optional, Type, Any ,List
+from typing import Optional, Type, Any ,List, Dict
 from pydantic import BaseModel, Field
+from rich.console import Console
+from rich.markdown import Markdown
 
 class ContentElement(BaseModel):
     type: str = Field(..., description="The type of content element (e.g., definition, example, activity).")
@@ -98,3 +100,320 @@ def show(self):
         print("\nLearning Adaptations: ", self.learning_adaptations or "None")
         print("Real-World Applications: ", self.real_world_applications or "None")
         print("Ethical Considerations: ", self.ethical_considerations or "None")
+
+class CaseStudy(BaseModel):
+    title: str
+    scenario: str
+    challenge: str
+    solution: str
+    outcome: str
+    lessons_learned: List[str]
+    related_concepts: List[str]
+
+class StudyGuide(BaseModel):
+    topic: str
+    difficulty_level: Optional[str] = Field(None, description="Difficulty level of the study material (e.g., Beginner, Intermediate, Advanced)")
+    estimated_study_time: Optional[str] = Field(None, description="Estimated time needed to cover the material")
+    prerequisites: Optional[List[str]] = Field(default_factory=list, description="Required prerequisite knowledge")
+    learning_objectives: List[str] = Field(default_factory=list, description="Specific learning objectives for the study guide")
+    overview: str
+    key_concepts: Dict[str, str] = Field(
+        default_factory=dict,
+        description="Dictionary mapping concept names to their detailed explanations"
+    )
+    important_dates: Optional[Dict[str, str]] = Field(
+        None,
+        description="Dictionary mapping dates to their significance"
+    )
+    practice_exercises: Optional[List[Dict[str, Any]]] = Field(
+        None,
+        description="List of practice exercises with solutions"
+    )
+    case_studies: Optional[List[CaseStudy]] = Field(
+        None,
+        description="Real-world case studies demonstrating practical applications"
+    )
+    study_tips: Optional[List[str]] = Field(
+        None,
+        description="Study strategies specific to this topic"
+    )
+    additional_resources: Optional[Dict[str, str]] = Field(
+        None,
+        description="Dictionary mapping resource names to their descriptions/URLs"
+    )
+    summary: Optional[str] = Field(None, description="Brief summary of key takeaways")
+
+    def show(self, format: str = "text"):
+        """
+        Display the study guide in various formats.
+        
+        Args:
+            format (str): Output format - "text", "markdown", or "rich"
+        """
+        if format == "markdown":
+            return self._generate_markdown()
+        elif format == "rich":
+            console = Console()
+            console.print(Markdown(self._generate_markdown()))
+        else:
+            self._print_text_format()
+
+    def _generate_markdown(self) -> str:
+        """Generate a markdown representation of the study guide."""
+        md = [f"# Study Guide: {self.topic}\n"]
+        
+        if self.difficulty_level:
+            md.append(f"**Difficulty Level:** {self.difficulty_level}")
+        if self.estimated_study_time:
+            md.append(f"**Estimated Study Time:** {self.estimated_study_time}\n")
+            
+        if self.prerequisites:
+            md.append("## Prerequisites")
+            for prereq in self.prerequisites:
+                md.append(f"- {prereq}")
+            md.append("")
+            
+        md.append("## Learning Objectives")
+        for obj in self.learning_objectives:
+            md.append(f"- {obj}")
+        md.append("")
+            
+        md.append("## Overview")
+        md.append(f"{self.overview}\n")
+        
+        md.append("## Key Concepts")
+        for concept, explanation in self.key_concepts.items():
+            md.append(f"### {concept}")
+            md.append(f"{explanation}\n")
+            
+        if self.important_dates:
+            md.append("## Important Dates")
+            for date, significance in self.important_dates.items():
+                md.append(f"- **{date}**: {significance}")
+            md.append("")
+            
+        if self.practice_exercises:
+            md.append("## Practice Exercises")
+            for i, exercise in enumerate(self.practice_exercises, 1):
+                md.append(f"### Exercise {i}")
+                md.append(f"**Problem:** {exercise['problem']}")
+                md.append(f"**Solution:** {exercise['solution']}\n")
+
+        if self.case_studies:
+            md.append("## Real-World Case Studies")
+            for i, case in enumerate(self.case_studies, 1):
+                md.append(f"### Case Study {i}: {case.title}")
+                md.append(f"**Scenario:** {case.scenario}")
+                md.append(f"**Challenge:** {case.challenge}")
+                md.append(f"**Solution:** {case.solution}")
+                md.append(f"**Outcome:** {case.outcome}")
+                md.append("\n**Key Lessons Learned:**")
+                for lesson in case.lessons_learned:
+                    md.append(f"- {lesson}")
+                md.append("\n**Related Concepts:**")
+                for concept in case.related_concepts:
+                    md.append(f"- {concept}")
+                md.append("")
+                
+        if self.study_tips:
+            md.append("## Study Tips")
+            for tip in self.study_tips:
+                md.append(f"- {tip}")
+            md.append("")
+            
+        if self.additional_resources:
+            md.append("## Additional Resources")
+            for resource, description in self.additional_resources.items():
+                md.append(f"- **{resource}**: {description}")
+            md.append("")
+            
+        if self.summary:
+            md.append("## Summary")
+            md.append(self.summary)
+            
+        return "\n".join(md)
+
+    def _print_text_format(self):
+        """Print the study guide in plain text format."""
+        print(f"=== Study Guide: {self.topic} ===\n")
+        
+        if self.difficulty_level:
+            print(f"Difficulty Level: {self.difficulty_level}")
+        if self.estimated_study_time:
+            print(f"Estimated Study Time: {self.estimated_study_time}\n")
+            
+        if self.prerequisites:
+            print("Prerequisites:")
+            for prereq in self.prerequisites:
+                print(f"- {prereq}")
+            print()
+            
+        print("Learning Objectives:")
+        for obj in self.learning_objectives:
+            print(f"- {obj}")
+        print()
+            
+        print(f"Overview:\n{self.overview}\n")
+        
+        print("Key Concepts:")
+        for concept, explanation in self.key_concepts.items():
+            print(f"\n{concept}:")
+            print(f"{explanation}")
+            
+        if self.important_dates:
+            print("\nImportant Dates:")
+            for date, significance in self.important_dates.items():
+                print(f"- {date}: {significance}")
+            
+        if self.practice_exercises:
+            print("\nPractice Exercises:")
+            for i, exercise in enumerate(self.practice_exercises, 1):
+                print(f"\nExercise {i}:")
+                print(f"Problem: {exercise['problem']}")
+                print(f"Solution: {exercise['solution']}")
+
+        if self.case_studies:
+            print("\nReal-World Case Studies:")
+            for i, case in enumerate(self.case_studies, 1):
+                print(f"\nCase Study {i}: {case.title}")
+                print(f"Scenario: {case.scenario}")
+                print(f"Challenge: {case.challenge}")
+                print(f"Solution: {case.solution}")
+                print(f"Outcome: {case.outcome}")
+                print("\nKey Lessons Learned:")
+                for lesson in case.lessons_learned:
+                    print(f"- {lesson}")
+                print("\nRelated Concepts:")
+                for concept in case.related_concepts:
+                    print(f"- {concept}")
+                print("-" * 50)
+                
+        if self.study_tips:
+            print("\nStudy Tips:")
+            for tip in self.study_tips:
+                print(f"- {tip}")
+                
+        if self.additional_resources:
+            print("\nAdditional Resources:")
+            for resource, description in self.additional_resources.items():
+                print(f"- {resource}: {description}")
+                
+        if self.summary:
+            print(f"\nSummary:\n{self.summary}")
+
+# Carrer Connection
+class Skill(BaseModel):
+    name: str = Field(..., description="Name of the skill")
+    description: str = Field(..., description="Detailed description of the skill")
+    importance_level: str = Field(..., description="How important this skill is for the career (Essential/Important/Helpful)")
+    acquisition_methods: List[str] = Field(..., description="Ways to acquire or develop this skill")
+
+class CareerPath(BaseModel):
+    title: str = Field(..., description="Job title or role name")
+    description: str = Field(..., description="Detailed description of the career path")
+    typical_responsibilities: List[str] = Field(..., description="List of typical job responsibilities")
+    required_education: str = Field(..., description="Required educational qualifications")
+    salary_range: str = Field(..., description="Typical salary range for this role")
+    growth_potential: str = Field(..., description="Career growth and advancement opportunities")
+    topic_application: str = Field(..., description="How the academic topic is applied in this role")
+    required_skills: List[Skill] = Field(..., description="Skills required for this career path")
+
+class ProfessionalInsight(BaseModel):
+    role: str = Field(..., description="Professional's current role")
+    experience_level: str = Field(..., description="Years of experience in the field")
+    company_type: str = Field(..., description="Type of company or industry sector")
+    key_insights: List[str] = Field(..., description="Key insights about the career path")
+    daily_applications: List[str] = Field(..., description="How they apply the topic in daily work")
+    advice_for_students: List[str] = Field(..., description="Professional advice for students")
+    career_journey: str = Field(..., description="Brief description of their career journey")
+
+class IndustryTrend(BaseModel):
+    name: str = Field(..., description="Name of the trend")
+    description: str = Field(..., description="Detailed description of the trend")
+    impact: str = Field(..., description="Expected impact on the industry")
+    timeframe: str = Field(..., description="Expected timeframe for this trend")
+    related_skills: List[str] = Field(..., description="Skills related to this trend")
+
+class Resource(BaseModel):
+    name: str = Field(..., description="Name of the resource")
+    type: str = Field(..., description="Type of resource (Organization/Platform/Publication)")
+    description: str = Field(..., description="Description of the resource")
+    url: Optional[str] = Field(None, description="URL for the resource if applicable")
+    cost: Optional[str] = Field(None, description="Cost information if applicable")
+
+class PreparationPath(BaseModel):
+    stage: str = Field(..., description="Stage of preparation (e.g., Education, Early Career)")
+    requirements: List[str] = Field(..., description="Requirements for this stage")
+    duration: str = Field(..., description="Expected duration of this stage")
+    milestones: List[str] = Field(..., description="Key milestones to achieve")
+    resources_needed: List[str] = Field(..., description="Resources needed for this stage")
+
+class CareerConnections(BaseModel):
+    topic: str = Field(..., description="The academic topic being connected to careers")
+    industry_overview: str = Field(..., description="Overview of the industry landscape")
+    career_paths: List[CareerPath] = Field(..., description="Detailed career paths related to the topic")
+    industry_trends: List[IndustryTrend] = Field(..., description="Current and emerging industry trends")
+    professional_insights: List[ProfessionalInsight] = Field(..., description="Insights from industry professionals")
+    preparation_paths: List[PreparationPath] = Field(..., description="Steps to prepare for these careers")
+    resources: List[Resource] = Field(..., description="Useful resources for career preparation")
+    skill_categories: Dict[str, List[Skill]] = Field(..., description="Categorized skills required across careers")
+
+    def show(self):
+        print("=" * 80)
+        print(f"Career Connections: {self.topic}")
+        print("=" * 80)
+        print("\nIndustry Overview:")
+        print(self.industry_overview)
+        
+        print("\nCareer Paths:")
+        for i, path in enumerate(self.career_paths, 1):
+            print(f"\n{i}. {path.title}")
+            print(f"   Description: {path.description}")
+            print("   Responsibilities:")
+            for resp in path.typical_responsibilities:
+                print(f"   - {resp}")
+            print(f"   Education: {path.required_education}")
+            print(f"   Salary Range: {path.salary_range}")
+            print(f"   Growth Potential: {path.growth_potential}")
+            print("   Required Skills:")
+            for skill in path.required_skills:
+                print(f"   - {skill.name} ({skill.importance_level})")
+
+        print("\nIndustry Trends:")
+        for trend in self.industry_trends:
+            print(f"\n- {trend.name}")
+            print(f"  Impact: {trend.impact}")
+            print(f"  Timeframe: {trend.timeframe}")
+
+        print("\nProfessional Insights:")
+        for insight in self.professional_insights:
+            print(f"\nFrom {insight.role} ({insight.experience_level})")
+            print("Key Insights:")
+            for key_insight in insight.key_insights:
+                print(f"- {key_insight}")
+            print("Advice for Students:")
+            for advice in insight.advice_for_students:
+                print(f"- {advice}")
+
+        print("\nPreparation Paths:")
+        for path in self.preparation_paths:
+            print(f"\n{path.stage}")
+            print("Requirements:")
+            for req in path.requirements:
+                print(f"- {req}")
+            print(f"Duration: {path.duration}")
+
+        print("\nResources:")
+        for resource in self.resources:
+            print(f"\n- {resource.name} ({resource.type})")
+            print(f"  Description: {resource.description}")
+            if resource.url:
+                print(f"  URL: {resource.url}")
+            if resource.cost:
+                print(f"  Cost: {resource.cost}")
+
+        print("\nSkill Categories:")
+        for category, skills in self.skill_categories.items():
+            print(f"\n{category}:")
+            for skill in skills:
+                print(f"- {skill.name}: {skill.description}")
diff --git a/educhain/utils/output_formatter.py b/educhain/utils/output_formatter.py
new file mode 100644
index 0000000..3b9073f
--- /dev/null
+++ b/educhain/utils/output_formatter.py
@@ -0,0 +1,166 @@
+# educhain/utils/output_formatter.py
+
+from typing import Any, Optional, List, Dict
+import pandas as pd
+from reportlab.lib import colors
+from reportlab.lib.pagesizes import letter
+from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
+from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
+from reportlab.pdfbase import pdfmetrics
+from reportlab.pdfbase.ttfonts import TTFont
+import json
+from datetime import datetime
+
+class OutputFormatter:
+    @staticmethod
+    def _convert_to_dict_list(data: Any) -> List[Dict]:
+        """Convert Pydantic model data to a list of dictionaries"""
+        if hasattr(data, 'questions'):
+            # If it's a question list model
+            return [q.dict() for q in data.questions]
+        elif isinstance(data, list):
+            # If it's already a list
+            return [item.dict() if hasattr(item, 'dict') else item for item in data]
+        else:
+            # Single item
+            return [data.dict() if hasattr(data, 'dict') else data]
+
+    @staticmethod
+    def to_csv(data: Any, filename: Optional[str] = None) -> str:
+        """Convert data to CSV format"""
+        if filename is None:
+            filename = f"questions_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
+        
+        dict_list = OutputFormatter._convert_to_dict_list(data)
+        df = pd.DataFrame(dict_list)
+        
+        # Handle nested structures (like options in MCQs)
+        for col in df.columns:
+            if isinstance(df[col].iloc[0], (list, dict)):
+                df[col] = df[col].apply(json.dumps)
+        
+        df.to_csv(filename, index=False)
+        return filename
+
+    @staticmethod
+    def _format_question(question: Dict, styles: Dict) -> List:
+        """Format a single question for PDF output"""
+        elements = []
+        
+        # Question number and text
+        question_text = Paragraph(f"Q{question.get('id', '')}: {question.get('question', '')}", 
+                                styles['Question'])
+        elements.append(question_text)
+        elements.append(Spacer(1, 12))
+
+        # Options (if present)
+        if 'options' in question:
+            options = question['options']
+            if isinstance(options, str):
+                try:
+                    options = json.loads(options)
+                except:
+                    options = [options]
+                    
+            for i, opt in enumerate(options):
+                if isinstance(opt, dict):
+                    opt_text = opt.get('text', '')
+                    is_correct = opt.get('correct', 'false') == 'true'
+                else:
+                    opt_text = str(opt)
+                    is_correct = False
+                
+                option_style = styles['CorrectOption'] if is_correct else styles['Option']
+                option_text = Paragraph(f"{chr(65+i)}. {opt_text}", option_style)
+                elements.append(option_text)
+                elements.append(Spacer(1, 6))
+
+        # Correct Answer (if not MCQ)
+        if 'answer' in question:
+            answer_text = Paragraph(f"Correct Answer: {question['answer']}", 
+                                  styles['CorrectAnswer'])
+            elements.append(answer_text)
+            elements.append(Spacer(1, 6))
+
+        # Explanation
+        if question.get('explanation'):
+            explanation_text = Paragraph(f"Explanation: {question['explanation']}", 
+                                      styles['Explanation'])
+            elements.append(explanation_text)
+            
+        elements.append(Spacer(1, 20))
+        return elements
+
+    @staticmethod
+    def to_pdf(data: Any, filename: Optional[str] = None) -> str:
+        """Convert data to PDF format using ReportLab"""
+        if filename is None:
+            filename = f"questions_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
+
+        # Create the PDF document
+        doc = SimpleDocTemplate(
+            filename,
+            pagesize=letter,
+            rightMargin=72,
+            leftMargin=72,
+            topMargin=72,
+            bottomMargin=72
+        )
+
+        # Define styles
+        styles = getSampleStyleSheet()
+        styles.add(ParagraphStyle(
+            name='Question',
+            parent=styles['Normal'],
+            fontSize=12,
+            spaceAfter=6,
+            fontName='Helvetica-Bold'
+        ))
+        styles.add(ParagraphStyle(
+            name='Option',
+            parent=styles['Normal'],
+            fontSize=11,
+            leftIndent=20,
+            fontName='Helvetica'
+        ))
+        styles.add(ParagraphStyle(
+            name='CorrectOption',
+            parent=styles['Normal'],
+            fontSize=11,
+            leftIndent=20,
+            textColor=colors.green,
+            fontName='Helvetica-Bold'
+        ))
+        styles.add(ParagraphStyle(
+            name='CorrectAnswer',
+            parent=styles['Normal'],
+            fontSize=11,
+            textColor=colors.green,
+            fontName='Helvetica-Bold'
+        ))
+        styles.add(ParagraphStyle(
+            name='Explanation',
+            parent=styles['Normal'],
+            fontSize=10,
+            leftIndent=20,
+            textColor=colors.gray,
+            fontName='Helvetica-Oblique'
+        ))
+
+        # Build the document content
+        elements = []
+        
+        # Add title
+        title = Paragraph("Generated Questions", styles['Title'])
+        elements.append(title)
+        elements.append(Spacer(1, 30))
+
+        # Process questions
+        dict_list = OutputFormatter._convert_to_dict_list(data)
+        for i, question in enumerate(dict_list, 1):
+            question['id'] = i
+            elements.extend(OutputFormatter._format_question(question, styles))
+
+        # Generate the PDF
+        doc.build(elements)
+        return filename
\ No newline at end of file


Test patch:
diff --git a/test_scripts/test_carrer_connections.py b/test_scripts/test_carrer_connections.py
new file mode 100644
index 0000000..bddf5fd
--- /dev/null
+++ b/test_scripts/test_carrer_connections.py
@@ -0,0 +1,39 @@
+from educhain.engines.content_engine import ContentEngine
+from educhain.core.config import LLMConfig
+
+def test_generate_career_connections():
+    try:
+        # Initialize LLM configuration
+        llm_config = LLMConfig(
+            model_name="gpt-4o",
+            api_key="",
+            max_tokens=4000,
+            temperature=0.5,
+        )
+
+        # Initialize content engine
+        content_engine = ContentEngine(llm_config=llm_config)
+
+        # Test parameters
+        topic = "Data Science"
+        industry_focus = "Technology"
+
+        # Generate the career connections
+        print(f"\nGenerating career connections for: {topic}")
+        print(f"Industry Focus: {industry_focus}")
+        
+        career_connections = content_engine.generate_career_connections(
+            topic=topic,
+            industry_focus=industry_focus,
+            output_format="csv"
+        )
+
+        career_connections.show()  # Using the show method we defined in the Pydantic model
+
+    except Exception as e:
+        print(f"\nError generating career connections: {e}")
+        import traceback
+        print(traceback.format_exc())
+
+if __name__ == "__main__":
+    test_generate_career_connections()
\ No newline at end of file
diff --git a/test_scripts/test_generate_lesson_.py b/test_scripts/test_generate_lesson.py
similarity index 90%
rename from test_scripts/test_generate_lesson_.py
rename to test_scripts/test_generate_lesson.py
index 41e82a1..493f8c6 100644
--- a/test_scripts/test_generate_lesson_.py
+++ b/test_scripts/test_generate_lesson.py
@@ -6,9 +6,9 @@ def test_generate_lesson_plan():
     try:
         
         llm_config = LLMConfig(
-            model_name="gpt-4o-mini",
+            model_name="gpt-4o",
             api_key="",
-            max_tokens=3000,
+            max_tokens=4000,
             temperature=0.5,
         )
 
@@ -22,6 +22,7 @@ def test_generate_lesson_plan():
         lesson_plan = content_engine.generate_lesson_plan(
             topic=topic,
             custom_instructions=custom_instructions,
+            output_format="csv"
         )
 
         # Display the lesson plan using the show() function
diff --git a/test_scripts/test_generate_questions.py b/test_scripts/test_generate_questions.py
new file mode 100644
index 0000000..8911e32
--- /dev/null
+++ b/test_scripts/test_generate_questions.py
@@ -0,0 +1,37 @@
+import sys
+from educhain.core.config import LLMConfig
+from educhain.engines.qna_engine import QnAEngine
+
+def test_question_generation():
+    try:
+        
+        llm_config = LLMConfig(
+            model_name="gpt-4o",
+            api_key="",
+            max_tokens=4000,
+            temperature=0.5,
+        )
+
+        qna_engine = QnAEngine(llm_config=llm_config)
+
+        topic = "Gravitation"
+        num = 5
+        question_type = "Multiple Choice"
+
+        # Generate the lesson plan
+        qna = qna_engine.generate_questions(
+            topic=topic,
+            num=num,
+            question_type=question_type,
+            output_format="csv"
+        )
+
+        # Display the lesson plan using the show() function
+        print(qna)
+
+    except Exception as e:
+        print(f"Error generating questions: {e}")
+
+# Run the test
+if __name__ == "__main__":
+    test_question_generation()
diff --git a/test_scripts/test_math.py b/test_scripts/test_math.py
index 39d9918..1d4ee02 100644
--- a/test_scripts/test_math.py
+++ b/test_scripts/test_math.py
@@ -10,12 +10,13 @@
 
 engine = QnAEngine(llm_config=llm_config)
 
-topic = "Geometry"
+topic = "Linear Algebra"
 
-num_questions = 7
+num_questions = 5
 response = engine.generate_mcq_math(
     topic=topic,
-    num=num_questions
+    num=num_questions,
+    output_format="pdf"
 )
 
 print(response)
diff --git a/test_scripts/test_study_guide.py b/test_scripts/test_study_guide.py
new file mode 100644
index 0000000..f4a64ba
--- /dev/null
+++ b/test_scripts/test_study_guide.py
@@ -0,0 +1,43 @@
+from educhain.engines.content_engine import ContentEngine
+from educhain.core.config import LLMConfig
+
+def test_generate_study_guide():
+    try:
+        # Initialize LLM configuration
+        llm_config = LLMConfig(
+            model_name="gpt-4o",
+            api_key="",
+            max_tokens=4000,
+            temperature=0.5,
+        )
+
+        # Initialize content engine
+        content_engine = ContentEngine(llm_config=llm_config)
+
+        # Test parameters
+        topic = "Ethical Hacking"
+        difficulty_level = "Beginner"
+        custom_instructions = """
+        Include hands-on examples and some real-world techniques.
+        Focus on practical applications and security best practices.
+        """
+
+        # Generate the study guide
+        print(f"\nGenerating study guide for: {topic}")
+        study_guide = content_engine.generate_study_guide(
+            topic=topic,
+            difficulty_level=difficulty_level,
+            custom_instructions=custom_instructions,
+            output_format="csv"
+        )
+
+        # Display results
+        print("\nGenerated Study Guide:")
+        print("-" * 50)
+        study_guide.show(format="text")  # Using the new format parameter
+
+    except Exception as e:
+        print(f"\nError generating study guide: {e}")
+
+if __name__ == "__main__":
+    test_generate_study_guide()
\ No newline at end of file