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()