File size: 6,518 Bytes
6798e8f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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()