Skip to content

Commit 80aba15

Browse files
committed
Added lab 6 instructions
1 parent 85f488c commit 80aba15

File tree

10 files changed

+211
-15
lines changed

10 files changed

+211
-15
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
meta {
2+
name: Get Resume Recommendation
3+
type: http
4+
seq: 12
5+
}
6+
7+
get {
8+
url: {{BASE_URL}}/api/job-posts/1/recommend
9+
body: none
10+
auth: inherit
11+
}
12+
13+
vars:pre-request {
14+
BASE_URL: http://127.0.0.1:8000
15+
}
16+
17+
settings {
18+
encodeUrl: true
19+
timeout: 0
20+
}

labs/06-retrieval.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Lab 6: Retrieve Recommended Resume
2+
3+
In this lab, we will add an API endpoint to retrieve the recommended resume and return it.
4+
5+
Here are the steps to complete:
6+
7+
1. Create a function `get_recommendation` in `ai.py` that takes the job description
8+
1. Create an api endpoint `api_recommend_resume` in `main.py`
9+
- Path `/api/job-posts/{job_post_id}/recommend`
10+
- Takes `job_post_id` as a parameter
11+
- Calls the `get_recommendation` function created in previous step
12+
- Returns the matching job application
13+
14+
Write tests along with the code.
15+
16+
## High Level Overview
17+
18+
1. We want to implement `get_recommendatation` in `ai.py`. First think about how we will test this function.
19+
1. One way can be to add some resumes to the vector store, then call `get_recommendation` with a job description and see whether it is returning the right one
20+
1. Write a test to do the above. It will fail when you run the tests, since we have not implemented it yet
21+
1. Make the test pass by implementing the functionality in `get_recommendation`
22+
1. Next we need to implement the API. Again -- how will we test this?
23+
1. Maybe we can create a dummy job post with a job description and then upload some resumes. Then we can call the recommendation API using the test client and see if we get the correct output.
24+
1. Write this a pyunit test that does this.
25+
1. Then implement the api endpoint till it passes
26+
1. We are done!
27+
28+
## Hints
29+
30+
### How do I test get_recommendatation?
31+
32+
<details>
33+
<summary>Answer</summary>
34+
35+
```python
36+
def test_retrieval(vector_store):
37+
for id, filename in enumerate(os.listdir("test/resumes")):
38+
with open(f"test/resumes/{filename}", "rb") as f:
39+
content = f.read()
40+
ingest_resume_for_recommendataions(content, filename, resume_id=id, vector_store=vector_store)
41+
result = get_recommendation("I am looking for an expert in AI", vector_store)
42+
assert "Andrew" in result.page_content
43+
```
44+
</details>
45+
46+
### How do I implement get_recommendation?
47+
48+
<details>
49+
<summary>Answer</summary>
50+
51+
```python
52+
def get_recommendation(job_description, vector_store):
53+
retriever = vector_store.as_retriever(search_kwargs={"k": 1})
54+
results = retriever.invoke(job_description)
55+
return results[0]
56+
```
57+
</details>
58+
59+
### How do I test the new API endpoint?
60+
61+
<details>
62+
<summary>Answer</summary>
63+
64+
```python
65+
def test_recommendation_api(db_session, client):
66+
job_board = JobBoard(slug="test", logo_url="http://example.com")
67+
db_session.add(job_board)
68+
db_session.commit()
69+
db_session.refresh(job_board)
70+
job_post = JobPost(title="AI Engineer",
71+
description="I am looking for a generalist who can work in python and typescript",
72+
job_board_id = job_board.id)
73+
db_session.add(job_post)
74+
db_session.commit()
75+
db_session.refresh(job_post)
76+
test_resumes = [
77+
('Andrew', 'Ng', '[email protected]', 'ProfileAndrewNg.pdf'),
78+
('Koudai', 'Aono', '[email protected]', 'ProfileKoudaiAono.pdf')
79+
]
80+
for first_name, last_name, email, filename in test_resumes:
81+
post_data = {
82+
"first_name": first_name,
83+
"last_name": last_name,
84+
"email": email,
85+
"job_post_id": job_post.id
86+
}
87+
with open(f"test/resumes/{filename}", "rb") as f:
88+
response = client.post("/api/job-applications", data=post_data, files={"resume": (filename, f, "application/pdf")})
89+
response = client.get(f"/api/job-posts/{job_post.id}/recommend")
90+
assert response.status_code == 200
91+
data = response.json()
92+
assert data['first_name'] == 'Koudai'
93+
assert data['last_name'] == 'Aono'
94+
```
95+
</details>
96+
97+
### How do I implement the new API endpoint?
98+
99+
<details>
100+
<summary>Answer</summary>
101+
102+
```python
103+
@app.get("/api/job-posts/{job_post_id}/recommend")
104+
async def api_recommend_resume(
105+
job_post_id,
106+
db: Session = Depends(get_db),
107+
vector_store = Depends(get_vector_store)):
108+
109+
job_post = db.get(JobPost, job_post_id)
110+
if not job_post:
111+
raise HTTPException(status_code=400)
112+
job_description = job_post.description
113+
recommended_resume = get_recommendation(job_description, vector_store)
114+
application_id = recommended_resume.metadata["_id"]
115+
job_application = db.get(JobApplication, application_id)
116+
return job_application
117+
```
118+
</details>

labs/07-homework.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Lab 7: Homework
2+
3+
Update the UI to use the new recommendataion system.
4+
5+
Since this is a repeat of frontend / backend, we won't be doing this in the class. You can try it out by yourself as a practise exercise.
6+
7+
## Part 1
8+
9+
We will start by creating a new page to view job details.
10+
11+
1. Create a new route to view a single job. In the jobs board page, instead of showing apply button and job dscription, link the job title to route to this new page.
12+
- What should be the URL structure for this new page?
13+
1. Create a backend api to return details of a single job. Input will be job id. Return the job details as well as the list of all applicants for the job - name, email, resume url
14+
1. Update the single job page to get the job id from url, and call this api. Display the job title, job description. Then show the apply button and then the list of all people who have applied for that job.
15+
16+
## Part 2
17+
18+
1. On this page, add a new button called "Get Recommendation".
19+
1. When the button is clicked, make a call to the recommendations API that we created in previous lab. Display the applicant name and link to the resume on the screen

main.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from pydantic import BaseModel, EmailStr, Field
77
from typing import List
88
from sqlalchemy import text
9-
from ai import evaluate_resume_with_ai, review_application, ingest_resume, get_vector_store
9+
from ai import evaluate_resume_with_ai, get_recommendation, review_application, ingest_resume, get_vector_store
1010
from auth import AdminAuthzMiddleware, AdminSessionMiddleware, authenticate_admin, delete_admin_session
1111
from converter import extract_text_from_pdf_bytes
1212
from db import get_db
@@ -110,7 +110,22 @@ async def api_close_job_post(job_post_id, db: Session = Depends(get_db)):
110110
db.add(jobPost)
111111
db.commit()
112112
return jobPost
113-
113+
114+
@app.get("/api/job-posts/{job_post_id}/recommend")
115+
async def api_recommend_resume(
116+
job_post_id,
117+
db: Session = Depends(get_db),
118+
vector_store = Depends(get_vector_store)):
119+
120+
job_post = db.get(JobPost, job_post_id)
121+
if not job_post:
122+
raise HTTPException(status_code=400)
123+
job_description = job_post.description
124+
recommended_resume = get_recommendation(job_description, vector_store)
125+
application_id = recommended_resume.metadata["_id"]
126+
job_application = db.get(JobApplication, application_id)
127+
return job_application
128+
114129
class JobPostForm(BaseModel):
115130
title : str
116131
description: str

test/test_recommendation.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
import time
3-
from ai import ingest_resume
3+
from ai import get_recommendation, ingest_resume
44
from main import ingest_resume_for_recommendataions
55
from models import JobBoard, JobPost
66

@@ -65,16 +65,40 @@ def test_job_application_api(db_session, vector_store, client):
6565
assert "Andrew" in result[0].page_content
6666
assert result[0].metadata["_id"] == job_post.id
6767

68-
"""
69-
text = "hello world"
70-
url = "helloworld.pdf"
71-
doc = Document(page_content=text, metadata={"file_url": url})
72-
embeddings = OpenAIEmbeddings(model="text-embedding-3-small", api_key=settings.OPENAI_API_KEY)
68+
def test_retrieval(vector_store):
69+
for id, filename in enumerate(os.listdir("test/resumes")):
70+
with open(f"test/resumes/{filename}", "rb") as f:
71+
content = f.read()
72+
ingest_resume_for_recommendataions(content, filename, resume_id=id, vector_store=vector_store)
73+
result = get_recommendation("I am looking for an expert in AI", vector_store)
74+
assert "Andrew" in result.page_content
7375

74-
doc_store = QdrantVectorStore.from_documents(
75-
[doc], embeddings, location=":memory:", collection_name="testing"
76-
)
77-
retriever = doc_store.as_retriever(search_kwargs={"k": 1})
78-
result = retriever.invoke("hello")
79-
print(result)
80-
"""
76+
def test_recommendation_api(db_session, client):
77+
job_board = JobBoard(slug="test", logo_url="http://example.com")
78+
db_session.add(job_board)
79+
db_session.commit()
80+
db_session.refresh(job_board)
81+
job_post = JobPost(title="AI Engineer",
82+
description="I am looking for a generalist who can work in python and typescript",
83+
job_board_id = job_board.id)
84+
db_session.add(job_post)
85+
db_session.commit()
86+
db_session.refresh(job_post)
87+
test_resumes = [
88+
('Andrew', 'Ng', '[email protected]', 'ProfileAndrewNg.pdf'),
89+
('Koudai', 'Aono', '[email protected]', 'ProfileKoudaiAono.pdf')
90+
]
91+
for first_name, last_name, email, filename in test_resumes:
92+
post_data = {
93+
"first_name": first_name,
94+
"last_name": last_name,
95+
"email": email,
96+
"job_post_id": job_post.id
97+
}
98+
with open(f"test/resumes/{filename}", "rb") as f:
99+
response = client.post("/api/job-applications", data=post_data, files={"resume": (filename, f, "application/pdf")})
100+
response = client.get(f"/api/job-posts/{job_post.id}/recommend")
101+
assert response.status_code == 200
102+
data = response.json()
103+
assert data['first_name'] == 'Koudai'
104+
assert data['last_name'] == 'Aono'

uploads/resumes/md-to-pdf (2).pdf

-23.5 KB
Binary file not shown.

uploads/resumes/md-to-pdf (21).pdf

-23.2 KB
Binary file not shown.

uploads/resumes/md-to-pdf (4).pdf

-17.9 KB
Binary file not shown.

uploads/resumes/md-to-pdf (9).pdf

-15.9 KB
Binary file not shown.

uploads/resumes/md-to-pdf.pdf

-26.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)