Sparkonix's picture
refactored the code
edc8356
Raw History Blame Contribute Delete
4.77 kB
import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Dict, Any, List, Tuple
import uvicorn
from dotenv import load_dotenv
from utils import PIIMasker
from models import EmailClassifier
# Load environment variables from .env file if available
try:
load_dotenv()
except ImportError:
pass # dotenv might not be installed in production
# Set database path for Hugging Face, using persistent storage
if os.path.exists('/data'):
db_path = "/data/emails.db"
else:
db_path = "emails.db" # Fallback to local directory
# Initialize the FastAPI application
app = FastAPI(title="Email Classification API",
description="API for classifying support emails and masking PII",
version="1.0.0")
# Initialize the PII masker and email classifier
pii_masker = PIIMasker(db_path=db_path)
email_classifier = EmailClassifier()
class EmailInput(BaseModel):
"""Input model for the email classification endpoint"""
input_email_body: str
class EntityInfo(BaseModel):
"""Model for entity information"""
position: Tuple[int, int]
classification: str
entity: str
class EmailOutput(BaseModel):
"""Output model for the email classification endpoint"""
input_email_body: str
list_of_masked_entities: List[EntityInfo]
masked_email: str
category_of_the_email: str
class MaskedEmailInput(BaseModel):
"""Input model for retrieving original email by masked email content"""
masked_email: str
access_key: str
@app.post("/classify", response_model=EmailOutput)
async def classify_email(email_input: EmailInput) -> Dict[str, Any]:
"""
Classify an email into a support category while masking PII
Args:
email_input: The input email data
Returns:
The classified email data with masked PII
"""
try:
# Process the email to mask PII and store original in database
processed_data = pii_masker.process_email(email_input.input_email_body)
# Classify the masked email
classified_data = email_classifier.process_email(processed_data)
# Make sure we return only the fields expected in the response model
return {
"input_email_body": email_input.input_email_body,
"list_of_masked_entities": classified_data["list_of_masked_entities"],
"masked_email": classified_data["masked_email"],
"category_of_the_email": classified_data["category_of_the_email"]
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error processing email: {str(e)}")
@app.post("/api/v1/unmask-email", response_model=Dict[str, Any])
async def unmask_email(masked_email_input: MaskedEmailInput) -> Dict[str, Any]:
"""
Retrieve the original unmasked email.
Args:
masked_email_input: Contains the masked email and access key
Returns:
The original email data with PII information
"""
try:
# Verify access key matches the global access key
if masked_email_input.access_key != os.environ.get(
"EMAIL_ACCESS_KEY", "default_secure_access_key"):
raise HTTPException(status_code=401, detail="Invalid access key")
# Retrieve the original email using the masked content
email_data = pii_masker.get_original_by_masked_email(
masked_email_input.masked_email
)
if not email_data:
raise HTTPException(
status_code=404,
detail="Original email not found for the provided masked email"
)
return {
"status": "success",
"data": {
"id": email_data["id"],
"original_email": email_data["original_email"],
"masked_email": email_data["masked_email"],
"masked_entities": email_data["masked_entities"],
"category": email_data.get("category", ""),
"created_at": email_data.get("created_at", "")
},
"message": "Original email retrieved successfully"
}
except Exception as e:
if isinstance(e, HTTPException):
raise e
raise HTTPException(
status_code=500,
detail=f"Error retrieving original email: {str(e)}"
)
@app.get("/health")
async def health_check():
"""
Health check endpoint
Returns:
Status message indicating the API is running
"""
return {"status": "healthy", "message": "Email classification API is running"}
# For local development and testing
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8000))
uvicorn.run("main:app", host="0.0.0.0", port=port, reload=True)