diff --git a/bot/bot.py b/bot/bot.py index 02b5d7b..25739cb 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -510,10 +510,24 @@ class Bot: if nip89content_str is not None: nip89content = json.loads(nip89content_str) info = "" + cashu_accepted = False + encryption_supported = False + if nip89content.get("name"): info += "Name: " + nip89content.get("name") + "\n" + if nip89content.get("image"): info += nip89content.get("image") + "\n" - info += "About:\n" + nip89content.get("about") + "\n" + if nip89content.get("about"): + info += "About:\n" + nip89content.get("about") + "\n\n" + if nip89content.get("acceptsCashu"): + cashu_accepted = str(nip89content.get("acceptsCashu")) + + if nip89content.get("encryptionSupported"): + encryption_supported = str(nip89content.get("encryptionSupported")) + + info += "Encryption supported: " + str(encryption_supported) + "\n" + info += "Cashu accepted: " + str(cashu_accepted) + "\n\n" + if nip89content.get("nip90Params"): params = nip89content["nip90Params"] info += "\nParameters:\n" for param in params: diff --git a/interfaces/dvmtaskinterface.py b/interfaces/dvmtaskinterface.py index 932074c..fb4dfa5 100644 --- a/interfaces/dvmtaskinterface.py +++ b/interfaces/dvmtaskinterface.py @@ -20,6 +20,7 @@ class DVMTaskInterface: PUBLIC_KEY: str DVM = DVM SUPPORTS_ENCRYPTION = True # DVMs build with this framework support encryption, but others might not. + ACCEPTS_CASHU = True # DVMs build with this framework support encryption, but others might not. dvm_config: DVMConfig admin_config: AdminConfig diff --git a/main.py b/main.py index 7264809..0adbcb4 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,9 @@ import json import os +from datetime import timedelta from pathlib import Path import dotenv -from nostr_sdk import PublicKey +from nostr_sdk import PublicKey, Options, Client, Keys from bot.bot import Bot from interfaces.dvmtaskinterface import DVMTaskInterface @@ -22,7 +23,8 @@ from utils.admin_utils import AdminConfig from utils.backend_utils import keep_alive from utils.definitions import EventDefinitions from utils.dvmconfig import DVMConfig -from utils.nip89_utils import NIP89Config, check_and_set_d_tag +from utils.external_dvm_utils import build_external_dvm +from utils.nip89_utils import NIP89Config, check_and_set_d_tag, nip89_fetch_events_pubkey from utils.nostr_utils import check_and_set_private_key from utils.output_utils import PostProcessFunctionType @@ -102,6 +104,8 @@ def playground(): "name": name, "image": "https://image.nostr.build/229c14e440895da30de77b3ca145d66d4b04efb4027ba3c44ca147eecde891f1.jpg", "about": "I draw images based on a prompt in the style of paper sketches", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } @@ -151,31 +155,13 @@ def playground(): #Let's define a function so we can add external DVMs to our bot, we will instanciate it afterwards - def build_external_dvm(name, pubkey, task, kind, fix_cost, per_unit_cost, - external_post_process=PostProcessFunctionType.NONE): - dvm_config = DVMConfig() - dvm_config.PUBLIC_KEY = PublicKey.from_hex(pubkey).to_hex() - dvm_config.FIX_COST = fix_cost - dvm_config.PER_UNIT_COST = per_unit_cost - dvm_config.EXTERNAL_POST_PROCESS_TYPE = external_post_process - nip89info = { - "name": name, - } - nip89config = NIP89Config() - nip89config.KIND = kind - nip89config.CONTENT = json.dumps(nip89info) - - interface = DVMTaskInterface(name=name, dvm_config=dvm_config, nip89config=nip89config, task=task) - - return interface # Spawn DVM7.. oh wait, actually we don't spawn a new DVM, we use the dvmtaskinterface to define an external dvm by providing some info about it, such as # their pubkey, a name, task, kind etc. (unencrypted) - tasktiger_external = build_external_dvm(name="External DVM: TaskTiger", - pubkey="d483935d6bfcef3645195c04c97bbb70aedb6e65665c5ea83e562ca3c7acb978", + tasktiger_external = build_external_dvm(pubkey="d483935d6bfcef3645195c04c97bbb70aedb6e65665c5ea83e562ca3c7acb978", task="text-to-image", kind=EventDefinitions.KIND_NIP90_GENERATE_IMAGE, - fix_cost=80, per_unit_cost=0) + fix_cost=80, per_unit_cost=0, config=bot_config) tasktiger_external.SUPPORTS_ENCRYPTION = False # if the dvm does not support encrypted events, just send a regular NIP90 event and mark it with p tag. Other dvms might answer initally bot_config.SUPPORTED_DVMS.append(tasktiger_external) @@ -187,12 +173,11 @@ def playground(): media_bringer.run() # DVM: 9 Another external dvm for recommendations: - ymhm_external = build_external_dvm(name="External DVM: You might have missed", - pubkey="6b37d5dc88c1cbd32d75b713f6d4c2f7766276f51c9337af9d32c8d715cc1b93", + ymhm_external = build_external_dvm(pubkey="6b37d5dc88c1cbd32d75b713f6d4c2f7766276f51c9337af9d32c8d715cc1b93", task="content-discovery", kind=EventDefinitions.KIND_NIP90_CONTENT_DISCOVERY, fix_cost=0, per_unit_cost=0, - external_post_process=PostProcessFunctionType.LIST_TO_EVENTS) + external_post_process=PostProcessFunctionType.LIST_TO_EVENTS, config=bot_config) # If we get back a list of people or events, we can post-process it to make it readable in social clients ymhm_external.SUPPORTS_ENCRYPTION = False diff --git a/tasks/advanced_search.py b/tasks/advanced_search.py index 3bfc9a8..8f7cb2c 100644 --- a/tasks/advanced_search.py +++ b/tasks/advanced_search.py @@ -168,6 +168,8 @@ def build_example(name, identifier, admin_config): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I search notes", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } @@ -193,7 +195,7 @@ if __name__ == '__main__': admin_config.UPDATE_PROFILE = False admin_config.LUD16 = "" - dvm = build_example("advanced_search", "discovery_content_search", admin_config) + dvm = build_example("Advanced Nostr Search", "discovery_content_search", admin_config) dvm.run() keep_alive() diff --git a/tasks/convert_media.py b/tasks/convert_media.py index 29c6544..8933bd9 100644 --- a/tasks/convert_media.py +++ b/tasks/convert_media.py @@ -100,6 +100,8 @@ def build_example(name, identifier, admin_config): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I convert videos from urls to given output format.", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } diff --git a/tasks/discovery_inactive_follows.py b/tasks/discovery_inactive_follows.py index 34092a5..bc7c9af 100644 --- a/tasks/discovery_inactive_follows.py +++ b/tasks/discovery_inactive_follows.py @@ -194,6 +194,8 @@ def build_example(name, identifier, admin_config): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I discover users you follow, but that have been inactive on Nostr", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } diff --git a/tasks/imagegeneration_openai_dalle.py b/tasks/imagegeneration_openai_dalle.py index db680f9..6017060 100644 --- a/tasks/imagegeneration_openai_dalle.py +++ b/tasks/imagegeneration_openai_dalle.py @@ -144,6 +144,8 @@ def build_example(name, identifier, admin_config): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I use OpenAI's DALLĀ·E 3", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } diff --git a/tasks/imagegeneration_sdxl.py b/tasks/imagegeneration_sdxl.py index 834ace7..c7eeaef 100644 --- a/tasks/imagegeneration_sdxl.py +++ b/tasks/imagegeneration_sdxl.py @@ -190,6 +190,8 @@ def build_example(name, identifier, admin_config, server_address, default_model= "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I draw images based on a prompt with a Model called unstable diffusion", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } nip89config = NIP89Config() diff --git a/tasks/imagegeneration_sdxlimg2img.py b/tasks/imagegeneration_sdxlimg2img.py index 8a13741..3ff416b 100644 --- a/tasks/imagegeneration_sdxlimg2img.py +++ b/tasks/imagegeneration_sdxlimg2img.py @@ -219,6 +219,8 @@ def build_example(name, identifier, admin_config, server_address, default_lora=" "name": name, "image": "https://image.nostr.build/229c14e440895da30de77b3ca145d66d4b04efb4027ba3c44ca147eecde891f1.jpg", "about": "I convert an image to another image, kinda random for now. ", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } diff --git a/tasks/textextraction_google.py b/tasks/textextraction_google.py index 5dc09ae..c48d786 100644 --- a/tasks/textextraction_google.py +++ b/tasks/textextraction_google.py @@ -150,6 +150,8 @@ def build_example(name, identifier, admin_config): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I extract text from media files with the Google API. I understand English by default", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } nip89config = NIP89Config() diff --git a/tasks/textextraction_pdf.py b/tasks/textextraction_pdf.py index f2e2878..4a5ad0b 100644 --- a/tasks/textextraction_pdf.py +++ b/tasks/textextraction_pdf.py @@ -104,6 +104,8 @@ def build_example(name, identifier, admin_config): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I extract text from pdf documents. I only support Latin letters", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } diff --git a/tasks/textextraction_whisperx.py b/tasks/textextraction_whisperx.py index f98f927..cbf53fa 100644 --- a/tasks/textextraction_whisperx.py +++ b/tasks/textextraction_whisperx.py @@ -175,6 +175,8 @@ def build_example(name, identifier, admin_config, server_address): "name": name, "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I extract text from media files with WhisperX", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } nip89config = NIP89Config() diff --git a/tasks/translation_google.py b/tasks/translation_google.py index 3a5b026..b0fa412 100644 --- a/tasks/translation_google.py +++ b/tasks/translation_google.py @@ -133,6 +133,8 @@ def build_example(name, identifier, admin_config): "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I translate text from given text/event/job. Currently using Google TranslationGoogle Services to translate " "input into the language defined in params.", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } nip89config = NIP89Config() diff --git a/tasks/translation_libretranslate.py b/tasks/translation_libretranslate.py index dd100fa..ee070fa 100644 --- a/tasks/translation_libretranslate.py +++ b/tasks/translation_libretranslate.py @@ -132,6 +132,8 @@ def build_example(name, identifier, admin_config): "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", "about": "I translate text from given text/event/job using LibreTranslate Services to translate " "input into the language defined in params.", + "encryptionSupported": True, + "cashuAccepted": True, "nip90Params": nip90params } nip89config = NIP89Config() diff --git a/utils/backend_utils.py b/utils/backend_utils.py index 8897c56..ce220eb 100644 --- a/utils/backend_utils.py +++ b/utils/backend_utils.py @@ -194,4 +194,6 @@ def keep_alive(): time.sleep(10) except KeyboardInterrupt: os.kill(os.getpid(), signal.SIGKILL) - exit(1) \ No newline at end of file + exit(1) + + diff --git a/utils/external_dvm_utils.py b/utils/external_dvm_utils.py new file mode 100644 index 0000000..c6e61ac --- /dev/null +++ b/utils/external_dvm_utils.py @@ -0,0 +1,68 @@ +import json +from datetime import timedelta + +from nostr_sdk import PublicKey, Options, Keys, Client + +from interfaces.dvmtaskinterface import DVMTaskInterface +from utils.dvmconfig import DVMConfig +from utils.nip89_utils import NIP89Config, nip89_fetch_events_pubkey +from utils.output_utils import PostProcessFunctionType + + +def build_external_dvm(pubkey, task, kind, fix_cost, per_unit_cost, config, + external_post_process=PostProcessFunctionType.NONE): + dvm_config = DVMConfig() + dvm_config.PUBLIC_KEY = PublicKey.from_hex(pubkey).to_hex() + dvm_config.FIX_COST = fix_cost + dvm_config.PER_UNIT_COST = per_unit_cost + dvm_config.EXTERNAL_POST_PROCESS_TYPE = external_post_process + + opts = (Options().wait_for_send(True).send_timeout(timedelta(seconds=config.RELAY_TIMEOUT)) + .skip_disconnected_relays(True)) + keys = Keys.from_sk_str(config.PRIVATE_KEY) + client = Client.with_opts(keys, opts) + + for relay in config.RELAY_LIST: + client.add_relay(relay) + client.connect() + + nip89content_str = nip89_fetch_events_pubkey(client, pubkey, kind) + name = "External DVM" + image = "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg" + about = "An External DVM with no info" + nip90params = {} + encryption_supported = False + cashu_accepted = False + print(nip89content_str) + if nip89content_str is not None: + nip89content = json.loads(nip89content_str) + if nip89content.get("name"): + name = nip89content.get("name") + if nip89content.get("image"): + image = nip89content.get("image") + if nip89content.get("about"): + about = nip89content.get("about") + if nip89content.get("nip90Params"): + nip90params = nip89content["nip90Params"] + if nip89content.get("encryptionSupported"): + encryption_supported = nip89content["encryptionSupported"] + if nip89content.get("cashuAccepted"): + cashu_accepted = nip89content["cashuAccepted"] + + nip89info = { + "name": name, + "image": image, + "about": about, + "encryptionSupported": encryption_supported, + "cashuAccepted": cashu_accepted, + "nip90Params": nip90params + } + nip89config = NIP89Config() + nip89config.KIND = kind + nip89config.CONTENT = json.dumps(nip89info) + + interface = DVMTaskInterface(name=name, dvm_config=dvm_config, nip89config=nip89config, task=task) + interface.SUPPORTS_ENCRYPTION = encryption_supported + interface.ACCEPTS_CASHU = cashu_accepted + + return interface \ No newline at end of file