File size: 19,204 Bytes
8c9ad61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5347681
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
import streamlit as st
import base64
import os
from io import BytesIO
from datetime import datetime
import json
from docx import Document
from docx.shared import Inches, Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY
from reportlab.lib import colors
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage
from PIL import Image as PILImage

AI71_BASE_URL = "https://api.ai71.ai/v1/"
AI71_API_KEY = os.getenv('AI71_API_KEY')

def get_llm():
    return ChatOpenAI(
        model="tiiuae/falcon-180B-chat",
        api_key=AI71_API_KEY,
        base_url=AI71_BASE_URL,
        streaming=True,
    )

def generate_resume_content(resume_data):
    llm = get_llm()
    
    prompt = f"""
    Generate a highly professional and ATS-optimized resume based on the following information:
    
    Name: {resume_data['name']}
    Email: {resume_data['email']}
    Phone: {resume_data['phone']}
    Location: {resume_data['location']}
    
    Work Experience:
    {json.dumps(resume_data['work_experience'], indent=2)}
    
    Education:
    {json.dumps(resume_data['education'], indent=2)}
    
    Skills: {', '.join(resume_data['skills'])}
    
    Please generate a compelling professional summary and enhance the job descriptions. 
    Use action verbs, quantify achievements where possible, and highlight key skills.
    Ensure the content is tailored for ATS optimization.
    The output should be in JSON format with the following structure:
    {{
        "summary": "Professional summary here",
        "work_experience": [
            {{
                "title": "Job title",
                "company": "Company name",
                "start_date": "Start date",
                "end_date": "End date",
                "description": "Enhanced job description with bullet points"
            }}
        ]
    }}
    """
    
    try:
        response = llm([HumanMessage(content=prompt)])
        enhanced_content = json.loads(response.content)
        
        resume_data['summary'] = enhanced_content['summary']
        resume_data['work_experience'] = enhanced_content['work_experience']
        
        return resume_data
    except Exception as e:
        st.error(f"An error occurred while generating AI content: {str(e)}")
        return resume_data

def create_docx(resume_data):
    doc = Document()
    
    # Styles
    styles = doc.styles
    style = styles.add_style('Name', 1)
    style.font.name = 'Calibri'
    style.font.size = Pt(24)
    style.font.bold = True
    style.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
    
    # Add photo if provided
    if 'photo' in resume_data and resume_data['photo']:
        image_stream = BytesIO(resume_data['photo'])
        doc.add_picture(image_stream, width=Inches(2.0))
    
    # Add name
    doc.add_paragraph(resume_data['name'], style='Name')
    
    # Add contact information
    contact_info = doc.add_paragraph()
    contact_info.alignment = WD_ALIGN_PARAGRAPH.CENTER
    contact_info.add_run(f"{resume_data['email']} | {resume_data['phone']} | {resume_data['location']}")
    
    # Add summary
    doc.add_heading('Professional Summary', level=1)
    doc.add_paragraph(resume_data['summary'])
    
    # Add work experience
    doc.add_heading('Work Experience', level=1)
    for job in resume_data['work_experience']:
        p = doc.add_paragraph(f"{job['title']} at {job['company']}", style='Heading 2')
        p.add_run(f"\n{job['start_date']} - {job['end_date']}")
        for bullet in job['description'].split('\n'):
            if bullet.strip():
                doc.add_paragraph(bullet.strip(), style='List Bullet')
    
    # Add education
    doc.add_heading('Education', level=1)
    for edu in resume_data['education']:
        p = doc.add_paragraph(f"{edu['degree']} in {edu['field']}", style='Heading 2')
        p.add_run(f"\n{edu['institution']}, {edu['graduation_date']}")
    
    # Add skills
    doc.add_heading('Skills', level=1)
    doc.add_paragraph(', '.join(resume_data['skills']))
    
    buffer = BytesIO()
    doc.save(buffer)
    buffer.seek(0)
    return buffer

def create_pdf(resume_data):
    buffer = BytesIO()
    doc = SimpleDocTemplate(buffer, pagesize=letter, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18)
    
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))
    styles.add(ParagraphStyle(name='Center', alignment=TA_CENTER))
    
    story = []
    
    # Add photo if provided
    if 'photo' in resume_data and resume_data['photo']:
        image_stream = BytesIO(resume_data['photo'])
        img = Image(image_stream, width=100, height=100)
        story.append(img)
    
    # Add name
    story.append(Paragraph(resume_data['name'], styles['Title']))
    
    # Add contact information
    story.append(Paragraph(f"{resume_data['email']} | {resume_data['phone']} | {resume_data['location']}", styles['Center']))
    story.append(Spacer(1, 12))
    
    # Add summary
    story.append(Paragraph('Professional Summary', styles['Heading1']))
    story.append(Paragraph(resume_data['summary'], styles['Justify']))
    story.append(Spacer(1, 12))
    
    # Add work experience
    story.append(Paragraph('Work Experience', styles['Heading1']))
    for job in resume_data['work_experience']:
        story.append(Paragraph(f"{job['title']} at {job['company']}", styles['Heading2']))
        story.append(Paragraph(f"{job['start_date']} - {job['end_date']}", styles['Normal']))
        for bullet in job['description'].split('\n'):
            if bullet.strip():
                story.append(Paragraph(f"β€’ {bullet.strip()}", styles['Normal']))
        story.append(Spacer(1, 12))
    
    # Add education
    story.append(Paragraph('Education', styles['Heading1']))
    for edu in resume_data['education']:
        story.append(Paragraph(f"{edu['degree']} in {edu['field']}", styles['Heading2']))
        story.append(Paragraph(f"{edu['institution']}, {edu['graduation_date']}", styles['Normal']))
        story.append(Spacer(1, 12))
    
    # Add skills
    story.append(Paragraph('Skills', styles['Heading1']))
    story.append(Paragraph(', '.join(resume_data['skills']), styles['Normal']))
    
    doc.build(story)
    buffer.seek(0)
    return buffer

def create_txt(resume_data):
    txt_content = f"{resume_data['name']}\n"
    txt_content += f"{resume_data['email']} | {resume_data['phone']} | {resume_data['location']}\n\n"
    
    txt_content += "Professional Summary\n"
    txt_content += f"{resume_data['summary']}\n\n"
    
    txt_content += "Work Experience\n"
    for job in resume_data['work_experience']:
        txt_content += f"{job['title']} at {job['company']}\n"
        txt_content += f"{job['start_date']} - {job['end_date']}\n"
        for bullet in job['description'].split('\n'):
            if bullet.strip():
                txt_content += f"β€’ {bullet.strip()}\n"
        txt_content += "\n"
    
    txt_content += "Education\n"
    for edu in resume_data['education']:
        txt_content += f"{edu['degree']} in {edu['field']}\n"
        txt_content += f"{edu['institution']}, {edu['graduation_date']}\n\n"
    
    txt_content += "Skills\n"
    txt_content += ', '.join(resume_data['skills'])
    
    return txt_content.encode()

def calculate_ats_score(resume_data):
    score = 0
    max_score = 100
    
    # Check for key sections
    if resume_data['name']: score += 5
    if resume_data['email']: score += 5
    if resume_data['phone']: score += 5
    if resume_data['location']: score += 5
    if resume_data['summary']: score += 10
    if resume_data['work_experience']: score += 20
    if resume_data['education']: score += 15
    if resume_data['skills']: score += 15
    
    # Check content quality
    if len(resume_data['summary'].split()) >= 50: score += 5
    if len(resume_data['work_experience']) >= 2: score += 5
    if len(resume_data['skills']) >= 5: score += 5
    
    # Check for keywords (this is a simplified version, in reality, you'd want to check against job-specific keywords)
    keywords = ['experience', 'skills', 'project', 'team', 'leadership', 'communication', 'achieved', 'improved', 'managed', 'developed']
    resume_text = ' '.join([str(value) for value in resume_data.values() if isinstance(value, str)])
    for keyword in keywords:
        if keyword in resume_text.lower():
            score += 1
    
    return min(score, max_score)

def main():
    st.set_page_config(page_title="AI-Enhanced Resume Builder", page_icon="πŸ“„", layout="wide")
    
    st.markdown("""
    <style>
    .big-font {
        font-size:30px !important;
        font-weight: bold;
    }
    .stButton>button {
        width: 100%;
    }
    </style>
    """, unsafe_allow_html=True)
    
    # Add sidebar
    st.sidebar.title("About This Project")
    st.sidebar.write("""
    Welcome to the AI-Enhanced Resume Builder!

    This project helps you create a professional, ATS-optimized resume with the power of AI. Here's what you can do:

    1. Input your personal information
    2. Add your work experience
    3. Include your education details
    4. List your skills
    5. Optionally upload a photo
    6. Generate AI-enhanced content
    7. Review and download your resume

    The AI will help improve your resume content and provide an ATS compatibility score.

    Get started by filling out the form and clicking 'Next' at each step!
    """)
    
    st.markdown('<p class="big-font">AI-Enhanced Resume Builder</p>', unsafe_allow_html=True)
    st.write("Create a professional, ATS-optimized resume with AI-powered content enhancement")
    
    # Initialize session state
    if 'step' not in st.session_state:
        st.session_state.step = 1
    
    if 'resume_data' not in st.session_state:
        st.session_state.resume_data = {
            'name': '', 'email': '', 'phone': '', 'location': '',
            'summary': '', 'work_experience': [], 'education': [], 'skills': [], 'photo': None
        }
    
    # Step 1: Personal Information
    if st.session_state.step == 1:
        st.subheader("Step 1: Personal Information")
        name = st.text_input("Full Name", st.session_state.resume_data['name'])
        email = st.text_input("Email", st.session_state.resume_data['email'])
        phone = st.text_input("Phone", st.session_state.resume_data['phone'])
        location = st.text_input("Location", st.session_state.resume_data['location'])
        
        photo_upload = st.file_uploader("Upload a photo (optional)", type=['jpg', 'jpeg', 'png'])
        if photo_upload:
            image = PILImage.open(photo_upload)
            st.image(image, caption='Uploaded Image', use_column_width=True)
            buffered = BytesIO()
            image.save(buffered, format="PNG")
            st.session_state.resume_data['photo'] = buffered.getvalue()
        
        if st.button("Next"):
            if name and email and phone and location:
                st.session_state.resume_data.update({
                    'name': name,
                    'email': email,
                    'phone': phone,
                    'location': location
                })
                st.session_state.step = 2
            else:
                st.error("Please fill in all required fields before proceeding.")
    
    # Step 2: Work Experience
    elif st.session_state.step == 2:
        st.subheader("Step 2: Work Experience")
        num_jobs = st.number_input("Number of jobs to add", min_value=1, max_value=10, value=len(st.session_state.resume_data['work_experience']) or 1)
        
        work_experience = []
        for i in range(num_jobs):
            st.write(f"Job {i+1}")
            job = {}
            job['title'] = st.text_input(f"Job Title {i+1}", st.session_state.resume_data['work_experience'][i]['title'] if i < len(st.session_state.resume_data['work_experience']) else '')
            job['company'] = st.text_input(f"Company {i+1}", st.session_state.resume_data['work_experience'][i]['company'] if i < len(st.session_state.resume_data['work_experience']) else '')
            job['start_date'] = st.date_input(f"Start Date {i+1}", value=datetime.strptime(st.session_state.resume_data['work_experience'][i]['start_date'] if i < len(st.session_state.resume_data['work_experience']) else '2020-01-01', '%Y-%m-%d')).strftime('%Y-%m-%d')
            job['end_date'] = st.date_input(f"End Date {i+1}", value=datetime.strptime(st.session_state.resume_data['work_experience'][i]['end_date'] if i < len(st.session_state.resume_data['work_experience']) else '2023-01-01', '%Y-%m-%d')).strftime('%Y-%m-%d')
            job['description'] = st.text_area(f"Job Description {i+1}", st.session_state.resume_data['work_experience'][i]['description'] if i < len(st.session_state.resume_data['work_experience']) else '', height=100)
            work_experience.append(job)
        
        col1, col2 = st.columns(2)
        if col1.button("Previous"):
            st.session_state.step = 1
        if col2.button("Next"):
            if all(job['title'] and job['company'] and job['description'] for job in work_experience):
                st.session_state.resume_data['work_experience'] = work_experience
                st.session_state.step = 3
            else:
                st.error("Please fill in all required fields for each job before proceeding.")
    
    # Step 3: Education
    elif st.session_state.step == 3:
        st.subheader("Step 3: Education")
        num_edu = st.number_input("Number of education entries", min_value=1, max_value=5, value=len(st.session_state.resume_data['education']) or 1)
        
        education = []
        for i in range(num_edu):
            st.write(f"Education {i+1}")
            edu = {}
            edu['degree'] = st.text_input(f"Degree {i+1}", st.session_state.resume_data['education'][i]['degree'] if i < len(st.session_state.resume_data['education']) else '')
            edu['field'] = st.text_input(f"Field of Study {i+1}", st.session_state.resume_data['education'][i]['field'] if i < len(st.session_state.resume_data['education']) else '')
            edu['institution'] = st.text_input(f"Institution {i+1}", st.session_state.resume_data['education'][i]['institution'] if i < len(st.session_state.resume_data['education']) else '')
            edu['graduation_date'] = st.date_input(f"Graduation Date {i+1}", value=datetime.strptime(st.session_state.resume_data['education'][i]['graduation_date'] if i < len(st.session_state.resume_data['education']) else '2023-01-01', '%Y-%m-%d')).strftime('%Y-%m-%d')
            education.append(edu)
        
        col1, col2 = st.columns(2)
        if col1.button("Previous"):
            st.session_state.step = 2
        if col2.button("Next"):
            if all(edu['degree'] and edu['field'] and edu['institution'] for edu in education):
                st.session_state.resume_data['education'] = education
                st.session_state.step = 4
            else:
                st.error("Please fill in all required fields for each education entry before proceeding.")
    
    # Step 4: Skills and Generation
    elif st.session_state.step == 4:
        st.subheader("Step 4: Skills and Resume Generation")
        skills_input = st.text_input("Skills (comma-separated)", ', '.join(st.session_state.resume_data['skills']))
        
        if st.button("Generate Resume"):
            if skills_input.strip():
                st.session_state.resume_data['skills'] = [skill.strip() for skill in skills_input.split(',') if skill.strip()]
                with st.spinner("Generating AI-enhanced resume content..."):
                    st.session_state.resume_data = generate_resume_content(st.session_state.resume_data)
                st.session_state.step = 5
                st.experimental_rerun()
            else:
                st.error("Please enter at least one skill before generating the resume.")
    
    # Step 5: Review and Download
    elif st.session_state.step == 5:
        st.subheader("Generated Resume")
        
        # Display resume content for review
        st.write("### Personal Information")
        st.write(f"**Name:** {st.session_state.resume_data['name']}")
        st.write(f"**Email:** {st.session_state.resume_data['email']}")
        st.write(f"**Phone:** {st.session_state.resume_data['phone']}")
        st.write(f"**Location:** {st.session_state.resume_data['location']}")
        
        if st.session_state.resume_data['photo']:
            st.image(st.session_state.resume_data['photo'], caption='Your Photo', width=200)
        
        st.write("### Professional Summary")
        st.write(st.session_state.resume_data['summary'])
        
        st.write("### Work Experience")
        for job in st.session_state.resume_data['work_experience']:
            st.write(f"**{job['title']} at {job['company']}**")
            st.write(f"{job['start_date']} - {job['end_date']}")
            st.write(job['description'])
        
        st.write("### Education")
        for edu in st.session_state.resume_data['education']:
            st.write(f"**{edu['degree']} in {edu['field']}**")
            st.write(f"{edu['institution']}, {edu['graduation_date']}")
        
        st.write("### Skills")
        st.write(', '.join(st.session_state.resume_data['skills']))
        
        # Calculate and display ATS score
        ats_score = calculate_ats_score(st.session_state.resume_data)
        st.write(f"### ATS Compatibility Score: {ats_score}%")
        
        # Download options
        st.write("### Download Options")
        col1, col2, col3 = st.columns(3)
        
        docx_buffer = create_docx(st.session_state.resume_data)
        col1.download_button(
            label="Download as DOCX",
            data=docx_buffer,
            file_name="resume.docx",
            mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        )
        
        pdf_buffer = create_pdf(st.session_state.resume_data)
        col2.download_button(
            label="Download as PDF",
            data=pdf_buffer,
            file_name="resume.pdf",
            mime="application/pdf"
        )
        
        txt_content = create_txt(st.session_state.resume_data)
        col3.download_button(
            label="Download as TXT",
            data=txt_content,
            file_name="resume.txt",
            mime="text/plain"
        )
        
        if st.button("Edit Resume"):
            st.session_state.step = 1
        
        if st.button("Start Over"):
            st.session_state.step = 1
            st.session_state.resume_data = {
                'name': '', 'email': '', 'phone': '', 'location': '',
                'summary': '', 'work_experience': [], 'education': [], 'skills': [], 'photo': None
            }
            st.experimental_rerun()

if __name__ == "__main__":
    main()