diff --git a/README.md b/README.md index 147ea9b..197d32f 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ history = addUserMessage(history,"Generate MATLAB code that computes that"); ### Calling MATLAB functions with the API The optional parameter `functions` can be used to provide function specifications to the API. The purpose of this is to enable models to generate function arguments which adhere to the provided specifications. -Note that the API is not able to directly call any function, so you should call the function and pass the values to the API directly. This process can be automated as shown in [ExampleFunctionCalling.m](/examples/ExampleFunctionCalling.m), but it's important to consider that ChatGPT can hallucinate function names, so avoid executing any arbitrary generated functions and only allow the execution of functions that you have defined. +Note that the API is not able to directly call any function, so you should call the function and pass the values to the API directly. This process can be automated as shown in [ExampleFunctionCalling.mlx](/examples/ExampleFunctionCalling.mlx), but it's important to consider that ChatGPT can hallucinate function names, so avoid executing any arbitrary generated functions and only allow the execution of functions that you have defined. For example, if you want to use the API for mathematical operations such as `sind`, instead of letting the model generate the result and risk running into hallucinations, you can give the model direct access to the function as follows: @@ -237,9 +237,9 @@ You can extract the arguments and write the data to a table, for example. ## Examples To learn how to use this in your workflows, see [Examples](/examples/). -- [ExampleSummarization.m](/examples/ExampleSummarization.m): Learn to create concise summaries of long texts with ChatGPT. (Requires Text Analytics Toolbox™) -- [ExampleChatBot.m](/examples/ExampleChatBot.m): Build a conversational chatbot capable of handling various dialogue scenarios using ChatGPT. (Requires Text Analytics Toolbox) -- [ExampleFunctionCalling.m](/examples/ExampleFunctionCalling.m): Learn how to create agents capable of executing MATLAB functions. +- [ExampleSummarization.mlx](/examples/ExampleSummarization.mlx): Learn to create concise summaries of long texts with ChatGPT. (Requires Text Analytics Toolbox™) +- [ExampleChatBot.mlx](/examples/ExampleChatBot.mlx): Build a conversational chatbot capable of handling various dialogue scenarios using ChatGPT. (Requires Text Analytics Toolbox) +- [ExampleFunctionCalling.mlx](/examples/ExampleFunctionCalling.mlx): Learn how to create agents capable of executing MATLAB functions. ## License diff --git a/examples/ExampleChatBot.m b/examples/ExampleChatBot.m deleted file mode 100644 index 425f3a3..0000000 --- a/examples/ExampleChatBot.m +++ /dev/null @@ -1,74 +0,0 @@ -%% Creating a Chatbot -% This script orchestrates a chat interaction with the OpenAI Chat Completions API, taking user -% inputs, maintaining a word count, and ensuring the chat remains within a -% predefined word limit. -% -% Running this example will start an interactive ChatBot in your terminal and it can be ended -% by pressing Ctrl+C or typing "end". - -% Set the maximum allowable number of words per chat session -wordLimit = 2000; - -% Define the keyword that, when entered by the user, ends the chat session -stopWord = "end"; - -modelName = "gpt-3.5-turbo"; -chat = openAIChat("You are a helpful assistant.", ModelName=modelName); - -messages = openAIMessages; - -query = ""; -totalWords = 0; -messagesSizes = []; - -% Main loop: continues indefinitely until the user inputs the stop word -while true - % Prompt the user for input and convert it to a string - query = input("User: ", "s"); - query = string(query); - - % If the user inputs the stop word, display a farewell message and exit the loop - if query == stopWord - disp("AI: Closing the chat. Have a great day!") - break; - end - - - numWordsQuery = countNumWords(query); - - % If the query exceeds the word limit, display an error message and halt execution - if numWordsQuery>wordLimit - error("Your query should have less than 2000 words. You query had " + numWordsQuery + " words") - end - - % Keep track of the size of each message and the total number of words used so far - messagesSizes = [messagesSizes; numWordsQuery]; %#ok - totalWords = totalWords + numWordsQuery; - - % If the total word count exceeds the limit, remove messages from the start of the session until it no longer does - while totalWords > wordLimit - totalWords = totalWords - messagesSizes(1); - messages = removeMessage(messages, 1); - messagesSizes(1) = []; - end - - % Add the user's message to the session and generate a response using the OpenAI API - messages = addUserMessage(messages, query); - [text, response] = generate(chat, messages); - - disp("AI: " + text) - - % Count the number of words in the AI's response and update the total word count - numWordsResponse = countNumWords(text); - messagesSizes = [messagesSizes; numWordsResponse]; %#ok - totalWords = totalWords + numWordsResponse; - - % Add the AI's response to the session - messages = addResponseMessage(messages, response); -end - -%% countNumWords function -% Function to count the number of words in a text string -function numWords = countNumWords(text) - numWords = doclength(tokenizedDocument(text)); -end \ No newline at end of file diff --git a/examples/ExampleChatBot.mlx b/examples/ExampleChatBot.mlx new file mode 100644 index 0000000..68d56b9 Binary files /dev/null and b/examples/ExampleChatBot.mlx differ diff --git a/examples/ExampleFunctionCalling.m b/examples/ExampleFunctionCalling.m deleted file mode 100644 index 3da0029..0000000 --- a/examples/ExampleFunctionCalling.m +++ /dev/null @@ -1,108 +0,0 @@ -%% Using ChatGPT with function calls -% This script automatically analyzes recent scientific papers from the -% ArXiv API, filtering papers based on the topic and using ChatGPT -% functions feature to extract relevant information on the papers. - -%% Initialize OpenAI API Function and Chat -% Set up the function to store paper details and initiate a chat with the OpenAI API -% with a defined role as a scientific paper expert. - -% Define the function that you want the model to have access to. The -% function is defined at the end of the example. -f = openAIFunction("writePaperDetails", "Function to write paper details to a table."); -f = addParameter(f, "name", type="string", description="Name of the paper."); -f = addParameter(f, "url", type="string", description="URL containing the paper."); -f = addParameter(f, "explanation", type="string", description="Explanation on why the paper is related to the given topic."); - -chat = openAIChat("You are an expert in filtering scientific papers. " + ... - "Given a certain topic, you are able to decide if the paper" + ... - " fits the given topic or not.", Functions=f); - -%% Query ArXiv API for Recent Papers -% Specify the category of interest, the date range for the query, and the maximum -% number of results to retrieve from the ArXiv API. - -category = "cs.CL"; -endDate = datetime("today", "Format","uuuuMMdd"); -startDate = datetime("today", "Format","uuuuMMdd") - 5; -maxResults = 40; -urlQuery = "https://export.arxiv.org/api/query?search_query=" + ... - "cat:" + category + ... - "&submittedDate=["+string(startDate)+"+TO+"+string(endDate)+"]"+... - "&max_results=" + maxResults + ... - "&sortBy=submittedDate&sortOrder=descending"; - -options = weboptions('Timeout',160); -code = webread(urlQuery,options); - -%% Extract Paper Entries and Filter by Topic -% Extract individual paper entries from the API response and use ChatGPT -% to determine whether each paper is related to the specified topic. - -% ChatGPT will parse the XML file, so we only need to extract the relevant -% entries. -entries = extractBetween(code, '', ''); - -% Determine the topic of interest -topic = "Embedding documents or sentences"; - -% Loop over the entries and see if they are relevant to the topic of -% interest. -for i = 1:length(entries) - prompt = "Given the following paper:" + newline +... - string(entries{i})+ newline +... - "Is it related to the topic: "+ topic +"?" + ... - " Answer 'yes' or 'no'."; - [text, response] = generate(chat, prompt); - - % If the model classifies this entry as relevant, then it tries to - % request a function call. - if contains("yes", text, IgnoreCase=true) - prompt = "Given the following paper:" + newline + string(entries{i})+ newline +... - "Given the topic: "+ topic + newline + "Write the details to a table."; - [text, response] = generate(chat, prompt); - - % If function_call if part of the response, it means the model is - % requesting a function call. The function call request should - % contain the needed arguments to call the function specified at - % the end of this example and defined with openAIFunctions - if isfield(response, "function_call") - funCall = response.function_call; - functionCallAttempt(funCall); - end - end -end - -%% Function to Handle Function Call Attempts -% This function handles function call attempts from the model, checking -% the function name and arguments before calling the appropriate function to -% store the paper details. - -function functionCallAttempt(funCall) -% The model can sometimes hallucinate function names, so you need to ensure -% that it's suggesting the correct name. -if funCall.name == "writePaperDetails" - try - % The model can sometimes return improperly formed JSON, which - % needs to be handled - funArgs = jsondecode(funCall.arguments); - catch ME - error("Model returned improperly formed JSON."); - end - % The model can hallucinate arguments. The code needs to ensure the - % arguments have been defined before calling the function. - if isfield(funArgs, "name") && isfield(funArgs, "url") && isfield(funArgs,"explanation") - writePaperDetails(string(funArgs.name), string(funArgs.url), string(funArgs.explanation)); - end -end -end - -%% Function to Write Paper Details to CSV File -% This function takes the details of a scientific paper and writes them to -% a CSV file for further review. - -function writePaperDetails(name, url, desc) -filename = "papers_to_read.csv"; -T = table(name, url, desc, VariableNames=["Name", "URL", "Description"]); -writetable(T, filename, WriteMode="append"); -end \ No newline at end of file diff --git a/examples/ExampleFunctionCalling.mlx b/examples/ExampleFunctionCalling.mlx new file mode 100644 index 0000000..ee82aa0 Binary files /dev/null and b/examples/ExampleFunctionCalling.mlx differ diff --git a/examples/ExampleSummarization.m b/examples/ExampleSummarization.m deleted file mode 100644 index 847596c..0000000 --- a/examples/ExampleSummarization.m +++ /dev/null @@ -1,96 +0,0 @@ -%% Summarization using ChatGPT -% This script leverages ChatGPT to summarize texts of different lengths. - -%% Summarizing small documents -% In this part of the script, a ChatGPT session is initialized to summarize a short -% piece of text extracted from a webpage hosted by MathWorks. - -% Initiating a ChatGPT session with the role defined as a professional summarizer -chat = openAIChat("You are a professional summarizer, create a summary of the provided text, be it an article," + ... - " post, conversation, or passage."); - -url = "https://www.mathworks.com/help/textanalytics"; -code = webread(url); -shortText = extractHTMLText(string(code)); - -% Utilizing ChatGPT to create a summary of the extracted text -shortTextSummary = generate(chat, shortText) - -%% Summarizing large documents -% This section of the script demonstrates how to incrementally summarize a large text -% by breaking it into smaller chunks and summarizing each chunk step by -% step. It uses as input text Alice's Adventures in Wonderland by -% Lewis Carroll from Project Gutenberg. - -options = weboptions(Timeout=30); -code = webread("https://www.gutenberg.org/files/11/11-h/11-h.htm", options); -longText = extractHTMLText(string(code)); - -incrementalSummary = longText; - -% Define the number of words in each chunk -limitChunkWords = 2000; - -% Creating initial divisions of the text into chunks -chunks = createChunks(incrementalSummary, limitChunkWords); - -% Initiating a ChatGPT session with the role of summarizing text -summarizer = openAIChat("You are a professional summarizer."); - -% Looping process to gradually summarize the text chunk by chunk, reducing -% the chunk size with each iteration. -numCalls = 0; -while numel(chunks)>1 - summarizedChunks = strings(size(chunks)); - numCalls = numCalls + numel(chunks); - % Add a limit to the number of calls, to ensure you are not making - % more calls than what is expected. You can change this value to match - % what is needed for your application. - if numCalls > 20 - error("Document is too long to be summarized.") - end - - for i = 1:length(chunks) - summarizedChunks(i) = generate(summarizer, "Summarize this content:" + newline + chunks(i)); - end - - % Merging the summarized chunks to serve as the base for the next iteration - incrementalSummary = join(summarizedChunks); - - % Forming new chunks with a reduced size for the subsequent iteration - chunks = createChunks(incrementalSummary, limitChunkWords); -end - -% Compiling the final summary by combining the summaries from all the chunks -fullSummary = generate(summarizer, "Combine these summaries:" + newline + incrementalSummary) - -%% CreateChunks function -% This function segments a long text into smaller parts of a predefined size -% to facilitate easier summarization. It preserves the structure of -% sentences. The chunkSize should be large enough to fit at least one -% sentence. - -function chunks = createChunks(text, chunkSize) - % Tokenizing the input text for processing - text = tokenizedDocument(text); - - % Splitting the tokenized text into individual sentences - text = splitSentences(text); - chunks = []; - currentChunk = ""; - currentChunkSize = 0; - - % Iterating through the sentences to aggregate them into chunks until the chunk - % attains the predefined size, after which a new chunk is started - for i=1:length(text) - newChunkSize = currentChunkSize + doclength(text(i)); - if newChunkSize < chunkSize - currentChunkSize = currentChunkSize + doclength(text(i)); - currentChunk = currentChunk + " " + joinWords(text(i)); - else - chunks = [chunks; currentChunk]; %#ok - currentChunkSize = doclength(text(i)); - currentChunk = joinWords(text(i)); - end - end -end \ No newline at end of file diff --git a/examples/ExampleSummarization.mlx b/examples/ExampleSummarization.mlx new file mode 100644 index 0000000..0f56748 Binary files /dev/null and b/examples/ExampleSummarization.mlx differ