diff --git a/openai_agent_example.py b/openai_agent_example.py index 52415d2..22c8f78 100644 --- a/openai_agent_example.py +++ b/openai_agent_example.py @@ -3,20 +3,20 @@ Written in 2024 by retoor@molodetz.nl. MIT license. Enjoy! -Purpose of this file is to be a native part of your application -instead of the nth-library. It's just not worth a library. -Especially not another one. Just modify and use it! +The purpose of this file is to be a native part of your application +instead of yet another library. It's just not worth making a library, +especially not another one. Just modify and use it! The docstrings of all methods contain tips and important facts. -This document contains all URL's for all services that you need. +This document contains all URLs for all services that you need. You'll need: - - OpenAI account. - - Named a project in OpenAI dashboard. - - Requested an api key and created an assistant. + - An OpenAI account. + - A named project in the OpenAI dashboard. + - A requested API key and an assistant created. -URL's to all these services are described in the class for convenience. -It can be hard to find initially. +URLs to all these services are described in the class for convenience. +They can be hard to find initially. The API keys described in this document are fake but are in the correct format for educational purposes. @@ -24,14 +24,14 @@ How to start: - sudo apt install python3.12-venv python3-pip -y - python3 -m venv .venv - . .venv/bin/activate - - pip install openapi + - pip install openai """ -# AGAIN. NOT REAL DATA, ONLY LOOKS THAT WAY FOR EDUCATIVE PURPOSES. -# Not required to use the Agent class. Agent class accepts api_key as parameter. +# AGAIN, NOT REAL DATA, ONLY LOOKS LIKE IT FOR EDUCATIONAL PURPOSES. +# Not required to use the Agent class. The Agent class accepts api_key as a parameter. API_KEY = "sk-proj-V1Jc3my22xSvtfZ3dxXNHgLWZIhEopmJVIMlcNrft_q-7p8dDT_-AQCE8wo9cKpO3v05egDm7CT3BlbkFjN21maiSZqS4oz8FSGiblOeKMH2i6BzIGdQWMcVbKHnRqWy0KiSwKQywJ7XEf792UgGFtwLtxkA" -# Not required to use the Agent class. Agent class accepts assistant_id as parameter. +# Not required to use the Agent class. The Agent class accepts assistant_id as a parameter. ASSISTANT_ID = "asst_NgncvKEN8CTf642RE8a4PgAp" @@ -45,13 +45,13 @@ from openai import OpenAI class Agent: """ - This class translates into an instance a single user session with its own memory. + This class represents a single user session with its own memory. The messages property of this class is a list containing the full chat history about - what the user said and what the assistant (agent) said. This can be used in future to continue - where you left off. Format is described in the docs of __init__ function below. + what the user said and what the assistant (agent) said. This can be used in the future to continue + where you left off. The format is described in the docs of the __init__ function below. - Introduction API usage for if you want to extend this class: + Introduction to API usage if you want to extend this class: https://platform.openai.com/docs/api-reference/introduction """ @@ -62,10 +62,10 @@ class Agent: You can find and create API keys here: https://platform.openai.com/api-keys - You can find assistant_id (agent_id) here. It is the id that starts with 'asst_', not your custom name: + You can find the assistant_id (agent_id) here. It is the ID that starts with 'asst_', not your custom name: https://platform.openai.com/assistants/ - Messages are optional in this format, this is to keep a message history that you can later use again: + Messages are optional and should be in this format to keep a message history that you can later use again: [ {"role": "user", "message": "What is choking the chicken?"}, {"role": "assistant", "message": "Lucky for the cock."} @@ -82,8 +82,8 @@ class Agent: self, prompt: str, width: Optional[int] = 512, height: Optional[int] = 512 ) -> dict: """ - In my opinion dall-e-2 produces unusual results. - Sizes: 256x256, 512x512 or 1024x1024. + In my opinion, DALL·E 2 produces unusual results. + Sizes: 256x256, 512x512, or 1024x1024. """ result = self.client.images.generate( model="dall-e-2", prompt=prompt, n=1, size=f"{width}x{height}" @@ -94,8 +94,8 @@ class Agent: async def models(self): """ List models in dict format. That's more convenient than the original - list method because this can be directly converted to json to be used - in your front end or api. That's not the original result which is a + list method because this can be directly converted to JSON to be used + in your frontend or API. This is not the original result, which is a custom list with unserializable models. """ return [ @@ -112,7 +112,7 @@ class Agent: self, prompt: str, height: Optional[int] = 1024, width: Optional[int] = 1024 ) -> dict: """ - Sadly only big sizes allowed. Is more pricy. + Sadly, only large sizes are allowed. It's more expensive. Sizes: 1024x1024, 1792x1024, or 1024x1792. """ result = self.client.images.generate( @@ -125,8 +125,8 @@ class Agent: self, message: str, interval: Optional[float] = 0.2 ) -> Generator[None, None, str]: """ - Chat with the agent. It yields on given interval to inform the caller it' still busy so you can - update the user with live status. It doesn't hang. You can use this fully async with other + Chat with the agent. It yields at the given interval to inform the caller it's still busy, so you can + update the user with a live status. It doesn't hang. You can use this fully asynchronously with other instances of this class. This function also updates the self.messages list with chat history for later use. @@ -158,7 +158,7 @@ class Agent: async def chatp(self, message: str) -> str: """ - Just like regular chat function but with progress indication and returns string directly. + Just like the regular chat function but with progress indication and returns a string directly. This is handy for interactive usage or for a process log. """ asyncio.get_event_loop() @@ -173,8 +173,8 @@ class Agent: async def read_line(self, ps: Optional[str] = "> "): """ - Non blocking read_line. - Blocking read line can break web socket connections. + Non-blocking read_line. + Blocking read_line can break WebSocket connections. That's why. """ loop = asyncio.get_event_loop() @@ -183,9 +183,9 @@ class Agent: async def cli(self): """ - Interactive client. Can be used on terminal by user or a different process. - The bottom new line is so that a process can check for \n\n to check if it's end response - and there's nothing left to wait for and thus can send next prompt if the '>' shows. + Interactive client. Can be used in a terminal by the user or a different process. + The bottom newline is so that a process can check for '\n\n' to determine if the response has ended + and there's nothing left to wait for, allowing the process to send the next prompt if the '>' shows. """ while True: try: @@ -196,24 +196,24 @@ class Agent: print(response.content[0].text.value) print("") except KeyboardInterrupt: - print("Exiting..") + print("Exiting...") break async def main(): """ Example main function. The keys here are not real but look exactly like - the real ones for example purposes and that you're sure your key is in the - right format. + the real ones for example purposes so you can verify your key is in the + correct format. """ agent = Agent(api_key=API_KEY, assistant_id=ASSISTANT_ID) - # Generate an image. Use dalle3, dalle2 is almost unusable. For image sizes look at the class method docstring. - list_containing_dicts_with_url_to_images = await agent.dalle3("Make photo realistic image of a rust dev") + # Generate an image. Use DALL·E 3, as DALL·E 2 is almost unusable. For image sizes, look at the class method docstring. + list_containing_dicts_with_url_to_images = await agent.dalle3("Make a photo-realistic image of a Rust developer") # Run interactive chat await agent.cli() if __name__ == "__main__": - # Only gets executed by direct execution of script. Not when imported. + # Only executed by direct execution of the script, not when imported. asyncio.run(main())