Spaces:
Sleeping
Sleeping
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()
|