Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -394,38 +394,77 @@ def fetch_muse_jobs_api(job_title, location=None, category=None, max_results=50)
|
|
394 |
|
395 |
# Adzuna API Integration
|
396 |
@st.cache_data(ttl=86400) # Cache results for 1 day
|
397 |
-
def fetch_adzuna_jobs_api(job_title, location="
|
398 |
"""
|
399 |
Fetches job listings from Adzuna API based on user preferences.
|
400 |
|
401 |
Args:
|
402 |
-
job_title (str): The job title to search for.
|
403 |
-
location (str, optional): The job location. Defaults to "
|
404 |
category (str, optional): The job category. Defaults to None.
|
405 |
max_results (int, optional): Maximum number of jobs to fetch. Defaults to 50.
|
406 |
|
407 |
Returns:
|
408 |
list: A list of job dictionaries.
|
409 |
"""
|
410 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
params = {
|
412 |
-
"app_id": ADZUNA_APP_ID,
|
413 |
-
"app_key": ADZUNA_APP_KEY,
|
414 |
-
"what": job_title,
|
415 |
"results_per_page": max_results,
|
416 |
"content-type": "application/json"
|
417 |
}
|
|
|
418 |
if category:
|
419 |
params["category"] = category
|
|
|
420 |
try:
|
421 |
response = requests.get(base_url, params=params)
|
422 |
-
response.raise_for_status()
|
423 |
jobs = response.json().get("results", [])
|
|
|
|
|
|
|
|
|
424 |
return jobs
|
425 |
-
|
426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
return []
|
428 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
429 |
def recommend_jobs(user_skills, user_preferences):
|
430 |
"""
|
431 |
Recommends jobs based on user skills and preferences from Remotive API.
|
@@ -1833,9 +1872,71 @@ def embed_youtube_videos(video_urls, module_name):
|
|
1833 |
for url in video_urls:
|
1834 |
st.video(url)
|
1835 |
|
1836 |
-
|
1837 |
-
|
1838 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1839 |
|
1840 |
def job_recommendations_module():
|
1841 |
st.header("🔍 Job Matching & Recommendations")
|
|
|
394 |
|
395 |
# Adzuna API Integration
|
396 |
@st.cache_data(ttl=86400) # Cache results for 1 day
|
397 |
+
def fetch_adzuna_jobs_api(job_title, location="us", category=None, max_results=50):
|
398 |
"""
|
399 |
Fetches job listings from Adzuna API based on user preferences.
|
400 |
|
401 |
Args:
|
402 |
+
job_title (str): The job title to search for (e.g., "Front end developer").
|
403 |
+
location (str, optional): The country code for the job location (e.g., "us" for USA). Defaults to "us".
|
404 |
category (str, optional): The job category. Defaults to None.
|
405 |
max_results (int, optional): Maximum number of jobs to fetch. Defaults to 50.
|
406 |
|
407 |
Returns:
|
408 |
list: A list of job dictionaries.
|
409 |
"""
|
410 |
+
# Mapping common location inputs to Adzuna country codes
|
411 |
+
location_mapping = {
|
412 |
+
"usa": "us",
|
413 |
+
"united states": "us",
|
414 |
+
"us": "us",
|
415 |
+
"india": "in",
|
416 |
+
"uk": "gb",
|
417 |
+
"united kingdom": "gb",
|
418 |
+
"canada": "ca",
|
419 |
+
# Add more mappings as needed
|
420 |
+
}
|
421 |
+
|
422 |
+
# Normalize and map the location input
|
423 |
+
normalized_location = location.strip().lower()
|
424 |
+
country_code = location_mapping.get(normalized_location, normalized_location)
|
425 |
+
|
426 |
+
# Construct the API endpoint
|
427 |
+
base_url = f"https://api.adzuna.com/v1/api/jobs/{country_code}/search/1"
|
428 |
+
|
429 |
+
# Prepare query parameters
|
430 |
params = {
|
431 |
+
"app_id": st.secrets["ADZUNA_APP_ID"], # Ensure ADZUNA_APP_ID is correctly set in secrets.toml
|
432 |
+
"app_key": st.secrets["ADZUNA_APP_KEY"], # Ensure ADZUNA_APP_KEY is correctly set in secrets.toml
|
433 |
+
"what": job_title.strip(),
|
434 |
"results_per_page": max_results,
|
435 |
"content-type": "application/json"
|
436 |
}
|
437 |
+
|
438 |
if category:
|
439 |
params["category"] = category
|
440 |
+
|
441 |
try:
|
442 |
response = requests.get(base_url, params=params)
|
443 |
+
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
|
444 |
jobs = response.json().get("results", [])
|
445 |
+
|
446 |
+
if not jobs:
|
447 |
+
st.info("ℹ️ No job listings found for the specified criteria.")
|
448 |
+
|
449 |
return jobs
|
450 |
+
|
451 |
+
except requests.exceptions.HTTPError as http_err:
|
452 |
+
if response.status_code == 403:
|
453 |
+
st.error("❌ Access Forbidden: Check your API credentials and permissions.")
|
454 |
+
elif response.status_code == 404:
|
455 |
+
st.error("❌ Resource Not Found: Verify the endpoint and parameters.")
|
456 |
+
else:
|
457 |
+
st.error(f"❌ HTTP error occurred: {http_err}")
|
458 |
return []
|
459 |
+
|
460 |
+
except requests.exceptions.RequestException as req_err:
|
461 |
+
st.error(f"❌ Request Exception: {req_err}")
|
462 |
+
return []
|
463 |
+
|
464 |
+
except Exception as e:
|
465 |
+
st.error(f"❌ An unexpected error occurred: {e}")
|
466 |
+
return []
|
467 |
+
|
468 |
def recommend_jobs(user_skills, user_preferences):
|
469 |
"""
|
470 |
Recommends jobs based on user skills and preferences from Remotive API.
|
|
|
1872 |
for url in video_urls:
|
1873 |
st.video(url)
|
1874 |
|
1875 |
+
def fetch_jsearch_estimated_salary(job_title, location, radius=100):
|
1876 |
+
"""
|
1877 |
+
Fetches estimated salary data for a given job title and location using the JSearch API.
|
1878 |
+
|
1879 |
+
Args:
|
1880 |
+
job_title (str): The job title to search for (e.g., "NodeJS Developer").
|
1881 |
+
location (str): The job location (e.g., "New York, NY, USA").
|
1882 |
+
radius (int, optional): Search radius in miles. Defaults to 100.
|
1883 |
+
|
1884 |
+
Returns:
|
1885 |
+
dict: A dictionary containing minimum, average, and maximum salary estimates.
|
1886 |
+
"""
|
1887 |
+
url = "https://jsearch.p.rapidapi.com/estimated-salary"
|
1888 |
+
|
1889 |
+
# Encode job title and location to handle spaces and special characters
|
1890 |
+
encoded_job_title = quote(job_title.strip())
|
1891 |
+
encoded_location = quote(location.strip())
|
1892 |
+
|
1893 |
+
querystring = {
|
1894 |
+
"job_title": encoded_job_title,
|
1895 |
+
"location": encoded_location,
|
1896 |
+
"radius": str(radius)
|
1897 |
+
}
|
1898 |
+
|
1899 |
+
headers = {
|
1900 |
+
"x-rapidapi-key": st.secrets["RAPIDAPI_KEY"], # Ensure RAPIDAPI_KEY is correctly set in secrets.toml
|
1901 |
+
"x-rapidapi-host": "jsearch.p.rapidapi.com"
|
1902 |
+
}
|
1903 |
+
|
1904 |
+
try:
|
1905 |
+
response = requests.get(url, headers=headers, params=querystring)
|
1906 |
+
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
|
1907 |
+
data = response.json()
|
1908 |
+
|
1909 |
+
# Extract salary estimates
|
1910 |
+
min_salary = data.get("min_salary")
|
1911 |
+
avg_salary = data.get("avg_salary")
|
1912 |
+
max_salary = data.get("max_salary")
|
1913 |
+
|
1914 |
+
if not all([min_salary, avg_salary, max_salary]):
|
1915 |
+
st.error("❌ Incomplete salary data received from the API.")
|
1916 |
+
return {}
|
1917 |
+
|
1918 |
+
return {
|
1919 |
+
"min_salary": min_salary,
|
1920 |
+
"avg_salary": avg_salary,
|
1921 |
+
"max_salary": max_salary
|
1922 |
+
}
|
1923 |
+
|
1924 |
+
except requests.exceptions.HTTPError as http_err:
|
1925 |
+
if response.status_code == 403:
|
1926 |
+
st.error("❌ Access Forbidden: Check your API key and permissions.")
|
1927 |
+
elif response.status_code == 404:
|
1928 |
+
st.error("❌ Resource Not Found: Verify the endpoint and parameters.")
|
1929 |
+
else:
|
1930 |
+
st.error(f"❌ HTTP error occurred: {http_err}")
|
1931 |
+
return {}
|
1932 |
+
|
1933 |
+
except requests.exceptions.RequestException as req_err:
|
1934 |
+
st.error(f"❌ Request Exception: {req_err}")
|
1935 |
+
return {}
|
1936 |
+
|
1937 |
+
except Exception as e:
|
1938 |
+
st.error(f"❌ An unexpected error occurred: {e}")
|
1939 |
+
return {}
|
1940 |
|
1941 |
def job_recommendations_module():
|
1942 |
st.header("🔍 Job Matching & Recommendations")
|