From b27c97348dc2b159c7f0cbc1d62c5559649552c6 Mon Sep 17 00:00:00 2001 From: Dirk Brand <51947788+dirkbrnd@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:49:08 +0200 Subject: [PATCH] Add giphy tool [PHI-2206] (#1565) ## Description This adds the GiphyTools and examples of how to search gifs as an agent. ## Type of change Please check the options that are relevant: - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Model update - [ ] Infrastructure change ## Checklist - [x] My code follows Phidata's style guidelines and best practices - [x] I have performed a self-review of my code - [x] I have added docstrings and comments for complex logic - [x] My changes generate no new warnings or errors - [x] I have added cookbook examples for my new addition (if needed) - [x] I have updated requirements.txt/pyproject.toml (if needed) - [x] I have verified my changes in a clean environment --------- Co-authored-by: Dirk Brand --- .gitignore | 2 + cookbook/playground/multimodal_agent.py | 19 ++++++- cookbook/tools/giphy_tool.py | 19 +++++++ phi/model/content.py | 1 + phi/tools/giphy.py | 71 +++++++++++++++++++++++++ phi/tools/google.py | 19 ------- 6 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 cookbook/tools/giphy_tool.py create mode 100644 phi/tools/giphy.py delete mode 100644 phi/tools/google.py diff --git a/.gitignore b/.gitignore index 4f5471ad0a..8e1e1380d6 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ agents.db data.db .ipynb_checkpoints + +*.db diff --git a/cookbook/playground/multimodal_agent.py b/cookbook/playground/multimodal_agent.py index 25f0405684..d9e8996d79 100644 --- a/cookbook/playground/multimodal_agent.py +++ b/cookbook/playground/multimodal_agent.py @@ -9,6 +9,7 @@ from phi.agent import Agent from phi.model.openai import OpenAIChat from phi.tools.dalle import Dalle +from phi.tools.giphy import GiphyTools from phi.tools.models_labs import ModelsLabs from phi.model.response import FileType from phi.playground import Playground, serve_playground_app @@ -85,8 +86,24 @@ storage=SqlAgentStorage(table_name="fal_agent", db_file=image_agent_storage_file), ) +gif_agent = Agent( + name="Gif Generator Agent", + model=OpenAIChat(id="gpt-4o"), + tools=[GiphyTools()], + description="You are an AI agent that can generate gifs using Giphy.", + instructions=[ + "When the user asks you to create a gif, come up with the appropriate Giphy query and use the `search_gifs` tool to find the appropriate gif.", + "Don't return the URL, only describe what you created.", + ], + markdown=True, + debug_mode=True, + add_history_to_messages=True, + add_datetime_to_instructions=True, + storage=SqlAgentStorage(table_name="gif_agent", db_file=image_agent_storage_file), +) + -app = Playground(agents=[image_agent, ml_gif_agent, ml_video_agent, fal_agent]).get_app(use_async=False) +app = Playground(agents=[image_agent, ml_gif_agent, ml_video_agent, fal_agent, gif_agent]).get_app(use_async=False) if __name__ == "__main__": serve_playground_app("multimodal_agent:app", reload=True) diff --git a/cookbook/tools/giphy_tool.py b/cookbook/tools/giphy_tool.py new file mode 100644 index 0000000000..b3a07b3156 --- /dev/null +++ b/cookbook/tools/giphy_tool.py @@ -0,0 +1,19 @@ +from phi.agent import Agent +from phi.model.openai import OpenAIChat +from phi.tools.giphy import GiphyTools + +"""Create an agent specialized in creating gifs using Giphy """ + +gif_agent = Agent( + name="Gif Generator Agent", + model=OpenAIChat(id="gpt-4o"), + tools=[GiphyTools(limit=5)], + description="You are an AI agent that can generate gifs using Giphy.", + instructions=[ + "When the user asks you to create a gif, come up with the appropriate Giphy query and use the `search_gifs` tool to find the appropriate gif.", + ], + debug_mode=True, + show_tool_calls=True, +) + +gif_agent.print_response("I want a gif to send to a friend for their birthday.") diff --git a/phi/model/content.py b/phi/model/content.py index 65a50650ec..529e90fef0 100644 --- a/phi/model/content.py +++ b/phi/model/content.py @@ -14,5 +14,6 @@ class Video(BaseModel): class Image(BaseModel): id: str url: str + alt_text: Optional[str] = None original_prompt: Optional[str] = None revised_prompt: Optional[str] = None diff --git a/phi/tools/giphy.py b/phi/tools/giphy.py new file mode 100644 index 0000000000..00c41067bf --- /dev/null +++ b/phi/tools/giphy.py @@ -0,0 +1,71 @@ +import os +import uuid +from typing import Optional + +import httpx + +from phi.agent import Agent +from phi.model.content import Image +from phi.tools import Toolkit +from phi.utils.log import logger + + +class GiphyTools(Toolkit): + def __init__( + self, + api_key: Optional[str] = None, + limit: int = 1, + ): + super().__init__(name="giphy_tools") + + self.api_key = api_key or os.getenv("GIPHY_API_KEY") + if not self.api_key: + logger.error("No Giphy API key provided") + + self.limit: int = limit + + self.register(self.search_gifs) + + def search_gifs(self, agent: Agent, query: str) -> str: + """Find a GIPHY gif + + Args: + query (str): A text description of the required gif. + + Returns: + result (str): A string containing urls of GIFs found + """ + + base_url = "https://api.giphy.com/v1/gifs/search" + params = { + "api_key": self.api_key, + "q": query, + "limit": self.limit, + } + + try: + response = httpx.get(base_url, params=params) + response.raise_for_status() + + # Extract the GIF URLs + data = response.json() + gif_urls = [] + for gif in data.get("data", []): + images = gif.get("images", {}) + original_image = images["original"] + + media_id = str(uuid.uuid4()) + gif_url = original_image["url"] + alt_text = gif["alt_text"] + gif_urls.append(gif_url) + + agent.add_image(Image(id=media_id, url=gif_url, alt_text=alt_text, revised_prompt=query)) + + return f"These are the found gifs {gif_urls}" + + except httpx.HTTPStatusError as e: + logger.error(f"HTTP error occurred: {e.response.status_code} - {e.response.text}") + except Exception as e: + logger.error(f"An error occurred: {e}") + + return "No gifs found" diff --git a/phi/tools/google.py b/phi/tools/google.py deleted file mode 100644 index 4e112f2c25..0000000000 --- a/phi/tools/google.py +++ /dev/null @@ -1,19 +0,0 @@ -from phi.tools import Toolkit -from phi.utils.log import logger - - -class GoogleTools(Toolkit): - def __init__(self): - super().__init__(name="google_tools") - - self.register(self.get_result_from_google) - - def get_result_from_google(self, query: str) -> str: - """Gets the result for a query from Google. - Use this function to find an answer when not available in the knowledge base. - - :param query: The query to search for. - :return: The result from Google. - """ - logger.info(f"Searching google for: {query}") - return "Sorry, this capability is not available yet."