Spaces:
Sleeping
Sleeping
import os | |
import json | |
import requests | |
import streamlit as st | |
from datetime import datetime | |
from docx import Document | |
from PyPDF2 import PdfReader | |
# ------------------------------------------------------------------------------ | |
# π CONFIGURATION - API & SETTINGS | |
# ------------------------------------------------------------------------------ | |
GROQ_API_KEY = os.getenv("GROQ_API") | |
GROQ_ENDPOINT = "https://api.groq.com/openai/v1/chat/completions" | |
GROQ_MODEL = "llama-3.3-70b-versatile" | |
# ------------------------------------------------------------------------------ | |
# π₯ API HANDLER FOR GROQ AI | |
# ------------------------------------------------------------------------------ | |
def call_groq_api(messages, temperature=0.7): | |
"""Handles API calls to Groq's Llama 3.3 model with robust error handling.""" | |
headers = { | |
"Authorization": f"Bearer {GROQ_API_KEY}", | |
"Content-Type": "application/json" | |
} | |
payload = { | |
"model": GROQ_MODEL, | |
"messages": messages, | |
"temperature": temperature, | |
"max_tokens": 1024 | |
} | |
try: | |
response = requests.post(GROQ_ENDPOINT, headers=headers, json=payload, timeout=15) | |
response.raise_for_status() | |
return response.json()["choices"][0]["message"]["content"].strip() | |
except requests.exceptions.RequestException as e: | |
st.error(f"β API Request Failed: {e}") | |
return None | |
# ------------------------------------------------------------------------------ | |
# π FILE PROCESSING (PDF / DOCX) | |
# ------------------------------------------------------------------------------ | |
def extract_resume_text(file_obj): | |
"""Extracts text from uploaded resumes (PDF, DOCX, TXT).""" | |
file_bytes = file_obj.read() | |
file_obj.seek(0) | |
ext = os.path.splitext(file_obj.name)[-1].lower() | |
if ext == ".pdf": | |
return "\n".join(page.extract_text() for page in PdfReader(file_bytes).pages if page.extract_text()) | |
elif ext in [".docx", ".doc"]: | |
return "\n".join([para.text for para in Document(file_bytes).paragraphs]) | |
else: | |
return file_bytes.decode("utf-8", errors="ignore") | |
# ------------------------------------------------------------------------------ | |
# π― AI-POWERED RESUME GENERATION | |
# ------------------------------------------------------------------------------ | |
def generate_resume(first_name, last_name, location, work_experience, school_experience, skills): | |
"""Generates a structured, ATS-friendly resume.""" | |
candidate_data = json.dumps({ | |
"first_name": first_name, | |
"last_name": last_name, | |
"location": location, | |
"work_experience": work_experience, | |
"school_experience": school_experience, | |
"skills": skills | |
}, indent=2) | |
messages = [ | |
{"role": "system", "content": "You are a professional resume writer specializing in ATS optimization."}, | |
{"role": "user", "content": f""" | |
Generate a **highly professional**, **ATS-optimized resume** using the following structured information: | |
{candidate_data} | |
- Ensure proper formatting: Name, Contact, Summary, Experience, Education, Skills, Certifications. | |
- Use industry best practices. | |
- Format each job with measurable achievements. | |
"""} | |
] | |
return call_groq_api(messages, temperature=0.5) | |
# ------------------------------------------------------------------------------ | |
# βοΈ AI-POWERED COVER LETTER GENERATION | |
# ------------------------------------------------------------------------------ | |
def generate_cover_letter(candidate_json, job_description): | |
"""Generates a compelling cover letter using structured candidate details.""" | |
date_str = datetime.today().strftime("%d - %b - %Y") | |
messages = [ | |
{"role": "system", "content": "You are a top-tier career advisor. Write highly persuasive cover letters."}, | |
{"role": "user", "content": f""" | |
Generate a **professional cover letter** using: | |
- Candidate Profile: {candidate_json} | |
- Job Description: {job_description} | |
- Date: {date_str} | |
- Ensure **persuasion**, **tailored content**, and **measurable achievements**. | |
- Format: **Introduction, Key Skills, Experience Alignment, Closing**. | |
"""} | |
] | |
return call_groq_api(messages, temperature=0.6) | |
# ------------------------------------------------------------------------------ | |
# π¨ STREAMLIT UI DESIGN | |
# ------------------------------------------------------------------------------ | |
st.set_page_config(page_title="AI Resume & Cover Letter Generator", layout="wide") | |
st.title("π AI-Powered Resume & Cover Letter Generator") | |
st.markdown("### Create a **perfect ATS-friendly Resume** and **tailored Cover Letter** using **Groq AI (Llama 3.3-70B)**") | |
tabs = st.tabs(["π Cover Letter Generator", "π Resume Creator"]) | |
# ----- COVER LETTER GENERATOR ----- | |
with tabs[0]: | |
st.header("π Cover Letter Generator") | |
resume_file = st.file_uploader("Upload Your Resume", type=["pdf", "docx", "txt"]) | |
job_description = st.text_area("Paste Job Description", height=200) | |
if st.button("πΉ Generate Cover Letter"): | |
if resume_file and job_description.strip(): | |
with st.spinner("β¨ Processing resume..."): | |
resume_text = extract_resume_text(resume_file) | |
candidate_json = generate_resume("First", "Last", "Houston, TX", "Experience", "Education", "Skills") | |
cover_letter = generate_cover_letter(candidate_json, job_description) | |
st.success("β Cover Letter Generated!") | |
st.text_area("π Your Cover Letter:", cover_letter, height=300) | |
else: | |
st.warning("β οΈ Please upload a resume and paste the job description.") | |
# ----- RESUME CREATOR ----- | |
with tabs[1]: | |
st.header("π Resume Creator") | |
with st.form("resume_form"): | |
col1, col2 = st.columns(2) | |
first_name = col1.text_input("First Name") | |
last_name = col2.text_input("Last Name") | |
location = st.text_input("Location") | |
work_experience = st.text_area("Work Experience", height=150) | |
school_experience = st.text_area("Education", height=150) | |
skills = st.text_area("Skills", height=100) | |
submit = st.form_submit_button("π Generate Resume") | |
if submit: | |
with st.spinner("π Creating Resume..."): | |
resume_text = generate_resume(first_name, last_name, location, work_experience, school_experience, skills) | |
st.success("β Resume Generated!") | |
st.text_area("π Your Resume:", resume_text, height=400) | |