-
-
Save duarteocarmo/4937eedc966a365ed2a518c1ff586c3d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Table of contents**<a id='toc0_'></a> \n", | |
"- [NOTE: Inspired by this](#toc1_) \n", | |
"- [Load model](#toc2_) \n", | |
"- [Outlines choice mode](#toc3_) \n", | |
"- [Pydantic like tutorial](#toc4_) \n", | |
"- [No chat templates, slightly bigger model](#toc5_) \n", | |
"- [Batch?](#toc6_) \n", | |
"\n", | |
"<!-- vscode-jupyter-toc-config\n", | |
"\tnumbering=false\n", | |
"\tanchor=true\n", | |
"\tflat=false\n", | |
"\tminLevel=1\n", | |
"\tmaxLevel=6\n", | |
"\t/vscode-jupyter-toc-config -->\n", | |
"<!-- THIS CELL WILL BE REPLACED ON TOC UPDATE. DO NOT WRITE YOUR TEXT IN THIS CELL -->" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/Users/duarteocarmo/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", | |
" from .autonotebook import tqdm as notebook_tqdm\n" | |
] | |
} | |
], | |
"source": [ | |
"import json\n", | |
"import outlines\n", | |
"import torch\n", | |
"from transformers import AutoTokenizer\n", | |
"from textwrap import dedent\n", | |
"from outlines.samplers import greedy, multinomial\n", | |
"from pydantic import BaseModel, Field, constr\n", | |
"from enum import Enum\n", | |
"import jupyter_black\n", | |
"import typing as t\n", | |
"from outlines import models, generate\n", | |
"import llama_cpp\n", | |
"\n", | |
"\n", | |
"jupyter_black.load()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# <a id='toc1_'></a>NOTE: Inspired by [this](https://github.com/willkurt/odsc-outlines-tutorial/blob/main/Answers/Exercise2-Solution.ipynb) [↑](#toc0_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/jpeg": "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", | |
"text/html": [ | |
"\n", | |
" <iframe\n", | |
" width=\"800\"\n", | |
" height=\"300\"\n", | |
" src=\"https://www.youtube.com/embed/2IkqM9k8swI\"\n", | |
" frameborder=\"0\"\n", | |
" allowfullscreen\n", | |
" \n", | |
" ></iframe>\n", | |
" " | |
], | |
"text/plain": [ | |
"<IPython.lib.display.YouTubeVideo at 0x435412700>" | |
] | |
}, | |
"execution_count": 16, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from IPython.display import YouTubeVideo\n", | |
"\n", | |
"YouTubeVideo(\"2IkqM9k8swI\", width=800, height=300)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# <a id='toc2_'></a>[Load model](#toc0_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"model_name = \"HuggingFaceTB/SmolLM-1.7B-Instruct\"\n", | |
"model = outlines.models.transformers(\n", | |
" model_name,\n", | |
" device=\"mps\",\n", | |
" model_kwargs={\n", | |
" \"torch_dtype\": torch.bfloat16,\n", | |
" \"trust_remote_code\": True,\n", | |
" },\n", | |
")\n", | |
"\n", | |
"tokenizer = AutoTokenizer.from_pretrained(model_name)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class Sentiment(str, Enum):\n", | |
" POSITIVE = \"POSITIVE\"\n", | |
" NEGATIVE = \"NEGATIVE\"\n", | |
" NEUTRAL = \"NEUTRAL\"\n", | |
"\n", | |
"\n", | |
"class SentimentClassification(BaseModel):\n", | |
" sentiment: Sentiment" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def create_prompt(message: str):\n", | |
"\n", | |
" SYSTEM_PROMPT = \"\"\"\n", | |
"You are a seasoned data analyst.\n", | |
"Classify the following text into three sentiment classes, namely:\n", | |
"NEGATIVE: if the text has a negative tone\n", | |
"POSITIVE: if the text has a positive tone\n", | |
"NEUTRAL: if the text has a neutral tone\n", | |
"\n", | |
"Consider the overall sentiment of the text.\n", | |
"Only reply with 'POSITIVE', 'NEGATIVE', or 'NEUTRAL'.\n", | |
"\"\"\".strip()\n", | |
"\n", | |
" messages = [\n", | |
" {\n", | |
" \"role\": \"user\",\n", | |
" \"content\": SYSTEM_PROMPT,\n", | |
" },\n", | |
" {\n", | |
" \"role\": \"assistant\",\n", | |
" \"content\": \"I undersand and only reply with 'POSITIVE', 'NEGATIVE', or 'NEUTRAL'.\",\n", | |
" },\n", | |
" {\"role\": \"user\", \"content\": message},\n", | |
" ]\n", | |
" sentiment_prompt = tokenizer.apply_chat_template(messages, tokenize=False)\n", | |
" return sentiment_prompt" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# <a id='toc3_'></a>[Outlines choice mode](#toc0_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/Users/duarteocarmo/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/transformers/generation/configuration_utils.py:590: UserWarning: `do_sample` is set to `False`. However, `temperature` is set to `0.0` -- this flag is only used in sample-based generation modes. You should set `do_sample=True` or unset `temperature`. This was detected when initializing the generation config instance, which means the corresponding file may hold incorrect parameterization and should be fixed.\n", | |
" warnings.warn(\n", | |
"/Users/duarteocarmo/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/transformers/generation/configuration_utils.py:590: UserWarning: `do_sample` is set to `False`. However, `temperature` is set to `0.0` -- this flag is only used in sample-based generation modes. You should set `do_sample=True` or unset `temperature`.\n", | |
" warnings.warn(\n", | |
"/Users/duarteocarmo/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/transformers/pytorch_utils.py:325: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", | |
" test_elements = torch.tensor(test_elements)\n" | |
] | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"POSITIVE\n" | |
] | |
} | |
], | |
"source": [ | |
"classifier = generate.choice(\n", | |
" model, [\"POSITIVE\", \"NEGATIVE\", \"NEUTRAL\"], sampler=greedy()\n", | |
")\n", | |
"answer = classifier(\n", | |
" create_prompt(\n", | |
" \"I love the new medication, it has helped me so much. I feel so much better now.\"\n", | |
" )\n", | |
")\n", | |
"print(answer)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# <a id='toc4_'></a>[Pydantic like tutorial](#toc0_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"msgs_to_classify = [\n", | |
" \"I love the new medication, it has helped me so much. I feel so much better now.\",\n", | |
" \"I am not sure about the new medication, it has not helped me at all.\",\n", | |
" \"The new medication is okay, it has helped me a little bit.\",\n", | |
"]" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def create_prompt(message: str) -> str:\n", | |
" complaint_messages = [\n", | |
" {\n", | |
" \"role\": \"user\",\n", | |
" \"content\": f\"\"\"\n", | |
" You are a seasoned data analyst at a pharmaceutical company.\n", | |
" Your aim is to process a message and return the following information in JSON format:\n", | |
" {{\n", | |
" 'sentiment': <{\"|\".join([e.value for e in Sentiment])}>,\n", | |
" }}\n", | |
" \"\"\",\n", | |
" },\n", | |
" {\n", | |
" \"role\": \"assistant\",\n", | |
" \"content\": \"I undersand and will process the message in the JSON format you described\",\n", | |
" },\n", | |
" {\"role\": \"user\", \"content\": message},\n", | |
" ]\n", | |
" complaint_prompt = tokenizer.apply_chat_template(complaint_messages, tokenize=False)\n", | |
" return complaint_prompt" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "ValidationError", | |
"evalue": "1 validation error for SentimentClassification\n__root__\n Extra data: line 1 column 26 (char 25) [type=value_error.jsondecode, input_value='{\"sentiment\": \"POSITIVE\"}AAAA', input_type=str]", | |
"output_type": "error", | |
"traceback": [ | |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", | |
"\u001b[0;31mJSONDecodeError\u001b[0m Traceback (most recent call last)", | |
"File \u001b[0;32m~/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/pydantic/main.py:1187\u001b[0m, in \u001b[0;36mBaseModel.parse_raw\u001b[0;34m(cls, b, content_type, encoding, proto, allow_pickle)\u001b[0m\n\u001b[1;32m 1186\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 1187\u001b[0m obj \u001b[38;5;241m=\u001b[39m \u001b[43mparse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_str_bytes\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1188\u001b[0m \u001b[43m \u001b[49m\u001b[43mb\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1189\u001b[0m \u001b[43m \u001b[49m\u001b[43mproto\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mproto\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1190\u001b[0m \u001b[43m \u001b[49m\u001b[43mcontent_type\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcontent_type\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1191\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1192\u001b[0m \u001b[43m \u001b[49m\u001b[43mallow_pickle\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mallow_pickle\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1193\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1194\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (\u001b[38;5;167;01mValueError\u001b[39;00m, \u001b[38;5;167;01mTypeError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m exc:\n", | |
"File \u001b[0;32m~/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/pydantic/deprecated/parse.py:49\u001b[0m, in \u001b[0;36mload_str_bytes\u001b[0;34m(b, content_type, encoding, proto, allow_pickle, json_loads)\u001b[0m\n\u001b[1;32m 48\u001b[0m b \u001b[38;5;241m=\u001b[39m b\u001b[38;5;241m.\u001b[39mdecode(encoding)\n\u001b[0;32m---> 49\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mjson_loads\u001b[49m\u001b[43m(\u001b[49m\u001b[43mb\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 50\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m proto \u001b[38;5;241m==\u001b[39m Protocol\u001b[38;5;241m.\u001b[39mpickle:\n", | |
"File \u001b[0;32m~/.asdf/installs/python/3.9.20/lib/python3.9/json/__init__.py:346\u001b[0m, in \u001b[0;36mloads\u001b[0;34m(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001b[0m\n\u001b[1;32m 343\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28mcls\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m object_hook \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m\n\u001b[1;32m 344\u001b[0m parse_int \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m parse_float \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m\n\u001b[1;32m 345\u001b[0m parse_constant \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m object_pairs_hook \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m kw):\n\u001b[0;32m--> 346\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_default_decoder\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdecode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 347\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", | |
"File \u001b[0;32m~/.asdf/installs/python/3.9.20/lib/python3.9/json/decoder.py:340\u001b[0m, in \u001b[0;36mJSONDecoder.decode\u001b[0;34m(self, s, _w)\u001b[0m\n\u001b[1;32m 339\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m end \u001b[38;5;241m!=\u001b[39m \u001b[38;5;28mlen\u001b[39m(s):\n\u001b[0;32m--> 340\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m JSONDecodeError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExtra data\u001b[39m\u001b[38;5;124m\"\u001b[39m, s, end)\n\u001b[1;32m 341\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m obj\n", | |
"\u001b[0;31mJSONDecodeError\u001b[0m: Extra data: line 1 column 26 (char 25)", | |
"\nDuring handling of the above exception, another exception occurred:\n", | |
"\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)", | |
"Cell \u001b[0;32mIn[9], line 5\u001b[0m\n\u001b[1;32m 2\u001b[0m prompts \u001b[38;5;241m=\u001b[39m [create_prompt(text) \u001b[38;5;28;01mfor\u001b[39;00m text \u001b[38;5;129;01min\u001b[39;00m msgs_to_classify]\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m msg \u001b[38;5;129;01min\u001b[39;00m msgs_to_classify:\n\u001b[0;32m----> 5\u001b[0m answer \u001b[38;5;241m=\u001b[39m \u001b[43msentiment_classifier\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcreate_prompt\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmsg\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28mprint\u001b[39m(msg)\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(answer)\n", | |
"File \u001b[0;32m~/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/outlines/generate/api.py:512\u001b[0m, in \u001b[0;36mSequenceGeneratorAdapter.__call__\u001b[0;34m(self, prompts, max_tokens, stop_at, seed, **model_specific_params)\u001b[0m\n\u001b[1;32m 500\u001b[0m generation_params \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprepare_generation_parameters(\n\u001b[1;32m 501\u001b[0m max_tokens, stop_at, seed\n\u001b[1;32m 502\u001b[0m )\n\u001b[1;32m 504\u001b[0m completions \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39mgenerate(\n\u001b[1;32m 505\u001b[0m prompts,\n\u001b[1;32m 506\u001b[0m generation_params,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 509\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mmodel_specific_params,\n\u001b[1;32m 510\u001b[0m )\n\u001b[0;32m--> 512\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_format\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcompletions\u001b[49m\u001b[43m)\u001b[49m\n", | |
"File \u001b[0;32m~/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/outlines/generate/api.py:488\u001b[0m, in \u001b[0;36mSequenceGeneratorAdapter._format\u001b[0;34m(self, sequences)\u001b[0m\n\u001b[1;32m 486\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m [\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_format(sequence) \u001b[38;5;28;01mfor\u001b[39;00m sequence \u001b[38;5;129;01min\u001b[39;00m sequences]\n\u001b[1;32m 487\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 488\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mformat_sequence\u001b[49m\u001b[43m(\u001b[49m\u001b[43msequences\u001b[49m\u001b[43m)\u001b[49m\n", | |
"File \u001b[0;32m~/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/outlines/generate/json.py:50\u001b[0m, in \u001b[0;36mjson.<locals>.<lambda>\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 48\u001b[0m regex_str \u001b[38;5;241m=\u001b[39m build_regex_from_schema(schema, whitespace_pattern)\n\u001b[1;32m 49\u001b[0m generator \u001b[38;5;241m=\u001b[39m regex(model, regex_str, sampler)\n\u001b[0;32m---> 50\u001b[0m generator\u001b[38;5;241m.\u001b[39mformat_sequence \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mlambda\u001b[39;00m x: \u001b[43mschema_object\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_raw\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 51\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mcallable\u001b[39m(schema_object):\n\u001b[1;32m 52\u001b[0m schema \u001b[38;5;241m=\u001b[39m pyjson\u001b[38;5;241m.\u001b[39mdumps(get_schema_from_signature(schema_object))\n", | |
"File \u001b[0;32m~/Library/Caches/pypoetry/virtualenvs/gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9/lib/python3.9/site-packages/pydantic/main.py:1214\u001b[0m, in \u001b[0;36mBaseModel.parse_raw\u001b[0;34m(cls, b, content_type, encoding, proto, allow_pickle)\u001b[0m\n\u001b[1;32m 1207\u001b[0m \u001b[38;5;66;03m# ctx is missing here, but since we've added `input` to the error, we're not pretending it's the same\u001b[39;00m\n\u001b[1;32m 1208\u001b[0m error: pydantic_core\u001b[38;5;241m.\u001b[39mInitErrorDetails \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 1209\u001b[0m \u001b[38;5;66;03m# The type: ignore on the next line is to ignore the requirement of LiteralString\u001b[39;00m\n\u001b[1;32m 1210\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtype\u001b[39m\u001b[38;5;124m'\u001b[39m: pydantic_core\u001b[38;5;241m.\u001b[39mPydanticCustomError(type_str, \u001b[38;5;28mstr\u001b[39m(exc)), \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 1211\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mloc\u001b[39m\u001b[38;5;124m'\u001b[39m: (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__root__\u001b[39m\u001b[38;5;124m'\u001b[39m,),\n\u001b[1;32m 1212\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124minput\u001b[39m\u001b[38;5;124m'\u001b[39m: b,\n\u001b[1;32m 1213\u001b[0m }\n\u001b[0;32m-> 1214\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pydantic_core\u001b[38;5;241m.\u001b[39mValidationError\u001b[38;5;241m.\u001b[39mfrom_exception_data(\u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m, [error])\n\u001b[1;32m 1215\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mmodel_validate(obj)\n", | |
"\u001b[0;31mValidationError\u001b[0m: 1 validation error for SentimentClassification\n__root__\n Extra data: line 1 column 26 (char 25) [type=value_error.jsondecode, input_value='{\"sentiment\": \"POSITIVE\"}AAAA', input_type=str]" | |
] | |
} | |
], | |
"source": [ | |
"sentiment_classifier = outlines.generate.json(model, SentimentClassification)\n", | |
"prompts = [create_prompt(text) for text in msgs_to_classify]\n", | |
"\n", | |
"for msg in msgs_to_classify:\n", | |
" answer = sentiment_classifier(create_prompt(msg))\n", | |
" print(msg)\n", | |
" print(answer)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# <a id='toc5_'></a>[No chat templates, slightly bigger model](#toc0_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"model = models.transformers(\"meta-llama/Llama-3.2-1B-Instruct\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"name='John' last_name='Smth' id=1\n" | |
] | |
} | |
], | |
"source": [ | |
"class User(BaseModel):\n", | |
" name: str\n", | |
" last_name: str\n", | |
" id: int\n", | |
"\n", | |
"\n", | |
"generator = generate.json(model, User)\n", | |
"result = generator(\"Create a user profile with the fields name, last_name and id\")\n", | |
"print(result)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"sentiment='NEUTRAL'\n" | |
] | |
} | |
], | |
"source": [ | |
"msg = \"This drug was the best thing I've ever taken. It completely changed my life.\"\n", | |
"PROMPT = \"\"\"\n", | |
"You are a seasoned data analyst.\n", | |
"Classify the following medical-related text into three sentiment classes, namely:\n", | |
"NEGATIVE: if the text has a negative tone\n", | |
"POSITIVE: if the text has a positive tone\n", | |
"NEUTRAL: if the text has a neutral tone\n", | |
"Consider the overall sentiment of the text.\n", | |
"\n", | |
"<text_to_classify>\n", | |
"{msg}\n", | |
"</text_to_classify>\n", | |
"\"\"\".strip()\n", | |
"\n", | |
"\n", | |
"class Sentiment(BaseModel):\n", | |
" sentiment: str = Field(pattern=\"^(POSITIVE|NEGATIVE|NEUTRAL)$\")\n", | |
"\n", | |
"\n", | |
"generator = generate.json(model, Sentiment)\n", | |
"result = generator(PROMPT.format(msg=msg))\n", | |
"print(result)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# <a id='toc6_'></a>[Batch?](#toc0_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Message: I have a complaint about the product; Sentiment: NEGATIVE\n", | |
"Message: I will never buy this product again; Sentiment: NEGATIVE\n", | |
"Message: I love this product, it is the best thing ever; Sentiment: NEUTRAL\n", | |
"Message: I am neutral about this product; Sentiment: NEUTRAL\n", | |
"Message: My mom recommended this product to me and I love it; Sentiment: POSITIVE\n", | |
"Message: I have had a great experience with this product; Sentiment: POSITIVE\n", | |
"Message: I have a complaint about the product; Sentiment: NEGATIVE\n", | |
"Message: I will never buy this product again; Sentiment: NEGATIVE\n", | |
"Message: I love this product, it is the best thing ever; Sentiment: NEUTRAL\n", | |
"Message: I am neutral about this product; Sentiment: POSITIVE\n", | |
"Message: My mom recommended this product to me and I love it; Sentiment: POSITIVE\n", | |
"Message: I have had a great experience with this product; Sentiment: POSITIVE\n", | |
"Message: I have a complaint about the product; Sentiment: NEGATIVE\n", | |
"Message: I will never buy this product again; Sentiment: NEGATIVE\n", | |
"Message: I love this product, it is the best thing ever; Sentiment: NEUTRAL\n", | |
"Message: I am neutral about this product; Sentiment: NEGATIVE\n", | |
"Message: My mom recommended this product to me and I love it; Sentiment: NEGATIVE\n", | |
"Message: I have had a great experience with this product; Sentiment: NEUTRAL\n", | |
"Message: I have a complaint about the product; Sentiment: NEGATIVE\n", | |
"Message: I will never buy this product again; Sentiment: NEGATIVE\n", | |
"Message: I love this product, it is the best thing ever; Sentiment: NEUTRAL\n", | |
"Message: I am neutral about this product; Sentiment: NEUTRAL\n", | |
"Message: My mom recommended this product to me and I love it; Sentiment: NEUTRAL\n", | |
"Message: I have had a great experience with this product; Sentiment: NEUTRAL\n", | |
"Message: I have a complaint about the product; Sentiment: NEGATIVE\n", | |
"Message: I will never buy this product again; Sentiment: NEGATIVE\n", | |
"Message: I love this product, it is the best thing ever; Sentiment: NEUTRAL\n", | |
"Message: I am neutral about this product; Sentiment: NEUTRAL\n", | |
"Message: My mom recommended this product to me and I love it; Sentiment: POSITIVE\n", | |
"Message: I have had a great experience with this product; Sentiment: NEUTRAL\n" | |
] | |
} | |
], | |
"source": [ | |
"messages = [\n", | |
" \"I have a complaint about the product\",\n", | |
" \"I will never buy this product again\",\n", | |
" \"I love this product, it is the best thing ever\",\n", | |
" \"I am neutral about this product\",\n", | |
" \"My mom recommended this product to me and I love it\",\n", | |
" \"I have had a great experience with this product\",\n", | |
"] * 5\n", | |
"prompts = [PROMPT.format(msg=msg) for msg in messages]\n", | |
"results = generator(prompts)\n", | |
"\n", | |
"for m, r in zip(messages, results):\n", | |
" print(f\"Message: {m}; Sentiment: {r.sentiment}\")" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "gtm-insights-intelligence-kfp-pipelines-Fe6-Kvub-py3.9", | |
"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.9.20" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment