Alpha108 commited on
Commit
bfc0ccf
Β·
verified Β·
1 Parent(s): f5cf43c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -36
app.py CHANGED
@@ -1,64 +1,84 @@
1
- import requests
2
  import streamlit as st
 
 
3
  from sentence_transformers import SentenceTransformer, util
 
 
 
 
4
 
5
- # Load embedding model
6
  @st.cache_resource
7
  def load_model():
8
  return SentenceTransformer("all-MiniLM-L6-v2")
9
 
10
  model = load_model()
11
 
12
- # Fetch jobs from RemoteOK
 
 
 
 
 
 
 
 
13
  def fetch_jobs():
 
14
  url = "https://remoteok.com/api"
15
  try:
16
  response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
17
- data = response.json()
18
- jobs = data[1:15] # skip metadata, get first 15 jobs
19
- return jobs
20
  except Exception as e:
21
- st.error(f"Error fetching jobs: {e}")
22
- return []
23
 
24
- # Match jobs with user skills
25
- def match_jobs(user_skills):
26
- jobs = fetch_jobs()
27
- if not jobs:
28
  return []
29
 
30
- user_embedding = model.encode(user_skills, convert_to_tensor=True)
31
-
32
  results = []
33
- for job in jobs:
34
- desc = f"{job.get('position','')} at {job.get('company','')}. Tags: {job.get('tags','')}"
35
- job_embedding = model.encode(desc, convert_to_tensor=True)
36
- similarity = util.cos_sim(user_embedding, job_embedding).item()
 
 
 
 
 
 
37
  results.append({
38
- "company": job.get("company"),
39
- "position": job.get("position"),
40
- "url": job.get("url"),
41
  "score": round(similarity * 100, 2)
42
  })
43
 
44
- results = sorted(results, key=lambda x: x["score"], reverse=True)
45
- return results[:5]
46
-
47
- # ---------------- UI ----------------
48
- st.set_page_config(page_title="AI Freelancer Job Matcher", page_icon="πŸ€–", layout="wide")
49
 
 
50
  st.title("πŸ€– AI Freelancer Job Matcher")
51
- st.markdown("Find jobs in real-time from **RemoteOK**, matched to your skills using AI.")
52
 
53
- skills = st.text_input("Enter your skills (comma separated)", "Python, AI, Docker")
 
 
 
 
 
 
 
 
 
54
 
55
- if st.button("Find Jobs"):
56
- results = match_jobs(skills)
57
- if results:
58
- for job in results:
59
- st.subheader(f"πŸ”Ή {job['position']} at {job['company']}")
60
- st.write(f"**Match:** {job['score']}%")
61
- st.markdown(f"[Apply here]({job['url']})")
62
  st.markdown("---")
63
  else:
64
- st.warning("No jobs found. Try again later.")
 
 
1
  import streamlit as st
2
+ import requests
3
+ import fitz # PyMuPDF for PDF extraction
4
  from sentence_transformers import SentenceTransformer, util
5
+ import torch
6
+
7
+ # -------------------- CONFIG --------------------
8
+ st.set_page_config(page_title="AI Job Matcher", page_icon="πŸ€–", layout="wide")
9
 
 
10
  @st.cache_resource
11
  def load_model():
12
  return SentenceTransformer("all-MiniLM-L6-v2")
13
 
14
  model = load_model()
15
 
16
+ # -------------------- FUNCTIONS --------------------
17
+ def extract_text_from_pdf(uploaded_file):
18
+ """Extract text from uploaded PDF."""
19
+ text = ""
20
+ doc = fitz.open(stream=uploaded_file.read(), filetype="pdf")
21
+ for page in doc:
22
+ text += page.get_text("text")
23
+ return text
24
+
25
  def fetch_jobs():
26
+ """Fetch jobs from RemoteOK API."""
27
  url = "https://remoteok.com/api"
28
  try:
29
  response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
30
+ if response.status_code == 200:
31
+ return response.json()[1:] # skip metadata
 
32
  except Exception as e:
33
+ st.error(f"⚠️ Error fetching jobs: {e}")
34
+ return []
35
 
36
+ def match_jobs(cv_text, jobs, top_n=5):
37
+ """Match CV text with job postings using embeddings."""
38
+ if not cv_text.strip():
 
39
  return []
40
 
41
+ cv_embedding = model.encode(cv_text, convert_to_tensor=True)
 
42
  results = []
43
+
44
+ for job in jobs[:30]: # limit for demo
45
+ title = job.get("position", "")
46
+ company = job.get("company", "")
47
+ desc = job.get("description", "")
48
+ job_text = f"{title} at {company}. {desc}"
49
+
50
+ job_embedding = model.encode(job_text, convert_to_tensor=True)
51
+ similarity = util.cos_sim(cv_embedding, job_embedding).item()
52
+
53
  results.append({
54
+ "title": title,
55
+ "company": company,
56
+ "url": job.get("url", ""),
57
  "score": round(similarity * 100, 2)
58
  })
59
 
60
+ return sorted(results, key=lambda x: x["score"], reverse=True)[:top_n]
 
 
 
 
61
 
62
+ # -------------------- UI --------------------
63
  st.title("πŸ€– AI Freelancer Job Matcher")
64
+ st.markdown("Upload your **CV (PDF)** and get real-time job matches from RemoteOK.")
65
 
66
+ uploaded_file = st.file_uploader("πŸ“„ Upload your CV", type=["pdf"])
67
+
68
+ if uploaded_file is not None:
69
+ cv_text = extract_text_from_pdf(uploaded_file)
70
+ st.success("βœ… CV uploaded & text extracted!")
71
+ st.text_area("Extracted CV Text", cv_text[:1000], height=200)
72
+
73
+ jobs = fetch_jobs()
74
+ if jobs:
75
+ results = match_jobs(cv_text, jobs)
76
 
77
+ st.subheader("🎯 Top Job Matches")
78
+ for r in results:
79
+ st.markdown(f"**{r['title']}** at *{r['company']}*")
80
+ st.write(f"Match Score: {r['score']}%")
81
+ st.markdown(f"[View Job Posting]({r['url']})")
 
 
82
  st.markdown("---")
83
  else:
84
+ st.warning("⚠️ No jobs fetched. Try again later.")