Vaibhav7625's picture
Updated images temp folder properly
6865d24
from fastapi import FastAPI, HTTPException, File, UploadFile, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
import asyncio
import uvicorn
import os
import json
import base64
from datetime import datetime
import threading
import time
import tempfile
from ai_models import AdvancedClassroomAI
# Initialize FastAPI app
app = FastAPI(
title="Advanced Classroom AI API",
description="AI-powered educational assistant with text, voice, and visual capabilities",
version="1.0.0"
)
# CORS middleware to allow frontend connections
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # More permissive for development
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Global AI instance and status tracking
ai_assistant = None
initialization_status = "starting"
initialization_start_time = None
initialization_error = None
# Initialize AI models in background
def initialize_ai():
global ai_assistant, initialization_status, initialization_start_time, initialization_error
initialization_start_time = time.time()
initialization_status = "initializing"
try:
print("πŸš€ Initializing AI models...")
print("πŸ“ This may take a few minutes on first run...")
ai_assistant = AdvancedClassroomAI(
device='cpu',
save_images=True,
display_images=False # Don't display in API mode
)
# Verify models are actually ready
if hasattr(ai_assistant, 'models_ready') and ai_assistant.models_ready:
initialization_status = "ready"
elapsed_time = time.time() - initialization_start_time
print(f"βœ… AI models initialized successfully in {elapsed_time:.2f} seconds!")
else:
initialization_status = "error"
initialization_error = "Models loaded but not ready"
print("❌ AI models loaded but not ready")
except Exception as e:
initialization_status = "error"
initialization_error = str(e)
print(f"❌ Failed to initialize AI models: {e}")
ai_assistant = None
# Start AI initialization in background thread
print("πŸš€ Starting AI model initialization in background...")
threading.Thread(target=initialize_ai, daemon=True).start()
# Serve generated images
os.makedirs(os.path.join(tempfile.gettempdir(), "generated_images"), exist_ok=True)
app.mount("/images", StaticFiles(directory=os.path.join(tempfile.gettempdir(), "generated_images")), name="images")
# Pydantic models for API
class ChatRequest(BaseModel):
message: str
subject: str = "General"
message_type: str = "text" # text, voice, visual
conversation_history: Optional[List[Dict[str, Any]]] = []
class ChatResponse(BaseModel):
response: str
analysis: Dict[str, Any]
image_url: Optional[str] = None
processing_time: float
success: bool
error: Optional[str] = None
class HealthResponse(BaseModel):
status: str
ai_models_ready: bool
timestamp: str
initialization_status: Optional[str] = None
models_loaded: Optional[bool] = None
error_message: Optional[str] = None
initialization_time: Optional[float] = None
# Health check endpoint with detailed status
@app.get("/health", response_model=HealthResponse)
async def health_check():
global ai_assistant, initialization_status, initialization_start_time, initialization_error
# Calculate initialization time
init_time = None
if initialization_start_time:
init_time = time.time() - initialization_start_time
# Determine if models are ready
models_ready = (
ai_assistant is not None and
hasattr(ai_assistant, 'models_ready') and
ai_assistant.models_ready and
initialization_status == "ready"
)
response = HealthResponse(
status="healthy" if models_ready else "initializing",
ai_models_ready=models_ready,
timestamp=datetime.now().isoformat(),
initialization_status=initialization_status,
models_loaded=ai_assistant is not None,
error_message=initialization_error,
initialization_time=init_time
)
print(f"Health check: {response.dict()}")
return response
# Main chat endpoint
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
global ai_assistant, initialization_status
try:
# Check if AI is ready with detailed status
if ai_assistant is None:
return ChatResponse(
response="AI models are still loading. Please try again in a moment.",
analysis={"subject": request.subject, "status": "loading", "initialization_status": initialization_status},
processing_time=0,
success=False,
error="AI models not ready"
)
if not hasattr(ai_assistant, 'models_ready') or not ai_assistant.models_ready:
return ChatResponse(
response="AI models are still initializing. Please wait a moment and try again.",
analysis={"subject": request.subject, "status": "initializing", "initialization_status": initialization_status},
processing_time=0,
success=False,
error="AI models not ready"
)
# Process the query using your AI models
print(f"Processing query: {request.message[:100]}...")
start_time = time.time()
result = ai_assistant.process_educational_query(request.message)
processing_time = time.time() - start_time
print(f"Query processed in {processing_time:.2f} seconds")
# Handle image URL if visual was generated
image_url = None
if result.get('visual_image'):
# Get the most recent image from the directory
images_dir = os.path.join(tempfile.gettempdir(), "generated_images")
if os.path.exists(images_dir):
image_files = [f for f in os.listdir(images_dir) if f.endswith('.png')]
if image_files:
# Get the most recent image
image_files.sort(key=lambda x: os.path.getctime(os.path.join(images_dir, x)), reverse=True)
image_url = f"/images/{image_files[0]}"
return ChatResponse(
response=result['text_response'],
analysis=result['analysis'],
image_url=image_url,
processing_time=processing_time,
success=result['success']
)
except Exception as e:
print(f"❌ Error in chat endpoint: {e}")
return ChatResponse(
response=f"I encountered an error processing your request: {str(e)}",
analysis={"subject": request.subject, "error": str(e)},
processing_time=0,
success=False,
error=str(e)
)
# Voice processing endpoint
@app.post("/voice", response_model=ChatResponse)
async def process_voice(
audio: UploadFile = File(...),
subject: str = "General"
):
try:
if ai_assistant is None or not ai_assistant.models_ready:
return ChatResponse(
response="AI models are not ready for voice processing.",
analysis={"subject": subject, "status": "not_ready"},
processing_time=0,
success=False,
error="AI models not ready"
)
# For now, return a placeholder response
# In a full implementation, you would:
# 1. Save the audio file
# 2. Use speech-to-text to convert audio to text
# 3. Process the text with your AI models
return ChatResponse(
response="Voice processing is not fully implemented yet. Please use text input.",
analysis={"subject": subject, "message_type": "voice"},
processing_time=0,
success=False,
error="Voice processing not implemented"
)
except Exception as e:
return ChatResponse(
response="Error processing voice input.",
analysis={"subject": subject, "error": str(e)},
processing_time=0,
success=False,
error=str(e)
)
# Subject-specific endpoints
@app.get("/subjects")
async def get_subjects():
return {
"subjects": [
"Mathematics",
"Physics",
"Biology",
"Chemistry",
"History",
"Geography",
"Literature",
"Computer Science",
"Economics",
"General"
]
}
# Get conversation analytics
@app.get("/analytics")
async def get_analytics():
try:
if ai_assistant is None:
return {"error": "AI assistant not initialized"}
history = getattr(ai_assistant, 'conversation_history', [])
# Calculate some basic analytics
total_queries = len(history)
subjects = {}
query_types = {}
for conversation in history:
subject = conversation.get('analysis', {}).get('subject', 'unknown')
query_type = conversation.get('analysis', {}).get('query_type', 'unknown')
subjects[subject] = subjects.get(subject, 0) + 1
query_types[query_type] = query_types.get(query_type, 0) + 1
return {
"total_queries": total_queries,
"subjects": subjects,
"query_types": query_types,
"average_processing_time": sum(c.get('processing_time', 0) for c in history) / max(total_queries, 1)
}
except Exception as e:
return {"error": str(e)}
# Clear conversation history
@app.post("/clear-history")
async def clear_history():
try:
if ai_assistant is not None:
if hasattr(ai_assistant, 'conversation_history'):
ai_assistant.conversation_history = []
return {"message": "Conversation history cleared successfully"}
return {"error": "AI assistant not initialized"}
except Exception as e:
return {"error": str(e)}
# Get available images
@app.get("/images/list")
async def list_images():
try:
images_dir = os.path.join(tempfile.gettempdir(), "generated_images")
if not os.path.exists(images_dir):
return {"images": []}
image_files = [f for f in os.listdir(images_dir) if f.endswith(('.png', '.jpg', '.jpeg'))]
image_files.sort(key=lambda x: os.path.getctime(os.path.join(images_dir, x)), reverse=True)
return {
"images": [{"filename": f, "url": f"/images/{f}"} for f in image_files]
}
except Exception as e:
return {"error": str(e)}
# Root endpoint with detailed status
@app.get("/")
async def root():
global ai_assistant, initialization_status, initialization_start_time, initialization_error
# Calculate initialization time
init_time = None
if initialization_start_time:
init_time = time.time() - initialization_start_time
models_ready = (
ai_assistant is not None and
hasattr(ai_assistant, 'models_ready') and
ai_assistant.models_ready and
initialization_status == "ready"
)
return {
"message": "Advanced Classroom AI API",
"status": "running",
"ai_ready": models_ready,
"initialization_status": initialization_status,
"initialization_time": init_time,
"error_message": initialization_error,
"models_loaded": ai_assistant is not None,
"endpoints": {
"chat": "/chat",
"voice": "/voice",
"health": "/health",
"subjects": "/subjects",
"analytics": "/analytics",
"images": "/images/list"
}
}
if __name__ == "__main__":
print("πŸš€ Starting Advanced Classroom AI API...")
port = int(os.environ.get("PORT", 8000)) # Use dynamic port from Render if available
uvicorn.run(
"app:app",
host="0.0.0.0",
port=port
)