diff --git a/Dockerfile b/Dockerfile.local similarity index 83% rename from Dockerfile rename to Dockerfile.local index c5589f2..023722c 100644 --- a/Dockerfile +++ b/Dockerfile.local @@ -14,12 +14,10 @@ RUN useradd jovyan -d /home/jovyan -m -p 0049e6b11c44d4b00006eb820983a7a76c84a12 mkdir -p /home/jovyan/work COPY ./jupyter_server_config.py /home/jovyan/.jupyter/jupyter_server_config.py - -COPY ./L2 /home/jovyan/work/L2 -COPY ./L3 /home/jovyan/work/L3 +COPY ./L1 /home/jovyan/work/L1 RUN chown -R jovyan:jovyan -R /home/jovyan RUN chown -R jovyan:jovyan -R /home/jovyan/work USER jovyan -CMD ["bash", "-c", "source /etc/bash.bashrc && jupyter notebook --no-browser"] +CMD ["jupyter", "lab"] diff --git a/L1/.ipynb_checkpoints/test-checkpoint.ipynb b/L1/.ipynb_checkpoints/test-checkpoint.ipynb new file mode 100644 index 0000000..49cc25c --- /dev/null +++ b/L1/.ipynb_checkpoints/test-checkpoint.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c34b3cbd-4745-4f0b-a18b-18d9e06d30fa", + "metadata": {}, + "outputs": [], + "source": [ + "from openai import OpenAI\n", + "client = OpenAI()\n", + "response = client.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=[{\"role\": \"user\", \"content\": \"What is Python?\"}]\n", + ")\n", + "print(response.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a1d4923-9b0b-477d-b2cb-5b649b7a8184", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/L1/test.ipynb b/L1/test.ipynb new file mode 100644 index 0000000..49cc25c --- /dev/null +++ b/L1/test.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c34b3cbd-4745-4f0b-a18b-18d9e06d30fa", + "metadata": {}, + "outputs": [], + "source": [ + "from openai import OpenAI\n", + "client = OpenAI()\n", + "response = client.chat.completions.create(\n", + " model=\"gpt-4o-mini\",\n", + " messages=[{\"role\": \"user\", \"content\": \"What is Python?\"}]\n", + ")\n", + "print(response.choices[0].message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a1d4923-9b0b-477d-b2cb-5b649b7a8184", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/L2/L_2.ipynb b/L2/L_2.ipynb deleted file mode 100644 index 2d5215d..0000000 --- a/L2/L_2.ipynb +++ /dev/null @@ -1,445 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "07384ca6-4098-4066-92c2-fca2f25f7e0f", - "metadata": {}, - "source": [ - "# L2: How To Use Structured Outputs" - ] - }, - { - "cell_type": "markdown", - "id": "75138467-2f8e-4743-9875-ff7c7bea318c", - "metadata": {}, - "source": [ - "

Note (Kernel Starting): This notebook takes about 30 seconds to be ready to use. You may start and watch the video while you wait.

" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62dba96a-9d73-4f3d-b5d7-7b5eb4f2c610", - "metadata": {}, - "outputs": [], - "source": [ - "# Warning control\n", - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1c006097-da90-491e-96ee-0121a6fc6bfb", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from helper import get_openai_api_key\n", - "KEY = get_openai_api_key()" - ] - }, - { - "cell_type": "markdown", - "id": "293583cb-9fa7-447b-8a4b-0c40a2bcaca1", - "metadata": {}, - "source": [ - "
\n", - "

💻   Access requirements.txt and helper.py files: 1) click on the \"File\" option on the top menu of the notebook and then 2) click on \"Open\".\n", - "\n", - "

⬇   Download Notebooks: 1) click on the \"File\" option on the top menu of the notebook and then 2) click on \"Download as\" and select \"Notebook (.ipynb)\".

\n", - "\n", - "

📒   For more help, please see the \"Appendix – Tips, Help, and Download\" Lesson.

\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0de02a15-37b7-4318-8388-0f8a5b3cd8a6", - "metadata": {}, - "outputs": [], - "source": [ - "from openai import OpenAI\n", - "\n", - "# Instantiate the client\n", - "client = OpenAI(\n", - " api_key=KEY\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "fcd5ca3c-ebd2-46e1-9a1f-5399a61d59da", - "metadata": {}, - "source": [ - "## Define structure with Pydantic" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d636037b-b7e1-438c-b065-bb45ca313afa", - "metadata": {}, - "outputs": [], - "source": [ - "# The user class from the slides\n", - "from pydantic import BaseModel\n", - "from typing import Optional\n", - "\n", - "class User(BaseModel):\n", - " name: str\n", - " age: int\n", - " email: Optional[str] = None" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2d76092e-6abb-430a-97ea-ec17e5fb0e86", - "metadata": {}, - "outputs": [], - "source": [ - "completion = client.beta.chat.completions.parse(\n", - " model=\"gpt-4o-mini\",\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n", - " {\"role\": \"user\", \"content\": \"Make up a user.\"},\n", - " ],\n", - " response_format=User,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "755ceee3-c2cf-4880-9a5b-baf92cf03b2c", - "metadata": {}, - "outputs": [], - "source": [ - "user = completion.choices[0].message.parsed\n", - "user" - ] - }, - { - "cell_type": "markdown", - "id": "d04c92a1-2936-4ca3-b8ab-aea726df3e74", - "metadata": {}, - "source": [ - "## The social media mention structure" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9c07b7a0-8f8e-4c39-8945-0aaa9c01ec14", - "metadata": {}, - "outputs": [], - "source": [ - "from pydantic import BaseModel\n", - "from enum import Enum\n", - "from typing import List, Optional, Literal\n", - "from openai import OpenAI\n", - "\n", - "class Mention(BaseModel):\n", - " # The model chooses the product the mention is about,\n", - " # as well as the social media post's sentiment\n", - " product: Literal['app', 'website', 'not_applicable']\n", - " sentiment: Literal['positive', 'negative', 'neutral']\n", - "\n", - " # Model can choose to respond to the user\n", - " needs_response: bool\n", - " response: Optional[str]\n", - "\n", - " # If a support ticket needs to be opened, \n", - " # the model can write a description for the\n", - " # developers\n", - " support_ticket_description: Optional[str]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8d97c861-7971-4068-b91a-f3547f954a2f", - "metadata": {}, - "outputs": [], - "source": [ - "# Example mentions\n", - "mentions = [\n", - " # About the app\n", - " \"@techcorp your app is amazing! The new design is perfect\",\n", - " # Website is down, negative sentiment + needs a fix\n", - " \"@techcorp website is down again, please fix!\",\n", - " # Nothing to respond to\n", - " \"hey @techcorp you're so evil\"\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ec4792ef-d6dc-4110-872c-9444074392f5", - "metadata": {}, - "outputs": [], - "source": [ - "def analyze_mention(\n", - " mention: str, \n", - " personality: str = \"friendly\"\n", - ") -> Mention:\n", - " completion = client.beta.chat.completions.parse(\n", - " model=\"gpt-4o-mini\",\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": f\"\"\"\n", - " Extract structured information from \n", - " social media mentions about our products.\n", - "\n", - " Provide\n", - " - The product mentioned (website, app, not applicable)\n", - " - The mention sentiment (positive, negative, neutral)\n", - " - Whether to respond (true/false). Don't respond to \n", - " inflammatory messages or bait.\n", - " - A customized response to send to the user if we need \n", - " to respond.\n", - " - An optional support ticket description to create.\n", - "\n", - " Your personality is {personality}.\n", - " \"\"\"},\n", - " {\"role\": \"user\", \"content\": mention},\n", - " ],\n", - " response_format=Mention,\n", - " )\n", - " return completion.choices[0].message.parsed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3334ce2f-aa63-467c-bcab-e1b8ef6bdbe3", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"User post:\", mentions[0])\n", - "processed_mention = analyze_mention(mentions[0])\n", - "processed_mention" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5f8e7188-9698-457b-814c-ee287da6e459", - "metadata": {}, - "outputs": [], - "source": [ - "rude_mention = analyze_mention(mentions[0], personality=\"rude\")\n", - "rude_mention.response" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e70084e-272f-4dc2-93b7-53b59672770b", - "metadata": {}, - "outputs": [], - "source": [ - "mention_json_string = processed_mention.model_dump_json(indent=2)\n", - "print(mention_json_string)" - ] - }, - { - "cell_type": "markdown", - "id": "27874677-2ce8-442a-8e95-d3b8fad47fda", - "metadata": {}, - "source": [ - "## You try!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d078671c-8943-4090-ae3e-e81257f00832", - "metadata": {}, - "outputs": [], - "source": [ - "class UserPost(BaseModel):\n", - " message: str\n", - "\n", - "def make_post(output_class):\n", - " completion = client.beta.chat.completions.parse(\n", - " model=\"gpt-4o-mini\",\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"\"\"\n", - " You are a customer of Tech Corp (@techcorp), a company\n", - " that provides an app and a website. Create a small \n", - " microblog-style post to them that sends some kind of \n", - " feedback, positive or negative.\n", - " \"\"\"},\n", - " {\"role\": \"user\", \"content\": \"Please write a post.\"},\n", - " ],\n", - " response_format=output_class,\n", - " )\n", - " return completion.choices[0].message.parsed\n", - "\n", - "new_post = make_post(UserPost)\n", - "new_post" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cdfebe75-27a6-420b-a6f1-af47c54640f1", - "metadata": {}, - "outputs": [], - "source": [ - "analyze_mention(new_post.message)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6c85817d-7934-45d4-9d67-55b3a9c47ce1", - "metadata": {}, - "outputs": [], - "source": [ - "class UserPostWithExtras(BaseModel):\n", - " user_mood: Literal[\"awful\", \"bad\", \"evil\"]\n", - " product: Literal['app', 'website', 'not_applicable']\n", - " sentiment: Literal['positive', 'negative', 'neutral']\n", - " internal_monologue: List[str]\n", - " message: str\n", - " \n", - "new_post = make_post(UserPostWithExtras)\n", - "new_post" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "42e7105d-20ff-4617-aeeb-5a628bd9a224", - "metadata": {}, - "outputs": [], - "source": [ - "analyze_mention(new_post.message)" - ] - }, - { - "cell_type": "markdown", - "id": "e2402d47-1d5f-4efe-97ea-31d02268c952", - "metadata": {}, - "source": [ - "## Programming with our mentions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b85e800e-4ea2-44f4-94c9-e2c8029ad2df", - "metadata": {}, - "outputs": [], - "source": [ - "from helper import print_mention\n", - "\n", - "# Loop through posts that tagged us and store the results in a list\n", - "rows = []\n", - "for mention in mentions:\n", - " # Call the LLM to get a Mention object we can program with\n", - " processed_mention = analyze_mention(mention)\n", - "\n", - " # Print out some information\n", - " print_mention(processed_mention, mention)\n", - " \n", - " # Convert our processed data to a dictionary\n", - " # using Pydantic tools\n", - " processed_dict = processed_mention.model_dump()\n", - " \n", - " # Store the original message in the dataframe row\n", - " processed_dict['mention'] = mention\n", - " rows.append(processed_dict)\n", - " \n", - " print(\"\") # Add separator to make it easier to read" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cad8446b-59a6-40f2-83b7-cdf1e89b9b18", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "df = pd.DataFrame(rows)\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cbc59204-0ecf-4a93-a2f4-474b01b12e4a", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "daac7379-90b3-4454-b900-cd6bebe33bfb", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5dbaed59-a641-4613-b1ff-80578c92f680", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "600883f1-f867-4a00-8e52-5983e3d942ca", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f16f063b-a94f-4e84-8cac-459f9334e652", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6af25623-e982-4abe-a521-53ab00c51caf", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.10.14" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/L2/helper.py b/L2/helper.py deleted file mode 100644 index 7712073..0000000 --- a/L2/helper.py +++ /dev/null @@ -1,28 +0,0 @@ -# Add your utilities or helper functions to this file. - -import os -from dotenv import load_dotenv, find_dotenv - -# these expect to find a .env file at the directory above the lesson. # the format for that file is (without the comment) #API_KEYNAME=AStringThatIsTheLongAPIKeyFromSomeService -def load_env(): - _ = load_dotenv(find_dotenv()) - -def get_openai_api_key(): - load_env() - openai_api_key = os.getenv("OPENAI_API_KEY") - return openai_api_key - -def print_mention(processed_mention, mention): - # Check if we need to respond - if processed_mention.needs_response: - # We need to respond - print(f"Responding to {processed_mention.sentiment} {processed_mention.product} feedback") - print(f" User: {mention}") - print(f" Response: {processed_mention.response}") - else: - print(f"Not responding to {processed_mention.sentiment} {processed_mention.product} post") - print(f" User: {mention}") - - if processed_mention.support_ticket_description: - print(f" Adding support ticket: {processed_mention.support_ticket_description}") - \ No newline at end of file diff --git a/L2/mentions-processed.csv b/L2/mentions-processed.csv deleted file mode 100644 index 204f4c1..0000000 --- a/L2/mentions-processed.csv +++ /dev/null @@ -1,4 +0,0 @@ -,product,sentiment,needs_response,response,support_ticket_description,mention -0,app,positive,True,"Thank you so much for your kind words! We're thrilled to hear that you love the new design. If you have any feedback or suggestions, feel free to share!",,@techcorp your app is amazing! The new design is perfect -1,website,negative,True,Hi there! We're sorry to hear you're having trouble with our website. Our team is aware of the issue and is working hard to fix it as quickly as possible. Thank you for your patience!,User reported that the website is down.,"@techcorp website is down again, please fix!" -2,not_applicable,negative,False,,,hey @techcorp you're so evil diff --git a/L2/requirements.txt b/L2/requirements.txt deleted file mode 100644 index bce4c8b..0000000 --- a/L2/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -python-dotenv==1.0.0 -openai==1.66.3 -pandas==2.2.3 -instructor==1.7.4 -outlines==0.2.1 -transformers==4.49.0 -sentencepiece==0.2.0 -datasets==3.3.2 diff --git a/L3/L3.ipynb b/L3/L3.ipynb deleted file mode 100644 index f774d7f..0000000 --- a/L3/L3.ipynb +++ /dev/null @@ -1,522 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "1c10b768-f5b4-43bc-a785-99077422ce78", - "metadata": {}, - "source": [ - "# Lesson 3: Chatbot Example" - ] - }, - { - "cell_type": "markdown", - "id": "85d4fedc-4b90-4754-9f2d-fd3cfa321a14", - "metadata": {}, - "source": [ - "In this lesson, you will familiarize yourself with the chatbot example you will work on during this course. The example includes the tool definitions and execution, as well as the chatbot code. Make sure to interact with the chatbot at the end of this notebook." - ] - }, - { - "cell_type": "markdown", - "id": "e0ed96ba-5ade-4af4-9096-406ce48d5cf2", - "metadata": {}, - "source": [ - "## Import Libraries" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd6bd1d4-f652-45d1-9efa-155a2cc01713", - "metadata": {}, - "outputs": [], - "source": [ - "import arxiv\n", - "import json\n", - "import os\n", - "from typing import List\n", - "from dotenv import load_dotenv\n", - "import anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "f20f163a-87af-4e0c-87ed-1624c150c572", - "metadata": {}, - "source": [ - "## Tool Functions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "549a7f46-74b3-4a1d-b084-055c99e3c318", - "metadata": {}, - "outputs": [], - "source": [ - "PAPER_DIR = \"papers\"" - ] - }, - { - "cell_type": "markdown", - "id": "9e43905e-56f3-404c-a322-f038055e9b1c", - "metadata": {}, - "source": [ - "The first tool searches for relevant arXiv papers based on a topic and stores the papers' info in a JSON file (title, authors, summary, paper url and the publication date). The JSON files are organized by topics in the `papers` directory. The tool does not download the papers. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "886633b8-ce67-4343-822d-cc3f98f953fa", - "metadata": {}, - "outputs": [], - "source": [ - "def search_papers(topic: str, max_results: int = 5) -> List[str]:\n", - " \"\"\"\n", - " Search for papers on arXiv based on a topic and store their information.\n", - " \n", - " Args:\n", - " topic: The topic to search for\n", - " max_results: Maximum number of results to retrieve (default: 5)\n", - " \n", - " Returns:\n", - " List of paper IDs found in the search\n", - " \"\"\"\n", - " \n", - " # Use arxiv to find the papers \n", - " client = arxiv.Client()\n", - "\n", - " # Search for the most relevant articles matching the queried topic\n", - " search = arxiv.Search(\n", - " query = topic,\n", - " max_results = max_results,\n", - " sort_by = arxiv.SortCriterion.Relevance\n", - " )\n", - "\n", - " papers = client.results(search)\n", - " \n", - " # Create directory for this topic\n", - " path = os.path.join(PAPER_DIR, topic.lower().replace(\" \", \"_\"))\n", - " os.makedirs(path, exist_ok=True)\n", - " \n", - " file_path = os.path.join(path, \"papers_info.json\")\n", - "\n", - " # Try to load existing papers info\n", - " try:\n", - " with open(file_path, \"r\") as json_file:\n", - " papers_info = json.load(json_file)\n", - " except (FileNotFoundError, json.JSONDecodeError):\n", - " papers_info = {}\n", - "\n", - " # Process each paper and add to papers_info \n", - " paper_ids = []\n", - " for paper in papers:\n", - " paper_ids.append(paper.get_short_id())\n", - " paper_info = {\n", - " 'title': paper.title,\n", - " 'authors': [author.name for author in paper.authors],\n", - " 'summary': paper.summary,\n", - " 'pdf_url': paper.pdf_url,\n", - " 'published': str(paper.published.date())\n", - " }\n", - " papers_info[paper.get_short_id()] = paper_info\n", - " \n", - " # Save updated papers_info to json file\n", - " with open(file_path, \"w\") as json_file:\n", - " json.dump(papers_info, json_file, indent=2)\n", - " \n", - " print(f\"Results are saved in: {file_path}\")\n", - " \n", - " return paper_ids" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d20ee17a-afe6-438a-95b1-6e87742c7fac", - "metadata": {}, - "outputs": [], - "source": [ - "search_papers(\"computers\")" - ] - }, - { - "cell_type": "markdown", - "id": "dfb83565-69af-47f3-9ba3-a96965cff7df", - "metadata": {}, - "source": [ - "The second tool looks for information about a specific paper across all topic directories inside the `papers` directory." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "df9b1997-81cd-447d-9665-1cb72d93bb9a", - "metadata": {}, - "outputs": [], - "source": [ - "def extract_info(paper_id: str) -> str:\n", - " \"\"\"\n", - " Search for information about a specific paper across all topic directories.\n", - " \n", - " Args:\n", - " paper_id: The ID of the paper to look for\n", - " \n", - " Returns:\n", - " JSON string with paper information if found, error message if not found\n", - " \"\"\"\n", - " \n", - " for item in os.listdir(PAPER_DIR):\n", - " item_path = os.path.join(PAPER_DIR, item)\n", - " if os.path.isdir(item_path):\n", - " file_path = os.path.join(item_path, \"papers_info.json\")\n", - " if os.path.isfile(file_path):\n", - " try:\n", - " with open(file_path, \"r\") as json_file:\n", - " papers_info = json.load(json_file)\n", - " if paper_id in papers_info:\n", - " return json.dumps(papers_info[paper_id], indent=2)\n", - " except (FileNotFoundError, json.JSONDecodeError) as e:\n", - " print(f\"Error reading {file_path}: {str(e)}\")\n", - " continue\n", - " \n", - " return f\"There's no saved information related to paper {paper_id}.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0ebe0de7-8f07-4e08-a670-7b371fc3d2d9", - "metadata": {}, - "outputs": [], - "source": [ - "extract_info('1310.7911v2')" - ] - }, - { - "cell_type": "markdown", - "id": "b5ea3013-e690-4bc8-8622-27b4d42d61e4", - "metadata": {}, - "source": [ - "## Tool Schema" - ] - }, - { - "cell_type": "markdown", - "id": "7c7d2260-452d-472a-b56e-326479cb18c9", - "metadata": {}, - "source": [ - "Here are the schema of each tool which you will provide to the LLM." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e5bdea5f-e93a-4018-8c13-00d5ee10c0b7", - "metadata": {}, - "outputs": [], - "source": [ - "tools = [\n", - " {\n", - " \"name\": \"search_papers\",\n", - " \"description\": \"Search for papers on arXiv based on a topic and store their information.\",\n", - " \"input_schema\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"topic\": {\n", - " \"type\": \"string\",\n", - " \"description\": \"The topic to search for\"\n", - " }, \n", - " \"max_results\": {\n", - " \"type\": \"integer\",\n", - " \"description\": \"Maximum number of results to retrieve\",\n", - " \"default\": 5\n", - " }\n", - " },\n", - " \"required\": [\"topic\"]\n", - " }\n", - " },\n", - " {\n", - " \"name\": \"extract_info\",\n", - " \"description\": \"Search for information about a specific paper across all topic directories.\",\n", - " \"input_schema\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"paper_id\": {\n", - " \"type\": \"string\",\n", - " \"description\": \"The ID of the paper to look for\"\n", - " }\n", - " },\n", - " \"required\": [\"paper_id\"]\n", - " }\n", - " }\n", - "]" - ] - }, - { - "cell_type": "markdown", - "id": "ec668d24-1559-41b7-bc8a-e2dca77dfaf2", - "metadata": {}, - "source": [ - "## Tool Mapping" - ] - }, - { - "cell_type": "markdown", - "id": "c728c1ec-36b1-48b4-9f85-622464ac79f4", - "metadata": {}, - "source": [ - "This code handles tool mapping and execution." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c90790c0-efc4-4068-9c00-d2592d80bc30", - "metadata": {}, - "outputs": [], - "source": [ - "mapping_tool_function = {\n", - " \"search_papers\": search_papers,\n", - " \"extract_info\": extract_info\n", - "}\n", - "\n", - "def execute_tool(tool_name, tool_args):\n", - " \n", - " result = mapping_tool_function[tool_name](**tool_args)\n", - "\n", - " if result is None:\n", - " result = \"The operation completed but didn't return any results.\"\n", - " \n", - " elif isinstance(result, list):\n", - " result = ', '.join(result)\n", - " \n", - " elif isinstance(result, dict):\n", - " # Convert dictionaries to formatted JSON strings\n", - " result = json.dumps(result, indent=2)\n", - " \n", - " else:\n", - " # For any other type, convert using str()\n", - " result = str(result)\n", - " return result" - ] - }, - { - "cell_type": "markdown", - "id": "4d8fc4d3-58ac-482c-8bbd-bccd6ef9fc31", - "metadata": {}, - "source": [ - "## Chatbot Code" - ] - }, - { - "cell_type": "markdown", - "id": "e9ba0fad-b0e4-4415-a431-341e9ca85087", - "metadata": {}, - "source": [ - "The chatbot handles the user's queries one by one, but it does not persist memory across the queries." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fe662400-8506-464e-a3da-75a3d8848bac", - "metadata": {}, - "outputs": [], - "source": [ - "load_dotenv() \n", - "client = anthropic.Anthropic()" - ] - }, - { - "cell_type": "markdown", - "id": "175586b4-acdf-4103-8039-134478a4f797", - "metadata": {}, - "source": [ - "### Query Processing" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12a896e0-3f56-417e-aa51-c61756048593", - "metadata": {}, - "outputs": [], - "source": [ - "def process_query(query):\n", - " \n", - " messages = [{'role': 'user', 'content': query}]\n", - " \n", - " response = client.messages.create(max_tokens = 2024,\n", - " model = 'claude-3-7-sonnet-20250219', \n", - " tools = tools,\n", - " messages = messages)\n", - " \n", - " process_query = True\n", - " while process_query:\n", - " assistant_content = []\n", - "\n", - " for content in response.content:\n", - " if content.type == 'text':\n", - " \n", - " print(content.text)\n", - " assistant_content.append(content)\n", - " \n", - " if len(response.content) == 1:\n", - " process_query = False\n", - " \n", - " elif content.type == 'tool_use':\n", - " \n", - " assistant_content.append(content)\n", - " messages.append({'role': 'assistant', 'content': assistant_content})\n", - " \n", - " tool_id = content.id\n", - " tool_args = content.input\n", - " tool_name = content.name\n", - " print(f\"Calling tool {tool_name} with args {tool_args}\")\n", - " \n", - " result = execute_tool(tool_name, tool_args)\n", - " messages.append({\"role\": \"user\", \n", - " \"content\": [\n", - " {\n", - " \"type\": \"tool_result\",\n", - " \"tool_use_id\": tool_id,\n", - " \"content\": result\n", - " }\n", - " ]\n", - " })\n", - " response = client.messages.create(max_tokens = 2024,\n", - " model = 'claude-3-7-sonnet-20250219', \n", - " tools = tools,\n", - " messages = messages) \n", - " \n", - " if len(response.content) == 1 and response.content[0].type == \"text\":\n", - " print(response.content[0].text)\n", - " process_query = False" - ] - }, - { - "cell_type": "markdown", - "id": "2921ee7f-d2be-464b-ab7b-8db2a3c13ba9", - "metadata": {}, - "source": [ - "### Chat Loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "16979cdc-81e9-432b-ba7f-e810b52961e8", - "metadata": {}, - "outputs": [], - "source": [ - "def chat_loop():\n", - " print(\"Type your queries or 'quit' to exit.\")\n", - " while True:\n", - " try:\n", - " query = input(\"\\nQuery: \").strip()\n", - " if query.lower() == 'quit':\n", - " break\n", - " \n", - " process_query(query)\n", - " print(\"\\n\")\n", - " except Exception as e:\n", - " print(f\"\\nError: {str(e)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "1cfaf254-f22a-4951-885e-1d21fbc41ff3", - "metadata": {}, - "source": [ - "Feel free to interact with the chatbot. Here's an example query: \n", - "\n", - "- Search for 2 papers on \"LLM interpretability\"\n", - "\n", - "To access the `papers` folder: 1) click on the `File` option on the top menu of the notebook and 2) click on `Open` and then 3) click on `L3`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "39676f70-1c72-4da3-8363-da281bd5a83e", - "metadata": {}, - "outputs": [], - "source": [ - "chat_loop()" - ] - }, - { - "cell_type": "markdown", - "id": "34df7890-4b4c-4ec9-b06f-abc8c4a290e8", - "metadata": {}, - "source": [ - "

🚨\n", - "  Different Run Results: The output generated by AI chat models can vary with each execution due to their dynamic, probabilistic nature. Don't be surprised if your results differ from those shown in the video.

" - ] - }, - { - "cell_type": "markdown", - "id": "fb34ee2d", - "metadata": {}, - "source": [ - "
\n", - "

💻   To Access the requirements.txt file or the papers folder: 1) click on the \"File\" option on the top menu of the notebook and then 2) click on \"Open\" and finally 3) click on \"L3\".\n", - "

" - ] - }, - { - "cell_type": "markdown", - "id": "508916f3-8fa1-4e21-bfa7-081a810bc36c", - "metadata": {}, - "source": [ - "In the next lessons, you will take out the tool definitions to wrap them in an MCP server. Then you will create an MCP client inside the chatbot to make the chatbot MCP compatible. " - ] - }, - { - "cell_type": "markdown", - "id": "d02d207b-e07d-49ff-bb03-7954aa86c167", - "metadata": {}, - "source": [ - "## Resources\n", - "\n", - "[Guide on how to implement tool use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use/overview#how-to-implement-tool-use)" - ] - }, - { - "cell_type": "markdown", - "id": "71e5135e-01c3-4632-9f83-a1e6dd811049", - "metadata": {}, - "source": [ - "
\n", - "\n", - "\n", - "

⬇   Download Notebooks: 1) click on the \"File\" option on the top menu of the notebook and then 2) click on \"Download as\" and select \"Notebook (.ipynb)\".

\n", - "\n", - "
" - ] - } - ], - "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.10.11" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/README.md b/README.md deleted file mode 100644 index f2a1968..0000000 --- a/README.md +++ /dev/null @@ -1,19 +0,0 @@ -## About The Project -This repo collects the following lectures to demonstrate the usage of sandbox builder: -- L2: course_id=1052, Getting Structured LLM Output -- L3: course_id=1057, MCP: Build Rich-Context AI Apps with Anthropic - -## Common Diretory Structures -``` -├── L2 -│   ├── L_2.ipynb -│   ├── helper.py -│   ├── mentions-processed.csv -│   └── requirements.txt -├── L3 -│   └── L3.ipynb -├── README.md -└── requirements.txt -``` - -## Proxy Environment variables diff --git a/jupyter_server_config.py b/jupyter_server_config.py index 1631cbb..817caff 100644 --- a/jupyter_server_config.py +++ b/jupyter_server_config.py @@ -2,64 +2,25 @@ # Distributed under the terms of the Modified BSD License. from jupyter_core.paths import jupyter_data_dir -import subprocess -import os -import errno -import stat c = get_config() -c.ServerApp.ip = '0.0.0.0' -c.ServerApp.port = 8888 +c.NotebookApp.ip = '0.0.0.0' +c.NotebookApp.port = 8888 c.NotebookApp.open_browser = False -c.ServerApp.notebook_dir = '/home/jovyan/work' -c.ServerApp.quit_button = False -c.ServerApp.shutdown_no_activity_timeout = 5*60 +c.NotebookApp.notebook_dir = '/home/jovyan/work' +c.NotebookApp.quit_button = False +c.NotebookApp.shutdown_no_activity_timeout = 5*60 c.MappingKernelManager.cull_idle_timeout = 20*60 c.MappingKernelManager.cull_interval = 30 c.MappingKernelManager.cull_connected = True -c.ServerApp.allow_remote_access = True -c.PasswordIdentityProvider.allow_password_change = False -c.ServerApp.allow_origin = '*' -c.ServerApp.disable_check_xsrf = True - +c.NotebookApp.allow_remote_access = True +c.NotebookApp.allow_password_change = False +c.NotebookApp.allow_origin = '*' +c.NotebookApp.disable_check_xsrf = True +c.FileContentsManager.delete_to_trash = False -c.ServerApp.tornado_settings = { +c.NotebookApp.tornado_settings = { 'headers': { - 'Content-Security-Policy': "frame-ancestors https://*.lab-develop.deeplearningai.net https://*.lab.deeplearningai.net https://*.lab.deeplearningai.net https://*.deeplearningai.net https://*.deeplearningai.net:* https://localhost https://localhost:* http://*.lab.deeplearningai.net http://*.lab.deeplearningai.net http://*.deeplearningai.net https://*.deeplearningai.net http://*.deeplearningai.net:* http://localhost http://localhost:* https://*.firebaseapp.com http://*.firebaseapp.com https://*.web.app http://*.web.app http://*.deeplearning.ai https://*.deeplearning.ai http://ac4e-develop.deeplearning.ai http://ac4e-test.deeplearning.ai http://ac4e.deeplearning.ai https://ac4e-develop.deeplearning.ai https://ac4e-test.deeplearning.ai https://ac4e.deeplearning.ai 'self' " + 'Content-Security-Policy': "frame-ancestors https://*.lab-develop.deeplearningai.net https://*.lab.deeplearningai.net https://*.lab.deeplearningai.net https://*.deeplearningai.net https://*.deeplearningai.net:* https://localhost https://localhost:* http://*.lab.deeplearningai.net http://*.lab.deeplearningai.net http://*.deeplearningai.net https://*.deeplearningai.net http://*.deeplearningai.net:* http://localhost http://localhost:* https://*.firebaseapp.com http://*.firebaseapp.com https://*.web.app http://*.web.app http://*.deeplearning.ai https://*.deeplearning.ai http://ac4e-develop.deeplearning.ai http://ac4e-test.deeplearning.ai http://ac4e.deeplearning.ai https://ac4e-develop.deeplearning.ai https://ac4e-test.deeplearning.ai https://ac4e.deeplearning.ai" } } -c.ServerApp.terminals_enabled=True - -c.ServerApp.terminado_settings = { "shell_command": "/bin/bash /start_terminal.sh" } - - -# https://github.com/jupyter/notebook/issues/3130 -c.FileContentsManager.delete_to_trash = False - -# Generate a self-signed certificate -if 'GEN_CERT' in os.environ: - dir_name = jupyter_data_dir() - pem_file = os.path.join(dir_name, 'notebook.pem') - try: - os.makedirs(dir_name) - except OSError as exc: # Python >2.5 - if exc.errno == errno.EEXIST and os.path.isdir(dir_name): - pass - else: - raise - # Generate a certificate if one doesn't exist on disk - subprocess.check_call(['openssl', 'req', '-new', - '-newkey', 'rsa:2048', - '-days', '365', - '-nodes', '-x509', - '-subj', '/C=XX/ST=XX/L=XX/O=generated/CN=generated', - '-keyout', pem_file, - '-out', pem_file]) - # Restrict access to the file - os.chmod(pem_file, stat.S_IRUSR | stat.S_IWUSR) - c.NotebookApp.certfile = pem_file - -# Change default umask for all subprocesses of the notebook server if set in -# the environment -if 'NB_UMASK' in os.environ: - os.umask(int(os.environ['NB_UMASK'], 8)) diff --git a/requirements.txt b/requirements.txt index 4d3deb2..d950bf1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,42 +1,9 @@ -annotated-types==0.7.0 -anthropic==0.50.0 -anyio==4.9.0 -arxiv==2.2.0 -certifi==2025.4.26 -charset-normalizer==3.4.2 -click==8.1.8 -distro==1.9.0 -feedparser==6.0.11 -h11==0.16.0 -httpcore==1.0.9 -httpx==0.28.1 -httpx-sse==0.4.0 -idna==3.10 -jiter==0.9.0 -markdown-it-py==3.0.0 -mcp[cli]==1.7.1 -mdurl==0.1.2 -pydantic==2.11.4 -pydantic-core==2.33.2 -pydantic-settings==2.9.1 -pygments==2.19.1 -pypdf2==3.0.1 -python-dotenv==1.1.0 -python-multipart==0.0.20 -requests==2.32.3 -rich==14.0.0 -sgmllib3k==1.0.0 -shellingham==1.5.4 -sniffio==1.3.1 -sse-starlette==2.3.4 -starlette==0.46.2 -typer==0.15.3 -typing-extensions==4.13.2 -typing-inspection==0.4.0 -urllib3==2.4.0 -uv==0.7.2 -uvicorn==0.34.2 -jupyter_server_terminals==0.4.4 jupyter -openai==1.66.3 -pandas==2.2.3 +nbconvert +langchain==0.3.18 +langchain-openai==0.3.5 +langchain-anthropic==0.3.7 +langgraph==0.2.72 +langmem==0.0.8 +python-dotenv==1.0.1 +aider-install==0.2.0