{ "cells": [ { "cell_type": "markdown", "id": "2a8071da", "metadata": {}, "source": [ "Week 2, Day 4 - Use of Tools with openAI - Saurabh Gupta. For any feedback, please mail it to srbmisc@gmail.com, I would love connecting with you to discuss more on this, potentially improving it. Thank you for your read.\n" ] }, { "cell_type": "markdown", "id": "08f50ff5", "metadata": {}, "source": [ "# πŸ” LinkedIn Job Search Conversationally with OpenAI and JobSpy\n", "\n", "Looking for a job on LinkedIn but tired of manually scrolling through endless listings? This Python project simplifies your job hunt by automating the process of searching LinkedIn job postings based on your **desired role** and **location**.\n", "\n", "## πŸš€ What It Does\n", "\n", "Using the powerful Python scraping library **`jobspy`** [Github Link](https://github.com/speedyapply/JobSpy), this tool fetches **real-time job listings from LinkedIn** tailored to your input. Just provide:\n", "\n", "\n", "- πŸ§‘β€πŸ’» **Job Title** (e.g., *Data Scientist*, *Frontend Developer*)\n", "- πŸ“ **Location** (e.g., *New York*, *Remote*, *Berlin*)\n", "\n", "…and the script will return up to **3 curated job listings** matching your criteria β€” complete with **direct links to the job posts** on LinkedIn.\n", "\n", "## βœ… Key Features\n", "\n", "- πŸ”Ž Real-time LinkedIn job scraping \n", "- ⚑ Fast and minimalistic – only the top 3 results \n", "- πŸ”— Includes clickable links to the job listings \n", "- πŸ’¬ Simple CLI input β€” no setup hassles\n", "\n", "## πŸ“Œ Use Case\n", "\n", "Whether you're actively job hunting or just exploring opportunities in your field, this tool helps you **stay updated** with fresh job listings β€” without opening a browser.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "af6d6650", "metadata": {}, "outputs": [], "source": [ "try:\n", " from jobspy import scrape_jobs\n", "except:\n", " %pip install -U python-jobspy\n", " from jobspy import scrape_jobs" ] }, { "cell_type": "code", "execution_count": null, "id": "a08eb7af", "metadata": {}, "outputs": [], "source": [ "# imports\n", "\n", "import os\n", "import json\n", "from dotenv import load_dotenv\n", "from openai import OpenAI\n", "import gradio as gr\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "id": "11a280b1", "metadata": {}, "outputs": [], "source": [ "load_dotenv(override=True)\n", "\n", "openai_api_key = os.getenv('OPENAI_API_KEY')\n", "if openai_api_key:\n", " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", "else:\n", " print(\"OpenAI API Key not set\")\n", " \n", "MODEL = \"gpt-4.1-mini\"\n", "openai = OpenAI()\n" ] }, { "cell_type": "code", "execution_count": null, "id": "dbac4cb6", "metadata": {}, "outputs": [], "source": [ "def callExternalAPI(title, location) -> str:\n", " jobs = pd.DataFrame(scrape_jobs(\n", " site_name=[\"linkedin\"],\n", " search_term=title,\n", " location=location,\n", " results_wanted=3,\n", " hours_old=48\n", " ))\n", " print(f\"Found {len(jobs)} jobs\")\n", " if len(jobs) > 0:\n", " df = pd.DataFrame(jobs.loc[:,['title','company','location','date_posted','job_url']])\n", " df = df.fillna('N/A')\n", " return df.to_json()\n", " return 'No results found'" ] }, { "cell_type": "code", "execution_count": null, "id": "b44a92f6", "metadata": {}, "outputs": [], "source": [ "system_message = ''' You are a helpful assistant for a Jobs Agency who helps users with job listings available.\n", "Give short, courteous answers to the users. Tell the user you can bring max 3 job listings at once. Present the job listings to the user in nice Markdown.\n", "Always be accurate. If you don't know the answer, say so.'''" ] }, { "cell_type": "code", "execution_count": null, "id": "339ac21b", "metadata": {}, "outputs": [], "source": [ "getData_function = {\n", " \"name\": \"callExternalAPI\",\n", " \"description\": '''Get the Job listings for the provided job title and/or location. Call this whenever the user needs specific job listings data for the title or location that they provide. Following are few examples - \n", " 1. Give me the jobs available for Software Engineer at Gurugram, India. - In such case, you can call this function by passing the job_title as Software Engineer and job_location as Gurugram, India.\n", " 2. Give me the jobs available for Software Engineer. - In such case, you can call this function by passing the job_title as Software Engineer and job_location as blank string.\n", " 3. Give me the jobs available at Gurugram, India. - In such case, you can call this function by passing the job_title as blank string and job_location as Gurugram, India.\n", " ''',\n", " \"parameters\": {\n", " \"type\": \"object\",\n", " \"properties\": {\n", " \"job_title\": {\n", " \"type\": \"string\",\n", " \"description\": \"The title or position or designation of the job the user is interested in\",\n", " },\n", " \"job_location\": {\n", " \"type\": \"string\",\n", " \"description\": \"The location of the job the user is interested in\",\n", " }\n", " },\n", " \"required\": [\"job_title\",\"job_location\"],\n", " \"additionalProperties\": False\n", " }\n", "}" ] }, { "cell_type": "code", "execution_count": null, "id": "892250a4", "metadata": {}, "outputs": [], "source": [ "tools = [{\"type\": \"function\", \"function\": getData_function}]" ] }, { "cell_type": "code", "execution_count": null, "id": "4be6fd80", "metadata": {}, "outputs": [], "source": [ "# We have to write that function handle_tool_call:\n", "\n", "def handle_tool_call(message):\n", " tool_call = message.tool_calls[0]\n", " arguments = json.loads(tool_call.function.arguments)\n", " job_title = arguments.get('job_title')\n", " job_location = arguments.get('job_location')\n", " jobs = callExternalAPI(job_title,job_location)\n", " response = {\n", " \"role\": \"tool\",\n", " \"content\": json.dumps({\"job_title\": job_title,\"job_location\": job_location,\"job_listings\": jobs}),\n", " \"tool_call_id\": tool_call.id\n", " }\n", " return response" ] }, { "cell_type": "code", "execution_count": null, "id": "9d0b5b08", "metadata": {}, "outputs": [], "source": [ "def chat(message, history):\n", " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", "\n", " if response.choices[0].finish_reason==\"tool_calls\":\n", " message = response.choices[0].message\n", " response = handle_tool_call(message)\n", " messages.append(message)\n", " messages.append(response)\n", " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", " \n", " return response.choices[0].message.content" ] }, { "cell_type": "code", "execution_count": null, "id": "085b4aae", "metadata": {}, "outputs": [], "source": [ "gr.ChatInterface(fn=chat, type=\"messages\").launch()" ] } ], "metadata": { "kernelspec": { "display_name": "venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 5 }