the real update
Browse files
app.py
CHANGED
@@ -1,142 +1,66 @@
|
|
1 |
-
import
|
2 |
import requests
|
3 |
-
import os
|
4 |
-
import subprocess
|
5 |
-
import threading
|
6 |
|
7 |
-
# API credentials
|
8 |
API_KEY = "c1b9b6be0amsh11316ef9a922bdbp1789f5jsn18a0023eef11"
|
9 |
API_HOST = "jsearch.p.rapidapi.com"
|
10 |
|
11 |
-
# Securely set Groq API key (for Career Counselor)
|
12 |
-
GROQ_API_KEY = "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"
|
13 |
-
os.environ["GROQ_API_KEY"] = GROQ_API_KEY
|
14 |
-
|
15 |
# Function to fetch job openings
|
16 |
-
def get_job_openings(job_title, location, location_type,
|
17 |
url = "https://jsearch.p.rapidapi.com/search"
|
18 |
querystring = {
|
19 |
"query": f"{job_title} in {location}",
|
20 |
"page": "1",
|
21 |
"num_pages": "1",
|
22 |
"remote_jobs_only": "true" if location_type == "REMOTE" else "false",
|
23 |
-
"employment_types":
|
24 |
-
"salary_min": salary_min,
|
25 |
-
"salary_max": salary_max
|
26 |
}
|
27 |
headers = {
|
28 |
"x-rapidapi-key": API_KEY,
|
29 |
"x-rapidapi-host": API_HOST
|
30 |
}
|
31 |
-
response = requests.get(url, headers=headers, params=querystring)
|
32 |
-
return response.json().get('data', []) if response.status_code == 200 else f"Error {response.status_code}: {response.text}"
|
33 |
-
|
34 |
-
# Function for job search UI
|
35 |
-
def search_jobs(job_title, location, location_type, employment_type, salary_min, salary_max):
|
36 |
-
jobs = get_job_openings(job_title, location, location_type, employment_type, salary_min, salary_max)
|
37 |
-
if isinstance(jobs, str):
|
38 |
-
return jobs
|
39 |
-
if not jobs:
|
40 |
-
return "No job openings found. Please try different inputs."
|
41 |
-
return "\n\n".join(
|
42 |
-
f"{idx}. {job.get('job_title', 'No Title')}\n"
|
43 |
-
f"Company: {job.get('employer_name', 'Unknown')}\n"
|
44 |
-
f"Location: {job.get('job_city', 'Unknown')}, {job.get('job_country', '')}\n"
|
45 |
-
f"Type: {job.get('job_employment_type', 'N/A')}\n"
|
46 |
-
f"Salary: {job.get('job_salary_currency', '')} {job.get('job_salary_min', 'N/A')} - {job.get('job_salary_max', 'N/A')}\n"
|
47 |
-
f"Posted On: {job.get('job_posted_at_datetime_utc', 'N/A')}\n"
|
48 |
-
f"Deadline: {job.get('job_offer_expiration_datetime_utc', 'N/A')}\n"
|
49 |
-
f"[View Job Posting]({job.get('job_apply_link', '#')})"
|
50 |
-
for idx, job in enumerate(jobs, start=1)
|
51 |
-
)
|
52 |
-
|
53 |
-
# Function to launch Career Counselor App in a separate thread
|
54 |
-
def launch_career_counselor():
|
55 |
-
def run_streamlit():
|
56 |
-
# Write the Streamlit app code to career_counselor.py
|
57 |
-
with open("career_counselor.py", "w") as f:
|
58 |
-
f.write("""
|
59 |
-
import os
|
60 |
-
import streamlit as st
|
61 |
-
from groq import Groq
|
62 |
-
|
63 |
-
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
64 |
-
client = Groq(api_key=GROQ_API_KEY)
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
st.header("Tell us about yourself")
|
70 |
-
skills = st.text_area("List your skills (e.g., Python, teamwork, CAD):")
|
71 |
-
interests = st.text_area("What areas of interest do you have? (e.g., AI, design, civil engineering):")
|
72 |
-
experience = st.text_area("Describe your experience (if any):")
|
73 |
-
|
74 |
-
def suggest_careers_groq(skills, interests, experience):
|
75 |
-
try:
|
76 |
-
prompt = f"Suggest careers based on Skills: {skills}, Interests: {interests}, Experience: {experience}"
|
77 |
-
chat_completion = client.chat.completions.create(
|
78 |
-
messages=[{"role": "user", "content": prompt}],
|
79 |
-
model="llama-3.3-70b-versatile",
|
80 |
-
stream=False,
|
81 |
-
)
|
82 |
-
return chat_completion.choices[0].message.content
|
83 |
-
except Exception as e:
|
84 |
-
st.error(f"Error: {e}")
|
85 |
-
return None
|
86 |
-
|
87 |
-
if st.button("Get Career Advice"):
|
88 |
-
if not skills or not interests:
|
89 |
-
st.error("Please provide skills and interests for better suggestions.")
|
90 |
else:
|
91 |
-
st.
|
92 |
-
|
93 |
-
st.write(response if response else "No recommendations available.")
|
94 |
|
95 |
-
|
96 |
-
st.
|
97 |
-
""")
|
98 |
-
# Use a clean environment and launch via the Python module to avoid extra flags.
|
99 |
-
env = os.environ.copy()
|
100 |
-
subprocess.Popen(
|
101 |
-
["python", "-m", "streamlit", "run", "career_counselor.py"],
|
102 |
-
stdout=subprocess.DEVNULL,
|
103 |
-
stderr=subprocess.DEVNULL,
|
104 |
-
env=env
|
105 |
-
)
|
106 |
-
threading.Thread(target=run_streamlit, daemon=True).start()
|
107 |
|
108 |
-
|
109 |
-
|
110 |
-
if option == "Career Connect (Job Search)":
|
111 |
-
return gr.update(visible=True), gr.update(visible=False), ""
|
112 |
-
elif option == "Career Counselor App":
|
113 |
-
launch_career_counselor()
|
114 |
-
return gr.update(visible=False), gr.update(visible=True), "🚀 Career Counselor App is launching..."
|
115 |
|
116 |
-
#
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
# Job search UI
|
123 |
-
job_search_interface = gr.Interface(
|
124 |
-
fn=search_jobs,
|
125 |
-
inputs=[
|
126 |
-
gr.Textbox(label="Enter Job Title", placeholder="e.g., Node.js Developer"),
|
127 |
-
gr.Textbox(label="Enter Location", placeholder="e.g., New York"),
|
128 |
-
gr.Radio(["ANY", "ON_SITE", "REMOTE", "HYBRID"], label="Location Type"),
|
129 |
-
gr.CheckboxGroup(["FULLTIME", "PARTTIME", "INTERN", "CONTRACTOR"],
|
130 |
-
label="Select Employment Type", value=["FULLTIME", "INTERN"]),
|
131 |
-
gr.Number(label="Minimum Salary ($)", value=0, minimum=0),
|
132 |
-
gr.Number(label="Maximum Salary ($)", value=100000, minimum=0)
|
133 |
-
],
|
134 |
-
outputs=gr.Textbox(label="Job Openings"),
|
135 |
-
visible=False
|
136 |
-
)
|
137 |
-
|
138 |
-
counselor_status = gr.Markdown("", visible=False)
|
139 |
-
|
140 |
-
option.change(main, inputs=option, outputs=[job_search_interface, counselor_status, gr.Textbox(label="Status")])
|
141 |
|
142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
import requests
|
|
|
|
|
|
|
3 |
|
4 |
+
# API credentials
|
5 |
API_KEY = "c1b9b6be0amsh11316ef9a922bdbp1789f5jsn18a0023eef11"
|
6 |
API_HOST = "jsearch.p.rapidapi.com"
|
7 |
|
|
|
|
|
|
|
|
|
8 |
# Function to fetch job openings
|
9 |
+
def get_job_openings(job_title, location, location_type, experience):
|
10 |
url = "https://jsearch.p.rapidapi.com/search"
|
11 |
querystring = {
|
12 |
"query": f"{job_title} in {location}",
|
13 |
"page": "1",
|
14 |
"num_pages": "1",
|
15 |
"remote_jobs_only": "true" if location_type == "REMOTE" else "false",
|
16 |
+
"employment_types": experience
|
|
|
|
|
17 |
}
|
18 |
headers = {
|
19 |
"x-rapidapi-key": API_KEY,
|
20 |
"x-rapidapi-host": API_HOST
|
21 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
+
response = requests.get(url, headers=headers, params=querystring)
|
24 |
+
if response.status_code == 200:
|
25 |
+
return response.json()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
else:
|
27 |
+
st.error(f"Error {response.status_code}: {response.text}")
|
28 |
+
return None
|
|
|
29 |
|
30 |
+
# Streamlit UI
|
31 |
+
st.set_page_config(page_title="Job Search", page_icon="🧑💼", layout="centered")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
+
st.title("🎯 Career Connect ")
|
34 |
+
st.write("Find the latest job openings based on your preferences.")
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
+
# User inputs
|
37 |
+
job_title = st.text_input("Enter Job Title:", placeholder="e.g., Node.js Developer")
|
38 |
+
location = st.text_input("Enter Location:", placeholder="e.g., New York")
|
39 |
+
location_type = st.selectbox("Location Type:", ["ANY", "ON_SITE", "REMOTE", "HYBRID"])
|
40 |
+
experience = st.selectbox("Experience Level:", ["FULLTIME", "PARTTIME", "INTERN", "CONTRACTOR"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
+
# Button to fetch job openings
|
43 |
+
if st.button("Search Jobs"):
|
44 |
+
if job_title and location:
|
45 |
+
with st.spinner("Fetching job openings..."):
|
46 |
+
data = get_job_openings(job_title, location, location_type, experience)
|
47 |
+
if data and 'data' in data:
|
48 |
+
st.success("Job Openings Retrieved!")
|
49 |
+
jobs = data['data']
|
50 |
+
|
51 |
+
if jobs:
|
52 |
+
for idx, job in enumerate(jobs, start=1):
|
53 |
+
st.subheader(f"{idx}. {job.get('job_title', 'No Title')}")
|
54 |
+
st.write(f"*Company:* {job.get('employer_name', 'Unknown')}")
|
55 |
+
st.write(f"*Location:* {job.get('job_city', 'Unknown')}, {job.get('job_country', '')}")
|
56 |
+
st.write(f"*Type:* {job.get('job_employment_type', 'N/A')}")
|
57 |
+
st.write(f"*Posted On:* {job.get('job_posted_at_datetime_utc', 'N/A')}")
|
58 |
+
st.write(f"*Deadline:* {job.get('job_offer_expiration_datetime_utc', 'N/A')}")
|
59 |
+
st.write(f"[🔗 View Job Posting]({job.get('job_apply_link', '#')})")
|
60 |
+
st.write("---")
|
61 |
+
else:
|
62 |
+
st.warning("No job openings found. Please try different inputs.")
|
63 |
+
else:
|
64 |
+
st.warning("No job data found. Please try again.")
|
65 |
+
else:
|
66 |
+
st.error("Please enter both job title and location.")
|