From 18e585b9e06b77063157fbf06df891735b19bd16 Mon Sep 17 00:00:00 2001 From: Cole Medin <47287758+coleam00@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:14:49 -0500 Subject: [PATCH] Initial commit --- .gitattributes | 2 + 1-first-agent/.env.example | 20 +++++ 1-first-agent/agents.py | 144 +++++++++++++++++++++++++++++++++ 1-first-agent/requirements.txt | 3 + LICENSE | 21 +++++ README.md | 80 ++++++++++++++++++ 6 files changed, 270 insertions(+) create mode 100644 .gitattributes create mode 100644 1-first-agent/.env.example create mode 100644 1-first-agent/agents.py create mode 100644 1-first-agent/requirements.txt create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/1-first-agent/.env.example b/1-first-agent/.env.example new file mode 100644 index 0000000..1be90a0 --- /dev/null +++ b/1-first-agent/.env.example @@ -0,0 +1,20 @@ +# Rename this file to .env once you have filled in the below environment variables! + +# Get your Open AI API Key by following these instructions - +https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key +OPENAI_API_KEY= + +# See all Open AI models you can use here - +# https://platform.openai.com/docs/models +# A good default to go with here is gpt-4o +OPENAI_MODEL= + +# Get your personal Asana access token through the developer console in Asana. +# Feel free to follow these instructions - +# https://developers.asana.com/docs/personal-access-token +ASANA_ACCESS_TOKEN= + +# The Asana project ID is in the URL when you visit a project in the Asana UI. +# If your URL is https://app.asana.com/0/123456789/1212121212, then your +# Asana project ID is 123456789 +ASANA_PROJECT_ID= \ No newline at end of file diff --git a/1-first-agent/agents.py b/1-first-agent/agents.py new file mode 100644 index 0000000..05b74e9 --- /dev/null +++ b/1-first-agent/agents.py @@ -0,0 +1,144 @@ +import asana +from asana.rest import ApiException +from openai import OpenAI +from dotenv import load_dotenv +from datetime import datetime +import json +import os + +load_dotenv() + +client = OpenAI() +model = os.getenv('OPENAI_MODEL', 'gpt-4o') + +configuration = asana.Configuration() +configuration.access_token = os.getenv('ASANA_ACCESS_TOKEN', '') +api_client = asana.ApiClient(configuration) + +tasks_api_instance = asana.TasksApi(api_client) + +def create_asana_task(task_name, due_on="today"): + """ + Creates a task in Asana given the name of the task and when it is due + + Example call: + + create_asana_task("Test Task", "2024-06-24") + Args: + task_name (str): The name of the task in Asana + due_on (str): The date the task is due in the format YYYY-MM-DD. If not given, the current day is used + Returns: + str: The API response of adding the task to Asana or an error message if the API call threw an error + """ + if due_on == "today": + due_on = str(datetime.now().date()) + + task_body = { + "data": { + "name": task_name, + "due_on": due_on, + "projects": [os.getenv("ASANA_PROJECT_ID", "")] + } + } + + try: + api_response = tasks_api_instance.create_task(task_body, {}) + return json.dumps(api_response, indent=2) + except ApiException as e: + return f"Exception when calling TasksApi->create_task: {e}" + +def get_tools(): + tools = [ + { + "type": "function", + "function": { + "name": "create_asana_task", + "description": "Creates a task in Asana given the name of the task and when it is due", + "parameters": { + "type": "object", + "properties": { + "task_name": { + "type": "string", + "description": "The name of the task in Asana" + }, + "due_on": { + "type": "string", + "description": "The date the task is due in the format YYYY-MM-DD. If not given, the current day is used" + }, + }, + "required": ["task_name"] + }, + }, + } + ] + + return tools + +def prompt_ai(messages): + # First, prompt the AI with the latest user message + completion = client.chat.completions.create( + model=model, + messages=messages, + tools=get_tools() + ) + + response_message = completion.choices[0].message + tool_calls = response_message.tool_calls + + # Second, see if the AI decided it needs to invoke a tool + if tool_calls: + # If the AI decided to invoke a tool, invoke it + available_functions = { + "create_asana_task": create_asana_task + } + + # Add the tool request to the list of messages so the AI knows later it invoked the tool + messages.append(response_message) + + # Next, for each tool the AI wanted to call, call it and add the tool result to the list of messages + for tool_call in tool_calls: + function_name = tool_call.function.name + function_to_call = available_functions[function_name] + function_args = json.loads(tool_call.function.arguments) + function_response = function_to_call(**function_args) + + messages.append({ + "tool_call_id": tool_call.id, + "role": "tool", + "name": function_name, + "content": function_response + }) + + # Call the AI again so it can produce a response with the result of calling the tool(s) + second_response = client.chat.completions.create( + model=model, + messages=messages, + ) + + return second_response.choices[0].message.content + + return response_message.content + +def main(): + messages = [ + { + "role": "system", + "content": f"You are a personal assistant who helps manage tasks in Asana. The current date is: {datetime.now().date()}" + } + ] + + while True: + user_input = input("Chat with AI (q to quit): ").strip() + + if user_input == 'q': + break + + messages.append({"role": "user", "content": user_input}) + ai_response = prompt_ai(messages) + + print(ai_response) + messages.append({"role": "assistant", "content": ai_response}) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/1-first-agent/requirements.txt b/1-first-agent/requirements.txt new file mode 100644 index 0000000..bf0a03c --- /dev/null +++ b/1-first-agent/requirements.txt @@ -0,0 +1,3 @@ +asana==5.0.0 +openai==1.10.0 +python-dotenv==0.13.0 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b05a952 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Cole Medin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..54388b7 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +
+ ++ Artificial Intelligence is the #1 thing for all developers to spend their time on now. + The problem is, most developers aren't focusing on AI agents, which is the real way to unleash the full power of AI. + This is why I'm creating this AI Agents Masterclass - so I can show YOU how to use AI agents to transform + businesses and create incredibly powerful software like I've already done many times! + Click the image or link above to go to the masterclass on YouTube. +
+ ++ What are AI Agents? · + How this Repo Works · + Instructions to Follow Along +
+
+