MBilal-72 commited on
Commit
6e64d6d
·
verified ·
1 Parent(s): d1ae37d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +107 -28
app.py CHANGED
@@ -6,8 +6,9 @@ from sentence_transformers import SentenceTransformer
6
  import faiss
7
  from groq import Groq
8
  from reportlab.lib.pagesizes import A4
9
- from reportlab.lib.styles import getSampleStyleSheet
10
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
 
11
  import io
12
 
13
  # -----------------------------
@@ -15,6 +16,7 @@ import io
15
  # -----------------------------
16
  REMOTEOK_URL = "https://remoteok.com/api"
17
  EMBED_MODEL = "BAAI/bge-small-en-v1.5"
 
18
 
19
  # Load embedding model
20
  @st.cache_resource
@@ -80,10 +82,6 @@ def generate_resume(resume_text, job):
80
  and this job description:\n{job['description']}\n
81
  Generate a structured resume in this format:
82
 
83
- Name & Contact
84
- -----------------
85
- [Fill with placeholder if not in resume]
86
-
87
  Summary
88
  -----------------
89
  [2-3 line summary tailored for the job]
@@ -106,23 +104,87 @@ def generate_resume(resume_text, job):
106
  """
107
 
108
  chat_completion = groq_client.chat.completions.create(
109
- model="openai/gpt-oss-120b",
110
  messages=[{"role": "user", "content": prompt}],
111
  temperature=0.7,
112
  )
113
  return chat_completion.choices[0].message.content
114
 
115
- def build_pdf(resume_text):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  buffer = io.BytesIO()
117
- doc = SimpleDocTemplate(buffer, pagesize=A4)
118
  styles = getSampleStyleSheet()
 
 
 
 
 
 
 
 
119
  story = []
120
 
121
- for line in resume_text.split("\n"):
122
- if line.strip() == "":
123
- story.append(Spacer(1, 12))
124
- else:
125
- story.append(Paragraph(line, styles["Normal"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  doc.build(story)
128
  buffer.seek(0)
@@ -133,11 +195,17 @@ def build_pdf(resume_text):
133
  # -----------------------------
134
  st.title("MATCHHIVE - AI Job Matcher")
135
 
 
136
  resume_file = st.file_uploader("Upload your resume (PDF or DOCX)", type=["pdf", "docx"])
137
  if resume_file:
138
  resume_text = extract_text_from_resume(resume_file)
139
 
140
  if resume_text.strip():
 
 
 
 
 
141
  st.subheader("Fetching jobs...")
142
  jobs = fetch_jobs()
143
 
@@ -149,17 +217,28 @@ if resume_file:
149
  f"[View Job Posting]({job['url']}) \n"
150
  f"**Match Score:** {score:.2f}")
151
 
152
- if st.button(f"Generate Resume for {job['position']}", key=job['id']):
153
- tailored_resume = generate_resume(resume_text, job)
154
-
155
- # Show editable preview
156
- edited_resume = st.text_area("Tailored Resume", tailored_resume, height=300)
157
-
158
- # Build PDF
159
- pdf_buffer = build_pdf(edited_resume)
160
- st.download_button(
161
- label="📥 Download Resume (PDF)",
162
- data=pdf_buffer,
163
- file_name="tailored_resume.pdf",
164
- mime="application/pdf",
165
- )
 
 
 
 
 
 
 
 
 
 
 
 
6
  import faiss
7
  from groq import Groq
8
  from reportlab.lib.pagesizes import A4
9
+ from reportlab.lib import colors
10
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
11
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, ListFlowable, ListItem
12
  import io
13
 
14
  # -----------------------------
 
16
  # -----------------------------
17
  REMOTEOK_URL = "https://remoteok.com/api"
18
  EMBED_MODEL = "BAAI/bge-small-en-v1.5"
19
+ AI_MODEL = "openai/gpt-oss-120b" # Groq model
20
 
21
  # Load embedding model
22
  @st.cache_resource
 
82
  and this job description:\n{job['description']}\n
83
  Generate a structured resume in this format:
84
 
 
 
 
 
85
  Summary
86
  -----------------
87
  [2-3 line summary tailored for the job]
 
104
  """
105
 
106
  chat_completion = groq_client.chat.completions.create(
107
+ model=AI_MODEL,
108
  messages=[{"role": "user", "content": prompt}],
109
  temperature=0.7,
110
  )
111
  return chat_completion.choices[0].message.content
112
 
113
+ def generate_cover_letter(resume_text, job, name, email, phone):
114
+ prompt = f"""
115
+ You are an AI career assistant.
116
+ Given this resume:\n{resume_text}\n
117
+ and this job description:\n{job['description']}\n
118
+ Generate a professional, one-page cover letter tailored to this role.
119
+ Format it like this:
120
+
121
+ Dear Hiring Manager,
122
+
123
+ [Intro paragraph: Show enthusiasm and alignment with company/role]
124
+ [Body paragraph: Highlight 2-3 most relevant skills/experiences from resume]
125
+ [Closing paragraph: Express eagerness and thank them]
126
+
127
+ Sincerely,
128
+ {name}
129
+ {email} | {phone}
130
+ """
131
+
132
+ chat_completion = groq_client.chat.completions.create(
133
+ model=AI_MODEL,
134
+ messages=[{"role": "user", "content": prompt}],
135
+ temperature=0.7,
136
+ )
137
+ return chat_completion.choices[0].message.content
138
+
139
+ def build_pdf(content, title="Resume", name="John Doe", email="john.doe@email.com", phone="+1 234 567 890"):
140
  buffer = io.BytesIO()
141
+ doc = SimpleDocTemplate(buffer, pagesize=A4, leftMargin=40, rightMargin=40, topMargin=40, bottomMargin=40)
142
  styles = getSampleStyleSheet()
143
+
144
+ # Custom styles
145
+ header_style = ParagraphStyle("Header", parent=styles["Heading1"], fontSize=18, spaceAfter=6, textColor=colors.HexColor("#2C3E50"), alignment=1)
146
+ contact_style = ParagraphStyle("Contact", parent=styles["Normal"], fontSize=11, textColor=colors.HexColor("#566573"), alignment=1)
147
+ section_style = ParagraphStyle("Section", parent=styles["Heading2"], fontSize=13, spaceBefore=15, spaceAfter=8, textColor=colors.HexColor("#1B2631"))
148
+ normal_style = ParagraphStyle("Normal", parent=styles["Normal"], fontSize=11, leading=15)
149
+ bullet_style = ParagraphStyle("Bullet", parent=styles["Normal"], fontSize=11, leading=15, leftIndent=20)
150
+
151
  story = []
152
 
153
+ # ---- HEADER ----
154
+ story.append(Paragraph(name, header_style))
155
+ story.append(Paragraph(f"{email} | {phone}", contact_style))
156
+ story.append(Spacer(1, 12))
157
+
158
+ # ---- BODY ----
159
+ if title == "Resume":
160
+ sections = content.split("**")
161
+ for sec in sections:
162
+ sec = sec.strip()
163
+ if not sec:
164
+ continue
165
+
166
+ if sec.lower().startswith("summary"):
167
+ story.append(Paragraph("Summary", section_style))
168
+ elif sec.lower().startswith("skills"):
169
+ story.append(Paragraph("Skills", section_style))
170
+ elif sec.lower().startswith("experience"):
171
+ story.append(Paragraph("Experience", section_style))
172
+ elif sec.lower().startswith("education"):
173
+ story.append(Paragraph("Education", section_style))
174
+ else:
175
+ if sec.startswith("- "):
176
+ bullets = [s.strip("- ").strip() for s in sec.split("\n") if s.strip()]
177
+ bullet_list = ListFlowable([ListItem(Paragraph(b, bullet_style)) for b in bullets], bulletType="bullet")
178
+ story.append(bullet_list)
179
+ else:
180
+ story.append(Paragraph(sec, normal_style))
181
+ story.append(Spacer(1, 8))
182
+ else:
183
+ # Treat as cover letter: keep paragraphs
184
+ for line in content.split("\n"):
185
+ if line.strip():
186
+ story.append(Paragraph(line.strip(), normal_style))
187
+ story.append(Spacer(1, 10))
188
 
189
  doc.build(story)
190
  buffer.seek(0)
 
195
  # -----------------------------
196
  st.title("MATCHHIVE - AI Job Matcher")
197
 
198
+ # Upload resume
199
  resume_file = st.file_uploader("Upload your resume (PDF or DOCX)", type=["pdf", "docx"])
200
  if resume_file:
201
  resume_text = extract_text_from_resume(resume_file)
202
 
203
  if resume_text.strip():
204
+ st.subheader("Contact Information")
205
+ name = st.text_input("Full Name", "John Doe")
206
+ email = st.text_input("Email", "john.doe@email.com")
207
+ phone = st.text_input("Phone", "+1 234 567 890")
208
+
209
  st.subheader("Fetching jobs...")
210
  jobs = fetch_jobs()
211
 
 
217
  f"[View Job Posting]({job['url']}) \n"
218
  f"**Match Score:** {score:.2f}")
219
 
220
+ col1, col2 = st.columns(2)
221
+
222
+ with col1:
223
+ if st.button(f"Generate Resume for {job['position']}", key=f"resume_{job['id']}"):
224
+ tailored_resume = generate_resume(resume_text, job)
225
+ edited_resume = st.text_area("Tailored Resume", tailored_resume, height=300)
226
+ pdf_buffer = build_pdf(edited_resume, title="Resume", name=name, email=email, phone=phone)
227
+ st.download_button(
228
+ label="📥 Download Resume (PDF)",
229
+ data=pdf_buffer,
230
+ file_name="tailored_resume.pdf",
231
+ mime="application/pdf",
232
+ )
233
+
234
+ with col2:
235
+ if st.button(f"Generate Cover Letter for {job['position']}", key=f"cl_{job['id']}"):
236
+ tailored_cl = generate_cover_letter(resume_text, job, name, email, phone)
237
+ edited_cl = st.text_area("Cover Letter", tailored_cl, height=300)
238
+ pdf_buffer = build_pdf(edited_cl, title="Cover Letter", name=name, email=email, phone=phone)
239
+ st.download_button(
240
+ label="📥 Download Cover Letter (PDF)",
241
+ data=pdf_buffer,
242
+ file_name="cover_letter.pdf",
243
+ mime="application/pdf",
244
+ )