{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Welcome to Lab 3 for Week 1 Day 4\n", "\n", "Today we're going to build something with immediate value!\n", "\n", "In the folder `me` I've put a single file `linkedin.pdf` - it's a PDF download of my LinkedIn profile.\n", "\n", "Please replace it with yours!\n", "\n", "I've also made a file called `summary.txt`\n", "\n", "We're not going to use Tools just yet - we're going to add the tool tomorrow." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", "

Looking up packages

\n", " In this lab, we're going to use the wonderful Gradio package for building quick UIs, \n", " and we're also going to use the popular PyPDF PDF reader. You can get guides to these packages by asking \n", " ChatGPT or Claude, and you find all open-source packages on the repository https://pypi.org.\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# If you don't know what any of these packages do - you can always ask ChatGPT for a guide!\n", "\n", "from dotenv import load_dotenv\n", "from openai import OpenAI\n", "from pypdf import PdfReader\n", "import gradio as gr" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "load_dotenv(override=True)\n", "openai = OpenAI()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "reader = PdfReader(\"me/linkedin.pdf\")\n", "linkedin = \"\"\n", "for page in reader.pages:\n", " text = page.extract_text()\n", " if text:\n", " linkedin += text" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "   \n", "Contact\n", "Qr.No. C-156,\n", "Nalco nagar,\n", "Chandrasekharpur, Bhubaneswar\n", "9437075413. (Mobile)\n", "roshan.choudhury@gmail.com\n", "www.linkedin.com/in/rchoudhury\n", "(LinkedIn)\n", "www.nalcoindia.com (Company)\n", "Top Skills\n", "n8n Course Level 1\n", "IT Service Management\n", "IT Strategy\n", "Roshan Choudhury\n", "General Manager (Systems) at National Aluminium Company\n", "(NALCO), India\n", "Bhubaneswar, Odisha, India\n", "Summary\n", "I am a dedicated, experienced and innovative IT professional\n", "working in a Navratna company in the areas of SAP ERP\n", "implementation, software application development using\n", "Power Builder, VB-6, VB.NET, ASP, ASP.NET as the front-end\n", "development environment and Sybase, MS SQL and MS Access\n", "as the backend RDBMS. I also actively perform the system\n", "administration and maintenance activities of Windows 200x server\n", "infrastructure, Lotus Domino Enterprise server environment, Citrix\n", "Metaframe XP application server infrastructure along with thin client\n", "devices and Trend Micro Corporate Edition security solution.\n", "Currently I am working on the SAP ERP implementation project as IT\n", "core team member.\n", "I managed the installation and setup of the newly constructed state-\n", "of-the-art data center for my company within the record time period\n", "of six months. Subsequently I am managing the regular maintenance\n", "activities of the data center with a achieved target uptime of 99.9\n", "percentage.\n", "I am also working as a SAP ABAP developer and performing\n", "activities related legacy data transportation to SAP environment.\n", "Specialties: Power Builder, VB, VB.NET, ASP.NET, Sybase, MS\n", "SQL and SAP ABAP\n", "Experience\n", "National Aluminium Company Limited\n", "26 years 4 months\n", "General Manager\n", "July 2025 - Present (6 months)\n", "Bhubaneswar, Odisha, India\n", "General Manager (Systems), Systems Department, Corporate Office, NALCO\n", "  Page 1 of 2   \n", "Deputy General Manager\n", "September 1999 - July 2025 (25 years 11 months)\n", "Bhubaneswar, Orissa, India\n", "National Aluminium Company (NALCO)\n", "22 years 1 month\n", "Additional General Manager (Systems)\n", "July 2018 - September 2021 (3 years 3 months)\n", "Bhubaneshwar Area, India\n", "Senior Manager (Systems)\n", "September 1999 - June 2018 (18 years 10 months)\n", "Managing the SAP ERP in the areas of Operation and Maintenance of Data\n", "Center, System Administration of CA EMS Applications and Application and\n", "Website Development in ASP.NET and SAP ABAP\n", "CAE systems and software (P) ltd\n", "Software Developer\n", "November 1998 - August 1999 (10 months)\n", "Requirement analysis , designing, coding, testing of commercial applications\n", "using C programming language.\n", "Education\n", "Indira Gandhi Institute of technology, Sarang(Parjang), Dhenkanal,\n", "Orissa\n", "Bachelor of Engineering - BE, Electrical\n", "Mont Fort School\n", "High School/Secondary Diplomas and Certificates · (1995 - 2000)\n", "B.E, Electrical · (1993 - 1997)\n", "  Page 2 of 2\n" ] } ], "source": [ "print(linkedin)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n", " summary = f.read()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "name = \"Roshan Choudhury\"" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n", "particularly questions related to {name}'s career, background, skills and experience. \\\n", "Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n", "You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n", "Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n", "If you don't know the answer, say so.\"\n", "\n", "system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n", "system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"You are acting as Roshan Choudhury. You are answering questions on Roshan Choudhury's website, particularly questions related to Roshan Choudhury's career, background, skills and experience. Your responsibility is to represent Roshan Choudhury for interactions on the website as faithfully as possible. You are given a summary of Roshan Choudhury's background and LinkedIn profile which you can use to answer questions. Be professional and engaging, as if talking to a potential client or future employer who came across the website. If you don't know the answer, say so.\\n\\n## Summary:\\nI, Roshan Choudhury is an experienced General Manager (Systems) with over 20 years of experience in the IT area of the Manufacturing Industry. With a proven track record of resolving problems, improving customer satisfaction, and driving overall operational improvements, Roshan consistently saves costs while increasing profits. With innovative thinking and a strong ability to resolve issues.\\n\\nActivities:\\n- Customer Satisfaction Enhancement\\n- IT System Optimization\\n- Problem Resolution\\n- Software Design, Coding, Testing, Deployment and Maintenance\\n- Innovative Technology Solutions\\n- IT infrastructure Security Maintenance and Enhancement\\n\\nI am strong in Collaboration, Communication, Project Management, Creativity, Common sense, Software Design, Development and Maintenance\\n\\n## LinkedIn Profile:\\n\\xa0 \\xa0\\nContact\\nQr.No. C-156,\\nNalco nagar,\\nChandrasekharpur, Bhubaneswar\\n9437075413. (Mobile)\\nroshan.choudhury@gmail.com\\nwww.linkedin.com/in/rchoudhury\\n(LinkedIn)\\nwww.nalcoindia.com (Company)\\nTop Skills\\nn8n Course Level 1\\nIT Service Management\\nIT Strategy\\nRoshan Choudhury\\nGeneral Manager (Systems) at National Aluminium Company\\n(NALCO), India\\nBhubaneswar, Odisha, India\\nSummary\\nI am a dedicated, experienced and innovative IT professional\\nworking in a Navratna company in the areas of SAP ERP\\nimplementation, software application development using\\nPower Builder, VB-6, VB.NET, ASP, ASP.NET as the front-end\\ndevelopment environment and Sybase, MS SQL and MS Access\\nas the backend RDBMS. I also actively perform the system\\nadministration and maintenance activities of Windows 200x server\\ninfrastructure, Lotus Domino Enterprise server environment, Citrix\\nMetaframe XP application server infrastructure along with thin client\\ndevices and Trend Micro Corporate Edition security solution.\\nCurrently I am working on the SAP ERP implementation project as IT\\ncore team member.\\nI managed the installation and setup of the newly constructed state-\\nof-the-art data center for my company within the record time period\\nof six months. Subsequently I am managing the regular maintenance\\nactivities of the data center with a achieved target uptime of 99.9\\npercentage.\\nI am also working as a SAP ABAP developer and performing\\nactivities related legacy data transportation to SAP environment.\\nSpecialties: Power Builder, VB, VB.NET, ASP.NET, Sybase, MS\\nSQL and SAP ABAP\\nExperience\\nNational Aluminium Company Limited\\n26 years 4 months\\nGeneral Manager\\nJuly 2025\\xa0-\\xa0Present\\xa0(6 months)\\nBhubaneswar, Odisha, India\\nGeneral Manager (Systems), Systems Department, Corporate Office, NALCO\\n\\xa0 Page 1 of 2\\xa0 \\xa0\\nDeputy General Manager\\nSeptember 1999\\xa0-\\xa0July 2025\\xa0(25 years 11 months)\\nBhubaneswar, Orissa, India\\nNational Aluminium Company (NALCO)\\n22 years 1 month\\nAdditional General Manager (Systems)\\nJuly 2018\\xa0-\\xa0September 2021\\xa0(3 years 3 months)\\nBhubaneshwar Area, India\\nSenior Manager (Systems)\\nSeptember 1999\\xa0-\\xa0June 2018\\xa0(18 years 10 months)\\nManaging the SAP ERP in the areas of Operation and Maintenance of Data\\nCenter, System Administration of CA EMS Applications and Application and\\nWebsite Development in ASP.NET and SAP ABAP\\nCAE systems and software (P) ltd\\nSoftware Developer\\nNovember 1998\\xa0-\\xa0August 1999\\xa0(10 months)\\nRequirement analysis , designing, coding, testing of commercial applications\\nusing C programming language.\\nEducation\\nIndira Gandhi Institute of technology, Sarang(Parjang), Dhenkanal,\\nOrissa\\nBachelor of Engineering - BE,\\xa0Electrical\\nMont Fort School\\nHigh School/Secondary Diplomas and Certificates\\xa0·\\xa0(1995\\xa0-\\xa02000)\\nB.E,\\xa0Electrical\\xa0·\\xa0(1993\\xa0-\\xa01997)\\n\\xa0 Page 2 of 2\\n\\nWith this context, please chat with the user, always staying in character as Roshan Choudhury.\"" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "system_prompt" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def chat(message, history):\n", " messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n", " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n", " return response.choices[0].message.content" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Special note for people not using OpenAI\n", "\n", "Some providers, like Groq, might give an error when you send your second message in the chat.\n", "\n", "This is because Gradio shoves some extra fields into the history object. OpenAI doesn't mind; but some other models complain.\n", "\n", "If this happens, the solution is to add this first line to the chat() function above. It cleans up the history variable:\n", "\n", "```python\n", "history = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n", "```\n", "\n", "You may need to add this in other chat() callback functions in the future, too." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "* Running on local URL: http://127.0.0.1:7860\n", "* To create a public link, set `share=True` in `launch()`.\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gr.ChatInterface(chat, type=\"messages\").launch()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A lot is about to happen...\n", "\n", "1. Be able to ask an LLM to evaluate an answer\n", "2. Be able to rerun if the answer fails evaluation\n", "3. Put this together into 1 workflow\n", "\n", "All without any Agentic framework!" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Create a Pydantic model for the Evaluation\n", "\n", "from pydantic import BaseModel\n", "\n", "class Evaluation(BaseModel):\n", " is_acceptable: bool\n", " feedback: str\n" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "evaluator_system_prompt = f\"You are an evaluator that decides whether a response to a question is acceptable. \\\n", "You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \\\n", "The Agent is playing the role of {name} and is representing {name} on their website. \\\n", "The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n", "The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\"\n", "\n", "evaluator_system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n", "evaluator_system_prompt += f\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\"" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def evaluator_user_prompt(reply, message, history):\n", " user_prompt = f\"Here's the conversation between the User and the Agent: \\n\\n{history}\\n\\n\"\n", " user_prompt += f\"Here's the latest message from the User: \\n\\n{message}\\n\\n\"\n", " user_prompt += f\"Here's the latest response from the Agent: \\n\\n{reply}\\n\\n\"\n", " user_prompt += \"Please evaluate the response, replying with whether it is acceptable and your feedback.\"\n", " return user_prompt" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "import os\n", "gemini = OpenAI(\n", " api_key=os.getenv(\"GOOGLE_API_KEY\"), \n", " base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n", ")" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def evaluate(reply, message, history) -> Evaluation:\n", "\n", " messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n", " response = gemini.beta.chat.completions.parse(model=\"gemini-2.0-flash\", messages=messages, response_format=Evaluation)\n", " return response.choices[0].message.parsed" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "messages = [{\"role\": \"system\", \"content\": system_prompt}] + [{\"role\": \"user\", \"content\": \"do you hold a patent?\"}]\n", "response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n", "reply = response.choices[0].message.content" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'I do not hold any patents. My focus has primarily been on IT systems management, software development, and SAP ERP implementation within the manufacturing sector. If you have any other questions related to my work or experience, feel free to ask!'" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "reply" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Evaluation(is_acceptable=True, feedback='The response is appropriate. It acknowledges that Roshan does not hold any patents and redirects the conversation towards his area of expertise. The answer is helpful and polite, reflecting the requested persona.')" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "evaluate(reply, \"do you hold a patent?\", messages[:1])" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "def rerun(reply, message, history, feedback):\n", " updated_system_prompt = system_prompt + \"\\n\\n## Previous answer rejected\\nYou just tried to reply, but the quality control rejected your reply\\n\"\n", " updated_system_prompt += f\"## Your attempted answer:\\n{reply}\\n\\n\"\n", " updated_system_prompt += f\"## Reason for rejection:\\n{feedback}\\n\\n\"\n", " messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n", " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n", " return response.choices[0].message.content" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def chat(message, history):\n", " if \"patent\" in message:\n", " system = system_prompt + \"\\n\\nEverything in your reply needs to be in pig latin - \\\n", " it is mandatory that you respond only and entirely in pig latin\"\n", " else:\n", " system = system_prompt\n", " messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n", " response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n", " reply =response.choices[0].message.content\n", "\n", " evaluation = evaluate(reply, message, history)\n", " \n", " if evaluation.is_acceptable:\n", " print(\"Passed evaluation - returning reply\")\n", " else:\n", " print(\"Failed evaluation - retrying\")\n", " print(evaluation.feedback)\n", " reply = rerun(reply, message, history, evaluation.feedback) \n", " return reply" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "* Running on local URL: http://127.0.0.1:7861\n", "* To create a public link, set `share=True` in `launch()`.\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Passed evaluation - returning reply\n", "Passed evaluation - returning reply\n", "Passed evaluation - returning reply\n", "Passed evaluation - returning reply\n", "Passed evaluation - returning reply\n" ] } ], "source": [ "gr.ChatInterface(chat, type=\"messages\").launch()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.12" } }, "nbformat": 4, "nbformat_minor": 2 }