PraneshJs commited on
Commit
f833cab
Β·
verified Β·
1 Parent(s): 70bdcac

added server name and port

Browse files
Files changed (1) hide show
  1. app.py +136 -136
app.py CHANGED
@@ -1,136 +1,136 @@
1
- import io
2
- import json
3
- from typing import Optional
4
-
5
- import gradio as gr
6
- import PyPDF2
7
-
8
- from resume_ai import score, improve
9
-
10
- def extract_text_from_pdf(file_obj: io.IOBase) -> str:
11
- """Extract text from a PDF file-like object."""
12
- try:
13
- reader = PyPDF2.PdfReader(file_obj)
14
- text_chunks = []
15
- for page in reader.pages:
16
- page_text = page.extract_text() or ""
17
- text_chunks.append(page_text)
18
- text = "\n".join(text_chunks).strip()
19
- if not text:
20
- raise ValueError("No extractable text found in PDF.")
21
- return text
22
- except Exception as e:
23
- raise ValueError(f"Error reading PDF: {e}")
24
-
25
- def read_resume_to_text(resume_file_path) -> str:
26
- """
27
- Accepts a file path and returns text content.
28
- Supports PDF and plain text files.
29
- """
30
- if resume_file_path is None:
31
- raise ValueError("Please upload a resume file.")
32
-
33
- filename = str(resume_file_path).lower()
34
- if filename.endswith(".pdf"):
35
- with open(resume_file_path, "rb") as f:
36
- return extract_text_from_pdf(f)
37
- else:
38
- with open(resume_file_path, "rb") as f:
39
- data = f.read()
40
- if not data:
41
- raise ValueError("Uploaded file is empty.")
42
- try:
43
- return data.decode("utf-8").strip()
44
- except UnicodeDecodeError:
45
- return data.decode("latin-1").strip()
46
-
47
- def score_fn(resume_file_path, job_desc: str) -> str:
48
- try:
49
- if not job_desc or not job_desc.strip():
50
- raise ValueError("Please paste a job description.")
51
- resume_text = read_resume_to_text(resume_file_path)
52
- result = score(resume_text, job_desc)
53
- return json.dumps(result, indent=2, ensure_ascii=False)
54
- except Exception as e:
55
- return f"Error: {e}"
56
-
57
- def improve_fn(resume_file_path, job_desc: Optional[str]) -> str:
58
- try:
59
- resume_text = read_resume_to_text(resume_file_path)
60
- jd_text = job_desc if job_desc and job_desc.strip() else None
61
- suggestions = improve(resume_text, jd_text)
62
- if isinstance(suggestions, (list, tuple)):
63
- bullets = "\n".join(f"- {s}" for s in suggestions)
64
- return f"### Suggestions\n{bullets}"
65
- elif isinstance(suggestions, dict):
66
- return "```json\n" + json.dumps(suggestions, indent=2, ensure_ascii=False) + "\n```"
67
- else:
68
- return str(suggestions)
69
- except Exception as e:
70
- return f"Error: {e}"
71
-
72
- def format_score_display(result_json) -> str:
73
- """
74
- Takes the result JSON (as dict or str), parses it, and returns a Markdown string for display.
75
- """
76
- if isinstance(result_json, str):
77
- try:
78
- result = json.loads(result_json)
79
- except Exception:
80
- return f"```\n{result_json}\n```"
81
- else:
82
- result = result_json
83
-
84
- md = f"## πŸ† ATS Compatibility Score: **{result.get('overall_score', 0)}%**\n\n"
85
- md += "### Category Scores\n"
86
- md += "| Skills | Experience | Education |\n"
87
- md += "|--------|------------|-----------|\n"
88
- cs = result.get("category_scores", {})
89
- md += f"| {cs.get('skills',0)}% | {cs.get('experience',0)}% | {cs.get('education',0)}% |\n\n"
90
-
91
- gaps = result.get("top_skill_gaps", [])
92
- if gaps:
93
- md += "### 🚩 Top Skill Gaps\n"
94
- for gap in gaps:
95
- md += f"- {gap}\n"
96
- return md
97
-
98
- # ...existing code...
99
-
100
- with gr.Blocks(title="Resume AI (Score & Improve)") as demo:
101
- gr.Markdown(
102
- """
103
- # πŸ“„ Resume AI β€” Score & Improve
104
- Upload your resume (PDF or TXT), paste a Job Description, and get:
105
- - **Score**: A formatted breakdown of your resume's ATS compatibility
106
- - **Improve**: A healthy set of suggestions to enhance your resume
107
- """
108
- )
109
-
110
- with gr.Row():
111
- resume = gr.File(label="Upload Resume (PDF or TXT)", file_types=[".pdf", ".txt"], type="filepath")
112
- jd = gr.Textbox(label="Job Description (paste here)", lines=10, placeholder="Paste JD text...")
113
-
114
- with gr.Row():
115
- score_btn = gr.Button("βš–οΈ Score Resume", variant="primary")
116
- improve_btn = gr.Button("✨ Improve Resume")
117
-
118
- score_out = gr.Markdown(label="Score (Formatted)")
119
- improve_out = gr.Markdown(label="Improvement Suggestions")
120
-
121
- def score_fn_display(resume_file_path, job_desc: str) -> str:
122
- try:
123
- if not job_desc or not job_desc.strip():
124
- raise ValueError("Please paste a job description.")
125
- resume_text = read_resume_to_text(resume_file_path)
126
- result = score(resume_text, job_desc)
127
- return format_score_display(result)
128
- except Exception as e:
129
- return f"Error: {e}"
130
-
131
- score_btn.click(fn=score_fn_display, inputs=[resume, jd], outputs=score_out)
132
- improve_btn.click(fn=improve_fn, inputs=[resume, jd], outputs=improve_out)
133
-
134
-
135
- if __name__ == "__main__":
136
- demo.queue().launch()
 
1
+ import io
2
+ import json
3
+ from typing import Optional
4
+
5
+ import gradio as gr
6
+ import PyPDF2
7
+
8
+ from resume_ai import score, improve
9
+
10
+ def extract_text_from_pdf(file_obj: io.IOBase) -> str:
11
+ """Extract text from a PDF file-like object."""
12
+ try:
13
+ reader = PyPDF2.PdfReader(file_obj)
14
+ text_chunks = []
15
+ for page in reader.pages:
16
+ page_text = page.extract_text() or ""
17
+ text_chunks.append(page_text)
18
+ text = "\n".join(text_chunks).strip()
19
+ if not text:
20
+ raise ValueError("No extractable text found in PDF.")
21
+ return text
22
+ except Exception as e:
23
+ raise ValueError(f"Error reading PDF: {e}")
24
+
25
+ def read_resume_to_text(resume_file_path) -> str:
26
+ """
27
+ Accepts a file path and returns text content.
28
+ Supports PDF and plain text files.
29
+ """
30
+ if resume_file_path is None:
31
+ raise ValueError("Please upload a resume file.")
32
+
33
+ filename = str(resume_file_path).lower()
34
+ if filename.endswith(".pdf"):
35
+ with open(resume_file_path, "rb") as f:
36
+ return extract_text_from_pdf(f)
37
+ else:
38
+ with open(resume_file_path, "rb") as f:
39
+ data = f.read()
40
+ if not data:
41
+ raise ValueError("Uploaded file is empty.")
42
+ try:
43
+ return data.decode("utf-8").strip()
44
+ except UnicodeDecodeError:
45
+ return data.decode("latin-1").strip()
46
+
47
+ def score_fn(resume_file_path, job_desc: str) -> str:
48
+ try:
49
+ if not job_desc or not job_desc.strip():
50
+ raise ValueError("Please paste a job description.")
51
+ resume_text = read_resume_to_text(resume_file_path)
52
+ result = score(resume_text, job_desc)
53
+ return json.dumps(result, indent=2, ensure_ascii=False)
54
+ except Exception as e:
55
+ return f"Error: {e}"
56
+
57
+ def improve_fn(resume_file_path, job_desc: Optional[str]) -> str:
58
+ try:
59
+ resume_text = read_resume_to_text(resume_file_path)
60
+ jd_text = job_desc if job_desc and job_desc.strip() else None
61
+ suggestions = improve(resume_text, jd_text)
62
+ if isinstance(suggestions, (list, tuple)):
63
+ bullets = "\n".join(f"- {s}" for s in suggestions)
64
+ return f"### Suggestions\n{bullets}"
65
+ elif isinstance(suggestions, dict):
66
+ return "```json\n" + json.dumps(suggestions, indent=2, ensure_ascii=False) + "\n```"
67
+ else:
68
+ return str(suggestions)
69
+ except Exception as e:
70
+ return f"Error: {e}"
71
+
72
+ def format_score_display(result_json) -> str:
73
+ """
74
+ Takes the result JSON (as dict or str), parses it, and returns a Markdown string for display.
75
+ """
76
+ if isinstance(result_json, str):
77
+ try:
78
+ result = json.loads(result_json)
79
+ except Exception:
80
+ return f"```\n{result_json}\n```"
81
+ else:
82
+ result = result_json
83
+
84
+ md = f"## πŸ† ATS Compatibility Score: **{result.get('overall_score', 0)}%**\n\n"
85
+ md += "### Category Scores\n"
86
+ md += "| Skills | Experience | Education |\n"
87
+ md += "|--------|------------|-----------|\n"
88
+ cs = result.get("category_scores", {})
89
+ md += f"| {cs.get('skills',0)}% | {cs.get('experience',0)}% | {cs.get('education',0)}% |\n\n"
90
+
91
+ gaps = result.get("top_skill_gaps", [])
92
+ if gaps:
93
+ md += "### 🚩 Top Skill Gaps\n"
94
+ for gap in gaps:
95
+ md += f"- {gap}\n"
96
+ return md
97
+
98
+ # ...existing code...
99
+
100
+ with gr.Blocks(title="Resume AI (Score & Improve)") as demo:
101
+ gr.Markdown(
102
+ """
103
+ # πŸ“„ Resume AI β€” Score & Improve
104
+ Upload your resume (PDF or TXT), paste a Job Description, and get:
105
+ - **Score**: A formatted breakdown of your resume's ATS compatibility
106
+ - **Improve**: A healthy set of suggestions to enhance your resume
107
+ """
108
+ )
109
+
110
+ with gr.Row():
111
+ resume = gr.File(label="Upload Resume (PDF or TXT)", file_types=[".pdf", ".txt"], type="filepath")
112
+ jd = gr.Textbox(label="Job Description (paste here)", lines=10, placeholder="Paste JD text...")
113
+
114
+ with gr.Row():
115
+ score_btn = gr.Button("βš–οΈ Score Resume", variant="primary")
116
+ improve_btn = gr.Button("✨ Improve Resume")
117
+
118
+ score_out = gr.Markdown(label="Score (Formatted)")
119
+ improve_out = gr.Markdown(label="Improvement Suggestions")
120
+
121
+ def score_fn_display(resume_file_path, job_desc: str) -> str:
122
+ try:
123
+ if not job_desc or not job_desc.strip():
124
+ raise ValueError("Please paste a job description.")
125
+ resume_text = read_resume_to_text(resume_file_path)
126
+ result = score(resume_text, job_desc)
127
+ return format_score_display(result)
128
+ except Exception as e:
129
+ return f"Error: {e}"
130
+
131
+ score_btn.click(fn=score_fn_display, inputs=[resume, jd], outputs=score_out)
132
+ improve_btn.click(fn=improve_fn, inputs=[resume, jd], outputs=improve_out)
133
+
134
+
135
+ if __name__ == "__main__":
136
+ demo.launch(server_name="0.0.0.0",server_port=7860, pwa=True)