Spaces:
Build error
Build error
finish the idea of micro learning part 3
Browse files- README.md +17 -0
- ai/agents.py +39 -0
- ai/huggingface.py +22 -0
- api/agents.py +35 -0
- api/main.py +114 -0
- app.py +117 -1
README.md
CHANGED
|
@@ -10,4 +10,21 @@ pinned: false
|
|
| 10 |
short_description: micro learning
|
| 11 |
---
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 10 |
short_description: micro learning
|
| 11 |
---
|
| 12 |
|
| 13 |
+
|
| 14 |
+
/micro_learning_platform
|
| 15 |
+
/api
|
| 16 |
+
main.py # FastAPI/Flask entry point
|
| 17 |
+
models.py # Data models
|
| 18 |
+
routes.py # API endpoints
|
| 19 |
+
/ai
|
| 20 |
+
huggingface.py # Hugging Face integration
|
| 21 |
+
agents.py # Your MCP agents
|
| 22 |
+
/data
|
| 23 |
+
content.py # Content management
|
| 24 |
+
users.py # User management
|
| 25 |
+
/frontend
|
| 26 |
+
templates/ # Simple templates if needed
|
| 27 |
+
static/ # CSS/JS assets
|
| 28 |
+
app.py # Main application entry
|
| 29 |
+
|
| 30 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
ai/agents.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# In ai/agents.py
|
| 2 |
+
class Agent:
|
| 3 |
+
def __init__(self, name, role):
|
| 4 |
+
self.name = name
|
| 5 |
+
self.role = role
|
| 6 |
+
|
| 7 |
+
def process(self, message, context=None):
|
| 8 |
+
raise NotImplementedError("Agents must implement process method")
|
| 9 |
+
|
| 10 |
+
class TutorAgent(Agent):
|
| 11 |
+
def __init__(self, hf_service):
|
| 12 |
+
super().__init__("Tutor", "Explains concepts")
|
| 13 |
+
self.hf = hf_service
|
| 14 |
+
|
| 15 |
+
def process(self, message, context=None):
|
| 16 |
+
# Use Hugging Face to generate explanations
|
| 17 |
+
return f"Let me explain: {message}"
|
| 18 |
+
|
| 19 |
+
class QuizAgent(Agent):
|
| 20 |
+
def __init__(self, hf_service):
|
| 21 |
+
super().__init__("Quiz", "Generates questions")
|
| 22 |
+
self.hf = hf_service
|
| 23 |
+
|
| 24 |
+
def process(self, content, context=None):
|
| 25 |
+
# Generate quiz questions based on content
|
| 26 |
+
return ["Question 1: ...?", "Question 2: ...?"]
|
| 27 |
+
|
| 28 |
+
class AgentCoordinator:
|
| 29 |
+
def __init__(self, hf_service):
|
| 30 |
+
self.hf = hf_service
|
| 31 |
+
self.agents = {
|
| 32 |
+
"tutor": TutorAgent(hf_service),
|
| 33 |
+
"quiz": QuizAgent(hf_service)
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
def dispatch(self, agent_type, message, context=None):
|
| 37 |
+
if agent_type in self.agents:
|
| 38 |
+
return self.agents[agent_type].process(message, context)
|
| 39 |
+
return "Agent not found"
|
ai/huggingface.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# In /ai/huggingface.py
|
| 2 |
+
import os
|
| 3 |
+
from transformers import pipeline
|
| 4 |
+
|
| 5 |
+
class HuggingFaceService:
|
| 6 |
+
def __init__(self):
|
| 7 |
+
# Load models once during initialization
|
| 8 |
+
self.summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
|
| 9 |
+
self.qa_model = pipeline("question-answering", model="deepset/roberta-base-squad2")
|
| 10 |
+
self.classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
| 11 |
+
|
| 12 |
+
def summarize_content(self, content, max_length=100):
|
| 13 |
+
"""Generate a short summary of learning content"""
|
| 14 |
+
return self.summarizer(content, max_length=max_length, min_length=30, do_sample=False)
|
| 15 |
+
|
| 16 |
+
def answer_question(self, question, context):
|
| 17 |
+
"""Answer a question based on the learning content"""
|
| 18 |
+
return self.qa_model(question=question, context=context)
|
| 19 |
+
|
| 20 |
+
def classify_content(self, content, labels=["beginner", "intermediate", "advanced"]):
|
| 21 |
+
"""Classify content by difficulty level"""
|
| 22 |
+
return self.classifier(content, candidate_labels=labels)
|
api/agents.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Enhanced QuizAgent in ai/agents.py
|
| 2 |
+
class QuizAgent(Agent):
|
| 3 |
+
def __init__(self, hf_service):
|
| 4 |
+
super().__init__("Quiz", "Generates questions")
|
| 5 |
+
self.hf = hf_service
|
| 6 |
+
|
| 7 |
+
def process(self, content, context=None):
|
| 8 |
+
# Generate 3-5 questions based on content
|
| 9 |
+
questions = []
|
| 10 |
+
|
| 11 |
+
# Extract key concepts using summarization
|
| 12 |
+
summary = self.hf.summarize_content(content)[0]['summary_text']
|
| 13 |
+
|
| 14 |
+
# Generate questions using question-answering in reverse
|
| 15 |
+
# We'll extract potential answers and create questions for them
|
| 16 |
+
sentences = summary.split('. ')
|
| 17 |
+
for sentence in sentences[:5]: # Limit to 5 questions
|
| 18 |
+
# Use the sentence as context and try to generate a question
|
| 19 |
+
potential_answer = sentence.strip()
|
| 20 |
+
|
| 21 |
+
# We'll need to integrate with a better question generation model here
|
| 22 |
+
# For now, create a simple question by masking parts of the sentence
|
| 23 |
+
words = potential_answer.split()
|
| 24 |
+
if len(words) > 5:
|
| 25 |
+
# Find a key noun or entity to ask about
|
| 26 |
+
# This is simplified - would need NER or POS tagging in production
|
| 27 |
+
question_word = words[len(words)//2]
|
| 28 |
+
question = potential_answer.replace(question_word, "___")
|
| 29 |
+
questions.append({
|
| 30 |
+
"question": f"Complete the following: {question}",
|
| 31 |
+
"answer": question_word,
|
| 32 |
+
"context": potential_answer
|
| 33 |
+
})
|
| 34 |
+
|
| 35 |
+
return questions
|
api/main.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# In api/main.py
|
| 2 |
+
from fastapi import FastAPI, HTTPException, Depends
|
| 3 |
+
from pydantic import BaseModel
|
| 4 |
+
from typing import List, Optional
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
# Add parent directory to path to import modules
|
| 9 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 10 |
+
|
| 11 |
+
from ai.huggingface import HuggingFaceService
|
| 12 |
+
from ai.agents import AgentCoordinator
|
| 13 |
+
from data.content import ContentManager
|
| 14 |
+
from data.users import UserManager
|
| 15 |
+
|
| 16 |
+
app = FastAPI(
|
| 17 |
+
title="Micro Learning API",
|
| 18 |
+
description="API for microlearning content and personalization",
|
| 19 |
+
version="0.1.0"
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
# Initialize services
|
| 23 |
+
hf_service = HuggingFaceService()
|
| 24 |
+
agent_coordinator = AgentCoordinator(hf_service)
|
| 25 |
+
content_manager = ContentManager()
|
| 26 |
+
user_manager = UserManager()
|
| 27 |
+
|
| 28 |
+
# Models
|
| 29 |
+
class ContentBase(BaseModel):
|
| 30 |
+
title: str
|
| 31 |
+
text: str
|
| 32 |
+
tags: List[str]
|
| 33 |
+
|
| 34 |
+
class ContentCreate(ContentBase):
|
| 35 |
+
pass
|
| 36 |
+
|
| 37 |
+
class Content(ContentBase):
|
| 38 |
+
id: str
|
| 39 |
+
|
| 40 |
+
class UserBase(BaseModel):
|
| 41 |
+
name: str
|
| 42 |
+
email: str
|
| 43 |
+
|
| 44 |
+
class UserCreate(UserBase):
|
| 45 |
+
pass
|
| 46 |
+
|
| 47 |
+
class User(UserBase):
|
| 48 |
+
id: str
|
| 49 |
+
progress: dict = {}
|
| 50 |
+
|
| 51 |
+
class ProgressUpdate(BaseModel):
|
| 52 |
+
module_id: str
|
| 53 |
+
completion: float # 0.0 to 1.0
|
| 54 |
+
|
| 55 |
+
# Routes
|
| 56 |
+
@app.get("/content/{content_id}", response_model=Content)
|
| 57 |
+
async def get_content(content_id: str):
|
| 58 |
+
content = content_manager.get_by_id(content_id)
|
| 59 |
+
if not content:
|
| 60 |
+
raise HTTPException(status_code=404, detail="Content not found")
|
| 61 |
+
return content
|
| 62 |
+
|
| 63 |
+
@app.post("/content/", response_model=str)
|
| 64 |
+
async def create_content(content: ContentCreate):
|
| 65 |
+
content_id = content_manager.save_content(content.dict())
|
| 66 |
+
return content_id
|
| 67 |
+
|
| 68 |
+
@app.get("/content/{content_id}/summary")
|
| 69 |
+
async def get_summary(content_id: str):
|
| 70 |
+
content = content_manager.get_by_id(content_id)
|
| 71 |
+
if not content:
|
| 72 |
+
raise HTTPException(status_code=404, detail="Content not found")
|
| 73 |
+
|
| 74 |
+
summary = hf_service.summarize_content(content['text'])
|
| 75 |
+
return {"summary": summary[0]['summary_text']}
|
| 76 |
+
|
| 77 |
+
@app.post("/content/{content_id}/ask")
|
| 78 |
+
async def ask_question(content_id: str, question: str):
|
| 79 |
+
content = content_manager.get_by_id(content_id)
|
| 80 |
+
if not content:
|
| 81 |
+
raise HTTPException(status_code=404, detail="Content not found")
|
| 82 |
+
|
| 83 |
+
answer = hf_service.answer_question(question, content['text'])
|
| 84 |
+
return {"answer": answer['answer'], "confidence": answer['score']}
|
| 85 |
+
|
| 86 |
+
@app.get("/content/{content_id}/quiz")
|
| 87 |
+
async def generate_quiz(content_id: str):
|
| 88 |
+
content = content_manager.get_by_id(content_id)
|
| 89 |
+
if not content:
|
| 90 |
+
raise HTTPException(status_code=404, detail="Content not found")
|
| 91 |
+
|
| 92 |
+
questions = agent_coordinator.dispatch("quiz", content['text'])
|
| 93 |
+
return {"questions": questions}
|
| 94 |
+
|
| 95 |
+
@app.post("/users/", response_model=str)
|
| 96 |
+
async def create_user(user: UserCreate):
|
| 97 |
+
user_id = user_manager.create_user(user.dict())
|
| 98 |
+
return user_id
|
| 99 |
+
|
| 100 |
+
@app.get("/users/{user_id}", response_model=User)
|
| 101 |
+
async def get_user(user_id: str):
|
| 102 |
+
user = user_manager.get_user(user_id)
|
| 103 |
+
if not user:
|
| 104 |
+
raise HTTPException(status_code=404, detail="User not found")
|
| 105 |
+
return user
|
| 106 |
+
|
| 107 |
+
@app.post("/users/{user_id}/progress")
|
| 108 |
+
async def update_progress(user_id: str, update: ProgressUpdate):
|
| 109 |
+
user = user_manager.get_user(user_id)
|
| 110 |
+
if not user:
|
| 111 |
+
raise HTTPException(status_code=404, detail="User not found")
|
| 112 |
+
|
| 113 |
+
user_manager.update_progress(user_id, update.module_id, update.completion)
|
| 114 |
+
return {"status": "updated"}
|
app.py
CHANGED
|
@@ -1 +1,117 @@
|
|
| 1 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Updated app.py for Hugging Face Spaces compatibility
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from ai.huggingface import HuggingFaceService
|
| 4 |
+
from data.content import ContentManager
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
# Initialize services - with error handling
|
| 8 |
+
try:
|
| 9 |
+
hf_service = HuggingFaceService()
|
| 10 |
+
content_manager = ContentManager()
|
| 11 |
+
except Exception as e:
|
| 12 |
+
print(f"Initialization error: {e}")
|
| 13 |
+
# Create mock services for demo if real ones fail
|
| 14 |
+
class MockHFService:
|
| 15 |
+
def summarize_content(self, content, max_length=100):
|
| 16 |
+
return [{"summary_text": "This is a mock summary for demo purposes."}]
|
| 17 |
+
def answer_question(self, question, context):
|
| 18 |
+
return {"answer": "This is a mock answer for demo purposes.", "score": 0.95}
|
| 19 |
+
def classify_content(self, content, labels=None):
|
| 20 |
+
return {"labels": ["beginner"], "scores": [0.9]}
|
| 21 |
+
|
| 22 |
+
class MockContentManager:
|
| 23 |
+
def get_by_id(self, content_id):
|
| 24 |
+
return {"title": "Sample Module", "text": "This is sample content for the microlearning demo."}
|
| 25 |
+
|
| 26 |
+
hf_service = MockHFService()
|
| 27 |
+
content_manager = MockContentManager()
|
| 28 |
+
|
| 29 |
+
# Demo content for testing
|
| 30 |
+
sample_content = {
|
| 31 |
+
"sample1": {"title": "Introduction to AI", "text": "Artificial Intelligence (AI) is the simulation of human intelligence processes by machines, especially computer systems."},
|
| 32 |
+
"sample2": {"title": "Python Basics", "text": "Python is a high-level, interpreted programming language known for its readability and simplicity."}
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
# Helper functions
|
| 36 |
+
def get_content_list():
|
| 37 |
+
return [{"id": k, "title": v["title"]} for k, v in sample_content.items()]
|
| 38 |
+
|
| 39 |
+
def display_content(content_id):
|
| 40 |
+
if content_id in sample_content:
|
| 41 |
+
return sample_content[content_id]["text"]
|
| 42 |
+
|
| 43 |
+
# Try to get from real content manager if demo content not found
|
| 44 |
+
content = content_manager.get_by_id(content_id)
|
| 45 |
+
if content and "text" in content:
|
| 46 |
+
return content["text"]
|
| 47 |
+
return "Content not found"
|
| 48 |
+
|
| 49 |
+
def summarize_content(content_id):
|
| 50 |
+
if content_id in sample_content:
|
| 51 |
+
text = sample_content[content_id]["text"]
|
| 52 |
+
else:
|
| 53 |
+
content = content_manager.get_by_id(content_id)
|
| 54 |
+
if not content or "text" not in content:
|
| 55 |
+
return "Content not found"
|
| 56 |
+
text = content["text"]
|
| 57 |
+
|
| 58 |
+
summary = hf_service.summarize_content(text)
|
| 59 |
+
return summary[0]['summary_text']
|
| 60 |
+
|
| 61 |
+
def answer_question(content_id, question):
|
| 62 |
+
if content_id in sample_content:
|
| 63 |
+
text = sample_content[content_id]["text"]
|
| 64 |
+
else:
|
| 65 |
+
content = content_manager.get_by_id(content_id)
|
| 66 |
+
if not content or "text" not in content:
|
| 67 |
+
return "Content not found"
|
| 68 |
+
text = content["text"]
|
| 69 |
+
|
| 70 |
+
answer = hf_service.answer_question(question, text)
|
| 71 |
+
return f"{answer['answer']} (confidence: {answer['score']:.2f})"
|
| 72 |
+
|
| 73 |
+
# Gradio interface
|
| 74 |
+
demo = gr.Blocks(title="Micro Learning Platform")
|
| 75 |
+
|
| 76 |
+
with demo:
|
| 77 |
+
gr.Markdown("# Micro Learning Platform")
|
| 78 |
+
|
| 79 |
+
with gr.Tab("Browse Content"):
|
| 80 |
+
gr.Markdown("## Available Learning Modules")
|
| 81 |
+
content_dropdown = gr.Dropdown(choices=get_content_list(), label="Select Module", value="sample1")
|
| 82 |
+
content_display = gr.Textbox(label="Content", lines=5)
|
| 83 |
+
view_button = gr.Button("View Content")
|
| 84 |
+
|
| 85 |
+
view_button.click(
|
| 86 |
+
display_content,
|
| 87 |
+
inputs=[content_dropdown],
|
| 88 |
+
outputs=[content_display]
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
with gr.Tab("Study Tools"):
|
| 92 |
+
with gr.Row():
|
| 93 |
+
study_content_dropdown = gr.Dropdown(choices=get_content_list(), label="Select Module", value="sample1")
|
| 94 |
+
|
| 95 |
+
with gr.Tab("Summarize"):
|
| 96 |
+
summarize_button = gr.Button("Summarize")
|
| 97 |
+
summary_output = gr.Textbox(label="Summary", lines=3)
|
| 98 |
+
|
| 99 |
+
summarize_button.click(
|
| 100 |
+
summarize_content,
|
| 101 |
+
inputs=[study_content_dropdown],
|
| 102 |
+
outputs=[summary_output]
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
with gr.Tab("Ask Question"):
|
| 106 |
+
question_input = gr.Textbox(label="Your Question")
|
| 107 |
+
ask_button = gr.Button("Ask")
|
| 108 |
+
answer_output = gr.Textbox(label="Answer")
|
| 109 |
+
|
| 110 |
+
ask_button.click(
|
| 111 |
+
answer_question,
|
| 112 |
+
inputs=[study_content_dropdown, question_input],
|
| 113 |
+
outputs=[answer_output]
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
# This is required for Hugging Face Spaces
|
| 117 |
+
demo.launch()
|