chirag1121 commited on
Commit
4703cd3
·
verified ·
1 Parent(s): 1f6fa0c

Create generator.py

Browse files
Files changed (1) hide show
  1. utils/generator.py +171 -0
utils/generator.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ generator.py — AI Resume Improvement Generator.
3
+
4
+ Uses google/flan-t5-base (free, open-source) to generate:
5
+ 1. An improved version of the resume text
6
+ 2. A polished professional summary
7
+
8
+ FLAN-T5 is instruction-tuned, making it ideal for text rewriting tasks
9
+ without requiring fine-tuning.
10
+
11
+ Model size: ~250 MB. Downloaded once and cached automatically by
12
+ HuggingFace transformers.
13
+ """
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # Lazy model loading — keeps Streamlit startup fast
17
+ # ---------------------------------------------------------------------------
18
+ _pipeline = None
19
+
20
+
21
+ def _get_pipeline():
22
+ """Load and cache the FLAN-T5 text2text pipeline."""
23
+ global _pipeline
24
+ if _pipeline is None:
25
+ from transformers import pipeline
26
+ _pipeline = pipeline(
27
+ "text2text-generation",
28
+ model="google/flan-t5-base",
29
+ max_new_tokens=512,
30
+ )
31
+ return _pipeline
32
+
33
+
34
+ # ---------------------------------------------------------------------------
35
+ # Public API
36
+ # ---------------------------------------------------------------------------
37
+
38
+ def generate_improved_resume(
39
+ resume_text: str,
40
+ job_description: str = "",
41
+ missing_sections: list = None,
42
+ ) -> str:
43
+ """
44
+ Generate an improved, ATS-friendly version of the resume.
45
+
46
+ Rewrites the resume with:
47
+ - Professional tone
48
+ - Bullet-point format
49
+ - Stronger action verbs
50
+ - Explicit mention of any missing sections
51
+
52
+ Args:
53
+ resume_text : original extracted resume text
54
+ job_description : optional job description to tailor the rewrite
55
+ missing_sections: list of sections the model should add
56
+
57
+ Returns:
58
+ Improved resume text as a string.
59
+ """
60
+ if not resume_text:
61
+ return "No resume text provided for improvement."
62
+
63
+ if missing_sections is None:
64
+ missing_sections = []
65
+
66
+ pipe = _get_pipeline()
67
+
68
+ # Build a focused, instruction-style prompt
69
+ # FLAN-T5 works best with clear task instructions
70
+ truncated_resume = _truncate(resume_text, 400)
71
+ jd_hint = f"\nThe target job requires: {_truncate(job_description, 100)}" if job_description else ""
72
+ missing_hint = (
73
+ f"\nMake sure to include sections for: {', '.join(missing_sections)}."
74
+ if missing_sections
75
+ else ""
76
+ )
77
+
78
+ prompt = (
79
+ f"Rewrite this resume to be professional, ATS-friendly, and impactful. "
80
+ f"Use bullet points, strong action verbs, and quantify achievements. "
81
+ f"Keep all original facts.{jd_hint}{missing_hint}\n\n"
82
+ f"Original Resume:\n{truncated_resume}\n\n"
83
+ f"Improved Resume:"
84
+ )
85
+
86
+ try:
87
+ result = pipe(prompt, max_new_tokens=512, do_sample=False)
88
+ improved = result[0]["generated_text"].strip()
89
+ return improved if improved else "⚠️ Could not generate improvement. Please try again."
90
+ except Exception as e:
91
+ return f"⚠️ Generation error: {str(e)}"
92
+
93
+
94
+ def generate_professional_summary(
95
+ name: str,
96
+ skills: list,
97
+ experience_present: bool,
98
+ job_title: str = "",
99
+ ) -> str:
100
+ """
101
+ Generate a short professional summary / objective paragraph.
102
+
103
+ Args:
104
+ name : candidate name (or empty string)
105
+ skills : list of extracted skill strings
106
+ experience_present: whether work experience was detected
107
+ job_title : optional target job title
108
+
109
+ Returns:
110
+ A 2–3 sentence professional summary.
111
+ """
112
+ pipe = _get_pipeline()
113
+
114
+ skills_str = ", ".join(skills[:8]) if skills else "various technical skills"
115
+ exp_phrase = (
116
+ "with hands-on professional experience"
117
+ if experience_present
118
+ else "seeking to start a professional career"
119
+ )
120
+ target = f" targeting a {job_title} role" if job_title else ""
121
+
122
+ prompt = (
123
+ f"Write a 2-3 sentence professional resume summary for a candidate "
124
+ f"{exp_phrase} in {skills_str}{target}. "
125
+ f"Keep it concise, first-person, and ATS-friendly."
126
+ )
127
+
128
+ try:
129
+ result = pipe(prompt, max_new_tokens=120, do_sample=False)
130
+ return result[0]["generated_text"].strip()
131
+ except Exception as e:
132
+ return f"⚠️ Summary generation error: {str(e)}"
133
+
134
+
135
+ def generate_section_content(section_name: str, context: str) -> str:
136
+ """
137
+ Generate content for a specific missing resume section.
138
+
139
+ Args:
140
+ section_name: e.g., 'Projects', 'Skills', 'Experience'
141
+ context : relevant resume text to base the generation on
142
+
143
+ Returns:
144
+ Generated section content as a string.
145
+ """
146
+ pipe = _get_pipeline()
147
+
148
+ prompt = (
149
+ f"Based on the following resume context, write a professional "
150
+ f"'{section_name}' section in bullet-point format:\n\n"
151
+ f"{_truncate(context, 200)}\n\n"
152
+ f"{section_name} Section:"
153
+ )
154
+
155
+ try:
156
+ result = pipe(prompt, max_new_tokens=200, do_sample=False)
157
+ return result[0]["generated_text"].strip()
158
+ except Exception as e:
159
+ return f"⚠️ Section generation error: {str(e)}"
160
+
161
+
162
+ # ---------------------------------------------------------------------------
163
+ # Internal helpers
164
+ # ---------------------------------------------------------------------------
165
+
166
+ def _truncate(text: str, max_words: int) -> str:
167
+ """Truncate text to max_words words to stay within model context limit."""
168
+ words = text.split()
169
+ if len(words) > max_words:
170
+ return " ".join(words[:max_words]) + "..."
171
+ return text