mgbam commited on
Commit
242cb8f
ยท
verified ยท
1 Parent(s): 4867dd6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -56
app.py CHANGED
@@ -1,25 +1,38 @@
 
1
  import gradio as gr
2
  import google.generativeai as genai
3
- import os
4
  from dotenv import load_dotenv
5
 
6
- # Load environment variable
 
 
 
 
 
7
  load_dotenv()
8
  API_KEY = os.getenv("GEMINI_API_KEY")
9
-
10
  genai.configure(api_key=API_KEY)
11
- model = genai.GenerativeModel("models/gemini-1.5-pro-latest")
12
-
13
- # --- AI Functions ---
 
 
 
 
 
 
 
 
 
14
  def generate_resume(name, email, phone, summary, experience, education, skills):
15
  prompt = f"""
16
- Create a professional resume using the following details:
17
 
18
  Name: {name}
19
  Email: {email}
20
  Phone: {phone}
21
 
22
- Summary:
23
  {summary}
24
 
25
  Experience:
@@ -30,74 +43,138 @@ def generate_resume(name, email, phone, summary, experience, education, skills):
30
 
31
  Skills:
32
  {skills}
33
-
34
- Format it clearly and professionally.
35
  """
36
- response = model.generate_content(prompt)
37
- return response.text
38
 
39
  def score_resume(resume, job_desc):
40
  prompt = f"""
41
- Evaluate how well the following resume matches the job description below.
42
- Return a match score out of 100 and specific, actionable suggestions to improve the resume.
 
 
 
 
 
 
 
 
 
 
43
 
44
- Resume:
 
 
 
 
 
 
 
 
 
45
  {resume}
46
 
47
- Job Description:
48
  {job_desc}
49
  """
50
- response = model.generate_content(prompt)
51
- return response.text
52
-
53
- def refine_section(section_text, instruction):
54
- prompt = f"Refine this section according to the instruction.\nInstruction: {instruction}\nText: {section_text}"
55
- response = model.generate_content(prompt)
56
- return response.text
57
-
58
- # --- Gradio UI ---
59
- with gr.Blocks() as demo:
60
- gr.Markdown("## ๐Ÿค– AI Resume Builder using Gemini")
61
-
62
- with gr.Tab("1๏ธโƒฃ Generate Resume"):
63
- name = gr.Textbox(label="Name")
64
- email = gr.Textbox(label="Email")
65
- phone = gr.Textbox(label="Phone")
66
- summary = gr.Textbox(label="Professional Summary")
67
- experience = gr.Textbox(label="Experience")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  education = gr.Textbox(label="Education")
69
- skills = gr.Textbox(label="Skills")
70
- resume_output = gr.Textbox(label="Generated Resume", lines=15)
71
- generate_btn = gr.Button("Generate Resume")
 
 
 
72
 
73
- generate_btn.click(
74
- fn=generate_resume,
75
  inputs=[name, email, phone, summary, experience, education, skills],
76
- outputs=resume_output
77
  )
78
 
79
- with gr.Tab("2๏ธโƒฃ Score Resume Against Job"):
80
- resume_input = gr.Textbox(label="Your Resume", lines=10)
81
- job_desc = gr.Textbox(label="Job Description", lines=5)
82
- score_output = gr.Textbox(label="Match Score & Suggestions", lines=10)
83
- score_btn = gr.Button("Evaluate")
 
 
 
 
84
 
85
  score_btn.click(
86
- fn=score_resume,
87
- inputs=[resume_input, job_desc],
88
- outputs=score_output
89
  )
90
 
91
- with gr.Tab("3๏ธโƒฃ Refine Resume Section"):
92
- section_input = gr.Textbox(label="Resume Section", lines=5)
93
- instruction_input = gr.Textbox(label="Refinement Instruction")
94
- refined_output = gr.Textbox(label="Refined Text", lines=5)
 
95
  refine_btn = gr.Button("Refine")
96
 
97
  refine_btn.click(
98
- fn=refine_section,
99
- inputs=[section_input, instruction_input],
100
- outputs=refined_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  )
102
 
103
- demo.launch()
 
1
+ import os, tempfile, datetime
2
  import gradio as gr
3
  import google.generativeai as genai
 
4
  from dotenv import load_dotenv
5
 
6
+ # โ”€โ”€ 3rdโ€‘party formatters โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
7
+ from docx import Document # python-docx
8
+ from reportlab.lib.pagesizes import LETTER # reportlab
9
+ from reportlab.pdfgen import canvas
10
+
11
+ # โ”€โ”€ Environment & Model โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
12
  load_dotenv()
13
  API_KEY = os.getenv("GEMINI_API_KEY")
 
14
  genai.configure(api_key=API_KEY)
15
+ model = genai.GenerativeModel("gemini-pro")
16
+
17
+ # โ”€โ”€ Core AI helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
18
+ def _ask_gemini(prompt: str) -> str:
19
+ """Utility wrapper with basic errorโ€handling."""
20
+ try:
21
+ rsp = model.generate_content(prompt, generation_config={"temperature": 0.7})
22
+ return rsp.text.strip()
23
+ except Exception as exc:
24
+ return f"[Gemini Error] {exc}"
25
+
26
+ # โ”€โ”€ Business Logic โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
27
  def generate_resume(name, email, phone, summary, experience, education, skills):
28
  prompt = f"""
29
+ Create a professionally formatted resume. Use Markdown headings and no firstโ€‘person pronouns.
30
 
31
  Name: {name}
32
  Email: {email}
33
  Phone: {phone}
34
 
35
+ Professional Summary:
36
  {summary}
37
 
38
  Experience:
 
43
 
44
  Skills:
45
  {skills}
 
 
46
  """
47
+ return _ask_gemini(prompt)
 
48
 
49
  def score_resume(resume, job_desc):
50
  prompt = f"""
51
+ Evaluate the RESUME against the JOB DESCRIPTION. Return JSON:
52
+ {{
53
+ "score": <0โ€‘100>,
54
+ "suggestions": [ "โ€ฆ", "โ€ฆ" ]
55
+ }}
56
+ RESUME:
57
+ {resume}
58
+
59
+ JOB DESCRIPTION:
60
+ {job_desc}
61
+ """
62
+ return _ask_gemini(prompt)
63
 
64
+ def refine_text(section_text, instruction):
65
+ prompt = f"Refine the following text.\nInstruction: {instruction}\nText:\n{section_text}"
66
+ return _ask_gemini(prompt)
67
+
68
+ def generate_cover_letter(resume, job_desc, tone):
69
+ prompt = f"""
70
+ Act as a career coach. Draft a oneโ€‘page cover letter **in {tone} tone** that aligns this RESUME
71
+ to the JOB DESCRIPTION. Do not exceed 300 words.
72
+
73
+ RESUME:
74
  {resume}
75
 
76
+ JOB DESCRIPTION:
77
  {job_desc}
78
  """
79
+ return _ask_gemini(prompt)
80
+
81
+ # โ”€โ”€ Fileโ€‘export helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
82
+ def _to_docx(text: str) -> str:
83
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".docx")
84
+ doc = Document()
85
+ for line in text.splitlines():
86
+ doc.add_paragraph(line)
87
+ doc.save(tmp.name)
88
+ return tmp.name
89
+
90
+ def _to_pdf(text: str) -> str:
91
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
92
+ c = canvas.Canvas(tmp.name, pagesize=LETTER)
93
+ width, height = LETTER
94
+ y = height - 72
95
+ for line in text.splitlines():
96
+ c.drawString(72, y, line)
97
+ y -= 14
98
+ if y < 72:
99
+ c.showPage()
100
+ y = height - 72
101
+ c.save()
102
+ return tmp.name
103
+
104
+ def generate_resume_and_files(*inputs):
105
+ resume_md = generate_resume(*inputs)
106
+ return (
107
+ resume_md,
108
+ _to_docx(resume_md),
109
+ _to_pdf(resume_md),
110
+ )
111
+
112
+ # โ”€โ”€ Gradio UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
113
+ with gr.Blocks(title="AIย Resumeย Builder using Gemini") as demo:
114
+ gr.Markdown("## ๐Ÿง ย AIโ€ฏResumeย Builderย ร—ย Gemini")
115
+
116
+ # โ”€โ”€ Tabย 1: Resume generation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
117
+ with gr.Tab("๐Ÿ“„ย Generate Resume"):
118
+ name = gr.Textbox(label="Name")
119
+ email = gr.Textbox(label="Email")
120
+ phone = gr.Textbox(label="Phone")
121
+ summary = gr.Textbox(label="Professional Summary")
122
+ experience= gr.Textbox(label="Experience")
123
  education = gr.Textbox(label="Education")
124
+ skills = gr.Textbox(label="Skills")
125
+
126
+ resume_out = gr.Markdown(label="Generated Resume")
127
+ docx_file = gr.File(label="โฌ‡ย Word (.docx)")
128
+ pdf_file = gr.File(label="โฌ‡ย PDF (.pdf)")
129
+ gen_btn = gr.Button("Generate Resume")
130
 
131
+ gen_btn.click(
132
+ generate_resume_and_files,
133
  inputs=[name, email, phone, summary, experience, education, skills],
134
+ outputs=[resume_out, docx_file, pdf_file],
135
  )
136
 
137
+ # โ”€โ”€ Tabย 2: Jobโ€‘match score โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
138
+ with gr.Tab("๐Ÿงฎย Score Resume Against Job"):
139
+ resume_in = gr.Textbox(label="Resumeย (Markdown)", lines=12)
140
+ jd_in = gr.Textbox(label="Jobย Description", lines=8)
141
+ score_out = gr.Markdown(label="Score & Suggestions")
142
+ score_btn = gr.Button("Evaluate")
143
+
144
+ def parse_score(rsp):
145
+ return rsp # we leave JSON parsing to the user for now
146
 
147
  score_btn.click(
148
+ lambda r, jd: parse_score(score_resume(r, jd)),
149
+ inputs=[resume_in, jd_in],
150
+ outputs=score_out,
151
  )
152
 
153
+ # โ”€โ”€ Tabย 3: Refine section โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
154
+ with gr.Tab("โœ๏ธย Refine Resume Section"):
155
+ sec_in = gr.Textbox(label="Section Text", lines=6)
156
+ instr_in = gr.Textbox(label="Instruction (e.g., make concise)")
157
+ refined = gr.Textbox(label="Refined Output", lines=6)
158
  refine_btn = gr.Button("Refine")
159
 
160
  refine_btn.click(
161
+ lambda text, instr: refine_text(text, instr),
162
+ inputs=[sec_in, instr_in],
163
+ outputs=refined,
164
+ )
165
+
166
+ # โ”€โ”€ Tabย 4: Coverโ€‘Letter generator โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
167
+ with gr.Tab("๐Ÿ“งย Coverโ€‘Letter Generator"):
168
+ cv_resume = gr.Textbox(label="Resumeย (Markdown)", lines=12)
169
+ cv_jd = gr.Textbox(label="Jobย Description", lines=8)
170
+ cv_tone = gr.Radio(["Professional", "Friendly", "Enthusiastic"], value="Professional", label="Tone")
171
+ cv_out = gr.Markdown(label="Generated Cover Letter")
172
+ cv_btn = gr.Button("Generate Cover Letter")
173
+
174
+ cv_btn.click(
175
+ lambda r, jd, tone: generate_cover_letter(r, jd, tone),
176
+ inputs=[cv_resume, cv_jd, cv_tone],
177
+ outputs=cv_out,
178
  )
179
 
180
+ demo.launch(share=False) # โ† Spaces already exposes the public URL