Spaces:
Sleeping
Sleeping
| 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 Remote Jobs Agent") | |
| # Remaining filter options | |
| COMPANY_INDUSTRIES = [ | |
| ("", ""), | |
| ("Business Development", "business"), | |
| ("Content & Editorial", "copywriting"), | |
| ("Creative & Design", "design-multimedia"), | |
| ("Customer Success", "supporting"), | |
| ("Data Science & Analytics", "data-science"), | |
| ("DevOps & Infrastructure", "admin"), | |
| ("Finance & Accounting", "accounting-finance"), | |
| ("HR & Recruiting", "hr"), | |
| ("Legal & Compliance", "legal"), | |
| ("Marketing & Sales", "marketing"), | |
| ("Product & Operations", "management"), | |
| ("Programming", "dev"), | |
| ("Sales", "seller"), | |
| ("SEO", "seo"), | |
| ("Social Media Marketing", "smm"), | |
| ("Software Engineering", "engineering"), | |
| ("Technical Support", "technical-support"), | |
| ("Web & App Design", "web-app-design"), | |
| ] | |
| COUNTRY_CHOICES = [ | |
| "", "APAC", "EMEA", "LATAM", "Argentina", "Australia", "Austria", "Belgium", "Brazil", "Bulgaria", | |
| "Canada", "China", "Costa Rica", "Croatia", "Cyprus", "Czechia", "Denmark", "Estonia", "Europe", | |
| "Finland", "France", "Germany", "Greece", "Hungary", "Ireland", "Israel", "Italy", "Japan", | |
| "Latvia", "Lithuania", "Mexico", "Netherlands", "New Zealand", "Norway", "Philippines", "Poland", | |
| "Portugal", "Romania", "Singapore", "Slovakia", "Slovenia", "South Korea", "Spain", "Sweden", | |
| "Switzerland", "Thailand", "Türkiye", "UAE", "UK", "USA", "Vietnam" | |
| ] | |
| def search_jobs_tool(industry: str = "", country: str = "", keyword: str = "", limit: int = 20) -> dict: | |
| """ | |
| Search remote jobs via Jobicy API, supports filters. | |
| Args: | |
| industry (str): Company industry filter. | |
| country (str): Region filter (e.g., usa, canada, ...). | |
| keyword (str): Free-form keyword tag. | |
| limit (int): Number of results (1–50). | |
| Returns: | |
| dict: {"jobs": [...]} or {"error": "..." } | |
| """ | |
| base = "https://jobicy.com/api/v2/remote-jobs" | |
| params = {"count": max(1, min(limit, 50))} | |
| if industry: | |
| params["industry"] = industry.lower().replace(" & ", "-").replace(" ", "-") | |
| if country and country.lower() != "anywhere": | |
| params["geo"] = country.lower() | |
| if keyword: | |
| params["tag"] = keyword.strip() | |
| logger.info(f"Requesting Jobicy API with params: {params}") | |
| try: | |
| resp = requests.get(base, params=params, headers={"User-Agent": "Mozilla/5.0"}, timeout=10) | |
| resp.raise_for_status() | |
| jobs_raw = resp.json().get("jobs", []) | |
| except Exception as e: | |
| return {"error": f"Fetch error: {e}"} | |
| def fmt(j): | |
| posted = j.get("pubDate", "")[:10] | |
| sal_min = j.get("annualSalaryMin") | |
| sal_max = j.get("annualSalaryMax") | |
| cur = j.get("salaryCurrency", "") | |
| salary = f"{sal_min}–{sal_max} {cur}".strip() if sal_min or sal_max else "Not specified" | |
| return { | |
| "title": j.get("jobTitle", "No Title"), | |
| "company": j.get("companyName", ""), | |
| "location": j.get("jobGeo", ""), | |
| "url": j.get("url", "#"), | |
| "pubDate": posted, | |
| "salary": salary | |
| } | |
| sorted_jobs = sorted(jobs_raw, key=lambda x: x.get("pubDate", ""), reverse=True)[:params["count"]] | |
| return {"jobs": [fmt(j) for j in sorted_jobs]} | |
| def search_jobs_ui(industry, country, keyword, limit): | |
| res = search_jobs_tool(industry=industry, country=country, keyword=keyword, limit=limit) | |
| if "error" in res: | |
| return f"❌ {res['error']}" | |
| if not res["jobs"]: | |
| return "No jobs found with these filters." | |
| md = "# Remote Jobs Results\n\n" | |
| for i, j in enumerate(res["jobs"], 1): | |
| md += ( | |
| f"### {i}. {j['title']}\n\n" | |
| f"**Company:** {j['company']}\n\n" | |
| f"**Location:** {j['location']}\n\n" | |
| f"**Salary:** {j['salary']}\n\n" | |
| f"**Posted On:** {j['pubDate']}\n\n" | |
| f"[Apply Here]({j['url']})\n\n---\n\n" | |
| ) | |
| return md | |
| app = gr.Interface( | |
| fn=search_jobs_ui, | |
| inputs=[ | |
| gr.Dropdown(label="Company Industry (optional) (Empty = All)", choices=COMPANY_INDUSTRIES, value=""), | |
| gr.Dropdown(label="Country / Region (optional) (Empty = Anywhere)", choices=COUNTRY_CHOICES, value=""), | |
| gr.Textbox(label="Keyword / Tag (optional)", placeholder="e.g., python, data, web"), | |
| gr.Slider(minimum=1, maximum=50, value=20, step=1, label="Number of Results"), | |
| ], | |
| outputs=gr.Markdown(), | |
| title="Jobicy Remote Job Search", | |
| description="Search remote jobs by industry, region, and keyword. Results sorted by most recent.", | |
| theme="huggingface" | |
| ) | |
| if __name__ == "__main__": | |
| app.launch(mcp_server=True) | |