Omar10lfc commited on
Commit
0ac9232
·
verified ·
1 Parent(s): a939f19

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -127
app.py CHANGED
@@ -1,128 +1,147 @@
1
- import gradio as gr
2
- from resume_agent import full_app, scanner_app
3
-
4
- def step1_analyze(job_input, resume_file_or_text):
5
- """
6
- Step 1: Runs ONLY the Scanner to find gaps.
7
- Output goes to the 'Human Feedback' box for you to edit.
8
- """
9
- # Handle File vs Text Input
10
- resume_path_or_text = ""
11
- if hasattr(resume_file_or_text, "name"):
12
- resume_path_or_text = resume_file_or_text.name
13
- else:
14
- resume_path_or_text = resume_file_or_text
15
-
16
- # Prepare Inputs
17
- inputs = {
18
- "job_description": job_input,
19
- "original_resume": resume_path_or_text,
20
- "resume_text": "",
21
- "job_text": "",
22
- "missing_skills": ""
23
- }
24
-
25
- try:
26
- result = scanner_app.invoke(inputs)
27
- # Return the missing skills list so you can see/edit it
28
- return result['missing_skills']
29
-
30
- except Exception as e:
31
- return f"Error during scan: {str(e)}"
32
-
33
-
34
- def step2_optimize(job_input, resume_file_or_text, user_notes):
35
- """
36
- Step 2: Runs the Full Optimizer.
37
- It uses the 'user_notes' (which you edited in the text box) as context.
38
- """
39
- # 1. Handle File vs Text Input
40
- resume_path_or_text = ""
41
- if hasattr(resume_file_or_text, "name"):
42
- resume_path_or_text = resume_file_or_text.name
43
- else:
44
- resume_path_or_text = resume_file_or_text
45
-
46
- # 2. Prepare Inputs
47
- # Notice we pass 'user_notes' into 'human_notes'
48
- inputs = {
49
- "job_description": job_input,
50
- "original_resume": resume_path_or_text,
51
- "human_notes": user_notes, # <--- CRITICAL: Uses your edited feedback
52
-
53
- # Initialize other fields
54
- "resume_text": "", "job_text": "", "optimized_resume": "",
55
- "feedback": "", "score": 0, "iteration": 0
56
- }
57
-
58
- try:
59
- # Run the "Full Graph" (Improver + Reviewer Loop)
60
- final_state = full_app.invoke(inputs)
61
-
62
- return (
63
- final_state.get('optimized_resume', "Error generating resume."),
64
- f"Score: {final_state.get('score', 0)}/100",
65
- final_state.get('feedback', 'No feedback provided.')
66
- )
67
-
68
- except Exception as e:
69
- return f"Error: {str(e)}", "Error", "Error"
70
-
71
-
72
- # --- BUILD THE USER INTERFACE ---
73
-
74
- with gr.Blocks(title="AI Resume Agent") as demo:
75
- gr.Markdown("# AI Resume Optimizer")
76
- gr.Markdown("An Agentic workflow: **Scan** for gaps first, **Edit** the plan, then **Generate** the result.")
77
-
78
- with gr.Row():
79
- with gr.Column(scale=1):
80
- job_in = gr.Textbox(
81
- label="1. Job Description (URL or Text)",
82
- placeholder="Paste Job Text OR a Link (https://...)",
83
- lines=3
84
- )
85
-
86
- resume_in = gr.File(
87
- label="2. Upload Resume (PDF)",
88
- file_types=[".pdf"],
89
- type="filepath"
90
- )
91
-
92
- # Action Button 1
93
- btn_analyze = gr.Button("Step 1: Find Missing Skills", variant="secondary")
94
- notes_in = gr.Textbox(
95
- label="3. Missing Skills & Context (Editable)",
96
- placeholder="Click 'Step 1' to see missing skills here. \nThen DELETE skills you don't have, or ADD context like 'I used this in my internship...'",
97
- lines=10,
98
- interactive=True
99
- )
100
-
101
- # Action Button 2
102
- btn_optimize = gr.Button("Step 2: Generate Optimized Resume", variant="primary")
103
-
104
- # (Results)
105
- with gr.Column(scale=1):
106
- score_out = gr.Label(label="Match Score")
107
- feedback_out = gr.Textbox(label="Critique Summary", lines=4)
108
- resume_out = gr.Textbox(
109
- label="Final Optimized Resume",
110
- lines=25,
111
- )
112
-
113
- # 1. Analyze Button
114
- btn_analyze.click(
115
- fn=step1_analyze,
116
- inputs=[job_in, resume_in],
117
- outputs=[notes_in]
118
- )
119
-
120
- # 2. Optimize Button -> Reads 'notes_in' -> Updates final outputs
121
- btn_optimize.click(
122
- fn=step2_optimize,
123
- inputs=[job_in, resume_in, notes_in],
124
- outputs=[resume_out, score_out, feedback_out]
125
- )
126
-
127
- if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  demo.launch(theme=gr.themes.Soft())
 
1
+ import gradio as gr
2
+ import os
3
+ from resume_agent import full_app, scanner_app
4
+
5
+ def step1_analyze(job_input, resume_file_or_text):
6
+ """
7
+ Step 1: Runs ONLY the Scanner to find gaps.
8
+ Output goes to the 'Human Feedback' box for you to edit.
9
+ """
10
+ # Handle File vs Text Input
11
+ resume_path_or_text = ""
12
+ if hasattr(resume_file_or_text, "name"):
13
+ resume_path_or_text = resume_file_or_text.name
14
+ else:
15
+ resume_path_or_text = resume_file_or_text
16
+
17
+ # Prepare Inputs
18
+ inputs = {
19
+ "job_description": job_input,
20
+ "original_resume": resume_path_or_text,
21
+ "resume_text": "",
22
+ "job_text": "",
23
+ "missing_skills": ""
24
+ }
25
+
26
+ try:
27
+ # Run the partial "Scanner Graph"
28
+ result = scanner_app.invoke(inputs)
29
+ # Return the missing skills list so you can see/edit it
30
+ return result['missing_skills']
31
+
32
+ except Exception as e:
33
+ return f"Error during scan: {str(e)}"
34
+
35
+
36
+ def step2_optimize(job_input, resume_file_or_text, user_notes):
37
+ """
38
+ Step 2: Runs the Full Optimizer + Document Generator.
39
+ It returns text previews AND file paths for the PDFs.
40
+ """
41
+ # 1. Handle File vs Text Input
42
+ resume_path_or_text = ""
43
+ if hasattr(resume_file_or_text, "name"):
44
+ resume_path_or_text = resume_file_or_text.name
45
+ else:
46
+ resume_path_or_text = resume_file_or_text
47
+
48
+ # 2. Prepare Inputs
49
+ inputs = {
50
+ "job_description": job_input,
51
+ "original_resume": resume_path_or_text,
52
+ "human_notes": user_notes, # Uses your edited feedback
53
+
54
+ # Initialize empty fields for the state
55
+ "resume_text": "", "job_text": "", "optimized_resume": "",
56
+ "feedback": "", "score": 0, "iteration": 0,
57
+ "cover_letter": "", "resume_pdf_path": "", "cover_letter_pdf_path": ""
58
+ }
59
+
60
+ try:
61
+ # Run the "Full Graph" (Improver -> Reviewer -> PDF Gen)
62
+ final_state = full_app.invoke(inputs)
63
+
64
+ # Extract Results
65
+ opt_resume_text = final_state.get('optimized_resume', "Error generating resume.")
66
+ score_text = f"Score: {final_state.get('score', 0)}/100"
67
+ feedback_text = final_state.get('feedback', 'No feedback provided.')
68
+
69
+ # Get PDF Paths
70
+ resume_pdf = final_state.get('resume_pdf_path')
71
+ cover_pdf = final_state.get('cover_letter_pdf_path')
72
+
73
+ return opt_resume_text, score_text, feedback_text, resume_pdf, cover_pdf
74
+
75
+ except Exception as e:
76
+ return f"Error: {str(e)}", "Error", "Error", None, None
77
+
78
+
79
+ # --- BUILD THE USER INTERFACE ---
80
+
81
+ with gr.Blocks(title="AI Resume Agent") as demo:
82
+ gr.Markdown("# AI Resume Optimizer")
83
+ gr.Markdown("An Agentic workflow: **Scan** for gaps, **Edit** the plan, then **Generate** professional PDFs.")
84
+
85
+ with gr.Row():
86
+ # --- LEFT COLUMN (Inputs) ---
87
+ with gr.Column(scale=1):
88
+ job_in = gr.Textbox(
89
+ label="1. Job Description (URL or Text)",
90
+ placeholder="Paste Job Text OR a Link (https://...)",
91
+ lines=3
92
+ )
93
+
94
+ resume_in = gr.File(
95
+ label="2. Upload Resume (PDF)",
96
+ file_types=[".pdf"],
97
+ type="filepath"
98
+ )
99
+
100
+ # Action Button 1
101
+ btn_analyze = gr.Button("Step 1: Find Missing Skills", variant="secondary")
102
+
103
+ notes_in = gr.Textbox(
104
+ label="3. Missing Skills & Context (Editable)",
105
+ placeholder="Click 'Step 1' to see missing skills here. \nThen DELETE skills you don't have, or ADD context like 'I used this in my internship...'",
106
+ lines=10,
107
+ interactive=True
108
+ )
109
+
110
+ # Action Button 2
111
+ btn_optimize = gr.Button("Step 2: Generate Optimized Resume", variant="primary")
112
+
113
+ # --- RIGHT COLUMN (Outputs) ---
114
+ with gr.Column(scale=1):
115
+ score_out = gr.Label(label="Match Score")
116
+ feedback_out = gr.Textbox(label="Critique Summary", lines=4)
117
+
118
+ # Text Preview - REMOVED 'show_copy_button' to fix crash
119
+ resume_out = gr.Textbox(
120
+ label="Final Resume (Text Preview)",
121
+ lines=15
122
+ )
123
+
124
+ # PDF Download Area
125
+ gr.Markdown("### 📥 Download Documents")
126
+ with gr.Row():
127
+ pdf_resume_out = gr.File(label="Optimized Resume PDF")
128
+ pdf_cover_out = gr.File(label="Cover Letter PDF")
129
+
130
+ # --- WIRING THE BUTTONS ---
131
+
132
+ # 1. Analyze Button -> Updates the 'notes_in' box
133
+ btn_analyze.click(
134
+ fn=step1_analyze,
135
+ inputs=[job_in, resume_in],
136
+ outputs=[notes_in]
137
+ )
138
+
139
+ # 2. Optimize Button -> Returns Text + PDF Files
140
+ btn_optimize.click(
141
+ fn=step2_optimize,
142
+ inputs=[job_in, resume_in, notes_in],
143
+ outputs=[resume_out, score_out, feedback_out, pdf_resume_out, pdf_cover_out]
144
+ )
145
+
146
+ if __name__ == "__main__":
147
  demo.launch(theme=gr.themes.Soft())