summaryrefslogtreecommitdiff
path: root/examples/pydantic-models-to-grammar-examples.py
diff options
context:
space:
mode:
authorMaximilian Winter <maximilian.winter.91@gmail.com>2024-01-12 20:46:45 +0100
committerGitHub <noreply@github.com>2024-01-12 21:46:45 +0200
commit52ee4540c0f2e11d52c839db6eb51d014ce060e1 (patch)
treeae5ed429efc613cd6e875fa5f13d41eef41808e4 /examples/pydantic-models-to-grammar-examples.py
parent3fe81781e3bf98b8e44946240a19f3a6ad08a11a (diff)
examples : add pydantic models to GBNF grammar generator (#4883)
* Create pydantic-models-to-grammar.py * Added some comments for usage * Refactored Grammar Generator Added example and usage instruction. * Update pydantic_models_to_grammar.py * Update pydantic-models-to-grammar-examples.py * Renamed module and imported it. * Update pydantic-models-to-grammar.py * Renamed file and fixed grammar generator issue.
Diffstat (limited to 'examples/pydantic-models-to-grammar-examples.py')
-rw-r--r--examples/pydantic-models-to-grammar-examples.py136
1 files changed, 136 insertions, 0 deletions
diff --git a/examples/pydantic-models-to-grammar-examples.py b/examples/pydantic-models-to-grammar-examples.py
new file mode 100644
index 00000000..a8a4919c
--- /dev/null
+++ b/examples/pydantic-models-to-grammar-examples.py
@@ -0,0 +1,136 @@
+# Function calling example using pydantic models.
+
+import json
+from enum import Enum
+from typing import Union, Optional
+
+import requests
+from pydantic import BaseModel, Field
+
+import importlib
+from pydantic_models_to_grammar import generate_gbnf_grammar_and_documentation
+
+# Function to get completion on the llama.cpp server with grammar.
+def create_completion(prompt, grammar):
+ headers = {"Content-Type": "application/json"}
+ data = {"prompt": prompt, "grammar": grammar}
+
+ response = requests.post("http://127.0.0.1:8080/completion", headers=headers, json=data)
+ data = response.json()
+
+ print(data["content"])
+ return data["content"]
+
+
+# A function for the agent to send a message to the user.
+class SendMessageToUser(BaseModel):
+ """
+ Send a message to the User.
+ """
+ chain_of_thought: str = Field(..., description="Your chain of thought while sending the message.")
+ message: str = Field(..., description="Message you want to send to the user.")
+
+ def run(self):
+ print(self.message)
+
+
+# Enum for the calculator function.
+class MathOperation(Enum):
+ ADD = "add"
+ SUBTRACT = "subtract"
+ MULTIPLY = "multiply"
+ DIVIDE = "divide"
+
+
+# Very simple calculator tool for the agent.
+class Calculator(BaseModel):
+ """
+ Perform a math operation on two numbers.
+ """
+ number_one: Union[int, float] = Field(..., description="First number.")
+ operation: MathOperation = Field(..., description="Math operation to perform.")
+ number_two: Union[int, float] = Field(..., description="Second number.")
+
+ def run(self):
+ if self.operation == MathOperation.ADD:
+ return self.number_one + self.number_two
+ elif self.operation == MathOperation.SUBTRACT:
+ return self.number_one - self.number_two
+ elif self.operation == MathOperation.MULTIPLY:
+ return self.number_one * self.number_two
+ elif self.operation == MathOperation.DIVIDE:
+ return self.number_one / self.number_two
+ else:
+ raise ValueError("Unknown operation.")
+
+
+# Here the grammar gets generated by passing the available function models to generate_gbnf_grammar_and_documentation function. This also generates a documentation usable by the LLM.
+# pydantic_model_list is the list of pydanitc models
+# outer_object_name is an optional name for an outer object around the actual model object. Like a "function" object with "function_parameters" which contains the actual model object. If None, no outer object will be generated
+# outer_object_content is the name of outer object content.
+# model_prefix is the optional prefix for models in the documentation. (Default="Output Model")
+# fields_prefix is the prefix for the model fields in the documentation. (Default="Output Fields")
+gbnf_grammar, documentation = generate_gbnf_grammar_and_documentation(
+ pydantic_model_list=[SendMessageToUser, Calculator], outer_object_name="function",
+ outer_object_content="function_parameters", model_prefix="Function", fields_prefix="Parameters")
+
+print(gbnf_grammar)
+print(documentation)
+
+system_message = "You are an advanced AI, tasked to assist the user by calling functions in JSON format. The following are the available functions and their parameters and types:\n\n" + documentation
+
+user_message = "What is 42 * 42?"
+prompt = f"<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{user_message}<|im_end|>\n<|im_start|>assistant"
+
+text = create_completion(prompt=prompt, grammar=gbnf_grammar)
+# This should output something like this:
+# {
+# "function": "calculator",
+# "function_parameters": {
+# "number_one": 42,
+# "operation": "multiply",
+# "number_two": 42
+# }
+# }
+function_dictionary = json.loads(text)
+if function_dictionary["function"] == "calculator":
+ function_parameters = {**function_dictionary["function_parameters"]}
+
+ print(Calculator(**function_parameters).run())
+ # This should output: 1764
+
+
+# A example structured output based on pydantic models. The LLM will create an entry for a Book database out of an unstructured text.
+class Category(Enum):
+ """
+ The category of the book.
+ """
+ Fiction = "Fiction"
+ NonFiction = "Non-Fiction"
+
+
+class Book(BaseModel):
+ """
+ Represents an entry about a book.
+ """
+ title: str = Field(..., description="Title of the book.")
+ author: str = Field(..., description="Author of the book.")
+ published_year: Optional[int] = Field(..., description="Publishing year of the book.")
+ keywords: list[str] = Field(..., description="A list of keywords.")
+ category: Category = Field(..., description="Category of the book.")
+ summary: str = Field(..., description="Summary of the book.")
+
+
+# We need no additional parameters other than our list of pydantic models.
+gbnf_grammar, documentation = generate_gbnf_grammar_and_documentation([Book])
+
+system_message = "You are an advanced AI, tasked to create a dataset entry in JSON for a Book. The following is the expected output model:\n\n" + documentation
+
+text = """The Feynman Lectures on Physics is a physics textbook based on some lectures by Richard Feynman, a Nobel laureate who has sometimes been called "The Great Explainer". The lectures were presented before undergraduate students at the California Institute of Technology (Caltech), during 1961–1963. The book's co-authors are Feynman, Robert B. Leighton, and Matthew Sands."""
+prompt = f"<|im_start|>system\n{system_message}<|im_end|>\n<|im_start|>user\n{text}<|im_end|>\n<|im_start|>assistant"
+
+text = create_completion(prompt=prompt, grammar=gbnf_grammar)
+
+json_data = json.loads(text)
+
+print(Book(**json_data))