import gradio as gr import pdfplumber from fetcher import fetch_jobs from formatter import format_jobs from cover_letter import generate_cover_letter # store jobs globally so cover letter tab can access them job_store = [] def read_cv(cv_file): if cv_file is None: return "" try: with pdfplumber.open(cv_file.name) as pdf: text = "" for page in pdf.pages: text += page.extract_text() or "" return text except Exception as e: return f"Could not read CV: {e}" def search_jobs(job_title): global job_store jobs = fetch_jobs(job_title) job_store = jobs if not jobs: return "No jobs found. Try a broader search term." formatted = format_jobs(jobs, job_title, "") return formatted def create_cover_letter(job_number, cv_file): global job_store cv_text = read_cv(cv_file) if not cv_text: return "Please upload your CV first." if not job_store: return "Please search for jobs first." try: index = int(job_number) - 1 job = job_store[index] except Exception: return "Invalid job number. Please enter a number from the job results." return generate_cover_letter( job["title"], job["company"], job["description"], cv_text ) with gr.Blocks(title="AI Job Finder Agent") as ui: gr.Markdown("# 🤖 AI Job Finder Agent") gr.Markdown("Find remote jobs and generate tailored cover letters from your CV") with gr.Tab("🔍 Find Jobs"): job_input = gr.Textbox( label="What role are you looking for?", placeholder="e.g. Python Developer, Designer, Data Analyst..." ) search_btn = gr.Button("Find Jobs", variant="primary") job_results = gr.Markdown() status_text = gr.Textbox(label="Status", interactive=False, value="Idle") def search_jobs_with_status(job_title): if not job_title or not job_title.strip(): return "", "Please enter a search query." return search_jobs(job_title), "Search completed" search_btn.click( fn=search_jobs_with_status, inputs=[job_input], outputs=[job_results, status_text] ) with gr.Tab("✉️ Generate Cover Letter"): gr.Markdown("Upload your CV and enter the job number from the search results") cv_upload = gr.File(label="Upload CV (PDF)", file_types=[".pdf"]) job_number = gr.Textbox( label="Job Number", placeholder="e.g. 1, 2, 3..." ) cl_btn = gr.Button("Generate Cover Letter", variant="primary") cl_output = gr.Markdown() cl_status = gr.Textbox(label="Status", interactive=False, value="Idle") def create_cover_letter_with_status(job_number, cv_file): if not job_number or not str(job_number).isdigit(): return "", "Invalid job number" if not cv_file: return "", "Upload CV first" return create_cover_letter(job_number, cv_file), "Cover letter generated" cl_btn.click( fn=create_cover_letter_with_status, inputs=[job_number, cv_upload], outputs=[cl_output, cl_status] ) ui.launch()