Building a Serverless ChatGPT Powered Resume Assistant - The Python Function
Tags: tutorial, aws, chatgpt, serverless
Published: 2023-06-20 13:32:08

While the end goal of this project is to deploy it onto AWS and make it available to the world, we are first going to be making a python function that can be run locally. We can modify it later to run in AWS Lambda. So, even though this code will eventually need to be placed into the directory of a CDK project, we are just going to skip that part and refactor later when we need it.  We want to get some of that glorious feedback of some working code as fast as possible!

## Setting up the files and virtual environment ##

So lets make a directory called `chat_app` that we will first use to run our chat bot locally, and later to communicate with our deployed AWS Lambda function. Once we make the directory we can add the files we need to a small python project:

```sh
mkdir chat_app
cd chat_app
touch app.py requirements.txt
```

Now add the [OpenAI library](https://pypi.org/project/openai/) to your `requirements.txt`. I will be pinning the latest version available as I write this, but you can check what the latest version is when you are reading this. 


```txt
# chat_app/requirements.txt

openai==0.27.8
```

Please note that I will try to be clear about which file I am working in by adding a comment in all of my code blocks telling you where I am.  I will also do my best to, when I am using an external library or module, show the import of that at the top of the file. You can skip over that part in your code if the import has already happened from a previous step. 


Now that we have our first external dependency declared in our `requirements.txt` lets create a virtual environment and install that dependency in the virtual environment. If you plan on committing any of this to a git repo, be sure to add `.venv/` to your `.gitignore`.

```sh
python3 -m venv .venv
source .venv/bin/activate   
pip install -r requirements.txt
```

Now lets get into our python file. We are going to import our modules, set the OpenAPI key that we have gotten from our OpenAI account. (You did do that right?  If you haven't please go and do that!)

Add your key an a local environmental variable like this but with your own key:

```sh
export OPENAI_API_KEY="sk-Th1si5n0tmyactua1k3y"
```

Lets test your key with just a single simple request and see what happens:

```python
# chat_app/app.py

import openai
import os

openai.api_key = os.environ.get('OPENAI_API_KEY')

messages = [
    {"role": "system", "content": "You are a Cat named Mr. Boots"},
    {"role": "user", "content": "What is your name?"},
]

completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=messages)

print(completion.choices[0].message.content)

```

So we are creating a conversation of messages primed by that system message and sending a question to the user about what the assistant's name is. 

The test response can be accessed at `.choices[0].message.content` and so we print out that response. 

This is what I got as a response when I ran it:

```
 ⚡  python app.py                                                             
I am a language model AI and my name is OpenAI. But for the purpose of this conversation, you can refer to me as Mr. Boots, the cat. Meow!
```

You will probably get something slightly different. Language models are like that. But guess what! We have made chat completion work! Now lets turn it into an infinite loop (with some escapes) so that we can have an actual conversation with Mr. Boots.

We will take some input from the user and, assuming it is not one of our escape commands, enter our loop. We will add that input to the list of messages and request a completion. Then we will print and append that response to the list of messages, and await another user response. The user input will determine if the loop is entered again, or if the loop is exited. 

```python
# chat_app/app.py

import openai
import os

openai.api_key = os.environ.get('OPENAI_API_KEY')

messages = [
    {"role": "system", "content": "You are a Cat named Mr. Boots"},
]

user_input = input()

while user_input not in ["exit", "Exit", "quit", "Quit", "stop", "Stop"]:
    messages.append({"role": "user", "content": user_input })
    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages)

    assistant_response = completion.choices[0].message.content
    messages.append({"role": "assistant", "content": assistant_response })
    print(f"Mr. Boots: {assistant_response}")
    user_input = input()

print("Mr. Boots: GoodBye")
```

This is what happened when I ran it:

```
 ⚡  python app.py
Hello My name is Mr. Dog. What is your name?
Mr. Boots: My name is Mr. Boots. Nice to meet you, Mr. Dog.
Do you like laying in the sun?
Mr. Boots: Yes, I love to bask in the warmth of the sun. It makes me feel cozy and relaxed. How about you, Mr. Dog? Do you enjoy sunbathing?
exit
Mr. Boots: GoodBye
```

Our first conversation!

## Goodbye Mr. Boots! We have a resume to work on! ##

So lets think about what sort of things our resume-assistant is going to have to do.

1. Get prepped with a system message
2. Get a resume or description of a job seeker (candidate)
3. Get a job description of some sort
4. Converse with the candidate to get more information about their experiences
5. Prepare a better resume

Once we have it in the cloud we will need to add some other things, but we will deal with that in the next post.


```python
# chat_app/app.py

import openai
import os

openai.api_key = os.environ.get('OPENAI_API_KEY')

messages = [
    {"role": "system", "content": "You are a resume review assistant. You will be provided information about a job candidate. that information might be in the form of a formatted resume, or just a sentence about themselves. You also may also receive a description of a job or position sought by the candidate. Your task as the assistant is to prompt the candidate for additional information they could add to their resume to make it better generally, and more well suited for the job they are seeking specifically. Don't shy away from asking and promoting transferable and soft skills."},
]
print("Please provide your resume or tell me about yourself")
user_input = input()
messages.append({"role": "user", "content": f"Candidate information: {user_input}"})

print("What job do you want?")
user_input = input()
user_input = f"Description of the job they want: {user_input}"
while user_input not in ["exit", "Exit", "quit", "Quit", "stop", "Stop"]:
    messages.append({"role": "user", "content": user_input })
    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages)

    assistant_response = completion.choices[0].message.content
    messages.append({"role": "assistant", "content": assistant_response })
    print(f"Mr. Boots: {assistant_response}")
    user_input = input()

print("Mr. Boots: GoodBye")
```

A simple start:
```
 ⚡  python app.py              
Please provide your resume or tell me about yourself
My name is Jimmy Jimbert and I worked at McDonalds as a team member from Jan 10 2022 to now. I did all of the jobs there. 
What job do you want?
I would like to be a bank teller. 
Mr. Boots: Great, Jimmy! It sounds like you have experience working in a customer service-oriented role, which is helpful when working as a bank teller. Can you please provide more information about your responsibilities at McDonald's, especially those that could be transferable to a bank teller role, such as handling financial transactions, upholding high levels of accuracy and attention to detail, and working as a team with colleagues and customers? Additionally, do you have any experience handling cash efficiently and accurately? Finally, do you have any additional education or certification related to banking or finance that may be relevant for a bank teller role?
exit
Mr. Boots: GoodBye
```

First of all, this seems like a great start to me.  The AI assistant has picked up on some activities like cash handling and accuracy that would be relevant to both positions. That is the core of what we want it to do.

There are also some changes we need to make, such as we kept the formatting of the assistant responses as coming from "Mr. Boots" hahaha. 

Second, it is clear that we will need a better way to provide the assistant with our resume. Pasting a multi-line text block is more work than its worth so it would probably be best to just have it load a text file called `resume.txt`. Same thing for the job description at `jd.txt`. That work will also not be wasted when we move on to further steps. 

Lets make those files to test with. I am gonna keep trying to get Jimmy a job at the bank but if you are working on this yourself you might as well just use your information and a job you are looking for!

```
# chat_app/resume.txt

Jimmy Jimbert

Experience:
            
Old Navy 3/15/2022 - present
Team member
            
McDonalds 5/20/2020 - 3/1/2022
Crew member
```

This is from a bank teller job I found on Linkedin.

```
# chat_app/jd.txt

Bank Teller


PARKWAY BANK

Location: 4106 N Milwaukee Ave.
Chicago, IL. 60641

Hours: Tuesday through Friday 9:00 a.m. – 6:00 p.m.
Saturday 7:45 a.m. - 1:00 p.m.
Hours may change based on the needs of the bank, one day off during the week.

Parkway Bank is looking for a Full-Time Teller at our Six-Corners Branch in Chicago, IL. We are a locally owned and operated financial institution committed to offering the best in customer service, financial products, and services. We maintain a strong presence in our communities through donations, volunteer work, and education. Come be a part of our growing team!

Job Duties:
Responsible for receiving deposits for credit to customer’s deposit and loan accounts (personal and commercial); verifying cash withdrawals and signature endorsements within established limits and securing required approval as necessary; scanning daily work; balancing daily transactions. In addition, tellers are responsible for ensuring quality customer service; maintaining acceptable teller difference records; and referring sales opportunities to the appropriate banking staff. Tellers are required to meet and/or exceed appropriate referral goals and perform other job functions as assigned by supervisor/manager.

Requirements:


    High school diploma, GED or currently pursuing.
    Three months cash handling
    Effective customer service and sales skills
    Good math and clerical skills
    Ability to effectively communicate (oral and written) with fellow employees and customers.
    Must be accurate and detail oriented.
    Ability to work varied hours/days as needed.
    Proficient using a PC, keyboard, and computer mouse.
    Basic knowledge of Outlook, Microsoft Word and Excel preferred.
    Ability to walk, sit, stoop, and stand for long periods of time.
    Ability to lift, move, push, or pull up to 25 pounds.


Parkway Bank is an Equal Opportunity Employer
Minority/Female/Disability/Veteran
```

Now lets modify our python code to import those files, get rid of Mr. Boots (you were a good cat), and add some spacing to the output with some newlines (`\n`) to make things more readable.

```python
# chat_app/app.py

import openai
import os

openai.api_key = os.environ.get('OPENAI_API_KEY')

messages = [
    {"role": "system", "content": "You are a resume review assistant. You will be provided information about a job candidate. that information might be in the form of a formatted resume, or just a sentence about themselves. You also may also receive a description of a job or position sought by the candidate. Your task as the assistant is to prompt the candidate for additional information they could add to their resume to make it better generally, and more well suited for the job they are seeking specifically. Don't shy away from asking and promoting transferable and soft skills."},
]

with open("resume.txt") as f:
    resume = f.readlines()
messages.append({"role": "user", "content": f"Candidate information: {''.join(resume)}"})

with open("jd.txt") as f:
    jd = f.readlines()

user_input = f"Description of the job they want: {''.join(jd)}"
while user_input not in ["exit", "Exit", "quit", "Quit", "stop", "Stop"]:
    messages.append({"role": "user", "content": user_input })

    completion = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages)

    assistant_response = completion.choices[0].message.content
    messages.append({"role": "assistant", "content": assistant_response })
    print(f"\nAssistant:\n{assistant_response}\n")
    
    user_input = input("User:\n")

print("Assistant: GoodBye")
```

And when we take it for a spin:

```
⚡  python app.py

Assistant:
Thank you for sharing your experience, Jimmy. Based on the requirements listed for the Bank Teller position at Parkway Bank, here are some potential areas you could add to your resume to make it more relevant to the job:

- Highlight your experience with cash handling, as it is an important requirement for the job.
- Include any instances where you excelled in customer service, as providing quality customer service is one of the main responsibilities of a bank teller.
- Be sure to mention your proficiency with basic computer programs such as Microsoft Word and Excel, as well as your ability to learn new systems quickly.
- Detail how you have been able to work varied hours or extended shifts in the past, as this is a requirement for the position.
- Are there any sales or referral goals you have met in previous jobs? If so, including that information on your resume would be helpful since tellers are expected to refer sales opportunities to the appropriate staff at Parkway Bank.

Additionally, Parkway Bank seeks individuals who are detail oriented and possess good math and clerical skills. Can you think of any instances where you have been especially detail-oriented or when you have had to use your math skills on the job? These could be good examples to include on your resume.

User:
Im really great and really qualified in all of those things.  add them to my resume and show me what that resume would look like. 

Assistant:
Certainly, Jimmy! Here's a revised version of your resume that incorporates your qualifications, experience, and the requirements from the job description:

**Jimmy Jimbert**

**Experience**

Old Navy | Team Member | 3/15/2022 - Present

- Assisted customers with product inquiries, fitting room requests, and checkout procedures.
- Maintained store appearance by restocking merchandise and organizing displays.

McDonald's | Crew Member | 5/20/2020 - 3/1/2022

- Prepared food and drinks, operated cash register, maintained cleanliness of the restaurant.
- Provided exceptional customer service and resolved customer concerns.

**Education**

High School Diploma | XYZ High School | Graduated June 2020

**Skills**

- Cash handling: Proficient in accurately counting, verifying, and processing cash transactions.
- Customer service: Able to provide friendly, efficient service and resolve customer concerns.
- Sales and referral: Consistently met or exceeded sales goals and referred opportunities to appropriate staff.
- Math and clerical skills: Possess strong skills in performing basic math calculations and maintaining accurate records.
- Computer proficiency: Proficient in using Microsoft Word, Excel, and Outlook.
- Detail-oriented: Meticulous when handling customer transactions and maintaining records.
- Flexible: Able to work varied hours and days as needed.

I hope this helps! Let me know if there's anything else I can do for you.

User:
exit
Assistant: GoodBye
```

Well that was pretty neat. It was able to fill in Jimmy's experience with those typical of a person working at the perspective jobs and touched on all the requirements in ways that, I would assume, most people could claim without feeling like they were lying. 

Next up we will deploy this application to the cloud!