|
|
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 |
|
|
|
|
|
|
|
|
try: |
|
|
load_dotenv() |
|
|
except ImportError: |
|
|
pass |
|
|
|
|
|
|
|
|
if os.path.exists('/data'): |
|
|
db_path = "/data/emails.db" |
|
|
else: |
|
|
db_path = "emails.db" |
|
|
|
|
|
|
|
|
app = FastAPI(title="Email Classification API", |
|
|
description="API for classifying support emails and masking PII", |
|
|
version="1.0.0") |
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
processed_data = pii_masker.process_email(email_input.input_email_body) |
|
|
|
|
|
classified_data = email_classifier.process_email(processed_data) |
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
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"} |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
port = int(os.environ.get("PORT", 8000)) |
|
|
uvicorn.run("main:app", host="0.0.0.0", port=port, reload=True) |
|
|
|