Spaces:
Paused
Paused
File size: 8,224 Bytes
bc300ce 8eddfe0 bc300ce ba381db bc300ce ba381db bc300ce | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | from datetime import timedelta, datetime
from collections import defaultdict
import json
from typing import Tuple
from google.cloud.storage import Client, transfer_manager
from config import JOB_TYPES, PERSON_NAME, PERSON_PRONOUN, RESET_QUERY, CV_DATA_DIRNAME, CV_DATA_GCS_BUCKET
def download_cv_data() -> None:
# download cv data from google cloud storage
storage_client = Client()
bucket = storage_client.bucket(CV_DATA_GCS_BUCKET)
cv_document_blobs = [blob.name for blob in bucket.list_blobs(prefix=CV_DATA_DIRNAME)]
results = transfer_manager.download_many_to_path(bucket, cv_document_blobs)
if not all(result is None for result in results):
exception_message = ""
for i, download_result in enumerate(results):
if download_result is not None:
exception_message += f"❗ Exception occurred while downloading {cv_document_blobs[i]} from {CV_DATA_GCS_BUCKET}: {download_result}; "
raise RuntimeError(exception_message)
def get_job_type(position: str) -> str:
position_lower = position.lower()
for job_type in JOB_TYPES:
if job_type.lower() in position_lower:
return job_type
raise ValueError(f"Position '{position}' does not match any known job types.")
def join_grammatically(words: list[str]) -> str:
if len(words) == 0:
raise ValueError("words must contain at least one word.")
elif len(words) == 1:
return words[0]
return ", ".join(words[:-2] + [" and ".join(words[-2:])])
def td_to_yoe_str(td: timedelta) -> str:
secs_in_year = 365.2425 * 24 * 3600
td_secs = td.total_seconds()
if td_secs < secs_in_year:
secs_in_month = 30.436875 * 24 * 3600
months = round(td_secs / secs_in_month)
return f"{months} {'month' if months <= 1 else 'months'}"
else:
return f"{td_secs / secs_in_year:.1f} years"
def get_job_documents(jobs_json: dict) -> Tuple[str, list[str]]:
jobs_docs = []
positions_in_order = []
yoe_by_job_type = defaultdict(timedelta)
for job_json in jobs_json["jobs"].values():
company_word = f"[{job_json["company"]["name"]}]({job_json["company"]["link"]}) in {job_json["company"]["location"]}"
for position in job_json["positions"]:
start_date = datetime.strptime(position["startDate"], "%Y-%m-%d")
end_date = datetime.strptime(position["endDate"], "%Y-%m-%d")
yoe_by_job_type[get_job_type(position["name"])] += end_date - start_date
job_doc = f"{PERSON_NAME} worked as {position["name"]} at {company_word} from {start_date.strftime('%B %Y')} to {end_date.strftime('%B %Y')}."
job_doc += f" Following are highlights of this position: {'; '.join(position['highlights'])}."
jobs_docs.append(job_doc)
positions_in_order.append(f"➢ {position["name"]} at {company_word} ({start_date.strftime('%B %Y')} - {end_date.strftime('%B %Y')})")
yoe_by_job_type_strs = [f"{td_to_yoe_str(yoe)} of experience as {job_type}" for job_type, yoe in yoe_by_job_type.items()]
intro_message = f"{PERSON_NAME} has {join_grammatically(yoe_by_job_type_strs)}. Following are positions {PERSON_PRONOUN} has worked as:\n"
intro_message += "\n".join(positions_in_order)
intro_message += f"\nYou can ask me about more details on any of these positions. As a reminder, you can say \'{RESET_QUERY}\' to reset chat."
return intro_message, jobs_docs
def get_education_documents(education_json: dict) -> Tuple[str, list[str]]:
education_docs = []
university_name = education_json["school"]["name"]
university_end_date = datetime.strptime(education_json["endDate"], "%Y-%m-%d").strftime("%B %Y")
degree_full_str = f"{education_json["degree"]["name"]}"
minors = [minor["name"] for minor in education_json["minors"]]
if len(minors) == 1:
degree_full_str += f" with minor in {minors[0]}"
elif len(minors) > 1:
degree_full_str += f" with minors in {", ".join(minors)}"
dept_courses = defaultdict(list[str])
for course_json in education_json["courses"]:
course_number = course_json["number"]
course_dept = course_number.split(" ")[0]
dept_courses[course_dept].append(f"➢ [{course_json["number"]}]({course_json["link"]}): {course_json["title"]}")
dept_names = education_json["courseDepartments"]
sorted_depts = sorted(dept_courses, key=lambda k: len(dept_courses[k]), reverse=True)
for dept in sorted_depts:
education_docs.append(f"In department of {dept_names[dept]}, {PERSON_NAME} took \n{"\n".join(dept_courses[dept])}.")
sorted_dept_names = "\n".join([f"➢ {dept_names[dept]} ({dept})" for dept in sorted_depts])
intro_message = (f"{PERSON_NAME} graduated from {university_name} in {university_end_date} with {degree_full_str}. "
f"{PERSON_PRONOUN.title()} took {len(education_json["courses"])} courses across following departments:\n{sorted_dept_names}."
f"\nYou can ask me about detailed list of courses {PERSON_NAME} took in each department. As a reminder, you can say \'{RESET_QUERY}\' to reset chat.")
return intro_message, education_docs
def get_paper_documents(papers_json: dict) -> Tuple[str, list[str]]:
intro_messages = []
paper_docs = []
for i, paper_json in enumerate(papers_json["papers"]):
paper_date = datetime.strptime(paper_json["date"], "%Y-%m")
intro_messages.append(f"{i + 1}: {paper_json["title"]} ({paper_date.strftime("%Y")})")
paper_doc = f"{i + 1}: Title of this paper is {paper_json["title"]}."
location_str = f" in {paper_json["location"]}" if "location" in paper_json else ""
paper_doc += f" It was published on {paper_date.strftime("%B %Y")}{location_str}."
if "conference" in paper_json:
paper_doc += f" It was published in {paper_json["conference"]}."
paper_doc += f" Link to paper is {paper_json["paperUrl"]}."
paper_doc += f" Following is description of this paper. {paper_json["desc"]}"
paper_docs.append(paper_doc)
intro_message = (f"{PERSON_NAME} wrote {len(intro_messages)} papers. Here are titles of these papers:\n{"\n".join(intro_messages)}"
f"\nYou can ask me about more details on any of these papers. As a reminder, you can say \'{RESET_QUERY}\' to reset chat.")
return intro_message, paper_docs
def get_skill_documents(skills_json: dict) -> Tuple[str, list[str]]:
skill_competency = defaultdict(int)
skills_by_category = defaultdict(list)
for skill_json in skills_json["skills"]:
skill_competency[skill_json["title"]] = skill_json["competency"]
for skill_category in skill_json["category"]:
skills_by_category[skill_category].append(skill_json["title"])
skill_docs = []
for category, skills in skills_by_category.items():
skills.sort(key=lambda x: skill_competency[x], reverse=True)
skill_docs.append(f"Technical skills related to {category} that {PERSON_NAME} has are: {", ".join(skills)}.")
sorted_skill_categories = list(skills_by_category.keys())
sorted_skill_categories.sort()
intro_message = (f"{PERSON_NAME} has various technical skills across following categories:\n"
f"{'\n'.join([f"➢ {category}" for category in sorted_skill_categories])}"
f"\nYou can ask me which technical skills {PERSON_NAME} has in one of these areas. As a reminder, you can say \'{RESET_QUERY}\' to reset chat.")
return intro_message, skill_docs
def print_docs(name, file_name, parse_func):
with open(f"cvdata/{file_name}") as f:
intro_message, docs = parse_func(json.load(f))
print(f'\n>>>>>>>>>> {name} <<<<<<<<<<')
print('========== Intro')
print(intro_message)
print('\n========== Docs')
for doc in docs:
print(doc + '\n')
if __name__ == "__main__":
print_docs("Jobs", "jobs.json", get_job_documents)
print_docs("Education", "education.json", get_education_documents)
print_docs("Papers", "papers.json", get_paper_documents)
print_docs("Skills", "skills.json", get_skill_documents) |