182 lines
7.8 KiB
Python
182 lines
7.8 KiB
Python
"""
|
|
Demo school initialization module for ClassroomCopilot
|
|
Creates the KevlarAI demo school
|
|
"""
|
|
import os
|
|
import json
|
|
import requests
|
|
from typing import Dict, Any
|
|
from modules.logger_tool import initialise_logger
|
|
from modules.database.services.provisioning_service import ProvisioningService
|
|
import time
|
|
|
|
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
|
|
|
|
class DemoSchoolInitializer:
|
|
"""Handles demo school creation"""
|
|
|
|
def __init__(self, supabase_url: str, service_role_key: str):
|
|
self.supabase_url = supabase_url
|
|
self.service_role_key = service_role_key
|
|
self.supabase_headers = {
|
|
"apikey": service_role_key,
|
|
"Authorization": f"Bearer {service_role_key}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
self.provisioning_service = ProvisioningService()
|
|
|
|
def create_kevlarai_school(self) -> Dict[str, Any]:
|
|
"""Create the KevlarAI demo school"""
|
|
logger.info("Creating KevlarAI demo school...")
|
|
|
|
try:
|
|
# Check if KevlarAI school already exists
|
|
response = self._supabase_request_with_retry(
|
|
'get',
|
|
f"{self.supabase_url}/rest/v1/institutes",
|
|
headers=self.supabase_headers,
|
|
params={
|
|
"select": "*",
|
|
"name": "eq.KevlarAI"
|
|
}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
existing_schools = response.json()
|
|
if existing_schools and len(existing_schools) > 0:
|
|
logger.info("KevlarAI school already exists")
|
|
school = existing_schools[0]
|
|
try:
|
|
self.provisioning_service.ensure_school(school["id"])
|
|
except Exception as provisioning_error:
|
|
logger.warning(f"Provisioning KevlarAI school failed: {provisioning_error}")
|
|
return {
|
|
"success": True,
|
|
"message": "KevlarAI school already exists",
|
|
"school": school
|
|
}
|
|
|
|
# Create KevlarAI school
|
|
school_data = {
|
|
"name": "KevlarAI",
|
|
"urn": "KEVLARAI001",
|
|
"status": "active",
|
|
"address": {
|
|
"street": "123 Innovation Drive",
|
|
"town": "Tech City",
|
|
"county": "Digital County",
|
|
"postcode": "TC1 2AI",
|
|
"country": "United Kingdom"
|
|
},
|
|
"website": "https://kevlar.ai",
|
|
"metadata": {
|
|
"school_type": "AI and Technology",
|
|
"phase_of_education": "Secondary and Further Education",
|
|
"establishment_status": "Open",
|
|
"specialization": "Artificial Intelligence, Machine Learning, Robotics"
|
|
}
|
|
}
|
|
|
|
# Insert the school
|
|
response = self._supabase_request_with_retry('post', f"{self.supabase_url}/rest/v1/institutes", headers={**self.supabase_headers, "Prefer": "return=representation"}, json=school_data, params={"select": "*"})
|
|
|
|
logger.info(f"Supabase response status: {response.status_code}")
|
|
logger.info(f"Supabase response headers: {dict(response.headers)}")
|
|
logger.info(f"Supabase response text: {response.text}")
|
|
|
|
if response.status_code in (200, 201):
|
|
try:
|
|
data = response.json()
|
|
school = data[0] if isinstance(data, list) and data else data
|
|
logger.info("Successfully created KevlarAI school")
|
|
# Ensure Neo4j provisioning is in place
|
|
try:
|
|
self.provisioning_service.ensure_school(school["id"])
|
|
except Exception as provisioning_error:
|
|
logger.warning(f"Provisioning KevlarAI school failed: {provisioning_error}")
|
|
return {
|
|
"success": True,
|
|
"message": "Successfully created KevlarAI school",
|
|
"school": school
|
|
}
|
|
except json.JSONDecodeError as e:
|
|
logger.error(f"Failed to parse JSON response: {str(e)}")
|
|
logger.error(f"Response text: {response.text}")
|
|
# If the status code is successful but we can't parse JSON,
|
|
# the school was likely created successfully
|
|
return {
|
|
"success": True,
|
|
"message": "Successfully created KevlarAI school (response not JSON)",
|
|
"school": None
|
|
}
|
|
else:
|
|
logger.error(f"Failed to create KevlarAI school: {response.text}")
|
|
return {
|
|
"success": False,
|
|
"message": f"Failed to create KevlarAI school: {response.text}"
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error creating KevlarAI school: {str(e)}")
|
|
return {
|
|
"success": False,
|
|
"message": f"Error creating KevlarAI school: {str(e)}"
|
|
}
|
|
|
|
def _supabase_request_with_retry(self, method, url, **kwargs):
|
|
"""Make a request to Supabase with retry logic"""
|
|
max_retries = 3
|
|
retry_delay = 2 # seconds
|
|
|
|
for attempt in range(max_retries):
|
|
try:
|
|
if method.lower() == 'get':
|
|
response = requests.get(url, **kwargs)
|
|
elif method.lower() == 'post':
|
|
response = requests.post(url, **kwargs)
|
|
elif method.lower() == 'put':
|
|
response = requests.put(url, **kwargs)
|
|
elif method.lower() == 'delete':
|
|
response = requests.delete(url, **kwargs)
|
|
else:
|
|
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
|
|
# If successful or client error (4xx), don't retry
|
|
if response.status_code < 500:
|
|
return response
|
|
|
|
# Server error (5xx), retry after delay
|
|
logger.warning(f"Supabase server error (attempt {attempt+1}/{max_retries}): {response.status_code} - {response.text}")
|
|
time.sleep(retry_delay * (attempt + 1)) # Exponential backoff
|
|
|
|
except requests.RequestException as e:
|
|
logger.warning(f"Supabase request exception (attempt {attempt+1}/{max_retries}): {str(e)}")
|
|
if attempt == max_retries - 1:
|
|
raise
|
|
time.sleep(retry_delay * (attempt + 1))
|
|
|
|
# If we get here, all retries failed with server errors
|
|
raise requests.RequestException(f"Failed after {max_retries} attempts to {method} {url}")
|
|
|
|
def initialize_demo_school() -> Dict[str, Any]:
|
|
"""Initialize demo school (KevlarAI)"""
|
|
logger.info("Starting demo school initialization...")
|
|
|
|
supabase_url = os.getenv("SUPABASE_URL")
|
|
service_role_key = os.getenv("SERVICE_ROLE_KEY")
|
|
|
|
if not supabase_url or not service_role_key:
|
|
return {"success": False, "message": "Missing SUPABASE_URL or SERVICE_ROLE_KEY environment variables"}
|
|
|
|
initializer = DemoSchoolInitializer(supabase_url, service_role_key)
|
|
|
|
# Create KevlarAI school
|
|
result = initializer.create_kevlarai_school()
|
|
|
|
if result["success"]:
|
|
logger.info("Demo school initialization completed successfully")
|
|
else:
|
|
logger.error(f"Demo school initialization failed: {result['message']}")
|
|
|
|
return result
|