From 8ead0829e4018578eb5e9fa65c5879e4dace2673 Mon Sep 17 00:00:00 2001 From: victorpolisetty <52013101+victorpolisetty@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:50:27 -0700 Subject: [PATCH 1/3] DALLE request mech tool --- packages/packages.json | 3 +- .../valory/customs/prepare_tx/component.yaml | 1 - packages/victorpolisetty/__init__.py | 19 +++++ .../customs/dalle_request/__init__.py | 19 +++++ .../customs/dalle_request/component.yaml | 18 ++++ .../customs/dalle_request/dalle_request.py | 84 +++++++++++++++++++ 6 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 packages/victorpolisetty/__init__.py create mode 100644 packages/victorpolisetty/customs/dalle_request/__init__.py create mode 100644 packages/victorpolisetty/customs/dalle_request/component.yaml create mode 100644 packages/victorpolisetty/customs/dalle_request/dalle_request.py diff --git a/packages/packages.json b/packages/packages.json index 47a469ef..dba8c1f5 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -15,7 +15,7 @@ "custom/napthaai/resolve_market_reasoning/0.1.0": "bafybeic43zq6xjkkc3o2gitxelr6v3nn6p2nctg6kf56tagrqvb6afxa6u", "custom/napthaai/prediction_request_rag/0.1.0": "bafybeie4z76wbnbvbsvborhrgeerbedtwxi3p2by7z3wyjhauwxwfgdaoa", "custom/napthaai/prediction_request_reasoning/0.1.0": "bafybeienoldwps2x4qwrpuah5aaxkvk7zqwzmyhyvyl7ktmiosbcpsuki4", - "custom/valory/prepare_tx/0.1.0": "bafybeidkghsricym5777edw3tvkuuzxkvmeai2r6phx43adfqwt3s5qwta", + "custom/valory/prepare_tx/0.1.0": "bafybeigo2yvfh63u6hdqufghng7flqesu76n7s5fchprndmjmdb3hqvyau", "custom/valory/short_maker/0.1.0": "bafybeif63rt4lkopu3rc3l7sg6tebrrwg2lxqufjx6dx4hoda5yzax43fa", "custom/napthaai/prediction_url_cot/0.1.0": "bafybeidu65l6abhfnxmeite6magzf6rqhmyyj427g3rtwms2oh5u5sc2eq", "custom/napthaai/prediction_url_cot_claude/0.1.0": "bafybeicbjywni5hx5ssoiv6tnnjbqzsck6cmtsdpr6m562z6afogz5eh44", @@ -23,6 +23,7 @@ "custom/napthaai/prediction_request_rag_claude/0.1.0": "bafybeickr32t7nmapuoymjyo3cf5rr2v2zapksxcivuqsgjr2gn6zo6y7y", "custom/napthaai/prediction_request_rag_cohere/0.1.0": "bafybeihh26kwgqkzojd4zastto5mgod7o7esll4f4icurvwumvwuzmosrm", "custom/valory/prediction_langchain/0.1.0": "bafybeihhii7veepp6ovkmqjnkp6euhkwm52obabgdltdj34ikisfd7yvqi", + "custom/victorpolisetty/dalle_request/0.1.0": "bafybeia6ks6hnjebnki23y7r426srvz4ab2d76z5o44wpdjhenxhkjl5ua", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", "protocol/valory/websocket_client/0.1.0": "bafybeifjk254sy65rna2k32kynzenutujwqndap2r222afvr3zezi27mx4", "contract/valory/agent_mech/0.1.0": "bafybeiah6b5epo2hlvzg5rr2cydgpp2waausoyrpnoarf7oa7bw33rex34", diff --git a/packages/valory/customs/prepare_tx/component.yaml b/packages/valory/customs/prepare_tx/component.yaml index 1c74cffb..35db89a4 100644 --- a/packages/valory/customs/prepare_tx/component.yaml +++ b/packages/valory/customs/prepare_tx/component.yaml @@ -8,7 +8,6 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeieynbsr6aijx2totfi5iw6thjwgzko526zcs5plgvgrq2lufso2sy prepare_tx.py: bafybeib7no24trithxrj5nwovwtezb3q3k32cpvo6mkaa2wynvqrpdwkxi - utils/agent/build_goal.py: bafybeif7kj2x362bhguey252op7bbaidcc7zarpgovqkgfiv5qqk7fizra fingerprint_ignore_patterns: [] entry_point: prepare_tx.py callable: run diff --git a/packages/victorpolisetty/__init__.py b/packages/victorpolisetty/__init__.py new file mode 100644 index 00000000..ba662b45 --- /dev/null +++ b/packages/victorpolisetty/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/packages/victorpolisetty/customs/dalle_request/__init__.py b/packages/victorpolisetty/customs/dalle_request/__init__.py new file mode 100644 index 00000000..ba662b45 --- /dev/null +++ b/packages/victorpolisetty/customs/dalle_request/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/packages/victorpolisetty/customs/dalle_request/component.yaml b/packages/victorpolisetty/customs/dalle_request/component.yaml new file mode 100644 index 00000000..8910480a --- /dev/null +++ b/packages/victorpolisetty/customs/dalle_request/component.yaml @@ -0,0 +1,18 @@ +name: dalle_request +author: victorpolisetty +version: 0.1.0 +type: custom +description: A tool that runs a prompt against the OpenAI DALL-E API. +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeicokooiqnmkldoi5tx6zv6svtjoak5ghj5o3vsi4iliq2pvqaa6uy + dalle_request.py: bafybeighmjmgrxkc65k2rh2nbclek3aorviuuye62gvtrmoocmrur475ri +fingerprint_ignore_patterns: [] +entry_point: dalle_request.py +callable: run +dependencies: + openai: + version: ==1.30.2 + tiktoken: + version: ==0.7.0 diff --git a/packages/victorpolisetty/customs/dalle_request/dalle_request.py b/packages/victorpolisetty/customs/dalle_request/dalle_request.py new file mode 100644 index 00000000..476360ec --- /dev/null +++ b/packages/victorpolisetty/customs/dalle_request/dalle_request.py @@ -0,0 +1,84 @@ +from typing import Any, Dict, Optional, Tuple +from openai import OpenAI +from tiktoken import encoding_for_model + +client: Optional[OpenAI] = None + +class OpenAIClientManager: + """Client context manager for OpenAI.""" + + def __init__(self, api_key: str): + self.api_key = api_key + + def __enter__(self) -> OpenAI: + global client + if client is None: + client = OpenAI(api_key=self.api_key) + return client + + def __exit__(self, exc_type, exc_value, traceback) -> None: + global client + if client is not None: + client.close() + client = None + +def count_tokens(text: str, model: str) -> int: + """Count the number of tokens in a text.""" + enc = encoding_for_model(model) + return len(enc.encode(text)) + + +DEFAULT_DALLE_SETTINGS = { + "size": "1024x1024", + "quality": "standard", + "n": 1, +} +PREFIX = "dall-e" +ENGINES = { + "text-to-image": ["-2", "-3"], +} +ALLOWED_TOOLS = [PREFIX + value for value in ENGINES["text-to-image"]] +ALLOWED_SIZE = ["1024x1024", "1024x1792", "1792x1024"] +ALLOWED_QUALITY = ["standard", "hd"] + + +# @with_key_rotation +def run(**kwargs) -> Tuple[Optional[str], Optional[Dict[str, Any]], Any, Any]: + """Run the task""" + with OpenAIClientManager(kwargs["api_keys"]["openai"]): + tool = kwargs["tool"] + prompt = kwargs["prompt"] + size = kwargs.get("size", DEFAULT_DALLE_SETTINGS["size"]) + quality = kwargs.get("quality", DEFAULT_DALLE_SETTINGS["quality"]) + n = kwargs.get("n", DEFAULT_DALLE_SETTINGS["n"]) + counter_callback = kwargs.get("counter_callback", None) + if tool not in ALLOWED_TOOLS: + return ( + f"Tool {tool} is not in the list of supported tools.", + None, + None, + None, + ) + if size not in ALLOWED_SIZE: + return ( + f"Size {size} is not in the list of supported sizes.", + None, + None, + None, + ) + if quality not in ALLOWED_QUALITY: + return ( + f"Quality {quality} is not in the list of supported qualities.", + None, + None, + None, + ) + + response = client.images.generate( + model=tool, + prompt=prompt, + size=size, + quality=quality, + n=n, + ) + return response.data[0].url, prompt, None, counter_callback \ No newline at end of file From 35ed92bc3200498ab662029c06ed3bf1d18e1eb4 Mon Sep 17 00:00:00 2001 From: victorpolisetty <52013101+victorpolisetty@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:30:20 -0700 Subject: [PATCH 2/3] add unit test and key rotation --- .../customs/dalle_request/dalle_request.py | 42 ++++++++++++++++++- tests/test_tools.py | 11 +++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/victorpolisetty/customs/dalle_request/dalle_request.py b/packages/victorpolisetty/customs/dalle_request/dalle_request.py index 476360ec..f316dfd7 100644 --- a/packages/victorpolisetty/customs/dalle_request/dalle_request.py +++ b/packages/victorpolisetty/customs/dalle_request/dalle_request.py @@ -1,8 +1,44 @@ -from typing import Any, Dict, Optional, Tuple +import functools +from typing import Any, Dict, Optional, Tuple, Callable from openai import OpenAI from tiktoken import encoding_for_model client: Optional[OpenAI] = None +MechResponse = Tuple[str, Optional[str], Optional[Dict[str, Any]], Any, Any] + + +def with_key_rotation(func: Callable): + @functools.wraps(func) + def wrapper(*args, **kwargs) -> MechResponse: + api_keys = kwargs["api_keys"] + retries_left: Dict[str, int] = api_keys.max_retries() + + def execute() -> MechResponse: + """Retry the function with a new key.""" + try: + result = func(*args, **kwargs) + # Ensure the result is a tuple and has the correct length + if isinstance(result, tuple) and len(result) == 4: + return result + (api_keys,) + else: + raise ValueError("Function did not return a valid MechResponse tuple.") + except openai.error.RateLimitError as e: + # try with a new key again + if retries_left["openai"] <= 0 and retries_left["openrouter"] <= 0: + raise e + retries_left["openai"] -= 1 + retries_left["openrouter"] -= 1 + api_keys.rotate("openai") + api_keys.rotate("openrouter") + return execute() + except Exception as e: + return str(e), "", None, None, api_keys + + mech_response = execute() + return mech_response + + return wrapper + class OpenAIClientManager: """Client context manager for OpenAI.""" @@ -22,6 +58,7 @@ def __exit__(self, exc_type, exc_value, traceback) -> None: client.close() client = None + def count_tokens(text: str, model: str) -> int: """Count the number of tokens in a text.""" enc = encoding_for_model(model) @@ -37,12 +74,13 @@ def count_tokens(text: str, model: str) -> int: ENGINES = { "text-to-image": ["-2", "-3"], } +ALLOWED_MODELS = [PREFIX] ALLOWED_TOOLS = [PREFIX + value for value in ENGINES["text-to-image"]] ALLOWED_SIZE = ["1024x1024", "1024x1792", "1792x1024"] ALLOWED_QUALITY = ["standard", "hd"] -# @with_key_rotation +@with_key_rotation def run(**kwargs) -> Tuple[Optional[str], Optional[Dict[str, Any]], Any, Any]: """Run the task""" with OpenAIClientManager(kwargs["api_keys"]["openai"]): diff --git a/tests/test_tools.py b/tests/test_tools.py index bb0c7882..c6171c97 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -20,6 +20,7 @@ from typing import List, Any from packages.gnosis.customs.omen_tools import omen_buy_sell +from packages.victorpolisetty.customs.dalle_request import dalle_request from packages.napthaai.customs.prediction_request_rag import prediction_request_rag from packages.napthaai.customs.prediction_request_rag_cohere import ( prediction_request_rag_cohere, @@ -175,3 +176,13 @@ def _validate_response(self, response: Any) -> None: super()._validate_response(response) expected_num_tx_params = 2 assert len(response[2].keys()) == expected_num_tx_params + +class TestDALLEGeneration(BaseToolTest): + """Test DALL-E Generation.""" + + tools = dalle_request.ALLOWED_TOOLS + models = dalle_request.ALLOWED_MODELS + prompts = [ + "Generate an image of a futuristic cityscape." + ] + tool_module = dalle_request \ No newline at end of file From 1f5d271f087713c4fd43d03eabaf5cf0866eb753 Mon Sep 17 00:00:00 2001 From: victorpolisetty <52013101+victorpolisetty@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:44:03 -0700 Subject: [PATCH 3/3] ran packages lock --- packages/gnosis/customs/omen_tools/component.yaml | 7 ++++--- packages/packages.json | 5 +---- packages/valory/services/mech/service.yaml | 2 +- .../victorpolisetty/customs/dalle_request/component.yaml | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/gnosis/customs/omen_tools/component.yaml b/packages/gnosis/customs/omen_tools/component.yaml index 0e362732..734ea8ab 100644 --- a/packages/gnosis/customs/omen_tools/component.yaml +++ b/packages/gnosis/customs/omen_tools/component.yaml @@ -2,12 +2,13 @@ name: omen_tools author: gnosis version: 0.1.0 type: custom -description: Collection of tools to prepare requests for interacting with prediction markets on Omen. +description: Collection of tools to prepare requests for interacting with prediction + markets on Omen. license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeibbn67pnrrm4qm3n3kbelvbs3v7fjlrjniywmw2vbizarippidtvi - prediction_sum_url_content.py: bafybeieywowx265yycgf5735bw4zyabfy6ivwnntl6smxa2hicktipgeby + omen_buy_sell.py: bafybeid3zaursxt2nkm2u7x7u4wlodg2ulzlieu5xxsfxjyxzi3vbcezdm fingerprint_ignore_patterns: [] entry_point: omen_buy_sell.py callable: run @@ -26,4 +27,4 @@ dependencies: langchain_community: version: ==0.2.1 openai: - version: ==1.30.2 \ No newline at end of file + version: ==1.30.2 diff --git a/packages/packages.json b/packages/packages.json index f89b9505..f90107ea 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -26,12 +26,9 @@ "custom/nickcom007/prediction_request_sme_lite/0.1.0": "bafybeidhuikn322h7oxgl5n2t5lvcl2dmv7cbmnes5tomabuucg6a42zkm", "custom/napthaai/prediction_request_reasoning_lite/0.1.0": "bafybeigxs5tq4w7ouamwlvv7vjw3z3jeercynsuka4mcpveshopvej4cyu", "custom/valory/prediction_langchain/0.1.0": "bafybeihhii7veepp6ovkmqjnkp6euhkwm52obabgdltdj34ikisfd7yvqi", -<<<<<<< HEAD - "custom/victorpolisetty/dalle_request/0.1.0": "bafybeia6ks6hnjebnki23y7r426srvz4ab2d76z5o44wpdjhenxhkjl5ua", -======= "custom/victorpolisetty/gemini_request/0.1.0": "bafybeig5x6b5jtanet2q5sk7er7fdzpippbvh4q5p7uxmxpriq66omjnaq", "custom/gnosis/omen_tools/0.1.0": "bafybeifxrawgu6m3dgsxvj7jrhxzr5gwi3zjk2m4gltkr5w3hxjjbla6nu", ->>>>>>> main + "custom/victorpolisetty/dalle_request/0.1.0": "bafybeicgjdvgamkgjebdrowrxdil3aghsbcm7epup6aqidikvjpmvomn6q", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", "protocol/valory/websocket_client/0.1.0": "bafybeifjk254sy65rna2k32kynzenutujwqndap2r222afvr3zezi27mx4", "contract/valory/agent_mech/0.1.0": "bafybeiah6b5epo2hlvzg5rr2cydgpp2waausoyrpnoarf7oa7bw33rex34", diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index 9020873e..ee3ddee3 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeid2hlmwtoze3xhhqqayisdg6xzxzgf42zw7hccdaszur7qfgp5vu4 +agent: valory/mech:0.1.0:bafybeih2oex4yt4mmiyarp2ivkqqfscoavyb7metchciiqmqdmv7lhyutq number_of_agents: 4 deployment: agent: diff --git a/packages/victorpolisetty/customs/dalle_request/component.yaml b/packages/victorpolisetty/customs/dalle_request/component.yaml index 8910480a..f2424cee 100644 --- a/packages/victorpolisetty/customs/dalle_request/component.yaml +++ b/packages/victorpolisetty/customs/dalle_request/component.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeicokooiqnmkldoi5tx6zv6svtjoak5ghj5o3vsi4iliq2pvqaa6uy - dalle_request.py: bafybeighmjmgrxkc65k2rh2nbclek3aorviuuye62gvtrmoocmrur475ri + dalle_request.py: bafybeicagzzicf7o6u6iotbvxfacdvntn5bpa4fptmst2iakjwaz7os2ry fingerprint_ignore_patterns: [] entry_point: dalle_request.py callable: run