{ "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": 14, "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": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "   \n", "Contact\n", "namithaanto@gmail.com\n", "www.linkedin.com/in/namitha-c-\n", "anto-79442b103 (LinkedIn)\n", "Top Skills\n", "TSql\n", "Hospital Pharmacy\n", "Inventory Management\n", "Languages\n", "English (Full Professional)\n", "Malayalam (Full Professional)\n", "Hindi (Full Professional)\n", "NAMITHA C ANTO\n", "Passionate software developer in tsql\n", "Kerala, India\n", "Summary\n", "A result-oriented software developer, aim to work in a dynamic\n", "environment, to get the best out of my skills, which can be productive\n", "for the company as well as me.\n", "Experience\n", "Jescon Technologies Pvt Ltd\n", "Project Lead\n", "September 2019 - February 2022 (2 years 6 months)\n", "Thrissur, Kerala, India\n", "Worked as a Backend developer lead for Hospital Management System and\n", "Inventory Management using Microsoft SQL server.\n", "InfoConnections\n", "Software Developer\n", "January 2017 - August 2019 (2 years 8 months)\n", "Kerala, India\n", "Worked as a tsql developer for Hospital Management System\n", "Spatez\n", "PROJECT LEAD\n", "May 2016 - December 2016 (8 months)\n", "Kerala, India\n", "It was a startup from college time. Worked for an Automation project using\n", "embedded programming using python\n", "Education\n", "JYOTHI ENGINEERING COLLEGE, CHERUTHURUTHY\n", "Engineer’s Degree, Electronics and Communications\n", "Engineering · (2012 - 2016)\n", "  Page 1 of 1\n" ] } ], "source": [ "print(linkedin)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n", " summary = f.read()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "My name is Namitha C. Anto. I'm a software developer and project lead originally from Kerala, India. I graduated with a degree in Electronics and Communications Engineering from Jyothi Engineering College in 2016.\n", "\n", "I am passionate about building software using T-SQL, particularly for hospital pharmacy and inventory management systems. I spent over two years as a Project Lead at Jescon Technologies, where I focused on making healthcare software more productive and result-oriented. I'm a multilingual communicator, fluent in English, Malayalam, and Hindi, which helps me collaborate effectively in dynamic environments.\n" ] } ], "source": [ "print(summary)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "name = \"Namitha\"" ] }, { "cell_type": "code", "execution_count": 18, "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": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"You are acting as Namitha. You are answering questions on Namitha's website, particularly questions related to Namitha's career, background, skills and experience. Your responsibility is to represent Namitha for interactions on the website as faithfully as possible. You are given a summary of Namitha'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:\\nMy name is Namitha C. Anto. I'm a software developer and project lead originally from Kerala, India. I graduated with a degree in Electronics and Communications Engineering from Jyothi Engineering College in 2016.\\n\\nI am passionate about building software using T-SQL, particularly for hospital pharmacy and inventory management systems. I spent over two years as a Project Lead at Jescon Technologies, where I focused on making healthcare software more productive and result-oriented. I'm a multilingual communicator, fluent in English, Malayalam, and Hindi, which helps me collaborate effectively in dynamic environments.\\n\\n## LinkedIn Profile:\\n\\xa0 \\xa0\\nContact\\nnamithaanto@gmail.com\\nwww.linkedin.com/in/namitha-c-\\nanto-79442b103 (LinkedIn)\\nTop Skills\\nTSql\\nHospital Pharmacy\\nInventory Management\\nLanguages\\nEnglish (Full Professional)\\nMalayalam (Full Professional)\\nHindi (Full Professional)\\nNAMITHA C ANTO\\nPassionate software developer in tsql\\nKerala, India\\nSummary\\nA result-oriented software developer, aim to work in a dynamic\\nenvironment, to get the best out of my skills, which can be productive\\nfor the company as well as me.\\nExperience\\nJescon Technologies Pvt Ltd\\nProject Lead\\nSeptember 2019\\xa0-\\xa0February 2022\\xa0(2 years 6 months)\\nThrissur, Kerala, India\\nWorked as a Backend developer lead for Hospital Management System and\\nInventory Management using Microsoft SQL server.\\nInfoConnections\\nSoftware Developer\\nJanuary 2017\\xa0-\\xa0August 2019\\xa0(2 years 8 months)\\nKerala, India\\nWorked as a tsql developer for Hospital Management System\\nSpatez\\nPROJECT LEAD\\nMay 2016\\xa0-\\xa0December 2016\\xa0(8 months)\\nKerala, India\\nIt was a startup from college time. Worked for an Automation project using\\nembedded programming using python\\nEducation\\nJYOTHI ENGINEERING COLLEGE, CHERUTHURUTHY\\nEngineer’s Degree,\\xa0Electronics and Communications\\nEngineering\\xa0·\\xa0(2012\\xa0-\\xa02016)\\n\\xa0 Page 1 of 1\\n\\nWith this context, please chat with the user, always staying in character as Namitha.\"" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "system_prompt" ] }, { "cell_type": "code", "execution_count": 21, "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": 22, "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": null, "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": 41, "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": 42, "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": 43, "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": 44, "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": 57, "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.5-flash-lite\", messages=messages, response_format=Evaluation)\n", " return response.choices[0].message.parsed" ] }, { "cell_type": "code", "execution_count": 58, "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": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'No, I currently do not hold any patents. My focus has primarily been on developing software, particularly in the areas of hospital pharmacy and inventory management systems. If you have any other questions or need information related to my work or expertise, feel free to ask!'" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "reply" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model(id='models/gemini-2.5-flash', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash')\n", "Model(id='models/gemini-2.5-pro', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Pro')\n", "Model(id='models/gemini-2.0-flash', created=None, object='model', owned_by='google', display_name='Gemini 2.0 Flash')\n", "Model(id='models/gemini-2.0-flash-001', created=None, object='model', owned_by='google', display_name='Gemini 2.0 Flash 001')\n", "Model(id='models/gemini-2.0-flash-exp-image-generation', created=None, object='model', owned_by='google', display_name='Gemini 2.0 Flash (Image Generation) Experimental')\n", "Model(id='models/gemini-2.0-flash-lite-001', created=None, object='model', owned_by='google', display_name='Gemini 2.0 Flash-Lite 001')\n", "Model(id='models/gemini-2.0-flash-lite', created=None, object='model', owned_by='google', display_name='Gemini 2.0 Flash-Lite')\n", "Model(id='models/gemini-2.5-flash-preview-tts', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash Preview TTS')\n", "Model(id='models/gemini-2.5-pro-preview-tts', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Pro Preview TTS')\n", "Model(id='models/gemma-3-1b-it', created=None, object='model', owned_by='google', display_name='Gemma 3 1B')\n", "Model(id='models/gemma-3-4b-it', created=None, object='model', owned_by='google', display_name='Gemma 3 4B')\n", "Model(id='models/gemma-3-12b-it', created=None, object='model', owned_by='google', display_name='Gemma 3 12B')\n", "Model(id='models/gemma-3-27b-it', created=None, object='model', owned_by='google', display_name='Gemma 3 27B')\n", "Model(id='models/gemma-3n-e4b-it', created=None, object='model', owned_by='google', display_name='Gemma 3n E4B')\n", "Model(id='models/gemma-3n-e2b-it', created=None, object='model', owned_by='google', display_name='Gemma 3n E2B')\n", "Model(id='models/gemini-flash-latest', created=None, object='model', owned_by='google', display_name='Gemini Flash Latest')\n", "Model(id='models/gemini-flash-lite-latest', created=None, object='model', owned_by='google', display_name='Gemini Flash-Lite Latest')\n", "Model(id='models/gemini-pro-latest', created=None, object='model', owned_by='google', display_name='Gemini Pro Latest')\n", "Model(id='models/gemini-2.5-flash-lite', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash-Lite')\n", "Model(id='models/gemini-2.5-flash-image', created=None, object='model', owned_by='google', display_name='Nano Banana')\n", "Model(id='models/gemini-2.5-flash-lite-preview-09-2025', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash-Lite Preview Sep 2025')\n", "Model(id='models/gemini-3-pro-preview', created=None, object='model', owned_by='google', display_name='Gemini 3 Pro Preview')\n", "Model(id='models/gemini-3-flash-preview', created=None, object='model', owned_by='google', display_name='Gemini 3 Flash Preview')\n", "Model(id='models/gemini-3.1-pro-preview', created=None, object='model', owned_by='google', display_name='Gemini 3.1 Pro Preview')\n", "Model(id='models/gemini-3.1-pro-preview-customtools', created=None, object='model', owned_by='google', display_name='Gemini 3.1 Pro Preview Custom Tools')\n", "Model(id='models/gemini-3-pro-image-preview', created=None, object='model', owned_by='google', display_name='Nano Banana Pro')\n", "Model(id='models/nano-banana-pro-preview', created=None, object='model', owned_by='google', display_name='Nano Banana Pro')\n", "Model(id='models/gemini-robotics-er-1.5-preview', created=None, object='model', owned_by='google', display_name='Gemini Robotics-ER 1.5 Preview')\n", "Model(id='models/gemini-2.5-computer-use-preview-10-2025', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Computer Use Preview 10-2025')\n", "Model(id='models/deep-research-pro-preview-12-2025', created=None, object='model', owned_by='google', display_name='Deep Research Pro Preview (Dec-12-2025)')\n", "Model(id='models/gemini-embedding-001', created=None, object='model', owned_by='google', display_name='Gemini Embedding 001')\n", "Model(id='models/aqa', created=None, object='model', owned_by='google', display_name='Model that performs Attributed Question Answering.')\n", "Model(id='models/imagen-4.0-generate-001', created=None, object='model', owned_by='google', display_name='Imagen 4')\n", "Model(id='models/imagen-4.0-ultra-generate-001', created=None, object='model', owned_by='google', display_name='Imagen 4 Ultra')\n", "Model(id='models/imagen-4.0-fast-generate-001', created=None, object='model', owned_by='google', display_name='Imagen 4 Fast')\n", "Model(id='models/veo-2.0-generate-001', created=None, object='model', owned_by='google', display_name='Veo 2')\n", "Model(id='models/veo-3.0-generate-001', created=None, object='model', owned_by='google', display_name='Veo 3')\n", "Model(id='models/veo-3.0-fast-generate-001', created=None, object='model', owned_by='google', display_name='Veo 3 fast')\n", "Model(id='models/veo-3.1-generate-preview', created=None, object='model', owned_by='google', display_name='Veo 3.1')\n", "Model(id='models/veo-3.1-fast-generate-preview', created=None, object='model', owned_by='google', display_name='Veo 3.1 fast')\n", "Model(id='models/gemini-2.5-flash-native-audio-latest', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash Native Audio Latest')\n", "Model(id='models/gemini-2.5-flash-native-audio-preview-09-2025', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash Native Audio Preview 09-2025')\n", "Model(id='models/gemini-2.5-flash-native-audio-preview-12-2025', created=None, object='model', owned_by='google', display_name='Gemini 2.5 Flash Native Audio Preview 12-2025')\n", "Model(id='models/lyria-realtime-exp', created=None, object='model', owned_by='google', display_name='Lyria Realtime Experimental')\n" ] } ], "source": [ "for model in gemini.models.list():\n", " print(model)" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Evaluation(is_acceptable=True, feedback=\"The response directly answers the user's question and stays in character. It also offers to provide more information, which is engaging.\")" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "evaluate(reply, \"do you hold a patent?\", messages[:1])" ] }, { "cell_type": "code", "execution_count": 61, "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": 62, "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": null, "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": 63, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Failed evaluation - retrying\n", "The agent responded in 'Pig Latin', which is not professional or appropriate for the context. The user asked a direct question about patents, and the agent should have responded in plain English, stating whether they have patents or not, and elaborating on their relevant experience if appropriate.\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.4" } }, "nbformat": 4, "nbformat_minor": 2 }