Spaces:
Sleeping
Sleeping
| """Interview scheduling UI components""" | |
| import streamlit as st | |
| import datetime | |
| from agents.interview_scheduler import InterviewScheduler | |
| from db.database import ResumeMatchDB | |
| def handle_interview_scheduling(result, match): | |
| """Handle interview scheduling for a candidate""" | |
| st.subheader("π Schedule Interview") | |
| interview_key = f"interview_{result['candidate_id']}" | |
| if interview_key not in st.session_state.interview_data: | |
| st.session_state.interview_data[interview_key] = { | |
| "interviewer": "", | |
| "meeting_link": "", | |
| "notes": "", | |
| "selected_slot": None | |
| } | |
| data = st.session_state.interview_data[interview_key] | |
| data["interviewer"] = st.text_input( | |
| "Interviewer Name", | |
| value=data["interviewer"], | |
| key=f"interviewer_{result['candidate_id']}" | |
| ) | |
| data["meeting_link"] = st.text_input( | |
| "Meeting Link (optional)", | |
| value=data["meeting_link"], | |
| key=f"meeting_{result['candidate_id']}" | |
| ) | |
| data["notes"] = st.text_area( | |
| "Additional Notes", | |
| value=data["notes"], | |
| key=f"notes_{result['candidate_id']}" | |
| ) | |
| scheduler = InterviewScheduler(result['candidate_name']) | |
| start_date = datetime.datetime.now() + datetime.timedelta(days=1) | |
| slots = scheduler.generate_interview_slots(start_date) | |
| data["selected_slot"] = st.selectbox( | |
| "Select Interview Slot", | |
| options=slots, | |
| format_func=lambda x: x.strftime("%A, %B %d, %Y at %I:%M %p"), | |
| key=f"slot_{result['candidate_id']}", | |
| index=slots.index(data["selected_slot"]) if data["selected_slot"] in slots else 0 | |
| ) | |
| if st.button("Schedule Interview", key=f"schedule_{result['candidate_id']}"): | |
| if data["selected_slot"] and data["interviewer"]: | |
| schedule_interview(result, match, data) | |
| else: | |
| st.error("Please provide interviewer name and select a time slot") | |
| def schedule_interview(result, match, data): | |
| """Schedule an interview, update session state, and send email notification""" | |
| db = ResumeMatchDB() | |
| scheduler = InterviewScheduler(result['candidate_name']) | |
| # Format date and time for email | |
| interview_date = data["selected_slot"].strftime("%A, %B %d, %Y") | |
| interview_time = data["selected_slot"].strftime("%I:%M %p %Z") | |
| # Generate meeting link HTML if available | |
| meeting_link_html = f"<p><strong>Meeting Link:</strong> <a href='{data['meeting_link']}'>{data['meeting_link']}</a></p>" if data['meeting_link'] else "" | |
| # Prepare email content | |
| email_subject = f"Interview Scheduled: {match['job_title']} on {interview_date}" | |
| email_body = f""" | |
| <p>Dear {result['candidate_name']},</p> | |
| <p>Your interview has been successfully scheduled for the position of <strong>{match['job_title']}</strong>.</p> | |
| <div style="background-color: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0;"> | |
| <h3 style="color: #2c3e50; margin-top: 0;">Interview Details</h3> | |
| <p><strong>Date:</strong> {interview_date}</p> | |
| <p><strong>Time:</strong> {interview_time}</p> | |
| <p><strong>Interviewer:</strong> {data['interviewer']}</p> | |
| {meeting_link_html} | |
| {f"<p><strong>Notes:</strong> {data['notes']}</p>" if data['notes'] else ""} | |
| </div> | |
| <p>Please ensure you have the following ready for the interview:</p> | |
| <ul> | |
| <li>A copy of your resume</li> | |
| <li>Any relevant work samples or portfolio items</li> | |
| <li>Questions you may have about the role</li> | |
| </ul> | |
| <p>If you need to reschedule or have any questions, please reply to this email.</p> | |
| <p style="margin-top: 30px;"> | |
| Best regards,<br> | |
| <strong>ResumeIQ Hiring Team</strong> | |
| </p> | |
| """ | |
| # Save to database | |
| db.schedule_interview( | |
| candidate_id=result['candidate_id'], | |
| job_id=match['job_id'], | |
| scheduled_date=data["selected_slot"], | |
| interviewer=data["interviewer"], | |
| meeting_link=data["meeting_link"], | |
| notes=data["notes"] | |
| ) | |
| # Update session state | |
| st.session_state.scheduled_interviews.append({ | |
| "candidate_id": result['candidate_id'], | |
| "candidate_name": result['candidate_name'], | |
| "job_title": match['job_title'], | |
| "interview_date": data["selected_slot"], | |
| "interviewer": data["interviewer"] | |
| }) | |
| # Send email notification | |
| from utils.email_sender import EmailSender | |
| email_sender = EmailSender() | |
| if email_sender.smtp_email and email_sender.smtp_password: | |
| try: | |
| email_sender.send_email( | |
| to_email=result['candidate_email'], | |
| subject=email_subject, | |
| body=email_body | |
| ) | |
| st.success("β Interview Scheduled & Email Sent!") | |
| except Exception as e: | |
| st.success("β Interview Scheduled!") | |
| st.warning(f"β οΈ Could not send email: {str(e)}") | |
| else: | |
| st.success("β Interview Scheduled!") | |
| st.warning("β οΈ Email not sent: SMTP not configured") | |
| # Show interview details | |
| st.write("### Interview Details") | |
| st.write(f"**Candidate:** {result['candidate_name']}") | |
| st.write(f"**Position:** {match['job_title']}") | |
| st.write(f"**Date & Time:** {interview_date} at {interview_time}") | |
| st.write(f"**Interviewer:** {data['interviewer']}") | |
| if data['meeting_link']: | |
| st.markdown(f"**Meeting Link:** [{data['meeting_link']}]({data['meeting_link']})") | |
| if data['notes']: | |
| st.write("**Notes:**", data['notes']) | |
| def display_scheduled_interviews(): | |
| """Display scheduled interviews and handle feedback""" | |
| st.subheader("π Upcoming Interviews") | |
| db = ResumeMatchDB() | |
| interviews = db.get_scheduled_interviews(status='pending') | |
| if interviews: | |
| with st.container(): | |
| for interview in interviews: | |
| col1, col2 = st.columns([3, 1]) | |
| with col1: | |
| st.markdown(f""" | |
| **π€ {interview['candidate_name']}** | |
| **πΌ {interview['job_title']}** | |
| **π {_format_date(interview['scheduled_date'])}** | |
| **π {interview['interviewer'] or 'Interviewer not specified'}** | |
| """) | |
| if interview['meeting_link']: | |
| st.markdown(f"**π [Join Meeting]({interview['meeting_link']})**") | |
| if interview['notes']: | |
| st.write(interview['notes']) | |
| with col2: | |
| if st.button("β Complete", key=f"complete_{interview['id']}"): | |
| db.update_interview_status(interview['id'], 'completed') | |
| st.rerun() | |
| st.markdown("---") | |
| else: | |
| st.info("No upcoming interviews scheduled.") | |
| def _format_date(date_str): | |
| """Format date string for better readability""" | |
| if date_str is None: | |
| return "Not scheduled" | |
| if isinstance(date_str, str): | |
| try: | |
| date_obj = datetime.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') | |
| except ValueError: | |
| return date_str | |
| else: | |
| date_obj = date_str | |
| return date_obj.strftime('%a, %b %d, %I:%M %p') | |