import os import sys import importlib.util BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Add structural paths for submodules if BASE_DIR not in sys.path: sys.path.insert(0, BASE_DIR) JOB_FINDER_DIR = os.path.join(BASE_DIR, "Job Finder") LEAD_AGENT_DIR = os.path.join(BASE_DIR, "Lead Agent") if JOB_FINDER_DIR not in sys.path: sys.path.insert(0, JOB_FINDER_DIR) if LEAD_AGENT_DIR not in sys.path: sys.path.insert(0, LEAD_AGENT_DIR) import gradio as gr from agent import generate_report # Dynamic loader helper def load_module_from_path(name, path): spec = importlib.util.spec_from_file_location(name, path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module # Lazy module caches: each tab can fail independently without crashing the whole app. job_fetcher = None job_formatter = None job_cover_letter = None lead_crew = None def ensure_job_modules_loaded(): global job_fetcher, job_formatter, job_cover_letter if job_fetcher and job_formatter and job_cover_letter: return job_fetcher = load_module_from_path("job_fetcher", os.path.join(JOB_FINDER_DIR, "fetcher.py")) job_formatter = load_module_from_path("job_formatter", os.path.join(JOB_FINDER_DIR, "formatter.py")) job_cover_letter = load_module_from_path("job_cover_letter", os.path.join(JOB_FINDER_DIR, "cover_letter.py")) def ensure_lead_module_loaded(): global lead_crew if lead_crew: return lead_crew = load_module_from_path("lead_crew", os.path.join(LEAD_AGENT_DIR, "crew.py")) # Job Finder state job_store = [] def search_jobs_wrapper(job_title): global job_store if not job_title or not job_title.strip(): return "Please enter a job title." try: ensure_job_modules_loaded() jobs = job_fetcher.fetch_jobs(job_title) except Exception as e: return f"Job Finder failed to load: {e}" job_store = jobs if not jobs: return "No jobs found. Try a broader search term." try: return job_formatter.format_jobs(jobs, job_title, "") except Exception as e: return f"Job formatting failed: {e}" def search_jobs_with_status(job_title): return search_jobs_wrapper(job_title), "Completed" def create_cover_letter_wrapper(job_number, cv_file): global job_store try: ensure_job_modules_loaded() except Exception as e: return f"Job Finder failed to load: {e}" if cv_file is None: return "Please upload your CV first." cv_text = "" try: import pdfplumber with pdfplumber.open(cv_file.name) as pdf: for page in pdf.pages: cv_text += page.extract_text() or "" except Exception as e: return f"Could not read CV: {e}" 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." try: return job_cover_letter.generate_cover_letter( job["title"], job["company"], job["description"], cv_text ) except Exception as e: return f"Cover letter generation failed: {e}" def create_cover_letter_with_status(job_number, cv_file): return create_cover_letter_wrapper(job_number, cv_file), "Completed" def generate_report_with_status(topic): if not topic or not topic.strip(): return "Please enter a topic.", "Idle" try: return generate_report(topic), "Completed" except Exception as e: return f"Research agent failed: {e}", "Failed" def generate_leads_wrapper(target_audience, service, sender_name): if not target_audience or not service or not sender_name: return "Please fill in all fields.", "Idle" try: ensure_lead_module_loaded() result = lead_crew.run_lead_gen(target_audience, service, sender_name) return result, "Completed" except Exception as e: return f"Lead Agent failed: {e}", "Failed" with gr.Blocks(title="AI All-in-One Agents") as ui: gr.Markdown("# AI All-in-One Agents\nUse the tabs to switch between Research, Job Finder, and Lead Gen agents.") with gr.Tab("Research & Report"): topic_input = gr.Textbox(label="Topic", placeholder="Enter research topic...", lines=1) topic_btn = gr.Button("Generate Report") topic_output = gr.Markdown() topic_status = gr.Textbox(label="Status", interactive=False, value="Idle") topic_btn.click( fn=generate_report_with_status, inputs=[topic_input], outputs=[topic_output, topic_status], show_progress=True, ) with gr.Tab("Job Finder"): job_input = gr.Textbox(label="Job title", placeholder="e.g. Python Developer") job_btn = gr.Button("Find Jobs") jobs_output = gr.Markdown() jobs_status = gr.Textbox(label="Status", interactive=False, value="Idle") job_btn.click( fn=search_jobs_with_status, inputs=[job_input], outputs=[jobs_output, jobs_status], show_progress=True, ) gr.Markdown("---") cv_upload = gr.File(label="Upload CV (PDF)", file_types=[".pdf"]) job_number = gr.Textbox(label="Job number", placeholder="e.g. 1") cover_btn = gr.Button("Generate Cover Letter") cover_output = gr.Markdown() cover_status = gr.Textbox(label="Status", interactive=False, value="Idle") cover_btn.click( fn=create_cover_letter_with_status, inputs=[job_number, cv_upload], outputs=[cover_output, cover_status], show_progress=True, ) with gr.Tab("Lead Gen & Outreach"): target_input = gr.Textbox(label="Target Audience", placeholder="e.g. digital marketing agencies") service_input = gr.Textbox(label="Your Service", placeholder="e.g. AI automation consulting") name_input = gr.Textbox(label="Your Name", placeholder="e.g. Uche") lead_btn = gr.Button("Generate Leads") lead_output = gr.Markdown() status_output = gr.Textbox(label="Status", interactive=False, value="Idle") lead_btn.click( fn=generate_leads_wrapper, inputs=[target_input, service_input, name_input], outputs=[lead_output, status_output], show_progress=True, ) ui.launch()