sudhanshu388 commited on
Commit
c076dd2
·
verified ·
1 Parent(s): ac09753

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -40
app.py CHANGED
@@ -5,11 +5,13 @@ ZeroGPU-accelerated Career Intelligence & Long-Term Memory OS.
5
  import os
6
  import spaces
7
  import gradio as gr
8
- from app.llm import ask_llm
9
- from app.routers.ats import run_ats_check
10
- from app.routers.matcher import run_resume_match, run_suggest_edits
11
- from app.routers.insights import run_company_analysis
12
- from app.services.email_outreach import extract_job_posting_fields, generate_outreach_email
 
 
13
 
14
  # --- ZeroGPU Handlers ---
15
  @spaces.GPU
@@ -17,9 +19,17 @@ def chat_response(message, history):
17
  if not message.strip():
18
  return ""
19
  try:
20
- response = ask_llm(
21
- messages=[{"role": "user", "content": message}],
22
- system_prompt="You are malloc(), an AI Career Intelligence Assistant with long-term memory. Provide sharp, concise, actionable advice."
 
 
 
 
 
 
 
 
23
  )
24
  return response
25
  except Exception as e:
@@ -30,16 +40,18 @@ def match_resume(resume_text, jd_text):
30
  if not resume_text or not jd_text:
31
  return "Please provide both Resume and Job Description text.", ""
32
  try:
33
- match_res = run_resume_match(resume_text, jd_text)
34
- edits_res = run_suggest_edits(resume_text, jd_text)
35
 
36
- summary = f"### Overall Match Score: {match_res.get('score', 0)}%\n\n"
37
- summary += f"**Matched Skills**: {', '.join(match_res.get('matched_skills', []))}\n\n"
38
- summary += f"**Missing / Gaps**: {', '.join(match_res.get('missing_skills', []))}\n\n"
 
 
39
 
40
  edits = "### Actionable Suggested Edits:\n"
41
- for item in edits_res.get("suggestions", []):
42
- edits += f"- **Original**: {item.get('original', '')}\n - **Suggested Edit**: {item.get('suggestion', '')}\n - **Reason**: {item.get('reason', '')}\n\n"
43
 
44
  return summary, edits
45
  except Exception as e:
@@ -50,12 +62,16 @@ def check_ats(resume_text):
50
  if not resume_text:
51
  return "Please paste resume text to audit."
52
  try:
53
- res = run_ats_check(resume_text)
54
- output = f"### ATS Parseability Score: {res.get('score', 0)}/100\n\n"
55
- output += f"- **Format Health**: {res.get('format_score', 0)}/100\n"
56
- output += f"- **Contact Info Present**: {res.get('has_contact', False)}\n"
57
- output += f"- **Sections Detected**: {', '.join(res.get('sections_found', []))}\n\n"
58
- output += f"**Identified Entities (BERT NER)**:\n{', '.join(res.get('entities', []))}"
 
 
 
 
59
  return output
60
  except Exception as e:
61
  return f"Error: {str(e)}"
@@ -65,12 +81,15 @@ def company_insights(company_name, website):
65
  if not company_name:
66
  return "Please enter a company name."
67
  try:
68
- res = run_company_analysis(company_name, website)
69
- output = f"### Company Insights for {company_name.upper()}\n\n"
70
- output += f"- **Classification**: {res.get('classification', 'MNC')}\n"
71
- output += f"- **Confidence**: {res.get('confidence', 0)}%\n"
72
- output += f"- **Culture Sentiment**: {res.get('sentiment', 'Neutral')}\n\n"
73
- output += f"**Analysis Summary**:\n{res.get('summary', 'Analysis completed.')}"
 
 
 
74
  return output
75
  except Exception as e:
76
  return f"Error: {str(e)}"
@@ -80,17 +99,19 @@ def email_outreach(jd_text, applicant_name, applicant_skills):
80
  if not jd_text:
81
  return "Please paste the job posting text.", ""
82
  try:
83
- fields = extract_job_posting_fields(jd_text)
84
- draft = generate_outreach_email(
85
- role=fields.get("role", "Candidate"),
86
- company=fields.get("company", "Hiring Team"),
87
- email=fields.get("email", ""),
88
- applicant_name=applicant_name or "Applicant",
89
- applicant_skills=applicant_skills or "Relevant Experience",
90
- jd_text=jd_text
91
  )
92
- summary = f"**Extracted Role**: {fields.get('role', 'N/A')}\n**Company**: {fields.get('company', 'N/A')}\n**Recipient Email**: {fields.get('email', 'N/A')}"
93
- return summary, draft
 
 
 
94
  except Exception as e:
95
  return f"Error: {str(e)}", ""
96
 
@@ -137,12 +158,12 @@ with gr.Blocks(title="MALLOC() [CORE_OS]", theme=theme) as demo:
137
  raw_jd = gr.Textbox(label="Informal / WhatsApp / LinkedIn Job Post", lines=6, placeholder="🏢 Company: ...\n💼 Role: ...\n📧 Apply: ...")
138
  with gr.Column():
139
  app_name = gr.Textbox(label="Your Name", placeholder="Your Full Name")
140
- app_skills = gr.Textbox(label="Top Key Skills to Highlight", placeholder="e.g. Python, FastAPI, React")
141
  email_btn = gr.Button("✉️ Parse & Generate Personalized Outreach", variant="primary")
142
  with gr.Row():
143
  email_fields = gr.Markdown()
144
  email_draft = gr.Textbox(label="Generated Email Draft", lines=8)
145
  email_btn.click(fn=email_outreach, inputs=[raw_jd, app_name, app_skills], outputs=[email_fields, email_draft])
146
 
147
- # Launch Space
148
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
5
  import os
6
  import spaces
7
  import gradio as gr
8
+
9
+ from app.llm import call_llm
10
+ from app.services.ats_checker import calculate_ats_audit
11
+ from app.services.job_matcher import analyze_resume_vs_job
12
+ from app.services.resume_editor import generate_resume_edits
13
+ from app.services.company_insights import get_company_insights
14
+ from app.services.email_outreach import parse_informal_jd_regex, draft_application_email
15
 
16
  # --- ZeroGPU Handlers ---
17
  @spaces.GPU
 
19
  if not message.strip():
20
  return ""
21
  try:
22
+ messages = []
23
+ for user_msg, bot_msg in (history or []):
24
+ if user_msg:
25
+ messages.append({"role": "user", "content": user_msg})
26
+ if bot_msg:
27
+ messages.append({"role": "assistant", "content": bot_msg})
28
+ messages.append({"role": "user", "content": message})
29
+
30
+ response = call_llm(
31
+ messages,
32
+ system="You are malloc(), an AI Career Intelligence Assistant with long-term memory. Provide sharp, concise, actionable advice."
33
  )
34
  return response
35
  except Exception as e:
 
40
  if not resume_text or not jd_text:
41
  return "Please provide both Resume and Job Description text.", ""
42
  try:
43
+ match_res = analyze_resume_vs_job(resume_text=resume_text, job_description=jd_text)
44
+ edits_res = generate_resume_edits(resume_text=resume_text, job_description=jd_text)
45
 
46
+ summary = f"### Overall Match Score: {match_res.match_score}%\n\n"
47
+ summary += f"**Verdict**: {match_res.verdict}\n\n"
48
+ summary += f"**Matched Skills**: {', '.join(match_res.matched_skills)}\n\n"
49
+ summary += f"**Missing / Gaps**: {', '.join(match_res.missing_skills)}\n\n"
50
+ summary += f"**Summary**: {match_res.summary}"
51
 
52
  edits = "### Actionable Suggested Edits:\n"
53
+ for item in edits_res.suggestions:
54
+ edits += f"- **Original**: {item.original_text}\n - **Suggested Edit**: {item.suggested_rewrite}\n - **Rationale**: {item.rationale}\n\n"
55
 
56
  return summary, edits
57
  except Exception as e:
 
62
  if not resume_text:
63
  return "Please paste resume text to audit."
64
  try:
65
+ res = calculate_ats_audit(resume_text=resume_text, file_name="resume.txt")
66
+ output = f"### ATS Parseability Score: {res.overall_score}/100\n\n"
67
+ output += f"- **Formatting & Layout**: {res.breakdown.formatting_and_layout}/100\n"
68
+ output += f"- **Section Completeness**: {res.breakdown.section_completeness}/100\n"
69
+ output += f"- **Entity Richness**: {res.breakdown.entity_richness}/100\n"
70
+ output += f"- **Contact Info**: {res.breakdown.contact_info}/100\n\n"
71
+ output += f"**Audit Recommendations**:\n"
72
+ for item in res.audit_items:
73
+ icon = "✅" if item.status == "pass" else "⚠️" if item.status == "warning" else "❌"
74
+ output += f"- {icon} **{item.category.upper()}**: {item.message}\n"
75
  return output
76
  except Exception as e:
77
  return f"Error: {str(e)}"
 
81
  if not company_name:
82
  return "Please enter a company name."
83
  try:
84
+ res = get_company_insights(company_name=company_name, company_url=website)
85
+ output = f"### Company Insights for {res.company_name.upper()}\n\n"
86
+ output += f"- **Classification**: {res.classification.predicted_category} ({res.classification.confidence_score}% confidence)\n"
87
+ output += f"- **Industry**: {res.industry.primary_industry}\n"
88
+ output += f"- **Culture Sentiment**: {res.culture.sentiment_label} (Score: {res.culture.positive_sentiment_score}% Positive)\n\n"
89
+ output += f"**Culture Summary**:\n{res.culture.summary}\n\n"
90
+ output += f"**Interview Focus Areas**:\n"
91
+ for topic in res.interview_prep.focus_areas:
92
+ output += f"- **{topic.topic}**: {topic.description}\n"
93
  return output
94
  except Exception as e:
95
  return f"Error: {str(e)}"
 
99
  if not jd_text:
100
  return "Please paste the job posting text.", ""
101
  try:
102
+ parsed_jd = parse_informal_jd_regex(jd_text)
103
+ selected_role = (parsed_jd.get("open_positions") or ["Candidate"])[0]
104
+ draft_res = draft_application_email(
105
+ resume_text=applicant_skills or "Software Engineering background",
106
+ selected_role=selected_role,
107
+ parsed_jd=parsed_jd,
108
+ applicant_name=applicant_name or "Applicant"
 
109
  )
110
+ summary = f"**Company**: {parsed_jd.get('company_name') or 'Hiring Team'}\n"
111
+ summary += f"**Role**: {selected_role}\n"
112
+ summary += f"**Recipient HR Email**: {parsed_jd.get('hr_email') or 'Not specified in text'}\n"
113
+ summary += f"**Subject Line**: {draft_res.get('subject', '')}"
114
+ return summary, draft_res.get("body", "")
115
  except Exception as e:
116
  return f"Error: {str(e)}", ""
117
 
 
158
  raw_jd = gr.Textbox(label="Informal / WhatsApp / LinkedIn Job Post", lines=6, placeholder="🏢 Company: ...\n💼 Role: ...\n📧 Apply: ...")
159
  with gr.Column():
160
  app_name = gr.Textbox(label="Your Name", placeholder="Your Full Name")
161
+ app_skills = gr.Textbox(label="Top Key Skills / Experience Snippet", placeholder="e.g. Python, FastAPI, React, 2 years experience")
162
  email_btn = gr.Button("✉️ Parse & Generate Personalized Outreach", variant="primary")
163
  with gr.Row():
164
  email_fields = gr.Markdown()
165
  email_draft = gr.Textbox(label="Generated Email Draft", lines=8)
166
  email_btn.click(fn=email_outreach, inputs=[raw_jd, app_name, app_skills], outputs=[email_fields, email_draft])
167
 
168
+ if __name__ == "__main__":
169
+ demo.launch(server_name="0.0.0.0", server_port=7860)