File size: 4,170 Bytes
efd6a61
 
 
 
 
75c5f1f
efd6a61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75c5f1f
efd6a61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75c5f1f
efd6a61
 
 
 
 
 
75c5f1f
 
efd6a61
 
75c5f1f
 
efd6a61
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
from fastapi import FastAPI, File, UploadFile, Form, HTTPException, Request, Depends
from fastapi.responses import JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, HttpUrl
from typing import Optional
import uvicorn
from fastapi.middleware.cors import CORSMiddleware
from utils import read_file, fetch_job_description, optimize_resume_api
import logging
from fastapi_cache import FastAPICache
from fastapi_cache.backends.inmemory import InMemoryBackend
from fastapi_cache.decorator import cache
import hashlib

# Set up logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

app = FastAPI(title="Resume Optimizer API")

app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])

security = HTTPBearer()

class OptimizationResponse(BaseModel):
    optimizedResume: str
    metadata: dict

class ErrorResponse(BaseModel):
    detail: str

def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
    token = credentials.credentials
    if token != "your_secret_token":
        raise HTTPException(status_code=401, detail="Invalid authentication token")
    return token

def generate_cache_key(resume_content: str, job_description_content: str) -> str:
    combined = resume_content + job_description_content
    return hashlib.md5(combined.encode()).hexdigest()

@app.post("/api/optimize-resume", response_model=OptimizationResponse, responses={400: {"model": ErrorResponse}, 401: {"model": ErrorResponse}, 500: {"model": ErrorResponse}})
@cache(expire=36000000)  # Cache for n seconds
async def optimize_resume(
    resume: Optional[UploadFile] = File(None),
    resumeText: Optional[str] = Form(None),
    jobDescription: Optional[str] = Form(None),
    jobDescriptionUrl: Optional[HttpUrl] = Form(None),
    token: str = Depends(verify_token)
):
    try:
        # Input validation
        if (resume is None) == (resumeText is None):
            raise ValueError("Provide either resume file or resume text, but not both")
        if (jobDescription is None) == (jobDescriptionUrl is None):
            raise ValueError("Provide either job description text or URL, but not both")
        
        # Process resume
        if resume:
            resume_content = read_file(resume)
        else:
            resume_content = resumeText
        
        # Process job description
        if jobDescription:
            job_description_content = jobDescription
        else:
            job_description_content = fetch_job_description(jobDescriptionUrl)

        # Generate cache key
        cache_key = generate_cache_key(resume_content, job_description_content)

        # Check cache
        cached_result = await FastAPICache.get(cache_key)
        if cached_result:
            return OptimizationResponse(**cached_result)

        # Perform optimization
        optimized_resume = optimize_resume_api(resume_content, job_description_content)

        metadata = {
            "original_resume": resume_content,
            "original_jd": job_description_content
        }

        result = OptimizationResponse(
            optimizedResume=optimized_resume,
            metadata=metadata
        )

        # Cache the result
        await FastAPICache.set(cache_key, result.dict(), expire=36000000)

        return result
    except ValueError as ve:
        logger.error(f"ValueError occurred: {str(ve)}", exc_info=True)
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"Unexpected error occurred: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
    
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})

@app.on_event("startup")
async def startup():
    FastAPICache.init(InMemoryBackend(), prefix="fastapi-cache")

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000, debug=True)