OppaAI's picture
Update app.py
be9d87d verified
raw
history blame
5.74 kB
import gradio as gr
from fastmcp import FastMCP
import logging
import requests
from datetime import datetime
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
mcp = FastMCP("Jobicy Canada Remote Jobs Agent")
@mcp.tool(name="search_jobs")
def search_jobs_tool(query: str = "", location: str = "", limit: int = 20) -> dict:
"""
Search for remote jobs using the Jobicy API.
Args:
query (str): Optional job title or keyword to filter results.
location (str): Optional country or location (e.g., "canada", "united states").
Use "Anywhere" or leave blank for global search.
limit (int): Maximum number of job results to return (1–50).
Returns:
dict: A dictionary with either a list of jobs (under "jobs") or an "error" message.
"""
base_url = "https://jobicy.com/api/v2/remote-jobs"
params = {}
if query.strip():
params["tag"] = query.strip()
if location.strip() and location.strip().lower() != "anywhere":
params["geo"] = location.strip().lower()
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/126.0.0.0 Safari/537.36"
}
try:
logger.info(f"Requesting Jobicy API with params: {params}")
response = requests.get(base_url, params=params, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
jobs_raw = data.get("jobs", [])
jobs = []
for job in jobs_raw:
salary_min = job.get("annualSalaryMin")
salary_max = job.get("annualSalaryMax")
currency = job.get("salaryCurrency", "")
if salary_min and salary_min != 0 and salary_max and salary_max != 0:
salary_str = f"{salary_min} - {salary_max} {currency}".strip()
else:
salary_str = "Not specified"
jobs.append({
"title": job.get("jobTitle", "No Title"),
"company": job.get("companyName", "Unknown Company"),
"location": job.get("jobGeo", "Remote"),
"url": job.get("url", "#"),
"pubDate": job.get("pubDate", "Unknown Date"),
"salary": salary_str
})
def parse_date(job):
try:
return datetime.fromisoformat(job["pubDate"].replace("Z", "+00:00"))
except Exception:
return datetime.min
jobs.sort(key=parse_date, reverse=True)
jobs = jobs[:limit]
logger.info(f"Found {len(jobs)} jobs from Jobicy after sorting.")
return {"jobs": jobs}
except requests.exceptions.HTTPError as http_err:
logger.error(f"HTTP error: {http_err}")
return {"error": f"HTTP error occurred: {http_err}"}
except requests.exceptions.Timeout:
logger.error("Request timed out.")
return {"error": "Request timed out. Please try again later."}
except requests.exceptions.RequestException as req_err:
logger.error(f"Request error: {req_err}")
return {"error": f"Request error: {req_err}"}
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
return {"error": f"Unexpected error: {str(e)}"}
def search_jobs_ui(query="", location="", limit=10):
limit = int(max(1, min(limit, 50)))
result = search_jobs_tool(query, location, limit)
if "error" in result:
return f"❌ Error: {result['error']}"
jobs = result.get("jobs", [])
if not jobs:
return "No jobs found for your search. Try different keywords or location."
output = "# Jobicy Remote Job Search Results\n\n"
for i, job in enumerate(jobs, 1):
try:
posted_date = job['pubDate'][:10]
except Exception:
posted_date = job['pubDate']
output += (
f"### {i}. {job['title']}\n\n"
f"Company: {job['company']}\n\n"
f"Location: {job['location']}\n\n"
f"Salary: {job['salary']}\n\n"
f"Posted On: {posted_date}\n\n"
f"[Apply Here]({job['url']})\n\n"
"---\n\n"
)
return output
country_choices = [
"Anywhere",
"argentina", "australia", "austria", "bangladesh", "belgium", "brazil", "canada", "chile", "china",
"colombia", "czech republic", "denmark", "egypt", "estonia", "finland", "france", "germany", "ghana",
"greece", "hong kong", "hungary", "iceland", "india", "indonesia", "ireland", "israel", "italy", "japan",
"kenya", "latvia", "lithuania", "malaysia", "mexico", "netherlands", "new zealand", "nigeria", "norway",
"pakistan", "philippines", "poland", "portugal", "romania", "russia", "saudi arabia", "serbia", "singapore",
"slovakia", "slovenia", "south africa", "south korea", "spain", "sweden", "switzerland", "taiwan", "thailand",
"turkey", "ukraine", "united arab emirates", "united kingdom", "united states", "vietnam"
]
app = gr.Interface(
fn=search_jobs_ui,
inputs=[
gr.Textbox(label="Job Title / Keyword (optional)", placeholder="e.g., Software Engineer"),
gr.Dropdown(label="Country (optional)", choices=country_choices, value="Anywhere", interactive=True),
gr.Slider(minimum=1, maximum=200, value=20, step=1, label="Number of Results"),
],
outputs=gr.Markdown(),
title="Jobicy Remote Job Search",
description="Search remote jobs by optional job title and country, sorted by most recent postings.",
theme="huggingface"
)
if __name__ == "__main__":
app.launch(mcp_server=True)