Files
LLM_Engineering_OLD/week2/community-contributions/day4_linkedin_job_search_assistant.ipynb
2025-09-21 17:56:31 -04:00

246 lines
8.3 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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
}