File size: 5,297 Bytes
25a0387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Header, Depends, BackgroundTasks
from sqlalchemy.orm import Session
from ...services import document_parser, scoring_engine, notification_service
from ...services import vector_store as vs
from ...schemas.models import AnalysisResponse, AnalysisResultCreate
from ...database import crud
from ...database.database import get_db
import uuid
import logging
import asyncio

router = APIRouter()

# def perform_analysis_and_save(
#     db: Session,
#     jd_text: str,
#     resume_bytes: bytes,
#     resume_filename: str,
#     api_key: str,
#     llm_model: str,
#     jd_id: int
# ):
#     try:
#         resume_text = document_parser.parse_document(resume_filename, resume_bytes)
#         if not resume_text.strip():
#             logging.error(f"Could not extract text from resume: {resume_filename}")
#             return

#         hard_score = scoring_engine.hard_match_score(resume_text, jd_text)
#         llm_results = scoring_engine.llm_analysis(resume_text, jd_text, api_key, llm_model)
#         final_score, verdict = scoring_engine.calculate_final_score_and_verdict(
#             hard_score, llm_results["semantic_score"]
#         )

#         analysis_data = AnalysisResultCreate(
#             relevance_score=final_score,
#             verdict=verdict,
#             missing_elements=llm_results["missing_elements"],
#             improvement_suggestions=llm_results["improvement_suggestions"],
#             filename=resume_filename
#         )

#         crud.create_analysis_result(db=db, result=analysis_data, jd_id=jd_id)

#         doc_id = str(uuid.uuid4())
#         metadata = {"filename": resume_filename, "score": final_score, "verdict": verdict, "jd_id": jd_id}
#         vs.vector_store.add_document(doc_id, resume_text, metadata)

#         # Send feedback webhook
#         student_email = scoring_engine.extract_email_from_text(resume_text)
#         if student_email:
#             # notification_service.send_feedback_webhook(student_email, analysis_data.dict())
#             asyncio.run(notification_service.send_feedback_webhook(student_email, analysis_data.model_dump()))

#     except Exception as e:
#         logging.error(f"Background analysis failed for {resume_filename}: {e}", exc_info=True)

# backend/app/api/endpoints/analysis.py

# ... (imports)

def perform_analysis_and_save(
    db: Session,
    jd_text: str,
    resume_bytes: bytes,
    resume_filename: str,
    api_key: str,
    llm_model: str,
    jd_id: int
):
    try:
        resume_text = document_parser.parse_document(resume_filename, resume_bytes)
        if not resume_text.strip():
            logging.error(f"Could not extract text from resume: {resume_filename}")
            return

        # --- NEW: Extract and store the student's email ---
        student_email = scoring_engine.extract_email_from_text(resume_text)

        hard_score = scoring_engine.hard_match_score(resume_text, jd_text)
        llm_results = scoring_engine.llm_analysis(resume_text, jd_text, api_key, llm_model)
        final_score, verdict = scoring_engine.calculate_final_score_and_verdict(
            hard_score, llm_results["semantic_score"]
        )

        analysis_data = AnalysisResultCreate(
            relevance_score=final_score,
            verdict=verdict,
            missing_elements=llm_results["missing_elements"],
            improvement_suggestions=llm_results["improvement_suggestions"],
            filename=resume_filename,
            # --- NEW: Add the email to the data to be saved ---
            student_email=student_email
        )

        crud.create_analysis_result(db=db, result=analysis_data, jd_id=jd_id)

        doc_id = str(uuid.uuid4())
        metadata = {"filename": resume_filename, "score": final_score, "verdict": verdict, "jd_id": jd_id}
        vs.vector_store.add_document(doc_id, resume_text, metadata)

        # --- THIS IS THE LINE TO REMOVE ---
        # if student_email:
        #     asyncio.run(notification_service.send_feedback_webhook(student_email, analysis_data.model_dump()))
        # ------------------------------------

    except Exception as e:
        logging.error(f"Background analysis failed for {resume_filename}: {e}", exc_info=True)



@router.post("/analyze/")
async def analyze_resume(
    background_tasks: BackgroundTasks,
    jd_id: int = Form(...),
    resume: UploadFile = File(...),
    api_key: str = Header(..., alias="X-API-Key"),
    llm_model: str = Header(..., alias="X-LLM-Model"),
    db: Session = Depends(get_db)
):
    if not api_key:
        raise HTTPException(status_code=400, detail="Gemini API Key is required.")

    jd_model = crud.get_job_description(db=db, jd_id=jd_id)
    if not jd_model:
        raise HTTPException(status_code=404, detail="Job Description not found.")

    if not resume.filename or not resume.filename.lower().endswith(('.pdf', '.docx')):
        raise HTTPException(status_code=400, detail="Invalid file type.")

    resume_bytes = await resume.read()

    background_tasks.add_task(
        perform_analysis_and_save,
        db, jd_model.description, resume_bytes, resume.filename, api_key, llm_model, jd_id
    )

    return {"message": "Analysis started in the background for " + resume.filename}