Skip to content

Commit

Permalink
Create utility method that uses ai model to suggest imrpoved descript…
Browse files Browse the repository at this point in the history
…ion (#31)

* feat: use google gemini model to suggest improved description for education and experience

* fix: update method descriptor

* feat: add api endpoint for getting description suggestion

* fix: fix lint errors

* fix: fix more lint errors

* Merge branch 'main' of https://github.com/citruscai/orientation-project-python-24.FAL.B into feat/suggest-description-updates

# Conflicts:
#	app.py
#	requirements.txt
#	utils.py

* fix:resolve lint errors

* fix: resolve lint errors part 2

* fix: resolve lint errors part 3

* fix: resolve lint errors part 4

* test: create test cases for description suggestion endpoint

* fix:lint fix

* fix: add patch import for mocking external dependencies in unit tests

* fix: fixing lint errors again part idk

* fix: lint errors agin gosh

* i hate my life
  • Loading branch information
citruscai authored Oct 10, 2024
1 parent 3aaf225 commit 262c29a
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 82 deletions.
175 changes: 100 additions & 75 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,171 +1,196 @@
'''
"""
Flask Application
'''
"""

from flask import Flask, jsonify, request
from models import Experience, Education, Skill, User
from utils import check_phone_number, correct_spelling
from utils import get_suggestion, check_phone_number, correct_spelling


app = Flask(__name__)

data = {
"user": [
User("Jackie Stewart",
"+4478322678",
"jack@resume.com")
],
"user": [User("Jackie Stewart", "+4478322678", "jack@resume.com")],
"experience": [
Experience("Software Developer",
"A Cool Company",
"October 2022",
"Present",
"Writing Python Code",
"example-logo.png"),
Experience("Intern",
"A Nice Company",
"October 2021",
"December 2021",
"Writing Scripts",
"example-logo.png")
Experience(
"Software Developer",
"A Cool Company",
"October 2022",
"Present",
"Writing Python Code",
"example-logo.png",
),
Experience(
"Intern",
"A Nice Company",
"October 2021",
"December 2021",
"Writing Scripts",
"example-logo.png",
),
],
"education": [
Education("Computer Science",
"University of Tech",
"September 2019",
"July 2022",
"80%",
"example-logo.png")
Education(
"Computer Science",
"University of Tech",
"September 2019",
"July 2022",
"80%",
"example-logo.png",
)
],
"skill": [
Skill("Python",
"1-2 Years",
"example-logo.png")
]
"skill": [Skill("Python", "1-2 Years", "example-logo.png")],
}


@app.route('/test')
@app.route("/test")
def hello_world():
'''
"""
Returns a JSON test message
'''
"""
return jsonify({"message": "Hello, World!"})

@app.route('/resume/user', methods=['GET', 'POST', 'PUT'])

@app.route("/resume/user", methods=["GET", "POST", "PUT"])
def user():
'''
"""
Handles User information
'''
"""

# defining sub function to reduce number of returns
def get_users():
return jsonify([user.__dict__ for user in data['user']]), 200
return jsonify([user.__dict__ for user in data["user"]]), 200

def add_user(body):
# retrieve user's information.
name = body['name']
phone_number = body['phone_number']
email = body['email_address']
name = body["name"]
phone_number = body["phone_number"]
email = body["email_address"]
# store the new user information.
if not check_phone_number(phone_number):
return jsonify({"error": "Incorrect phone number !"}), 400
new_user = User(name, phone_number, email)
data['user'].append(new_user)
data["user"].append(new_user)
return jsonify(new_user.__dict__), 201

# edit the user information.
def edit_user(body):
name = body['name']
phone_number = body['phone_number']
email = body['email_address']
for i, user_ in enumerate(data['user']):
name = body["name"]
phone_number = body["phone_number"]
email = body["email_address"]
for i, user_ in enumerate(data["user"]):
if user_.email_address == email:
if not check_phone_number(phone_number):
return jsonify({"error": "Incorrect phone number !"}), 400
data['user'][i] = User(name, phone_number, email)
return jsonify(data['user'][i].__dict__), 200
data["user"][i] = User(name, phone_number, email)
return jsonify(data["user"][i].__dict__), 200
return jsonify({"error": "User not found !"}), 404

if request.method == 'GET':
if request.method == "GET":
return get_users()
if request.method == 'POST':
if request.method == "POST":
body = request.get_json()
return add_user(body)
if request.method == 'PUT':
if request.method == "PUT":
body = request.get_json()
return edit_user(body)
return jsonify({"error": "Unsupported request method !"}), 405

@app.route('/resume/experience', methods=['GET', 'POST'])

@app.route("/resume/experience", methods=["GET", "POST"])
def experience():
'''
"""
Handle experience requests
'''
if request.method == 'GET':
return jsonify({"experience": [exp.__dict__ for exp in data["experience"]]})
"""

if request.method == 'POST':
if request.method == "GET":
return jsonify(
{"experience": [exp.__dict__ for exp in data["experience"]]})

if request.method == "POST":
new_experience = request.json
experience_instance = Experience(
new_experience["title"],
new_experience["company"],
new_experience["start_date"],
new_experience["end_date"],
new_experience["description"],
new_experience["logo"]
new_experience["logo"],
)
data["experience"].append(experience_instance)
return jsonify({"id": len(data["experience"]) - 1})

return jsonify({})

@app.route('/resume/education', methods=['GET', 'POST'])

@app.route("/resume/education", methods=["GET", "POST"])
def education():
'''
"""
Handles education requests
'''
if request.method == 'GET':
return jsonify({"education": [edu.__dict__ for edu in data["education"]]})
"""
if request.method == "GET":
return jsonify(
{"education": [edu.__dict__ for edu in data["education"]]})

if request.method == 'POST':
if request.method == "POST":
new_education = request.json
education_instance = Education(
new_education["course"],
new_education["school"],
new_education["start_date"],
new_education["end_date"],
new_education["grade"],
new_education["logo"]
new_education["logo"],
)
data["education"].append(education_instance)
return jsonify({"id": len(data["education"]) - 1})

return jsonify({})


@app.route('/resume/skill', methods=['GET', 'POST'])
@app.route("/resume/skill", methods=["GET", "POST"])
def skill():
'''
"""
Handles Skill requests
'''
if request.method == 'GET':
"""

if request.method == "GET":
return jsonify({"skills": [skill.__dict__ for skill in data["skill"]]})

if request.method == 'POST':
if request.method == "POST":
new_skill = request.json
skill_instance = Skill(new_skill["name"], new_skill["proficiency"], new_skill["logo"])
skill_instance = Skill(
new_skill["name"], new_skill["proficiency"], new_skill["logo"]
)
data["skill"].append(skill_instance)
return jsonify({"id": len(data["skill"]) - 1})

return jsonify({})

@app.route('/resume/spellcheck', methods=['POST'])

@app.route("/resume/spellcheck", methods=["POST"])
def spellcheck():
'''
"""
Corrects the spelling of a text
'''
"""
body = request.get_json()
try:
text = body['text']
text = body["text"]
corrected_text = correct_spelling(text)

return jsonify({"before": text, "after": corrected_text}), 200
except KeyError:
return jsonify({"error": "Missing text parameter"}), 400


@app.route("/suggestion", methods=["POST"])
def get_description_suggestion():
"""
Handles suggestion requests
"""
description = request.json.get("description")
description_type = request.json.get("type")
if not description or not description_type:
return jsonify({"error": "Description and type are required"}), 400
suggestion = get_suggestion(description, description_type)
return jsonify({"suggestion": suggestion})
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
flask
pytest
pylint
pyspellchecker
google-generativeai
python-dotenv
pyspellchecker

38 changes: 38 additions & 0 deletions test_pytest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
'''
Tests in Pytest
'''
from unittest.mock import patch
import pytest
from app import app



def test_client():
'''
Makes a request and checks the message received is the same
Expand Down Expand Up @@ -136,3 +139,38 @@ def test_correct_spelling(text, expected):
response = app.test_client().post('/resume/spellcheck', json={'text': text})
assert response.status_code == 200
assert response.json['after'] == expected

# testcases for ai suggested imrpvoed descriptions
@patch('app.get_suggestion')
def test_get_description_suggestion(mock_get_suggestion):
'''
Test the /suggestion route with valid inputs
'''
mock_get_suggestion.return_value = "Improved description"

response = app.test_client().post('/suggestion', json={
'description': 'This is a sample description.',
'type': 'experience'
})

assert response.status_code == 200
assert response.json['suggestion'] == 'Improved description'


def test_get_description_suggestion_missing_fields():
'''
Test the /suggestion route with missing fields
'''
# Missing 'type'
response = app.test_client().post('/suggestion', json={
'description': 'This is a sample description.'
})
assert response.status_code == 400
assert response.json['error'] == 'Description and type are required'

# Missing 'description'
response = app.test_client().post('/suggestion', json={
'type': 'experience'
})
assert response.status_code == 400
assert response.json['error'] == 'Description and type are required'
44 changes: 38 additions & 6 deletions utils.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,51 @@
""" Util functions for the Flask App."""
"""
Utility Methods File
"""

import os
import re
from spellchecker import SpellChecker
import google.generativeai as genai
from dotenv import load_dotenv


load_dotenv()


GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
genai.configure(api_key=GOOGLE_API_KEY)


def get_suggestion(description, description_type):
"""
give suggestions for description section using gemini (free alternative to openai's chatgpt api)
"""
prompt = ""
if description_type == "education":
prompt = f"Improve the following education \
experience description for resume: {description}"
elif description_type == "experience":
prompt = f"Improve the following professional \
experience description for resume: {description}"

model = genai.GenerativeModel("gemini-pro")
response = model.generate_content(prompt)
return response.text


def check_phone_number(phone_number):
""" Checks if the phone number is valid and follows
the international country code
"""Checks if the phone number is valid and follows
the international country code
"""
regex = re.compile(r'^\+\d{1,3}\d{1,14}$')
regex = re.compile(r"^\+\d{1,3}\d{1,14}$")
return bool(regex.match(phone_number))


def correct_spelling(text: str):
""" Corrects the spelling of a text"""
"""Corrects the spelling of a text"""

spell_checker = SpellChecker()
word_pattern = r'\w+|[^\w\s]'
word_pattern = r"\w+|[^\w\s]"

misspelled = spell_checker.unknown(re.findall(word_pattern, text))
corrected_text = text
Expand Down

0 comments on commit 262c29a

Please sign in to comment.