From f629e181ad20ae3a5c597c6a5df53b0fe3a5def2 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 18 Mar 2025 19:41:00 +0000 Subject: [PATCH 1/4] Structured outputs demos --- structured_outputs_basic.py | 59 ++++++++++++++++++++++ structured_outputs_description.py | 59 ++++++++++++++++++++++ structured_outputs_enum.py | 68 ++++++++++++++++++++++++++ structured_outputs_function_calling.py | 49 +++++++++++++++++++ structured_outputs_nested.py | 62 +++++++++++++++++++++++ 5 files changed, 297 insertions(+) create mode 100644 structured_outputs_basic.py create mode 100644 structured_outputs_description.py create mode 100644 structured_outputs_enum.py create mode 100644 structured_outputs_function_calling.py create mode 100644 structured_outputs_nested.py diff --git a/structured_outputs_basic.py b/structured_outputs_basic.py new file mode 100644 index 0000000..455c422 --- /dev/null +++ b/structured_outputs_basic.py @@ -0,0 +1,59 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + + +class CalendarEvent(BaseModel): + name: str + date: str + participants: list[str] + + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extract the event information."}, + {"role": "user", "content": "Alice and Bob are going to a science fair on Friday."}, + ], + response_format=CalendarEvent, +) + + +message = completion.choices[0].message +if (message.refusal): + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) diff --git a/structured_outputs_description.py b/structured_outputs_description.py new file mode 100644 index 0000000..bb5aedb --- /dev/null +++ b/structured_outputs_description.py @@ -0,0 +1,59 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel, Field + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + + +class CalendarEvent(BaseModel): + name: str + date: str = Field(..., description="A date in the format YYYY-MM-DD") + participants: list[str] + + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extract the event information. If no year is specified, assume the current year (2025)."}, + {"role": "user", "content": "Alice and Bob are going to a science fair on the 1st of april."}, + ], + response_format=CalendarEvent, +) +CalendarEvent(name='Science Fair', date='2025-04-01', participants=['Alice', 'Bob']) + +message = completion.choices[0].message +if (message.refusal): + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) \ No newline at end of file diff --git a/structured_outputs_enum.py b/structured_outputs_enum.py new file mode 100644 index 0000000..9eec74d --- /dev/null +++ b/structured_outputs_enum.py @@ -0,0 +1,68 @@ +import os +from enum import Enum + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + + +class DayOfWeek(str, Enum): + SUNDAY = "Sunday" + MONDAY = "Monday" + TUESDAY = "Tuesday" + WEDNESDAY = "Wednesday" + THURSDAY = "Thursday" + FRIDAY = "Friday" + SATURDAY = "Saturday" + +class CalendarEvent(BaseModel): + name: str + date: DayOfWeek + participants: list[str] + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extract the event information."}, + {"role": "user", "content": "Alice and Bob are going to a science fair on Friday."}, + ], + response_format=CalendarEvent, +) + + +message = completion.choices[0].message +if (message.refusal): + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) diff --git a/structured_outputs_function_calling.py b/structured_outputs_function_calling.py new file mode 100644 index 0000000..e366e32 --- /dev/null +++ b/structured_outputs_function_calling.py @@ -0,0 +1,49 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + +class GetDeliveryDate(BaseModel): + order_id: str + +response = client.chat.completions.create( + model=MODEL_NAME, + messages=[ + {"role": "system", + "content": "You're a customer support bot. Use the tools to assist the user."}, + {"role": "user", + "content": "Hi, can you tell me the delivery date for my order #12345?"}], + tools=[openai.pydantic_function_tool(GetDeliveryDate)]) + +rich.print(response.choices[0].message.tool_calls[0].function) \ No newline at end of file diff --git a/structured_outputs_nested.py b/structured_outputs_nested.py new file mode 100644 index 0000000..2674cf3 --- /dev/null +++ b/structured_outputs_nested.py @@ -0,0 +1,62 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + + +class Participant(BaseModel): + name: str + job_title: str + +class CalendarEvent(BaseModel): + name: str + date: str + participants: list[Participant] + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extract the event information."}, + {"role": "user", "content": "Alice the carpenter and Bob the plumber are going to a science fair on Friday."}, + ], + response_format=CalendarEvent, +) + + +message = completion.choices[0].message +if (message.refusal): + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) From cbaa11baf12d13a835c71cacf8ead94bcedacbef Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 18 Mar 2025 19:42:45 +0000 Subject: [PATCH 2/4] Formatting --- structured_outputs_basic.py | 3 +-- structured_outputs_description.py | 12 +++++++----- structured_outputs_enum.py | 25 +++++++++++++------------ structured_outputs_function_calling.py | 21 +++++++++++---------- structured_outputs_nested.py | 15 ++++++++------- 5 files changed, 40 insertions(+), 36 deletions(-) diff --git a/structured_outputs_basic.py b/structured_outputs_basic.py index 455c422..c201a6d 100644 --- a/structured_outputs_basic.py +++ b/structured_outputs_basic.py @@ -34,7 +34,6 @@ MODEL_NAME = os.environ["OPENAI_MODEL"] - class CalendarEvent(BaseModel): name: str date: str @@ -52,7 +51,7 @@ class CalendarEvent(BaseModel): message = completion.choices[0].message -if (message.refusal): +if message.refusal: rich.print(message.refusal) else: event = message.parsed diff --git a/structured_outputs_description.py b/structured_outputs_description.py index bb5aedb..9e896bd 100644 --- a/structured_outputs_description.py +++ b/structured_outputs_description.py @@ -34,7 +34,6 @@ MODEL_NAME = os.environ["OPENAI_MODEL"] - class CalendarEvent(BaseModel): name: str date: str = Field(..., description="A date in the format YYYY-MM-DD") @@ -44,16 +43,19 @@ class CalendarEvent(BaseModel): completion = client.beta.chat.completions.parse( model=MODEL_NAME, messages=[ - {"role": "system", "content": "Extract the event information. If no year is specified, assume the current year (2025)."}, + { + "role": "system", + "content": "Extract the event information. If no year is specified, assume the current year (2025).", + }, {"role": "user", "content": "Alice and Bob are going to a science fair on the 1st of april."}, ], response_format=CalendarEvent, ) -CalendarEvent(name='Science Fair', date='2025-04-01', participants=['Alice', 'Bob']) +CalendarEvent(name="Science Fair", date="2025-04-01", participants=["Alice", "Bob"]) message = completion.choices[0].message -if (message.refusal): +if message.refusal: rich.print(message.refusal) else: event = message.parsed - rich.print(event) \ No newline at end of file + rich.print(event) diff --git a/structured_outputs_enum.py b/structured_outputs_enum.py index 9eec74d..c06f076 100644 --- a/structured_outputs_enum.py +++ b/structured_outputs_enum.py @@ -35,20 +35,21 @@ MODEL_NAME = os.environ["OPENAI_MODEL"] - class DayOfWeek(str, Enum): - SUNDAY = "Sunday" - MONDAY = "Monday" - TUESDAY = "Tuesday" - WEDNESDAY = "Wednesday" - THURSDAY = "Thursday" - FRIDAY = "Friday" - SATURDAY = "Saturday" + SUNDAY = "Sunday" + MONDAY = "Monday" + TUESDAY = "Tuesday" + WEDNESDAY = "Wednesday" + THURSDAY = "Thursday" + FRIDAY = "Friday" + SATURDAY = "Saturday" + class CalendarEvent(BaseModel): - name: str - date: DayOfWeek - participants: list[str] + name: str + date: DayOfWeek + participants: list[str] + completion = client.beta.chat.completions.parse( model=MODEL_NAME, @@ -61,7 +62,7 @@ class CalendarEvent(BaseModel): message = completion.choices[0].message -if (message.refusal): +if message.refusal: rich.print(message.refusal) else: event = message.parsed diff --git a/structured_outputs_function_calling.py b/structured_outputs_function_calling.py index e366e32..1ce9693 100644 --- a/structured_outputs_function_calling.py +++ b/structured_outputs_function_calling.py @@ -35,15 +35,16 @@ class GetDeliveryDate(BaseModel): - order_id: str + order_id: str + response = client.chat.completions.create( - model=MODEL_NAME, - messages=[ - {"role": "system", - "content": "You're a customer support bot. Use the tools to assist the user."}, - {"role": "user", - "content": "Hi, can you tell me the delivery date for my order #12345?"}], - tools=[openai.pydantic_function_tool(GetDeliveryDate)]) - -rich.print(response.choices[0].message.tool_calls[0].function) \ No newline at end of file + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "You're a customer support bot. Use the tools to assist the user."}, + {"role": "user", "content": "Hi, can you tell me the delivery date for my order #12345?"}, + ], + tools=[openai.pydantic_function_tool(GetDeliveryDate)], +) + +rich.print(response.choices[0].message.tool_calls[0].function) diff --git a/structured_outputs_nested.py b/structured_outputs_nested.py index 2674cf3..0833007 100644 --- a/structured_outputs_nested.py +++ b/structured_outputs_nested.py @@ -34,15 +34,16 @@ MODEL_NAME = os.environ["OPENAI_MODEL"] - class Participant(BaseModel): - name: str - job_title: str + name: str + job_title: str + class CalendarEvent(BaseModel): - name: str - date: str - participants: list[Participant] + name: str + date: str + participants: list[Participant] + completion = client.beta.chat.completions.parse( model=MODEL_NAME, @@ -55,7 +56,7 @@ class CalendarEvent(BaseModel): message = completion.choices[0].message -if (message.refusal): +if message.refusal: rich.print(message.refusal) else: event = message.parsed From 809755a3e4d043a7aca6eaf4ec6f2caabec117aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwyneth=20Pe=C3=B1a-Siguenza?= Date: Thu, 20 Mar 2025 14:40:21 +0000 Subject: [PATCH 3/4] I translated to Spanish and added section in READMEs --- README.md | 10 +++ spanish/README.md | 12 ++++ spanish/structured_outputs_basic.py | 58 ++++++++++++++++ spanish/structured_outputs_description.py | 60 ++++++++++++++++ spanish/structured_outputs_enum.py | 69 +++++++++++++++++++ .../structured_outputs_function_calling.py | 50 ++++++++++++++ spanish/structured_outputs_nested.py | 63 +++++++++++++++++ 7 files changed, 322 insertions(+) create mode 100644 spanish/structured_outputs_basic.py create mode 100644 spanish/structured_outputs_description.py create mode 100644 spanish/structured_outputs_enum.py create mode 100644 spanish/structured_outputs_function_calling.py create mode 100644 spanish/structured_outputs_nested.py diff --git a/README.md b/README.md index 2c87365..c1d07e8 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,16 @@ Then run the scripts (in order of increasing complexity): * [`rag_documents_flow.py`](./rag_pdfs.py): A RAG flow that retrieves matching results from the local JSON file created by `rag_documents_ingestion.py`. * [`rag_documents_hybrid.py`](./rag_documents_hybrid.py): A RAG flow that implements a hybrid retrieval with both vector and keyword search, merging with Reciprocal Rank Fusion (RRF), and semantic re-ranking with a cross-encoder model. +## Structured outputs with OpenAI + +These scripts demonstrate how to use the OpenAI API to generate structured responses using Pydantic data models: + +* [`structured_outputs_basic.py`](./structured_outputs_basic.py): Basic example extracting simple event information using a Pydantic model. +* [`structured_outputs_description.py`](./structured_outputs_description.py): Uses additional descriptions in Pydantic model fields to clarify to the model how to format the response. +* [`structured_outputs_enum.py`](./structured_outputs_enum.py): Uses enumerations (Enums) to restrict possible values in structured responses. +* [`structured_outputs_function_calling.py`](./structured_outputs_function_calling.py): Demonstrates how to use functions defined with Pydantic for automatic function calling based on user queries. +* [`structured_outputs_nested.py`](./structured_outputs_nested.py): Uses nested Pydantic models to handle more complex structured responses, such as events with participants having multiple attributes. + ## Setting up the environment If you open this up in a Dev Container or GitHub Codespaces, everything will be setup for you. diff --git a/spanish/README.md b/spanish/README.md index a135a5e..3c1ac14 100644 --- a/spanish/README.md +++ b/spanish/README.md @@ -43,6 +43,18 @@ Luego ejecuta los scripts (en orden de complejidad creciente): * [`rag_documents_flow.py`](./rag_pdfs.py): Un flujo RAG que recupera resultados coincidentes del archivo JSON local creado por `rag_documents_ingestion.py`. * [`rag_documents_hybrid.py`](./rag_documents_hybrid.py): Un flujo RAG que implementa una recuperación híbrida con búsqueda vectorial y por palabras clave, fusionando con Reciprocal Rank Fusion (RRF), y reclasificación semántica con un modelo cross-encoder. +## Salidas estructuradas con OpenAI + +Estos scripts muestran cómo usar la API de OpenAI para generar respuestas estructuradas usando modelos de datos con Pydantic: + +* [`structured_outputs_basic.py`](./structured_outputs_basic.py): Ejemplo básico que extrae información sencilla de un evento usando un modelo Pydantic. +* [`structured_outputs_description.py`](./structured_outputs_description.py): Usa descripciones adicionales en los campos del modelo Pydantic para aclararle al modelo cómo formatear la respuesta. +* [`structured_outputs_enum.py`](./structured_outputs_enum.py): Usa enumeraciones (Enums) para restringir los valores posibles en la respuesta estructurada. +* [`structured_outputs_function_calling.py`](./structured_outputs_function_calling.py): Muestra cómo usar funciones definidas con Pydantic para que el modelo las llame automáticamente según la consulta del usuario. +* [`structured_outputs_nested.py`](./structured_outputs_nested.py): Usa modelos anidados con Pydantic para manejar respuestas estructuradas más complejas, como eventos con participantes que tienen múltiples atributos. + + + ## Configuración del entorno Si abres esto en un Dev Container o GitHub Codespaces, todo estará configurado para ti. diff --git a/spanish/structured_outputs_basic.py b/spanish/structured_outputs_basic.py new file mode 100644 index 0000000..03550f1 --- /dev/null +++ b/spanish/structured_outputs_basic.py @@ -0,0 +1,58 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + +class CalendarEvent(BaseModel): + name: str + date: str + participants: list[str] + + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extrae la info del evento."}, + {"role": "user", "content": "Alice y Bob van a ir a una feria de ciencias el viernes."}, + ], + response_format=CalendarEvent, +) + + +message = completion.choices[0].message +if message.refusal: + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) diff --git a/spanish/structured_outputs_description.py b/spanish/structured_outputs_description.py new file mode 100644 index 0000000..5107fbb --- /dev/null +++ b/spanish/structured_outputs_description.py @@ -0,0 +1,60 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel, Field + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + +class CalendarEvent(BaseModel): + name: str + date: str = Field(..., description="A date in the format YYYY-MM-DD") + participants: list[str] + + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + { + "role": "system", + "content": "Extrae la info del evento. Si no dice el año, asumí que es este año (2025).", + }, + {"role": "user", "content": "Alice y Bob van a ir a una feria de ciencias el 1 de abril."}, + ], + response_format=CalendarEvent, +) +CalendarEvent(name="Feria de Ciencias", date="2025-04-01", participants=["Alice", "Bob"]) +message = completion.choices[0].message +if message.refusal: + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) diff --git a/spanish/structured_outputs_enum.py b/spanish/structured_outputs_enum.py new file mode 100644 index 0000000..2ec953a --- /dev/null +++ b/spanish/structured_outputs_enum.py @@ -0,0 +1,69 @@ +import os +from enum import Enum + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + +class DayOfWeek(str, Enum): + DOMINGO = "Domingo" + LUNES = "Lunes" + MARTES = "Martes" + MIÉRCOLES = "Miércoles" + JUEVES = "Jueves" + VIERNES = "Viernes" + SÁBADO = "Sábado" + + +class CalendarEvent(BaseModel): + name: str + date: DayOfWeek + participants: list[str] + + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extrae la info del evento."}, + {"role": "user", "content": "Alice y Bob van a ir a una feria de ciencias el viernes."}, + ], + response_format=CalendarEvent, +) + + +message = completion.choices[0].message +if message.refusal: + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) diff --git a/spanish/structured_outputs_function_calling.py b/spanish/structured_outputs_function_calling.py new file mode 100644 index 0000000..717c205 --- /dev/null +++ b/spanish/structured_outputs_function_calling.py @@ -0,0 +1,50 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + +class GetDeliveryDate(BaseModel): + order_id: str + + +response = client.chat.completions.create( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Eres un bot de atención al cliente. Usá las herramientas para ayudar al usuario."}, + {"role": "user", "content": "Hola, ¿me puedes decir cuándo llegará mi pedido #12345?"}, + ], + tools=[openai.pydantic_function_tool(GetDeliveryDate)], +) + +rich.print(response.choices[0].message.tool_calls[0].function) diff --git a/spanish/structured_outputs_nested.py b/spanish/structured_outputs_nested.py new file mode 100644 index 0000000..9f56bad --- /dev/null +++ b/spanish/structured_outputs_nested.py @@ -0,0 +1,63 @@ +import os + +import azure.identity +import openai +import rich +from dotenv import load_dotenv +from pydantic import BaseModel + +# Setup the OpenAI client to use either Azure, OpenAI.com, or Ollama API +load_dotenv(override=True) +API_HOST = os.getenv("API_HOST", "github") + +if API_HOST == "azure": + token_provider = azure.identity.get_bearer_token_provider( + azure.identity.DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" + ) + client = openai.AzureOpenAI( + api_version=os.environ["AZURE_OPENAI_VERSION"], + azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], + azure_ad_token_provider=token_provider, + ) + MODEL_NAME = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +elif API_HOST == "ollama": + client = openai.OpenAI(base_url=os.environ["OLLAMA_ENDPOINT"], api_key="nokeyneeded") + MODEL_NAME = os.environ["OLLAMA_MODEL"] + +elif API_HOST == "github": + client = openai.OpenAI(base_url="https://models.inference.ai.azure.com", api_key=os.environ["GITHUB_TOKEN"]) + MODEL_NAME = os.getenv("GITHUB_MODEL", "gpt-4o") + +else: + client = openai.OpenAI(api_key=os.environ["OPENAI_KEY"]) + MODEL_NAME = os.environ["OPENAI_MODEL"] + + +class Participant(BaseModel): + name: str + job_title: str + + +class CalendarEvent(BaseModel): + name: str + date: str + participants: list[Participant] + + +completion = client.beta.chat.completions.parse( + model=MODEL_NAME, + messages=[ + {"role": "system", "content": "Extrae la info del evento."}, + {"role": "user", "content": "Alice, que es carpintera, y Bob, que es plomero, van a ir a una feria de ciencias el viernes."}, + ], + response_format=CalendarEvent, +) + + +message = completion.choices[0].message +if message.refusal: + rich.print(message.refusal) +else: + event = message.parsed + rich.print(event) From f1a8f2115103b434d2ff0f42337723156ffa53dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwyneth=20Pe=C3=B1a-Siguenza?= Date: Thu, 20 Mar 2025 14:48:50 +0000 Subject: [PATCH 4/4] ran pre commit --- rag_ingested_chunks.json | 2 +- spanish/structured_outputs_function_calling.py | 5 ++++- spanish/structured_outputs_nested.py | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/rag_ingested_chunks.json b/rag_ingested_chunks.json index 3cf1c30..984f2fa 100644 --- a/rag_ingested_chunks.json +++ b/rag_ingested_chunks.json @@ -243635,4 +243635,4 @@ -0.012606247328221798 ] } -] \ No newline at end of file +] diff --git a/spanish/structured_outputs_function_calling.py b/spanish/structured_outputs_function_calling.py index 717c205..4e5ed12 100644 --- a/spanish/structured_outputs_function_calling.py +++ b/spanish/structured_outputs_function_calling.py @@ -41,7 +41,10 @@ class GetDeliveryDate(BaseModel): response = client.chat.completions.create( model=MODEL_NAME, messages=[ - {"role": "system", "content": "Eres un bot de atención al cliente. Usá las herramientas para ayudar al usuario."}, + { + "role": "system", + "content": "Eres un bot de atención al cliente. Usá las herramientas para ayudar al usuario.", + }, {"role": "user", "content": "Hola, ¿me puedes decir cuándo llegará mi pedido #12345?"}, ], tools=[openai.pydantic_function_tool(GetDeliveryDate)], diff --git a/spanish/structured_outputs_nested.py b/spanish/structured_outputs_nested.py index 9f56bad..67f5889 100644 --- a/spanish/structured_outputs_nested.py +++ b/spanish/structured_outputs_nested.py @@ -49,7 +49,10 @@ class CalendarEvent(BaseModel): model=MODEL_NAME, messages=[ {"role": "system", "content": "Extrae la info del evento."}, - {"role": "user", "content": "Alice, que es carpintera, y Bob, que es plomero, van a ir a una feria de ciencias el viernes."}, + { + "role": "user", + "content": "Alice, que es carpintera, y Bob, que es plomero, van a ir a una feria de ciencias el viernes.", + }, ], response_format=CalendarEvent, )