From 1f5afda37bec4293072897ab472c42ad81051843 Mon Sep 17 00:00:00 2001 From: Syed Abrar Ahmad Date: Sun, 10 Aug 2025 16:27:22 +0500 Subject: [PATCH] Added a new notebook for week 2 Exercise. --- .../week2_exercise_by_abrar.ipynb | 482 ++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 week2/community-contributions/week2_exercise_by_abrar.ipynb diff --git a/week2/community-contributions/week2_exercise_by_abrar.ipynb b/week2/community-contributions/week2_exercise_by_abrar.ipynb new file mode 100644 index 0000000..2c53738 --- /dev/null +++ b/week2/community-contributions/week2_exercise_by_abrar.ipynb @@ -0,0 +1,482 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ddfa9ae6-69fe-444a-b994-8c4c5970a7ec", + "metadata": {}, + "source": [ + "# Project - Cricket Anaylyst AI Assistant\n", + "\n", + "Cricket Analyst AI Assistant is an intelligent tool that analyzes cricket data to compare players, evaluate performances across formats, and provide insightful statistics. It processes historical and recent match data to deliver easy-to-understand summaries, helping fans, analysts, and coaches make informed decisions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b50bbe2-c0b1-49c3-9a5c-1ba7efa2bcb4", + "metadata": {}, + "outputs": [], + "source": [ + "# imports\n", + "\n", + "import os\n", + "import json\n", + "from dotenv import load_dotenv\n", + "from openai import OpenAI\n", + "import gradio as gr\n", + "import speech_recognition as sr\n", + "import pandas as pd\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "747e8786-9da8-4342-b6c9-f5f69c2e22ae", + "metadata": {}, + "outputs": [], + "source": [ + "# Initialization\n", + "\n", + "load_dotenv(override=True)\n", + "\n", + "openai_api_key = os.getenv('OPENAI_API_KEY')\n", + "if openai_api_key:\n", + " print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n", + "else:\n", + " print(\"OpenAI API Key not set\")\n", + " \n", + "MODEL = \"gpt-4o-mini\"\n", + "openai = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a521d84-d07c-49ab-a0df-d6451499ed97", + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"\"\"\n", + "You are a Cricket Analyst AI with deep knowledge of cricket statistics and match analysis.\n", + "When comparing players, call the `analyze_cricket` tool to get factual data before answering.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7be34a6-7288-43b0-ad4e-bbed836cb786", + "metadata": {}, + "outputs": [], + "source": [ + "# Sample cricket stats as a list of dicts\n", + "cricket_data = [\n", + " {\"Player\": \"Virat Kohli\", \"Format\": \"ODI\", \"Year\": 2023, \"Runs\": 1377, \"Matches\": 27, \"Average\": 57.37, \"StrikeRate\": 93.21},\n", + " {\"Player\": \"Virat Kohli\", \"Format\": \"ODI\", \"Year\": 2022, \"Runs\": 765, \"Matches\": 20, \"Average\": 42.50, \"StrikeRate\": 88.40},\n", + " {\"Player\": \"Virat Kohli\", \"Format\": \"ODI\", \"Year\": 2021, \"Runs\": 560, \"Matches\": 15, \"Average\": 40.00, \"StrikeRate\": 90.10},\n", + " {\"Player\": \"Babar Azam\", \"Format\": \"ODI\", \"Year\": 2023, \"Runs\": 1454, \"Matches\": 26, \"Average\": 62.00, \"StrikeRate\": 89.50},\n", + " {\"Player\": \"Babar Azam\", \"Format\": \"ODI\", \"Year\": 2022, \"Runs\": 1198, \"Matches\": 18, \"Average\": 66.55, \"StrikeRate\": 92.00},\n", + " {\"Player\": \"Babar Azam\", \"Format\": \"ODI\", \"Year\": 2021, \"Runs\": 949, \"Matches\": 15, \"Average\": 67.78, \"StrikeRate\": 90.50},\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "36bedabf-a0a7-4985-ad8e-07ed6a55a3a4", + "metadata": {}, + "source": [ + "## Tools\n", + "\n", + "Tools starts from here. \n", + "For this notebook, I have just wrote one Tool, you can add multiple tools for your agent." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46a0a260-b11b-4bde-ab80-911a81e2c281", + "metadata": {}, + "outputs": [], + "source": [ + "def analyze_cricket(data_list, player1, player2, match_format=\"ODI\", years=3):\n", + " \"\"\"\n", + " Compare two cricket players' performances using an in-memory list of dicts.\n", + " \"\"\"\n", + " print(\"Tool 'analyze_cricket' is called\")\n", + " df = pd.DataFrame(data_list)\n", + " latest_year = df['Year'].max()\n", + " min_year = latest_year - years + 1\n", + "\n", + " filtered = df[\n", + " (df['Format'].str.upper() == match_format.upper()) &\n", + " (df['Year'] >= min_year) &\n", + " (df['Player'].isin([player1, player2]))\n", + " ]\n", + " if filtered.empty:\n", + " return {\"error\": f\"No data found for {player1} and {player2} in {match_format} for last {years} years.\"}\n", + "\n", + " summary = filtered.groupby(\"Player\").agg({\n", + " \"Matches\": \"sum\",\n", + " \"Runs\": \"sum\",\n", + " \"Average\": \"mean\",\n", + " \"StrikeRate\": \"mean\"\n", + " }).round(2)\n", + "\n", + " return summary.reset_index().to_dict(orient=\"records\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbfd413e-b5d4-42bd-b86f-ed9b4ee360eb", + "metadata": {}, + "outputs": [], + "source": [ + "# Example usage:\n", + "result = analyze_cricket(cricket_data, \"Virat Kohli\", \"Babar Azam\", \"ODI\", 3)\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c92699c1-802b-4948-a654-df89e0c19adb", + "metadata": {}, + "outputs": [], + "source": [ + "# Tool definition \n", + "analyze_cricket_functions = {\n", + " \"name\": \"analyze_cricket\",\n", + " \"description\": \"Compare two cricket players' performances over the last N years.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"player1\": {\"type\": \"string\", \"description\": \"Name of first player\"},\n", + " \"player2\": {\"type\": \"string\", \"description\": \"Name of second player\"},\n", + " \"match_format\": {\"type\": \"string\", \"enum\": [\"ODI\", \"Test\", \"T20\"], \"description\": \"Format of the match\"},\n", + " \"years\": {\"type\": \"integer\", \"description\": \"Number of years to compare\"}\n", + " },\n", + " \"required\": [\"player1\", \"player2\"]\n", + " }\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdca8679-935f-4e7f-97e6-e71a4d4f228c", + "metadata": {}, + "outputs": [], + "source": [ + "# And this is included in a list of tools:\n", + "\n", + "tools = [{\"type\": \"function\", \"function\": analyze_cricket_functions}]" + ] + }, + { + "cell_type": "markdown", + "id": "c3d3554f-b4e3-4ce7-af6f-68faa6dd2340", + "metadata": {}, + "source": [ + "## Getting OpenAI to use our Tool\n", + "\n", + "There's some fiddly stuff to allow OpenAI \"to call our tool\"\n", + "\n", + "What we actually do is give the LLM the opportunity to inform us that it wants us to run the tool.\n", + "\n", + "Here's how the new chat function looks:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce9b0744-9c78-408d-b9df-9f6fd9ed78cf", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(message, history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": message}]\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", + "\n", + " if response.choices[0].finish_reason==\"tool_calls\":\n", + " message = response.choices[0].message\n", + " response, player1, player2 = handle_tool_call(message)\n", + " messages.append(message)\n", + " messages.append(response)\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " \n", + " return response.choices[0].message.content" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0992986-ea09-4912-a076-8e5603ee631f", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to write that function handle_tool_call:\n", + "\n", + "def handle_tool_call(message):\n", + " tool_call = message.tool_calls[0]\n", + " print(\"tool_call.id\", tool_call.id)\n", + " arguments = json.loads(tool_call.function.arguments)\n", + " print(\"arguments\", arguments)\n", + " player1 = arguments.get('player1')\n", + " player2 = arguments.get('player2')\n", + " match_format = arguments.get('match_format', 'ODI')\n", + " years = arguments.get('years', 3)\n", + " result = analyze_cricket(cricket_data, player1, player2, match_format, years)\n", + " print(\"result from analyze_cricket function: \", result)\n", + " response = {\n", + " \"role\": \"tool\",\n", + " \"content\": json.dumps(result),\n", + " \"tool_call_id\": tool_call.id\n", + " }\n", + " return response, player1, player2" + ] + }, + { + "cell_type": "markdown", + "id": "924e7225-b76d-4518-abad-5bea5c356cf8", + "metadata": {}, + "source": [ + "# Sample User prompt\n", + "\n", + "1. ### Compare Babar and Virat in ODI matches over the last 3 years.\n", + "Here \n", + "Player1 is Babar\n", + "Player2 is Virat\n", + "match_format is ODI\n", + "years is 3\n", + "\n", + "\n", + "2. ### can you please give me the comparison of Virat and babar?\n", + "Here you are not provided the info of format and number of years. In this case, the function will pick the default values for the match format, which is ODI and years which is 3.\n", + "\n", + "\n", + "3. ### Compare Rizwan and Babar in ODI Matches over the last years.\n", + "The given data is not available in the above data list. \n", + "- **Output**: \n", + "It seems that I couldn't retrieve specific data for Mohammad Rizwan and Babar Azam in ODI matches over the last three years. However, I can provide a general comparison based on available statistics up to October 2023.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4be8a71-b19e-4c2f-80df-f59ff2661f14", + "metadata": {}, + "outputs": [], + "source": [ + "gr.ChatInterface(fn=chat, type=\"messages\").launch()" + ] + }, + { + "cell_type": "markdown", + "id": "473e5b39-da8f-4db1-83ae-dbaca2e9531e", + "metadata": {}, + "source": [ + "# Let's go multi-modal!!\n", + "\n", + "We can use DALL-E-3, the image generation model behind GPT-4o, to make us some images\n", + "\n", + "Let's put this in a function called artist.\n", + "\n", + "### Price alert: each time I generate an image it costs about 4 cents - don't go crazy with images!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c27c4ba-8ed5-492f-add1-02ce9c81d34c", + "metadata": {}, + "outputs": [], + "source": [ + "# Some imports for handling images\n", + "\n", + "import base64\n", + "from io import BytesIO\n", + "from PIL import Image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "773a9f11-557e-43c9-ad50-56cbec3a0f8f", + "metadata": {}, + "outputs": [], + "source": [ + "def artist(player1, player2):\n", + " return None\n", + " # image_response = openai.images.generate(\n", + " # model=\"dall-e-3\",\n", + " # prompt=f\"An image representing a comparison of {player1} and {player2}, showing their country flags and bowling or batting style\",\n", + " # size=\"1024x1024\",\n", + " # n=1,\n", + " # response_format=\"b64_json\",\n", + " # )\n", + " # image_base64 = image_response.data[0].b64_json\n", + " # image_data = base64.b64decode(image_base64)\n", + " # return Image.open(BytesIO(image_data))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d877c453-e7fb-482a-88aa-1a03f976b9e9", + "metadata": {}, + "outputs": [], + "source": [ + "image = artist(\"Babar\", \"Virat\")\n", + "display(image)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "728a12c5-adc3-415d-bb05-82beb73b079b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffbfe93b-5e86-4e68-ba71-b301cd5230db", + "metadata": {}, + "outputs": [], + "source": [ + "from pydub import AudioSegment\n", + "from pydub.playback import play\n", + "\n", + "def talker(message):\n", + " response = openai.audio.speech.create(\n", + " model=\"tts-1\",\n", + " voice=\"onyx\", # Also, try replacing onyx with alloy\n", + " input=message\n", + " )\n", + " \n", + " audio_stream = BytesIO(response.content)\n", + " audio = AudioSegment.from_file(audio_stream, format=\"mp3\")\n", + " play(audio)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b88d775d-d357-4292-a1ad-5dc5ed567281", + "metadata": {}, + "outputs": [], + "source": [ + "talker(\"Well, hi there\")" + ] + }, + { + "cell_type": "markdown", + "id": "1d48876d-c4fa-46a8-a04f-f9fadf61fb0d", + "metadata": {}, + "source": [ + "# Our Agent Framework\n", + "\n", + "The term 'Agentic AI' and Agentization is an umbrella term that refers to a number of techniques, such as:\n", + "\n", + "1. Breaking a complex problem into smaller steps, with multiple LLMs carrying out specialized tasks\n", + "2. The ability for LLMs to use Tools to give them additional capabilities\n", + "3. The 'Agent Environment' which allows Agents to collaborate\n", + "4. An LLM can act as the Planner, dividing bigger tasks into smaller ones for the specialists\n", + "5. The concept of an Agent having autonomy / agency, beyond just responding to a prompt - such as Memory\n", + "\n", + "We're showing 1 and 2 here, and to a lesser extent 3 and 5. In week 8 we will do the lot!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba820c95-02f5-499e-8f3c-8727ee0a6c0c", + "metadata": {}, + "outputs": [], + "source": [ + "def chat(history):\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + history\n", + " response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n", + " image = None\n", + " \n", + " if response.choices[0].finish_reason==\"tool_calls\":\n", + " message = response.choices[0].message\n", + " response, player1, player2 = handle_tool_call(message)\n", + " messages.append(message)\n", + " messages.append(response)\n", + " \n", + " image = artist(player1, player2) #QUERY: how can i pass the value of format_dropdown in this function? \n", + " \n", + " response = openai.chat.completions.create(model=MODEL, messages=messages)\n", + " \n", + " reply = response.choices[0].message.content\n", + " history += [{\"role\":\"assistant\", \"content\":reply}]\n", + "\n", + " # Comment out or delete the next line if you'd rather skip Audio for now..\n", + " talker(reply)\n", + " \n", + " return history, image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f38d0d27-33bf-4992-a2e5-5dbed973cde7", + "metadata": {}, + "outputs": [], + "source": [ + "# More involved Gradio code as we're not using the preset Chat interface!\n", + "# Passing in inbrowser=True in the last line will cause a Gradio window to pop up immediately.\n", + "\n", + "with gr.Blocks() as ui:\n", + " with gr.Row():\n", + " chatbot = gr.Chatbot(height=500, type=\"messages\")\n", + " image_output = gr.Image(height=500)\n", + "\n", + " with gr.Row(): #QUERY: How can I receive the value of \"Yes\" or \"No\" in chat function?\n", + " format_dropdown = gr.Dropdown(\n", + " choices=[\"Yes\", \"No\"],\n", + " label=\"Do you want image?\"\n", + " )\n", + " with gr.Row():\n", + " entry = gr.Textbox(label=\"Chat with our AI Assistant:\")\n", + " with gr.Row():\n", + " clear = gr.Button(\"Clear\")\n", + "\n", + " def do_entry(message, history):\n", + " history += [{\"role\": \"user\", \"content\": message}]\n", + " return \"\", history\n", + "\n", + " entry.submit(do_entry, inputs=[entry, chatbot, format_dropdown], outputs=[entry, chatbot]).then(\n", + " chat, inputs=chatbot, outputs=[chatbot, image_output]\n", + " ) #QUERY: This part is a little bit confusing for me.\n", + " clear.click(lambda: None, inputs=None, outputs=chatbot, queue=False)\n", + "\n", + "ui.launch(inbrowser=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}