Merge pull request #290 from msource1/main
Week 1 Day 5 - Title Generator V3 - using Firecrawl
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7df20212-bfa8-4b2b-aec5-7b562dd15ee8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Issue with Gradio when using Claude for Conversational AI (chatbots)\n",
|
||||
"\n",
|
||||
"As explained in Day 3 (notebook), Gradio has been upgraded to pass in history in a format OpenAI accepts.\n",
|
||||
"\n",
|
||||
"This update simplifies the development work as Gradio manages the history in the background and provides a history structure that matches OpenAi. Fortunately, this works with other models that leverage the client libraries for OpenAI, such as Llama and Gemini. \n",
|
||||
"\n",
|
||||
"However, leveraging Gradio's ChatInterface while using Claude models generates a BadRequest error. \n",
|
||||
"\n",
|
||||
"In analyzing the history list from Gradio, it has the following format:\n",
|
||||
"\n",
|
||||
"`{'role': 'assistant', 'metadata': None, 'content': '[assistant message here]', 'options': None}`\n",
|
||||
"\n",
|
||||
"OpenAi accepts this format without issues, as do other models such as Llama and Gemini - at least while leveraging the client libraries for OpenAI. They accept both formats. \n",
|
||||
"\n",
|
||||
"However, Claude's API requires the following format:\n",
|
||||
"\n",
|
||||
"`{'role': 'user', 'content': '[user message here]'}`\n",
|
||||
"\n",
|
||||
"Claude rejects anything different from this format.\n",
|
||||
"\n",
|
||||
"Run the code below to get the details! "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b5398289-f4d0-4317-b9c2-fff06c4bbfec",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# imports\n",
|
||||
"\n",
|
||||
"import os\n",
|
||||
"from dotenv import load_dotenv\n",
|
||||
"from openai import OpenAI\n",
|
||||
"import google.generativeai\n",
|
||||
"import anthropic\n",
|
||||
"import gradio as gr\n",
|
||||
"from pprint import pprint # for a nicely formatted printout of a list"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "76df1fb5-76f8-4b52-afbb-12b892208b50",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# set environment variables for OpenAi\n",
|
||||
"load_dotenv(override=True)\n",
|
||||
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
|
||||
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
|
||||
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
|
||||
"\n",
|
||||
"# validate API Key\n",
|
||||
"if not openai_api_key:\n",
|
||||
" raise ValueError(\"No OpenAI API key was found! Please check the .env file.\")\n",
|
||||
"else:\n",
|
||||
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
|
||||
"\n",
|
||||
"if not anthropic_api_key:\n",
|
||||
" raise ValueError(\"No Anthropic API key was found! Please check the .env file.\")\n",
|
||||
"else:\n",
|
||||
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
|
||||
"\n",
|
||||
"if not google_api_key:\n",
|
||||
" raise ValueError(\"No Gemini API key was found! Please check the .env file.\")\n",
|
||||
"else:\n",
|
||||
" print(f\"Gemini API Key exists and begins {google_api_key[:8]}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f2429366-a9ab-4e72-a651-56f17b779cf4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# constants\n",
|
||||
"MODELS = { 'GPT': 'gpt-4o-mini', \n",
|
||||
" 'LLAMA': 'llama3.2', \n",
|
||||
" # 'DEEPSEEK': 'deepseek-r1:1.5b',\n",
|
||||
" 'CLAUDE': 'claude-3-haiku-20240307',\n",
|
||||
" 'GEMINI': 'gemini-2.0-flash-exp'\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"CLIENTS = { 'GPT': OpenAI(), \n",
|
||||
" 'LLAMA': OpenAI(base_url='http://localhost:11434/v1', api_key='ollama'),\n",
|
||||
" # 'DEEPSEEK': OpenAI(base_url='http://localhost:11434/v1', api_key='ollama'),\n",
|
||||
" 'CLAUDE': anthropic.Anthropic(),\n",
|
||||
" 'GEMINI': OpenAI(base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\", api_key=google_api_key)\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"# system prompt\n",
|
||||
"system_message = \"You are a nice assistant that like to chat with users\"\n",
|
||||
"\n",
|
||||
"# to save/print the history structure\n",
|
||||
"console = []"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bb34616a-2304-4a56-af3a-8d353629722b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Testing GPT\n",
|
||||
"\n",
|
||||
"This runs without issues. You may change the model to Llama or Gemini for further testing."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9e69eb7a-50cf-478c-83f6-4ce923a9c53a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def gpt_chat(message, history):\n",
|
||||
" # change to Llama or Gemini for test\n",
|
||||
" model = 'GPT'\n",
|
||||
"\n",
|
||||
" # add system message to history\n",
|
||||
" if not history:\n",
|
||||
" history.append({\"role\": \"system\", \"content\": system_message})\n",
|
||||
"\n",
|
||||
" # conversation including new user message\n",
|
||||
" messages = history + [{\"role\": \"user\", \"content\": message}]\n",
|
||||
"\n",
|
||||
" # send request to OpenAi\n",
|
||||
" response = CLIENTS[model].chat.completions.create(\n",
|
||||
" model = MODELS[model],\n",
|
||||
" max_tokens = 200,\n",
|
||||
" messages = messages,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # save history structure\n",
|
||||
" global console\n",
|
||||
" console = history[:]\n",
|
||||
" \n",
|
||||
" # post in Gradio's chat interface\n",
|
||||
" return response.choices[0].message.content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "20444651-440c-4b6d-996d-87a21c28f28e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Have a conversation of several messages (3 or more)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "90dac8e6-e1ef-455a-94e9-06735e6c17fb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Gradio with GPT\n",
|
||||
"gr.ChatInterface(fn=gpt_chat, type=\"messages\", examples=[\"How are you today?\", \"Please, tell me a joke.\"]).launch()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b4048069-b712-491a-96d5-f8fd9f0fe533",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Notice how the history structure includes both formats, and this is okay with OpenAi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2f8acbde-f5c3-4890-af5b-69a24ded9b45",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# audit console\n",
|
||||
"pprint(console)\n",
|
||||
"\n",
|
||||
"# empty list\n",
|
||||
"console.clear()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "deaeb8a0-266a-4b5d-8536-e5c59391baa5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Testing with Claude\n",
|
||||
"\n",
|
||||
"This first test will generate a BadRequest error on the second message from the user. The first message sent follows the required format preventing errors."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "268e662d-84f5-4b09-8472-c3545a04f2a4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Chat using Gradio's history - generates error after the second message from user\n",
|
||||
"def claude_chat(message, history): # Gradio requires the history parameter, but it goes unused. \n",
|
||||
" \n",
|
||||
" # save history structure\n",
|
||||
" global console\n",
|
||||
" console = history[:]\n",
|
||||
" \n",
|
||||
" model = 'CLAUDE'\n",
|
||||
"\n",
|
||||
" # conversation including new user message - this is why the first message does not generate an error\n",
|
||||
" messages = history + [{\"role\": \"user\", \"content\": message}]\n",
|
||||
"\n",
|
||||
" # send the request to Claude\n",
|
||||
" response = CLIENTS[model].messages.create(\n",
|
||||
" model = MODELS[model],\n",
|
||||
" max_tokens = 200,\n",
|
||||
" system = system_message,\n",
|
||||
" messages = messages,\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" # post in Gradio's chat interface\n",
|
||||
" return response.content[0].text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5fd5e221-ab81-4567-a14d-5638d9919a40",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Have a conversation of several messages (3 or more)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fbd1a4b2-afcf-4345-bf1a-283c16076e07",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Gradio with Claude\n",
|
||||
"gr.ChatInterface(fn=claude_chat, type=\"messages\", examples=[\"How are you today?\", \"Please, tell me a joke.\"]).launch()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "834bf737-b3d3-4225-be12-f493f3490f16",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Notice how the history structure changes for the second message. This cause a BadRequest error with Claude."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c6cfa123-83d5-46d8-ac33-74fd9cae0ab3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# audit console\n",
|
||||
"pprint(console)\n",
|
||||
"\n",
|
||||
"# empty list\n",
|
||||
"console.clear()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c0b5c4e0-7544-4279-8006-fde4be9c656f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Have a new conversation of several messages (3 or more), but this time leveraging a local history repository instead of Gradio's. \n",
|
||||
"\n",
|
||||
"The code leverages the list `console` as the local repository. Note that Gradio still requires the second parameter (history) is required even though it is not used. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8c50326e-8496-499a-81d9-28b883ac9b6b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def claude_chat(message, history): # Gradio requires the history parameter, but it goes unused. \n",
|
||||
" # local history repository instead of Gradio's \n",
|
||||
" global console\n",
|
||||
" model = 'CLAUDE'\n",
|
||||
"\n",
|
||||
" # append new user message to history - using Claude's required format\n",
|
||||
" console.append({\"role\": \"user\", \"content\": message})\n",
|
||||
"\n",
|
||||
" # send the request to Claude\n",
|
||||
" response = CLIENTS[model].messages.create(\n",
|
||||
" model = MODELS[model],\n",
|
||||
" max_tokens = 200,\n",
|
||||
" system = system_message,\n",
|
||||
" messages = console, # use local history repository\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # append the assistant response to history - using Claude's required format\n",
|
||||
" console.append({\"role\": \"assistant\", \"content\": response.content[0].text})\n",
|
||||
"\n",
|
||||
" # post in Gradio's chat interface\n",
|
||||
" return response.content[0].text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f19621f5-8dd6-4a88-9a21-9aab04a9dd90",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Gradio with Claude\n",
|
||||
"gr.ChatInterface(fn=claude_chat, type=\"messages\", examples=[\"How are you today?\", \"Please, tell me a joke.\"]).launch()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d6c33236-0d2f-4341-b9ec-e3d7b3eeaec6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Notice that the history structure follows the required format."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bd5dd244-abc7-4654-97d2-c140b2a934d2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# audit console\n",
|
||||
"pprint(console)\n",
|
||||
"\n",
|
||||
"# empty list\n",
|
||||
"console.clear()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "48fc0b5f-09de-413f-a809-7bbba5a1ae3e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Conclusion\n",
|
||||
"\n",
|
||||
"1. OpenAi (and models that leverage the client libraries for OpenAI) supports both formats for the conversation history.\n",
|
||||
"\n",
|
||||
" (Gradio's) `{'role': 'assistant', 'metadata': None, 'content': '[assistant message here]', 'options': None}`\n",
|
||||
"\n",
|
||||
" (Claude's) `{'role': 'user', 'content': '[user message here]'}`\n",
|
||||
" \n",
|
||||
"2. Claude only supports the following format for the conversation history:\n",
|
||||
"\n",
|
||||
" (Claude's) `{'role': 'user', 'content': '[user message here]'}`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "913b171a-8b3e-43e4-ac38-cedf2c4cdedf",
|
||||
"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.11.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user