File size: 6,719 Bytes
6817686
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8f98f93
6817686
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import tempfile
import pandas as pd
import streamlit as st
from pathlib import Path
from src.extractor import extract_text, get_pdf_preview
from src.matcher import compute_match
from config import APP_ICON, APP_TITLE
from core.logger import get_logger

logger = get_logger(__name__)

st.set_page_config(page_title = APP_TITLE, page_icon = APP_ICON, layout = "wide" )

#initalising the session state

if "resumes" not in st.session_state:
    st.session_state.resume = {}

if "selected_resume" not in st.session_state:
    st.session_state.selected_resume = None

if "jd_text" not in st.session_state:
    st.session_state.jd_text = ""

if "results" not in st.session_state:
    st.session_state.results = {}

if "previews" not in st.session_state:
    st.session_state.previews = {}

st.title(f"{APP_ICON} {APP_TITLE}")
st.caption("Upload resume · Paste a job description · Get instant match analysis")
st.divider()

col_left, col_right = st.columns(2)

with col_left:
    st.subheader("Resumes")

    upload_files = st.file_uploader("Upload one or more resumes",
                                    type = ["pdf"],
                                    accept_multiple_files = True)
    
    #Process the upload files

    if upload_files:
        for file in upload_files:
            name = file.name

            if name not in st.session_state.resume:
                with st.spinner(f"Extracting {name}..."):
                    try:

                        pdf_bytes = file.read()
                        preview_bytes = get_pdf_preview(pdf_bytes)
                        st.session_state.previews[name] = preview_bytes

                        with tempfile.NamedTemporaryFile(suffix = ".pdf", delete = False, dir="/tmp" ) as temp:
                            temp.write(pdf_bytes)
                            temp_path = Path(temp.name)

                        text = extract_text(temp_path)
                        temp_path.unlink()
                        st.session_state.resume[name] = text
                        logger.info(f"Resume stored: {name}")
                        st.success(f"{name} extracted")

                    except Exception as e:
                        logger.error(f"Failed to extract: {name} : {e}")
                        st.error(f"Failed to rad: {name}")
    
    if st.session_state.resume:
        st.divider()

        resume_names = list(st.session_state.resume.keys())

        selected = st.selectbox("Select resume to preview",
                                options = resume_names,
                                key = "selected_resume")
        
        if selected:
            st.markdown("**Fist page Preview: **")

            if selected in st.session_state.previews:
                st.image(
                    st.session_state.previews[selected],
                    caption = selected,
                    use_container_width = True
                )
            
            st.caption(f"Extracted: {len(st.session_state.resume[selected])} chars")

with col_right:
    st.subheader("Job Discription")

    jd_text = st.text_area(
        "Paste the job discription here",
        height = 400,
        placeholder = "e.g. We are looking for AI Engineer ...",
        key = "jd_text"
    )

    if len(jd_text) < 500:
        st.warning(f"JD seems too short — add more details for better matching")
    elif len(jd_text) > 5000:
        st.warning(f"JD is very long — consider pasting key requirements only")
    else:
        st.caption(f"{len(jd_text.split())} words — good length")

st.divider()

col_empty_left, col_btn, ccol_empty_right = st.columns([3, 4, 3])
with col_btn:
    analyze_clicked = st.button(
        "Analyze Match",
        type = "primary",
        use_container_width = True
    )

    if analyze_clicked:
        if not st.session_state.resume:
            st.warning("Please upload at least one Resume")
        elif not jd_text.strip():
            st.warning("Please paste a job description")
        else:
            selected = st.session_state.selected_resume
            resume_text = st.session_state.resume[selected]

            with st.spinner(f"Analysing {selected}..."):
                try:
                    result = compute_match(resume_text, jd_text)
                    st.session_state.results[selected] = result
                    logger.info(f"Analysis complete: {selected}")

                except Exception as e:
                    logger.error(f"Analysis failed for {selected}: {e}")
                    st.error("Analysis failed - please try again")

if st.session_state.results:
    selected = st.session_state.selected_resume

    if selected in st.session_state.results:
        results = st.session_state.results[selected]

        st.divider()
        st.subheader(f"Results - {selected}")

        col1, col2, col3 = st.columns(3)

        with col1:
            st.metric(
                label = "match Score",
                value = f"{result['match_percentage']}%"
            )

        with col2:
            st.metric(
                label = "Missing Skills",
                value = len(result['missing_skills'])
            )
        
        with col3:
            st.metric(
                label="Matched Skills",
                value=len(result['match_skills'])
            )
        
        verdict = result['verdict']
        if verdict == "Strong Match":
            st.success(f"{verdict}")
        elif verdict == "Good Match":
            st.info(f"{verdict}")
        elif verdict == "Weak Match":
            st.warning(f"{verdict}")
        else:
            st.error(f"{verdict}")
            
        col_match, col_miss = st.columns(2)

        with col_match:
            st.markdown("**Matched Skills**")
            for skill in result['match_skills']:
                st.markdown(f"- {skill}")

        with col_miss:
            st.markdown("**Missing Skills**")
            for skill in  result["missing_skills"]:
                st.markdown(f"- {skill}")


st.divider()
st.subheader("Summary - All Resumes")

if not st.session_state.results:
    st.info("Analyse resume to see summary here")
else:
    row = []

    for resume_name, result in st.session_state.results.items():
        row.append({
            "Resume": resume_name,
            "Match%": result["match_percentage"],
            "Matched Skills": len(result["match_skills"]),
            "Missing Skills": len(result["missing_skills"]),
            "Verdict": result["verdict"]
        })
    
    df = pd.DataFrame(row)
    df = df.sort_values("Match%", ascending = False)

    st.dataframe(
        df,
        use_container_width = True,
        hide_index = True
    )