From 846cf5578349c0cb49ae5491e4a81cf468a4f2b9 Mon Sep 17 00:00:00 2001 From: Ashpreet Bedi Date: Fri, 18 Oct 2024 15:04:27 +0100 Subject: [PATCH] v2.5.7 --- cookbook/agents/generate_image.py | 4 +- cookbook/agents/generate_video.py | 4 +- cookbook/playground/demo.py | 126 ++++++++++++++++++ .../playground/{serve_ollama.py => ollama.py} | 2 +- cookbook/playground/serve_8118.py | 73 ---------- cookbook/playground/{serve.py => test.py} | 12 +- phi/tools/dalle.py | 27 ++-- phi/tools/{video_gen.py => models_labs.py} | 38 +++--- phi/tools/sleep.py | 17 +++ pyproject.toml | 2 +- 10 files changed, 191 insertions(+), 114 deletions(-) create mode 100644 cookbook/playground/demo.py rename cookbook/playground/{serve_ollama.py => ollama.py} (97%) delete mode 100644 cookbook/playground/serve_8118.py rename cookbook/playground/{serve.py => test.py} (94%) rename phi/tools/{video_gen.py => models_labs.py} (68%) create mode 100644 phi/tools/sleep.py diff --git a/cookbook/agents/generate_image.py b/cookbook/agents/generate_image.py index 5e1e40adbf..bf1207c61a 100644 --- a/cookbook/agents/generate_image.py +++ b/cookbook/agents/generate_image.py @@ -1,10 +1,10 @@ from phi.agent import Agent from phi.model.openai import OpenAIChat -from phi.tools.dalle import DalleTools +from phi.tools.dalle import Dalle agent = Agent( model=OpenAIChat(id="gpt-4o"), - tools=[DalleTools()], + tools=[Dalle()], markdown=True, debug_mode=True, instructions=[ diff --git a/cookbook/agents/generate_video.py b/cookbook/agents/generate_video.py index b71f71e840..f047a75c5e 100644 --- a/cookbook/agents/generate_video.py +++ b/cookbook/agents/generate_video.py @@ -1,12 +1,12 @@ from phi.agent import Agent from phi.model.openai import OpenAIChat -from phi.tools.video_gen import VideoGenTools +from phi.tools.models_labs import ModelsLabs agent = Agent( name="Video Generation Agent", agent_id="video-generation-agent", model=OpenAIChat(id="gpt-4o"), - tools=[VideoGenTools()], + tools=[ModelsLabs()], markdown=True, debug_mode=True, show_tool_calls=True, diff --git a/cookbook/playground/demo.py b/cookbook/playground/demo.py new file mode 100644 index 0000000000..f8b68e2309 --- /dev/null +++ b/cookbook/playground/demo.py @@ -0,0 +1,126 @@ +"""Run `pip install openai sqlalchemy pypdf duckduckgo-search yfinance exa_py lancedb tantivy` to install dependencies.""" + +from textwrap import dedent +from datetime import datetime + +from phi.agent import Agent +from phi.knowledge.pdf import PDFUrlKnowledgeBase +from phi.model.openai import OpenAIChat +from phi.playground import Playground, serve_playground_app +from phi.storage.agent.sqlite import SqlAgentStorage +from phi.tools.dalle import Dalle +from phi.tools.duckduckgo import DuckDuckGo +from phi.tools.exa import ExaTools +from phi.tools.yfinance import YFinanceTools +from phi.vectordb.lancedb import LanceDb, SearchType + +lance_db_uri = "tmp/lancedb" +db_session_storage_file: str = "agents.db" + +web_agent = Agent( + name="Web Agent", + role="Search the web for information", + agent_id="web-agent", + model=OpenAIChat(id="gpt-4o"), + tools=[DuckDuckGo()], + instructions=["Break down the users request into 2-3 different searches.", "Always include sources"], + storage=SqlAgentStorage(table_name="web_agent", db_file=db_session_storage_file), + add_history_to_messages=True, + num_history_responses=5, + add_datetime_to_instructions=True, + markdown=True, +) + +finance_agent = Agent( + name="Finance Agent", + role="Get financial data", + agent_id="finance-agent", + model=OpenAIChat(id="gpt-4o"), + tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True, company_news=True)], + instructions=["Always use tables to display data"], + storage=SqlAgentStorage(table_name="finance_agent", db_file=db_session_storage_file), + add_history_to_messages=True, + num_history_responses=5, + add_datetime_to_instructions=True, + markdown=True, +) + +image_agent = Agent( + name="Image Agent", + role="Generate images given a prompt", + agent_id="image-agent", + model=OpenAIChat(id="gpt-4o"), + tools=[Dalle(model="dall-e-3", size="1792x1024", quality="hd", style="vivid")], + storage=SqlAgentStorage(table_name="image_agent", db_file=db_session_storage_file), + add_history_to_messages=True, + add_datetime_to_instructions=True, + markdown=True, +) + +research_agent = Agent( + name="Research Agent", + role="Write research reports for the New York Times", + agent_id="research-agent", + model=OpenAIChat(id="gpt-4o"), + tools=[ExaTools(start_published_date=datetime.now().strftime("%Y-%m-%d"), type="keyword")], + description=( + "You are a Research Agent that has the special skill of writing New York Times worthy articles. " + "If you can directly respond to the user, do so. If the user asks for a report or provides a topic, follow the instructions below." + ), + instructions=[ + "For the provided topic, run 3 different searches.", + "Read the results carefully and prepare a NYT worthy article.", + "Focus on facts and make sure to provide references.", + ], + expected_output=dedent("""\ + Your articles should be engaging, informative, well-structured and in markdown format. They should follow the following structure: + + ## Engaging Article Title + + ### Overview + {give a brief introduction of the article and why the user should read this report} + {make this section engaging and create a hook for the reader} + + ### Section 1 + {break the article into sections} + {provide details/facts/processes in this section} + + ... more sections as necessary... + + ### Takeaways + {provide key takeaways from the article} + + ### References + - [Reference 1](link) + - [Reference 2](link) + """), + storage=SqlAgentStorage(table_name="research_agent", db_file=db_session_storage_file), + add_history_to_messages=True, + add_datetime_to_instructions=True, + markdown=True, +) + +recipes_knowledge_base = PDFUrlKnowledgeBase( + urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], + vector_db=LanceDb(table_name="thai_recipes", uri=lance_db_uri, search_type=SearchType.vector), +) + +recipe_agent = Agent( + name="Thai Recipes Agent", + agent_id="thai-recipes-agent", + model=OpenAIChat(id="gpt-4o"), + description="You are an expert at Thai Recipes and have a knowledge base full of special Thai recipes.", + instructions=["Always search your knowledge base first for the recipe."], + knowledge=recipes_knowledge_base, + storage=SqlAgentStorage(table_name="thai_recipe_agent", db_file=db_session_storage_file), + add_history_to_messages=True, + add_datetime_to_instructions=True, + markdown=True, +) + +app = Playground(agents=[web_agent, finance_agent, image_agent, research_agent, recipe_agent]).get_app() + +if __name__ == "__main__": + # Load the knowledge base: Comment out after first run + recipes_knowledge_base.load(upsert=True) + serve_playground_app("demo:app", reload=True) diff --git a/cookbook/playground/serve_ollama.py b/cookbook/playground/ollama.py similarity index 97% rename from cookbook/playground/serve_ollama.py rename to cookbook/playground/ollama.py index b196a3b91d..243e3435d0 100644 --- a/cookbook/playground/serve_ollama.py +++ b/cookbook/playground/ollama.py @@ -70,4 +70,4 @@ app = Playground(agents=[finance_agent, research_agent]).get_app() if __name__ == "__main__": - serve_playground_app("serve_ollama:app", port=8118, reload=True) + serve_playground_app("ollama:app", port=8118, reload=True) diff --git a/cookbook/playground/serve_8118.py b/cookbook/playground/serve_8118.py deleted file mode 100644 index 2ff1f5a66f..0000000000 --- a/cookbook/playground/serve_8118.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Run `pip install yfinance exa_py` to install dependencies.""" - -from textwrap import dedent -from datetime import datetime - -from phi.agent import Agent -from phi.model.openai import OpenAIChat -from phi.tools.exa import ExaTools -from phi.tools.yfinance import YFinanceTools -from phi.storage.agent.postgres import PgAgentStorage -from phi.playground import Playground, serve_playground_app - -db_url: str = "postgresql+psycopg://ai:ai@localhost:5532/ai" - -finance_agent = Agent( - name="Finance Agent", - agent_id="finance-agent", - model=OpenAIChat(id="gpt-4o"), - tools=[YFinanceTools(enable_all=True)], - instructions=["Use tables where possible"], - show_tool_calls=True, - markdown=True, - debug_mode=True, - add_history_to_messages=True, - description="You are a finance agent", - add_datetime_to_instructions=True, - storage=PgAgentStorage(table_name="finance_agent_sessions_8118", db_url=db_url), -) - -research_agent = Agent( - name="Research Agent", - agent_id="research-agent", - model=OpenAIChat(id="gpt-4o"), - tools=[ExaTools(start_published_date=datetime.now().strftime("%Y-%m-%d"), type="keyword")], - description="You are a Research Agent writing an article for the New York Times.", - instructions=[ - "For the provided topic, run 3 different searches.", - "Read the results carefully and prepare a NYT worthy article.", - "Focus on facts and make sure to provide references.", - ], - expected_output=dedent("""\ - An engaging, informative, and well-structured article in markdown format: - - ## Engaging Article Title - - ### Overview - {give a brief introduction of the article and why the user should read this report} - {make this section engaging and create a hook for the reader} - - ### Section 1 - {break the article into sections} - {provide details/facts/processes in this section} - - ... more sections as necessary... - - ### Takeaways - {provide key takeaways from the article} - - ### References - - [Reference 1](link) - - [Reference 2](link) - """), - markdown=True, - debug_mode=True, - add_history_to_messages=True, - add_datetime_to_instructions=True, - storage=PgAgentStorage(table_name="research_agent_sessions_8118", db_url=db_url), -) - -app = Playground(agents=[finance_agent, research_agent]).get_app() - -if __name__ == "__main__": - serve_playground_app("serve_8118:app", port=8118, reload=True) diff --git a/cookbook/playground/serve.py b/cookbook/playground/test.py similarity index 94% rename from cookbook/playground/serve.py rename to cookbook/playground/test.py index c57f96e12d..b890b11db1 100644 --- a/cookbook/playground/serve.py +++ b/cookbook/playground/test.py @@ -1,4 +1,4 @@ -"""Run `pip install yfinance exa_py` to install dependencies.""" +"""Run `pip install openai yfinance exa_py` to install dependencies.""" from textwrap import dedent from datetime import datetime @@ -11,8 +11,8 @@ from phi.knowledge.pdf import PDFUrlKnowledgeBase from phi.vectordb.pgvector import PgVector, SearchType from phi.playground import Playground, serve_playground_app -from phi.tools.video_gen import VideoGenTools -from phi.tools.dalle import DalleTools +from phi.tools.models_labs import ModelsLabs +from phi.tools.dalle import Dalle db_url: str = "postgresql+psycopg://ai:ai@localhost:5532/ai" @@ -20,7 +20,7 @@ name="Video Gen Agent", agent_id="video-gen-agent", model=OpenAIChat(id="gpt-4o"), - tools=[VideoGenTools()], + tools=[ModelsLabs()], markdown=True, debug_mode=True, show_tool_calls=True, @@ -56,7 +56,7 @@ name="Dalle Agent", agent_id="dalle-agent", model=OpenAIChat(id="gpt-4o"), - tools=[DalleTools()], + tools=[Dalle()], markdown=True, debug_mode=True, ) @@ -129,4 +129,4 @@ if __name__ == "__main__": # Load the knowledge base: Comment out after first run # recipe_knowledge_base.load(upsert=True) - serve_playground_app("serve:app", reload=True) + serve_playground_app("test:app", reload=True) diff --git a/phi/tools/dalle.py b/phi/tools/dalle.py index 46add86189..c6cc3372c7 100644 --- a/phi/tools/dalle.py +++ b/phi/tools/dalle.py @@ -1,6 +1,7 @@ -from phi.tools import Toolkit -from typing import Optional from os import getenv +from typing import Optional, Literal + +from phi.tools import Toolkit from phi.utils.log import logger @@ -10,22 +11,23 @@ raise ImportError("`openai` not installed. Please install using `pip install openai`") -class DalleTools(Toolkit): +class Dalle(Toolkit): def __init__( self, model: str = "dall-e-3", - size: str = "1280x720", - quality: str = "standard", n: int = 1, + size: Optional[Literal["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"]] = "1024x1024", + quality: Literal["standard", "hd"] = "standard", + style: Literal["vivid", "natural"] = "vivid", api_key: Optional[str] = None, ): super().__init__(name="dalle") self.model = model + self.n = n self.size = size self.quality = quality - self.n = n - + self.style = style self.api_key = api_key or getenv("OPENAI_API_KEY") if not self.api_key: logger.error("OPENAI_API_KEY not set. Please set the OPENAI_API_KEY environment variable.") @@ -33,10 +35,10 @@ def __init__( self.register(self.generate_image) def generate_image(self, prompt: str) -> str: - """Use this function to generate an image using DALL-E. + """Use this function to generate an image given a prompt. Args: - prompt (str): The prompt to generate an image from. + prompt (str): A text description of the desired image. Returns: str: The URL of the generated image, or an error message. @@ -48,11 +50,12 @@ def generate_image(self, prompt: str) -> str: client = OpenAI(api_key=self.api_key) logger.info(f"Generating image for prompt: {prompt}") response = client.images.generate( - model=self.model, prompt=prompt, - size=self.size, # type: ignore - quality=self.quality, # type: ignore + model=self.model, n=self.n, + quality=self.quality, + size=self.size, + style=self.style, ) return response.data[0].url or "Error: No image URL returned" except Exception as e: diff --git a/phi/tools/video_gen.py b/phi/tools/models_labs.py similarity index 68% rename from phi/tools/video_gen.py rename to phi/tools/models_labs.py index b1b6fcd825..a54f461d23 100644 --- a/phi/tools/video_gen.py +++ b/phi/tools/models_labs.py @@ -1,34 +1,37 @@ +import json from os import getenv from typing import Optional +try: + import requests +except ImportError: + raise ImportError("`requests` not installed. Please install using `pip install requests`") + from phi.tools import Toolkit from phi.utils.log import logger -import requests -import json - -class VideoGenTools(Toolkit): +class ModelsLabs(Toolkit): def __init__( self, api_key: Optional[str] = None, url: str = "https://modelslab.com/api/v6/video/text2video", ): - super().__init__(name="video_gen") + super().__init__(name="models_labs") + + self.url = url self.api_key = api_key or getenv("MODELS_LAB_API_KEY") if not self.api_key: logger.error("MODELS_LAB_API_KEY not set. Please set the MODELS_LAB_API_KEY environment variable.") - self.url = url - self.register(self.generate_video) def generate_video(self, prompt: str) -> str: - """Use this function to generate a video using VideoGen. + """Use this function to generate a video given a prompt. Args: - prompt (str): The input text for video generation. + prompt (str): A text description of the desired video. Returns: str: The generated video information in JSON format. @@ -55,18 +58,19 @@ def generate_video(self, prompt: str) -> str: headers = {"Content-Type": "application/json"} - logger.info("Generating video with prompt: %s", prompt) + logger.info(f"Generating video for prompt: {prompt}") response = requests.request("POST", self.url, data=payload, headers=headers) - logger.info("response - %s", response.text) + logger.info(f"Response - {response.text}") response.raise_for_status() result = response.json() + if "error" in result: + logger.error(f"Failed to generate video: {result['error']}") + return f"Error: {result['error']}" + parsed_result = json.dumps(result, indent=4) - logger.info("Video generation request successful") + logger.info(f"Video generated successfully: {parsed_result}") return parsed_result - except requests.RequestException as e: - logger.error("Failed to generate video: %s", e) - return f"Error: {e}" - except json.JSONDecodeError as e: - logger.error("Failed to parse response: %s", e) + except Exception as e: + logger.error(f"Failed to generate video: {e}") return f"Error: {e}" diff --git a/phi/tools/sleep.py b/phi/tools/sleep.py new file mode 100644 index 0000000000..5c650a0e6b --- /dev/null +++ b/phi/tools/sleep.py @@ -0,0 +1,17 @@ +import time + +from phi.tools import Toolkit +from phi.utils.log import logger + + +class Sleep(Toolkit): + def __init__(self): + super().__init__(name="sleep") + + self.register(self.sleep) + + def sleep(self, seconds: int) -> None: + """Use this function to sleep for a given number of seconds.""" + logger.info(f"Sleeping for {seconds} seconds") + time.sleep(seconds) + logger.info(f"Awake after {seconds} seconds") diff --git a/pyproject.toml b/pyproject.toml index bd430f21b1..4d8b1ee245 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "phidata" -version = "2.5.6" +version = "2.5.7" description = "Build AI Agents with memory, knowledge and tools." requires-python = ">=3.7" readme = "README.md"