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)