Spaces:
Running
Running
File size: 16,000 Bytes
7a18af6 f703328 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
import streamlit as st
from crewai import Crew
from jd_generator import jd_generator, create_jd_task
from resume_ranker import resume_ranker, create_resume_rank_task
from email_automation import email_automation, create_email_task, simulate_email_api
from interview_scheduler import interview_scheduler, create_schedule_task, simulate_calendar_api, create_schedule_summary_task
from interview_agent import interview_agent, create_interview_task, evaluate_response_task
from hire_recommendation import hire_recommendation_agent, create_hire_recommendation_task
from sentiment_analyzer import sentiment_analyzer, create_sentiment_task
from datetime import datetime
import os
import logging
from streamlit_extras.add_vertical_space import add_vertical_space
# Setup logging
logging.basicConfig(filename="Logs/app.log", level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
st.set_page_config(page_title="AI Recruitment System", layout="wide")
st.title("AI Recruitment System")
# MCP Context
if "mcp_context" not in st.session_state:
st.session_state.mcp_context = {
"job_description": None,
"ranked_resumes": None,
"scheduled_time": None,
"interview_transcript": None
}
# Sidebar for transparency
st.sidebar.markdown("""
### AI Capabilities & Limitations
- **Powered by llama3-70b-8192**: Generates human-like text but may produce inaccuracies.
- **RAG**: Enhances outputs with web data, limited by search quality.
- **Simulation**: Email and calendar APIs are simulated.
### Ethical Hiring
Data is processed in-memory and not stored unless saved by the user.
""")
tabs = st.tabs([
"JD Generator", "Resume Ranker", "Email Automation", "Interview Scheduler",
"Interview Agent", "Hire Recommendation", "Sentiment Analyzer"
])
# Tab 1: JD Generator
with tabs[0]:
st.header("JD Generator")
with st.expander("Template & Inputs", expanded=True):
st.markdown("**Upload a JD template** *(optional, defaults to Templates/jd_template.txt)*")
template_file = st.file_uploader("Upload JD Template (.txt)", type=["txt"], key="jd_template")
if template_file:
with open("Templates/jd_template.txt", "wb") as f:
f.write(template_file.read())
job_title = st.text_input("Job Title", "e.g., Senior Python Developer", key="jd_job_title", help="Enter the job title")
skills = st.text_area("Required Skills", "e.g., Python, Flask, SQL, AWS", key="jd_skills")
experience_level = st.text_input("Experience Level", "e.g., 5+ years", key="jd_experience")
if st.button("Generate Job Description", key="jd_button", help="Generate a detailed job description"):
if job_title and skills and experience_level:
with st.spinner("Generating detailed JD..."):
try:
jd_task = create_jd_task(job_title, skills, experience_level)
crew = Crew(agents=[jd_generator], tasks=[jd_task], verbose=True)
result = crew.kickoff()
st.session_state.mcp_context["job_description"] = result
st.subheader("Generated Job Description")
st.markdown(result) # Use markdown to render formatted output
logging.info(f"JD generated for {job_title}")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"JD generation failed: {str(e)}")
else:
st.error("Fill in all fields.")
logging.warning("JD generation attempted with missing fields")
# Tab 2: Resume Ranker
with tabs[1]:
st.header("Resume Ranker")
with st.expander("Inputs", expanded=True):
job_desc = st.text_area("Job Description", value=st.session_state.mcp_context["job_description"] or "", key="resume_job_desc", help="Paste or enter job description")
dir_path = st.text_input("Directory Path", "e.g., D:/resumes", key="dir_path")
uploaded_files = st.file_uploader("Upload Resume PDFs", type=["pdf"], accept_multiple_files=True, key="resume_files")
if st.button("Rank Resumes", key="resume_button", help="Rank uploaded or directory resumes"):
if job_desc:
if (dir_path and os.path.isdir(dir_path)) or uploaded_files:
with st.spinner("Ranking resumes..."):
try:
task = create_resume_rank_task(job_desc, dir_path, uploaded_files)
if task:
crew = Crew(agents=[resume_ranker], tasks=[task], verbose=True)
result = crew.kickoff()
st.session_state.mcp_context["ranked_resumes"] = result
st.subheader("Ranked Resumes")
st.write(result)
logging.info("Resumes ranked")
else:
st.error("No valid resumes found.")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Resume ranking failed: {str(e)}")
else:
st.error("Provide a directory path or upload resumes.")
else:
st.error("Provide a job description.")
# Tab 3: Email Automation (Personalized AI-Generated Content)
with tabs[2]:
st.header("Email Automation")
with st.expander("Email Details", expanded=True):
st.markdown("**Enter details for a personalized email**")
candidate_name = st.text_input("Candidate Name", "e.g., John Doe", key="email_candidate", help="Candidate's full name")
job_title_email = st.text_input("Job Title", "e.g., Senior Python Developer", key="email_job_title", help="Job title for the email")
email_type = st.selectbox("Email Type", ["interview_invite", "hiring_team_update"], key="email_type", help="Choose email purpose")
details = st.text_area("Details", value=st.session_state.mcp_context["scheduled_time"] or "e.g., March 25, 2025, 10 AM", key="email_details", help="e.g., interview time or update details")
recipient_email = st.text_input("Recipient Email", "e.g., [email protected]", key="email_recipient", help="Recipient's email address")
if st.button("Send Email", key="email_button", help="Generate and simulate sending a personalized email"):
if candidate_name and job_title_email and details and recipient_email:
with st.spinner("Generating personalized email..."):
try:
task = create_email_task(candidate_name, email_type, job_title_email, details, recipient_email)
crew = Crew(agents=[email_automation], tasks=[task], verbose=True)
email_content = crew.kickoff()
result = simulate_email_api(email_content, recipient_email)
st.subheader("Email Content")
st.write(email_content)
st.subheader("API Response")
st.write(result)
logging.info(f"Email simulated for {recipient_email}")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Email generation failed: {str(e)}")
else:
st.error("Fill in all fields.")
# Tab 4: Interview Scheduler (Candidate Availability Only)
with tabs[3]:
st.header("Interview Scheduler")
with st.expander("Scheduling Details", expanded=True):
st.markdown("**Enter candidate availability** ")
candidate_name_sched = st.text_input("Candidate Name", "e.g., John Doe", key="sched_candidate", help="Candidate's full name")
job_title_sched = st.text_input("Job Title", "e.g., Senior Python Developer", key="sched_job_title", help="Job title for the interview")
candidate_avail = st.text_area("Candidate Availability", "e.g., March 25, 2025, 9 AM - 12 PM", key="sched_candidate_avail", help="e.g., March 25, 2025, 9 AM - 12 PM")
if st.button("Schedule Interview", key="sched_button", help="Schedule the interview based on candidate availability"):
if candidate_name_sched and job_title_sched and candidate_avail:
with st.spinner("Scheduling interview..."):
try:
time_task = create_schedule_task(job_title_sched, candidate_name_sched, candidate_avail)
crew = Crew(agents=[interview_scheduler], tasks=[time_task], verbose=True)
scheduled_time_str = crew.kickoff()
scheduled_time = datetime.strptime(scheduled_time_str, "%B %d, %Y, %I:%M %p")
calendar_result = simulate_calendar_api(candidate_name_sched, job_title_sched, scheduled_time)
st.session_state.mcp_context["scheduled_time"] = scheduled_time_str
summary_task = create_schedule_summary_task(candidate_name_sched, job_title_sched, scheduled_time_str)
crew = Crew(agents=[interview_scheduler], tasks=[summary_task], verbose=True)
summary = crew.kickoff()
st.subheader("Scheduled Time")
st.write(scheduled_time_str)
st.subheader("Calendar Response")
st.write(calendar_result)
st.subheader("Interview Summary")
st.write(summary)
logging.info(f"Interview scheduled for {candidate_name_sched} with summary")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Scheduling failed: {str(e)}")
else:
st.error("Fill in all fields.")
logging.warning("Scheduling attempted with missing fields")
# Tab 5: Interview Agent
with tabs[4]:
st.header("Interview Agent")
with st.expander("Job Description", expanded=True):
st.markdown("**Enter the job description** *(e.g., Senior Python Developer requiring...)*")
job_desc_interview = st.text_area("Job Description", value=st.session_state.mcp_context["job_description"] or "", key="interview_job_desc")
if "interview_history" not in st.session_state:
st.session_state.interview_history = []
if "current_question" not in st.session_state:
st.session_state.current_question = None
if st.button("Start Interview", key="start_interview", help="Begin the interview"):
if job_desc_interview:
with st.spinner("Generating Initial Question..."):
try:
task = create_interview_task(job_desc_interview)
crew = Crew(agents=[interview_agent], tasks=[task], verbose=True)
question = crew.kickoff()
st.session_state.current_question = question
st.session_state.interview_history = [{"role": "agent", "content": str(question)}]
logging.info("Interview started")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Interview start failed: {str(e)}")
else:
st.error("Provide a job description.")
if st.session_state.interview_history:
st.subheader("Conversation History")
for message in st.session_state.interview_history:
st.write(f"**{message['role'].capitalize()}**: {message['content']}")
if st.session_state.current_question:
candidate_response = st.text_area("Your Response", key="candidate_response", value="", height=100)
if st.button("Submit Response", key="submit_response", help="Submit your answer"):
if candidate_response:
with st.spinner("Generating Follow-up..."):
try:
st.session_state.interview_history.append({"role": "candidate", "content": candidate_response})
eval_task = evaluate_response_task(job_desc_interview, st.session_state.interview_history, candidate_response)
crew = Crew(agents=[interview_agent], tasks=[eval_task], verbose=True)
follow_up = crew.kickoff()
st.session_state.current_question = follow_up
st.session_state.interview_history.append({"role": "agent", "content": str(follow_up)})
st.session_state.mcp_context["interview_transcript"] = "\n".join([f"{m['role']}: {m['content']}" for m in st.session_state.interview_history])
st.experimental_rerun()
logging.info("Follow-up question generated")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Follow-up generation failed: {str(e)}")
else:
st.error("Provide a response.")
# Tab 6: Hire Recommendation
with tabs[5]:
st.header("Hire Recommendation Agent")
with st.expander("Transcript Input", expanded=True):
transcript_default = st.session_state.mcp_context["interview_transcript"] or ""
transcript_file = st.file_uploader("Upload Transcript (.txt)", type=["txt"], key="hire_transcript")
transcript_text = st.text_area("Or Paste Transcript", value=transcript_default, key="hire_transcript_text")
if st.button("Generate Recommendation", key="hire_button", help="Analyze transcript for hiring decision"):
transcript = transcript_file.read().decode("utf-8") if transcript_file else transcript_text
if transcript:
with st.spinner("Analyzing Transcript..."):
try:
task = create_hire_recommendation_task(transcript)
crew = Crew(agents=[hire_recommendation_agent], tasks=[task], verbose=True)
result = crew.kickoff()
st.subheader("Hiring Recommendation")
st.write(result)
logging.info("Hiring recommendation generated")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Hire recommendation failed: {str(e)}")
else:
st.error("Upload a file or paste a transcript.")
# Tab 7: Sentiment Analyzer
with tabs[6]:
st.header("Sentiment Analyzer")
with st.expander("Transcript Input", expanded=True):
sentiment_default = st.session_state.mcp_context["interview_transcript"] or ""
sentiment_file = st.file_uploader("Upload Transcript (.txt)", type=["txt"], key="sentiment_transcript")
sentiment_text = st.text_area("Or Paste Transcript", value=sentiment_default, key="sentiment_transcript_text")
if st.button("Analyze Sentiment", key="sentiment_button", help="Analyze transcript sentiment"):
transcript = sentiment_file.read().decode("utf-8") if sentiment_file else sentiment_text
if transcript:
with st.spinner("Analyzing Sentiment..."):
try:
task = create_sentiment_task(transcript)
crew = Crew(agents=[sentiment_analyzer], tasks=[task], verbose=True)
result = crew.kickoff()
st.subheader("Sentiment Analysis")
st.write(result)
logging.info("Sentiment analysis completed")
except Exception as e:
st.error(f"Error: {str(e)}. See Logs/app.log for details.")
logging.error(f"Sentiment analysis failed: {str(e)}")
else:
st.error("Upload a file or paste a transcript.")
add_vertical_space(2) |