File size: 8,272 Bytes
0578892
8e96671
 
0578892
8e96671
 
 
ab13803
1e333df
0578892
8e96671
3ebfb41
8e96671
 
ab13803
8e96671
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6a3560f
 
bb4e2a5
6a3560f
 
8e96671
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
066b023
8e96671
 
 
 
 
 
 
 
 
 
 
 
066b023
 
ab13803
8e96671
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0578892
 
8e96671
 
 
6a3560f
 
ab13803
 
8e96671
 
 
 
 
 
 
 
 
 
 
0578892
8e96671
 
 
 
 
 
 
 
 
0578892
8e96671
 
 
 
 
 
0578892
8e96671
 
 
 
 
62f321d
bb4e2a5
 
 
 
 
 
62f321d
8e96671
 
21d8abe
8e96671
62f321d
8e96671
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import os
import operator
from typing import TypedDict, Annotated, Sequence

from langchain_openai.chat_models import ChatOpenAI
from langchain_core.messages import BaseMessage, SystemMessage
from langgraph.graph import StateGraph, END
import panel as pn

pn.extension()
os.environ["LANGCHAIN_TRACING_V2"] = "true"

JOB_DESCRIPTION = """
Quansight has its roots in the Python data science community. Our founders have had significant involvement in creating and maintaining NumPy, SciPy, Jupyter, Spyder, Dask, Conda, Numba, and other projects, as well as PyData NumFOCUS, and Anaconda. Our mission is to connect companies to open-source communities to create sustainable solutions that benefit the whole ecosystem.

We accomplish this mission by providing various services ranging from open-source software development to training and consulting. We believe in a culture of do-ers, learners, and collaborators. We are looking for people who are motivated, humble, curious, and respectful of others.

We are looking for enthusiastic and highly motivated software developers with extensive experience in the Scientific Python and PyData ecosystems to help support Quansight’s growing consulting business. This is an excellent opportunity for you to apply your software development skills to the open-source, Python, data-science, AI, big data and visualization ecosystems, and to help customers apply these tools to solve practical business problems.

What you’ll do
As a Senior PyData Software Engineer, you will be a key member of our team solving problems for our clients using tools from the Python open-source ecosystem. As appropriate, you will help maintain and push developments back upstream to open source projects. We are especially interested in people with a strong technical background who have experience or have an interest in becoming technical leads. Our client projects vary widely across business domains and technologies, being comfortable with growing and learning new technologies will be important to fitting in at Quansight. Key areas we touch on when building solutions for clients include algorithm development, data engineering, data science, machine learning/AI, visualization, packaging, infrastructure and integration.

Requirements:
Fluency in Python
Extensive experience with the Scientific Python and Data Science ecosystems, i.e. Pandas, NumPy, Scikit-Learn, etc.
Experience applying the PyData stack to data and scientific projects
Familiarity with software engineering best practices, including unit tests, code review, version control, CI/CD, etc.
Superior written and verbal communication skills, including writing and reviewing  documentation
Ability to make technical and architectural decisions with minimal oversight. 
Additionally one or more of the following skills will help you stand out:

Contributions to open source projects
Skills in other programming languages
Experience with Generative AI / LLM's 
Experience with Visualization tools like Panel, Streamlit, Dash etc.
Experience with DevOps and Infrastructure-as-Code approaches
Experience with Python packaging and Conda environments
Experience with advanced Python data libraries such as Dask and Numba
Experience working in a client-facing environment
Exposure to building data engineering pipelines using Prefect, Airflow and similar tools
Practical Experience in MLOps approaches
Ability to provide technical leadership to others
Why should you join?
You'll become essential to a small, collaborative, fully distributed accessibility and engineering team. We strive to provide a working environment that gives you room to learn and grow.
""".strip()

RESUME_BULLETS = """
o Investigated the cause of anomalous sea surface temperatures following tropical cyclones (TCs) in the Eastern Tropical Pacific
o Deduced, quantitatively, that TCs tend to suppress low clouds there, enhancing shortwave fluxes, inducing a warming anomaly
o Demonstrated that long-short-term-memory models improved predictions at long leads but not at short leads
""".strip()

AVATARS = {
    "critique": "🔍",
    "revise": "📝",
}


class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    original_bullets: str
    job_description: str
    keywords_count: int


async def revise(state: AgentState):
    instructions = """
        Understand the critique first and identify what keywords from the critique
        needs to be bolded. Then apply the actionable steps to revise the resume bullets.

        Revisions should be similar length as the original bullets.

        Ensure the keywords from the critique are not awkwardly
        placed, not deceitful, and the bullets are coherent and in proper sentence casing.
    """
    messages = [SystemMessage(instructions)] + state["messages"][-2:]
    response = await model.ainvoke(messages)
    return {"messages": [response]}


async def critique(state: AgentState):
    job_description = state["job_description"]
    keywords_slider = state["keywords_count"]
    instructions = f"""
        You are a resume reviewer, optimizing for ATS.
        Review the job description and first list out
        at least `{keywords_slider}` unique, critical
        ATS keywords from the `Job Description`.

        If previously `Critique`d, verify if the changes were accurately made;
        if not, rephrase original critique to be more actionable.

        Determine whether the resume bullets have at least 
        {keywords_slider} keywords from the `Job Description` in bold.

        If not, provide actionable steps to revise (but do not do the revision),
        e.g. explicitly telling what keywords to bold from `Job Description` or
        what to rephrase to include reflecting the `Job Description`. 

        If no changes are needed, simply output "Looks good!";
        else output the critique starting with `Critique`: and keywords.

        Here's the `Job Description`:
        '''
        {job_description}
        '''
    """
    messages = [SystemMessage(instructions)] + state["messages"][-2:]
    response = await model.ainvoke(messages)
    return {"messages": [response]}


def continue_revising(state: AgentState):
    last_message = state["messages"][-1].content
    return "looks good" not in last_message.lower()


async def respond(content: str, user: str, instance: pn.chat.ChatInterface):
    if not job_input.value:
        instance.stream(
            user="Exception", value="Please provide a job description.", respond=False
        )
        return

    response = app.astream(
        {
            "original_bullets": resume_input.value,
            "messages": [content],
            "job_description": job_input.value,
            "keywords_count": keywords_slider.value,
        }
    )
    async for chunk in response:
        for user, output in chunk.items():
            message = output["messages"][-1].content
            if user != "__end__":
                avatar = AVATARS.get(user, "🤖")
                instance.stream(user=user.title(), value=message, avatar=avatar)


model = ChatOpenAI()
# add components
workflow = StateGraph(AgentState)
workflow.add_node("critique", critique)
workflow.add_node("revise", revise)

# add connections
workflow.set_entry_point("critique")
workflow.add_edge("revise", "critique")
workflow.add_conditional_edges(
    "critique", continue_revising, {True: "revise", False: END}
)
app = workflow.compile()

# create UI
keywords_slider = pn.widgets.IntSlider(
    start=1,
    end=10,
    value=3,
    name="Keywords to Match",
    sizing_mode="stretch_width",
)
job_input = pn.widgets.TextAreaInput(
    value=JOB_DESCRIPTION,
    name="Job Description",
    resizable="height",
    auto_grow=True,
    sizing_mode="stretch_width",
)
resume_input = pn.widgets.TextAreaInput(
    placeholder="Paste in the bullets you want revised.",
    resizable="height",
    rows=4,
    value=RESUME_BULLETS,
)
interface = pn.chat.ChatInterface(
    callback=respond,
    widgets=[resume_input],
    show_undo=False,
    show_button_name=False,
)
template = pn.template.FastListTemplate(
    main=[interface],
    sidebar=[keywords_slider, job_input],
    sidebar_width=500,
    title="Resume Reviser",
)
template.servable()