From 808bc6e35c03f84c71bb736167d270aa8ca855ba Mon Sep 17 00:00:00 2001 From: Romamo Date: Tue, 3 Dec 2024 21:12:27 +0200 Subject: [PATCH 1/2] Added apicaller tool --- cookbook/tools/apicaller_tools.py | 19 ++++++++++++ phi/tools/apicaller.py | 48 +++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 cookbook/tools/apicaller_tools.py create mode 100644 phi/tools/apicaller.py diff --git a/cookbook/tools/apicaller_tools.py b/cookbook/tools/apicaller_tools.py new file mode 100644 index 0000000000..9a80c2c462 --- /dev/null +++ b/cookbook/tools/apicaller_tools.py @@ -0,0 +1,19 @@ +from phi.agent import Agent +from phi.tools.apicaller import ApiCaller + +# Use any OpenAPI spec file +OPENAPI_SPEC = 'https://petstore3.swagger.io/api/v3/openapi.json' +# Generate swagger client and copy the client package to the current directory +CLIENT_PACKAGE = 'swagger_client' +agent = Agent(tools=[ApiCaller(CLIENT_PACKAGE, OPENAPI_SPEC, + generate_swagger=True, + configuration={'host': 'https://petstore3.swagger.io/api/v3'})], show_tool_calls=True) +agent.print_response("Get pet id 1", markdown=True) + +# # Use any OpenAPI spec file +# OPENAPI_SPEC = 'https://raw.githubusercontent.com/sonallux/spotify-web-api/refs/heads/main/official-spotify-open-api.yml' +# # Generate swagger client and copy the client package to the current directory +# CLIENT_PACKAGE = 'swagger_client' +# +# agent = Agent(tools=[ApiCaller(CLIENT_PACKAGE, OPENAPI_SPEC, path='spotify_swagger')], show_tool_calls=True, debug_mode=True) +# agent.print_response("make me a playlist with the first song from kind of blue. call it machine blues.", markdown=True) diff --git a/phi/tools/apicaller.py b/phi/tools/apicaller.py new file mode 100644 index 0000000000..fef0569fcd --- /dev/null +++ b/phi/tools/apicaller.py @@ -0,0 +1,48 @@ +import json + +from pydantic.alias_generators import to_snake + +from phi.tools import Toolkit, Function + +try: + from apicaller import SwaggerCaller +except ImportError as e: + raise ImportError("`apicaller` not installed. Please install using `pip install six urllib3 pyapicaller`") + +def to_dict(obj): + if isinstance(obj, list): + return [to_dict(item) for item in obj] + if hasattr(obj, 'to_dict'): + return obj.to_dict() + return obj + +class ApiCaller(Toolkit): + def __init__( + self, + swagger_client: str, + openapi: str, + path: str = 'swagger_clients', + configuration: dict = None, + generate_swagger = False + ): + super().__init__(name="apicaller") + self._caller = SwaggerCaller(swagger_client, openapi, path=path, configuration=configuration) + if generate_swagger: + self._caller.generate() + self.register_all() + + + def register_all(self): + def create_callable(function_name): + def api_function(**kwargs): + parameters = {to_snake(k): v for k, v in kwargs['parameters'].items()} if kwargs else {} + response = self._caller.call_api(function_name, **parameters) + return json.dumps(to_dict(response)) + return api_function + + for f_dict in self._caller.get_tools(): + f = Function(name=f_dict['function']['name'], + description=f_dict['function']['description'], + parameters=f_dict['function']['parameters'], + entrypoint=create_callable(f_dict['function']['name'])) + self.functions[f.name] = f From bf19b630096de739ef7d3b9c1e04c4c6fac9022f Mon Sep 17 00:00:00 2001 From: Romamo Date: Thu, 5 Dec 2024 09:39:59 +0200 Subject: [PATCH 2/2] Added apicaller small explanation --- cookbook/tools/apicaller_tools.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/cookbook/tools/apicaller_tools.py b/cookbook/tools/apicaller_tools.py index 9a80c2c462..082578bdf8 100644 --- a/cookbook/tools/apicaller_tools.py +++ b/cookbook/tools/apicaller_tools.py @@ -1,19 +1,39 @@ from phi.agent import Agent from phi.tools.apicaller import ApiCaller +""" +Use ApiCaller to generate functions from an OpenAPI spec and call APIs directly. + +Prerequisites: +1. OpenAPI spec in JSON/YAML format (URL or local file path). +2. Swagger client for indirect API calls (optional): + a. Set generate_swagger=True to auto-generate using generator3.swagger.io and save it to `swagger_clients` folder. + b. Or, manually generate via editor.swagger.io and copy the swagger_client package to `swagger_clients` folder. +""" + +# Petstore example # Use any OpenAPI spec file OPENAPI_SPEC = 'https://petstore3.swagger.io/api/v3/openapi.json' # Generate swagger client and copy the client package to the current directory CLIENT_PACKAGE = 'swagger_client' agent = Agent(tools=[ApiCaller(CLIENT_PACKAGE, OPENAPI_SPEC, generate_swagger=True, - configuration={'host': 'https://petstore3.swagger.io/api/v3'})], show_tool_calls=True) + configuration={'host': 'https://petstore3.swagger.io/api/v3'})], + show_tool_calls=True) agent.print_response("Get pet id 1", markdown=True) +# Spotify example + # # Use any OpenAPI spec file # OPENAPI_SPEC = 'https://raw.githubusercontent.com/sonallux/spotify-web-api/refs/heads/main/official-spotify-open-api.yml' # # Generate swagger client and copy the client package to the current directory # CLIENT_PACKAGE = 'swagger_client' -# -# agent = Agent(tools=[ApiCaller(CLIENT_PACKAGE, OPENAPI_SPEC, path='spotify_swagger')], show_tool_calls=True, debug_mode=True) +# Sptofy access token +# ACCESS_TOKEN = 'ACCESS_TOKEN' +#swagger_caller = SwaggerCaller(CLIENT_PACKAGE, OPENAPI_SPEC, configuration={'access_token': ACCESS_TOKEN}) + +# agent = Agent(tools=[ApiCaller(CLIENT_PACKAGE, OPENAPI_SPEC, +# generate_swagger=True, +# configuration={'access_token': ACCESS_TOKEN}], +# show_tool_calls=True, debug_mode=True) # agent.print_response("make me a playlist with the first song from kind of blue. call it machine blues.", markdown=True)