diff --git a/examples/ollama_dvm/test_client.py b/examples/ollama_dvm/test_client.py index 331745d..ab9a8c5 100644 --- a/examples/ollama_dvm/test_client.py +++ b/examples/ollama_dvm/test_client.py @@ -1,17 +1,19 @@ +import asyncio import json import time from pathlib import Path from threading import Thread import dotenv -from nostr_sdk import Keys, Client, NostrSigner, Tag, EventBuilder, Filter, HandleNotification, Timestamp, nip04_decrypt +from nostr_sdk import Keys, Client, NostrSigner, Tag, EventBuilder, Filter, HandleNotification, Timestamp, \ + nip04_decrypt, Event from nostr_dvm.utils.dvmconfig import DVMConfig from nostr_dvm.utils.nostr_utils import send_event, check_and_set_private_key from nostr_dvm.utils.definitions import EventDefinitions -def nostr_client_test_llm(prompt): +async def nostr_client_test_llm(prompt): keys = Keys.parse(check_and_set_private_key("test_client")) iTag = Tag.parse(["i", prompt, "text"]) @@ -28,13 +30,13 @@ def nostr_client_test_llm(prompt): client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client(): +async def nostr_client(): keys = Keys.parse(check_and_set_private_key("test_client")) sk = keys.secret_key() pk = keys.public_key() @@ -42,28 +44,28 @@ def nostr_client(): client = Client(keys) dvmconfig = DVMConfig() for relay in dvmconfig.RELAY_LIST: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() dm_zap_filter = Filter().pubkey(pk).kinds([EventDefinitions.KIND_DM, EventDefinitions.KIND_ZAP]).since( Timestamp.now()) # events to us specific dvm_filter = (Filter().kinds([EventDefinitions.KIND_NIP90_RESULT_GENERATE_TEXT, EventDefinitions.KIND_FEEDBACK]).since(Timestamp.now())) # public events - client.subscribe([dm_zap_filter, dvm_filter]) + await client.subscribe([dm_zap_filter, dvm_filter]) - nostr_client_test_llm("Tell me a joke about a purple Ostrich!") + await nostr_client_test_llm("Tell me a joke about a purple Ostrich!") print("Sending Job Request") #nostr_client_test_image_private("a beautiful ostrich watching the sunset") class NotificationHandler(HandleNotification): - def handle(self, relay_url, event): + def handle(self, relay_url, subscription_id, event: Event): print(f"Received new event from {relay_url}: {event.as_json()}") if event.kind() == 7000: print("[Nostr Client]: " + event.as_json()) - elif 6000 < event.kind() < 6999: + elif 6000 < event.kind().as_u64() < 6999: print("[Nostr Client]: " + event.as_json()) print("[Nostr Client]: " + event.content()) @@ -75,12 +77,12 @@ def nostr_client(): print("[Nostr Client]: " + f"Received new zap:") print(event.as_json()) - def handle_msg(self, relay_url, msg): + async def handle_msg(self, relay_url, msg): return - client.handle_notifications(NotificationHandler()) + asyncio.create_task(client.handle_notifications(NotificationHandler())) while True: - time.sleep(5.0) + await asyncio.sleep(5.0) if __name__ == '__main__': @@ -92,5 +94,5 @@ if __name__ == '__main__': else: raise FileNotFoundError(f'.env file not found at {env_path} ') - nostr_dvm_thread = Thread(target=nostr_client()) - nostr_dvm_thread.start() + asyncio.run(nostr_client()) + diff --git a/examples/tts_dvm/test_client.py b/examples/tts_dvm/test_client.py index a12a3a5..9133237 100644 --- a/examples/tts_dvm/test_client.py +++ b/examples/tts_dvm/test_client.py @@ -1,3 +1,4 @@ +import asyncio import json import time from pathlib import Path @@ -5,7 +6,7 @@ from threading import Thread import dotenv from nostr_sdk import Keys, Client, Tag, EventBuilder, Filter, HandleNotification, Timestamp, nip04_decrypt, \ - NostrSigner + NostrSigner, Event from nostr_dvm.utils.dvmconfig import DVMConfig from nostr_dvm.utils.nostr_utils import send_event, check_and_set_private_key @@ -39,7 +40,7 @@ def nostr_client_test_tts(prompt): send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client(): +async def nostr_client(): keys = Keys.parse(check_and_set_private_key("test_client")) sk = keys.secret_key() pk = keys.public_key() @@ -49,15 +50,15 @@ def nostr_client(): dvmconfig = DVMConfig() for relay in dvmconfig.RELAY_LIST: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() dm_zap_filter = Filter().pubkey(pk).kinds([EventDefinitions.KIND_DM, EventDefinitions.KIND_ZAP]).since( Timestamp.now()) # events to us specific dvm_filter = (Filter().kinds([EventDefinitions.KIND_NIP90_RESULT_TEXT_TO_SPEECH, EventDefinitions.KIND_FEEDBACK]).since(Timestamp.now())) # public events - client.subscribe([dm_zap_filter, dvm_filter]) + await client.subscribe([dm_zap_filter, dvm_filter]) nostr_client_test_tts("Hello, this is a test. Mic check one, two.") @@ -66,11 +67,11 @@ def nostr_client(): #nostr_client_test_image_private("a beautiful ostrich watching the sunset") class NotificationHandler(HandleNotification): - def handle(self, relay_url, event): + def handle(self, relay_url, subscription_id, event: Event): print(f"Received new event from {relay_url}: {event.as_json()}") if event.kind() == 7000: print("[Nostr Client]: " + event.as_json()) - elif 6000 < event.kind() < 6999: + elif 6000 < event.kind().as_u64() < 6999: print("[Nostr Client]: " + event.as_json()) print("[Nostr Client]: " + event.content()) @@ -82,12 +83,12 @@ def nostr_client(): print("[Nostr Client]: " + f"Received new zap:") print(event.as_json()) - def handle_msg(self, relay_url, msg): + async def handle_msg(self, relay_url, msg): return - client.handle_notifications(NotificationHandler()) + asyncio.create_task(client.handle_notifications(NotificationHandler())) while True: - time.sleep(5.0) + await asyncio.sleep(5.0) if __name__ == '__main__': @@ -99,5 +100,4 @@ if __name__ == '__main__': else: raise FileNotFoundError(f'.env file not found at {env_path} ') - nostr_dvm_thread = Thread(target=nostr_client()) - nostr_dvm_thread.start() + asyncio.run(nostr_client()) \ No newline at end of file diff --git a/examples/unleashed_dvm/test_client.py b/examples/unleashed_dvm/test_client.py index 9c964b3..41db3a8 100644 --- a/examples/unleashed_dvm/test_client.py +++ b/examples/unleashed_dvm/test_client.py @@ -1,3 +1,4 @@ +import asyncio import json import time from datetime import timedelta @@ -6,14 +7,14 @@ from threading import Thread import dotenv from nostr_sdk import Keys, Client, Tag, EventBuilder, Filter, HandleNotification, Timestamp, nip04_decrypt, \ - NostrSigner, Options + NostrSigner, Options, Event from nostr_dvm.utils.dvmconfig import DVMConfig from nostr_dvm.utils.nostr_utils import send_event, check_and_set_private_key from nostr_dvm.utils.definitions import EventDefinitions -def nostr_client_test(prompt): +async def nostr_client_test(prompt): keys = Keys.parse(check_and_set_private_key("test_client")) iTag = Tag.parse(["i", prompt, "text"]) @@ -32,13 +33,13 @@ def nostr_client_test(prompt): signer = NostrSigner.keys(keys) client = Client.with_opts(signer,opts) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client(): +async def nostr_client(): keys = Keys.parse(check_and_set_private_key("test_client")) sk = keys.secret_key() pk = keys.public_key() @@ -48,28 +49,28 @@ def nostr_client(): dvmconfig = DVMConfig() for relay in dvmconfig.RELAY_LIST: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() dm_zap_filter = Filter().pubkey(pk).kinds([EventDefinitions.KIND_DM, EventDefinitions.KIND_ZAP]).since( Timestamp.now()) # events to us specific dvm_filter = (Filter().kinds([EventDefinitions.KIND_NIP90_RESULT_GENERATE_TEXT, EventDefinitions.KIND_FEEDBACK]).since(Timestamp.now())) # public events - client.subscribe([dm_zap_filter, dvm_filter]) + await client.subscribe([dm_zap_filter, dvm_filter]) #nostr_client_test("What has Pablo been up to?") - nostr_client_test("What is Gigi talking about recently?") + await nostr_client_test("What is Gigi talking about recently?") print("Sending Job Request") class NotificationHandler(HandleNotification): - def handle(self, relay_url, event): + def handle(self, relay_url, subscription_id, event: Event): print(f"Received new event from {relay_url}: {event.as_json()}") if event.kind() == 7000: print("[Nostr Client]: " + event.as_json()) - elif 6000 < event.kind() < 6999: + elif 6000 < event.kind().as_u64() < 6999: print("[Nostr Client " + event.author().to_bech32() + "]: " + event.as_json()) print("[Nostr Client " + event.author().to_bech32() + "]: " + event.content()) @@ -85,9 +86,10 @@ def nostr_client(): def handle_msg(self, relay_url, msg): return - client.handle_notifications(NotificationHandler()) + asyncio.create_task(client.handle_notifications(NotificationHandler())) + while True: - time.sleep(1) + await asyncio.sleep(1) if __name__ == '__main__': @@ -99,5 +101,4 @@ if __name__ == '__main__': else: raise FileNotFoundError(f'.env file not found at {env_path} ') - nostr_dvm_thread = Thread(target=nostr_client()) - nostr_dvm_thread.start() + asyncio.run(nostr_client()) \ No newline at end of file diff --git a/nostr_dvm/backends/nova_server/utils.py b/nostr_dvm/backends/nova_server/utils.py index ce92e1a..43d1bb2 100644 --- a/nostr_dvm/backends/nova_server/utils.py +++ b/nostr_dvm/backends/nova_server/utils.py @@ -1,3 +1,4 @@ +import asyncio import io import json import os @@ -32,6 +33,7 @@ def send_request_to_server(request_form, address): def send_file_to_server(filepath, address): + result = "" print("Sending file to Server") url = ('http://' + address + '/upload') try: @@ -72,7 +74,8 @@ def check_server_status(jobID, address) -> str | pd.DataFrame: if log != "": print(log) # WAITING = 0, RUNNING = 1, FINISHED = 2, ERROR = 3 - time.sleep(1.0) + asyncio.sleep(1.0) + if status == 2: try: diff --git a/nostr_dvm/bot.py b/nostr_dvm/bot.py index 9e28b63..dbb76ec 100644 --- a/nostr_dvm/bot.py +++ b/nostr_dvm/bot.py @@ -150,7 +150,7 @@ class Bot: index = int(split[0]) - 1 # if user sends index info, e.g. 1 info, we fetch the nip89 information and reply with it. if len(split) > 1 and split[1].lower() == "info": - answer_nip89(nostr_event, index, giftwrap, sender) + await answer_nip89(nostr_event, index, giftwrap, sender) # otherwise we probably have to do some work, so build an event from input and send it to the DVM else: task = self.dvm_config.SUPPORTED_DVMS[index].TASK @@ -198,7 +198,7 @@ class Bot: self.job_list.append(entry) # send the event to the DVM - send_event(nip90request, client=self.client, dvm_config=self.dvm_config) + await send_event(nip90request, client=self.client, dvm_config=self.dvm_config) # print(nip90request.as_json()) @@ -220,7 +220,7 @@ class Bot: "sat).\n Not all DVMs might " "accept Cashu tokens.") if giftwrap: - self.client.send_sealed_msg(PublicKey.parse(sender), message, None) + await self.client.send_private_msg(PublicKey.parse(sender), message, None) else: evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender), message,None).to_event(self.keys) @@ -232,32 +232,32 @@ class Bot: self.client) print(cashu_message) if cashu_message == "success": - update_user_balance(self.dvm_config.DB, sender, total_amount, client=self.client, + await update_user_balance(self.dvm_config.DB, sender, total_amount, client=self.client, config=self.dvm_config) else: time.sleep(2.0) message = "Error: " + cashu_message + ". Token has not been redeemed." if giftwrap: - self.client.send_sealed_msg(PublicKey.parse(sender), message, None) + await self.client.send_private_msg(PublicKey.parse(sender), message, None) else: evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.from_hex(sender), message, None).to_event(self.keys) - send_event(evt, client=self.client, dvm_config=self.dvm_config) + await send_event(evt, client=self.client, dvm_config=self.dvm_config) elif decrypted_text.lower().startswith("what's the second best"): time.sleep(3.0) message = "No, there is no second best.\n\nhttps://cdn.nostr.build/p/mYLv.mp4" if giftwrap: - self.client.send_sealed_msg(PublicKey.parse(sender), message, None) + await self.client.send_private_msg(PublicKey.parse(sender), message, None) else: - evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender), + evt = await EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender), message, nostr_event.id()).to_event(self.keys) - send_event(evt, client=self.client, dvm_config=self.dvm_config) + await send_event(evt, client=self.client, dvm_config=self.dvm_config) else: # Build an overview of known DVMs and send it to the user - answer_overview(nostr_event, giftwrap, sender) + await answer_overview(nostr_event, giftwrap, sender) except Exception as e: print("Error in bot " + str(e)) @@ -314,14 +314,14 @@ class Bot: client=self.client, config=self.dvm_config) time.sleep(2.0) if entry["giftwrap"]: - self.client.send_sealed_msg(PublicKey.parse(entry["npub"]), content, None) + await self.client.send_private_msg(PublicKey.parse(entry["npub"]), content, None) else: reply_event = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.from_hex(entry['npub']), content, None).to_event(self.keys) - send_event(reply_event, client=self.client, dvm_config=dvm_config) + await send_event(reply_event, client=self.client, dvm_config=dvm_config) print(status + ": " + content) print( "[" + self.NAME + "] Received reaction from " + nostr_event.author().to_hex() + " message to orignal sender " + user.name) @@ -346,7 +346,7 @@ class Bot: message = "Paid " + str(amount) + " Sats from balance to DVM. New balance is " + str(balance) + " Sats.\n" if entry["giftwrap"]: - self.client.send_sealed_msg(PublicKey.parse(entry["npub"]), message, None) + await self.client.send_private_msg(PublicKey.parse(entry["npub"]), message, None) else: evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(entry["npub"]), @@ -437,7 +437,7 @@ class Bot: print("[" + self.NAME + "] Received results, message to orignal sender " + user.name) time.sleep(1.0) if entry["giftwrap"]: - self.client.send_sealed_msg(PublicKey.parse(user.npub), content, None) + await self.client.send_private_msg(PublicKey.parse(user.npub), content, None) else: reply_event = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(user.npub), @@ -482,7 +482,7 @@ class Bot: print("[" + self.NAME + "] Note Zap received for Bot balance: " + str( invoice_amount) + " Sats from " + str( user.name)) - update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client, + await update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client, config=self.dvm_config) # a regular note @@ -490,13 +490,13 @@ class Bot: print("[" + self.NAME + "] Profile Zap received for Bot balance: " + str( invoice_amount) + " Sats from " + str( user.name)) - update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client, + await update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client, config=self.dvm_config) except Exception as e: print("[" + self.NAME + "] Error during content decryption:" + str(e)) - def answer_overview(nostr_event, giftwrap, sender): + async def answer_overview(nostr_event, giftwrap, sender): message = "DVMs that I support:\n\n" index = 1 for p in self.dvm_config.SUPPORTED_DVMS: @@ -512,13 +512,13 @@ class Bot: text = message + "\nSelect an Index and provide an input (e.g. \"2 A purple ostrich\")\nType \"index info\" to learn more about each DVM. (e.g. \"2 info\")\n\n Type \"balance\" to see your current balance" if giftwrap: - self.client.send_sealed_msg(PublicKey.parse(sender), text, None) + await self.client.send_private_msg(PublicKey.parse(sender), text, None) else: evt = EventBuilder.encrypted_direct_msg(self.keys, PublicKey.parse(sender), text, nostr_event.id()).to_event(self.keys) - send_event(evt, client=self.client, dvm_config=dvm_config) + await send_event(evt, client=self.client, dvm_config=dvm_config) def answer_blacklisted(nostr_event, giftwrap, sender): message = "Your are currently blocked from this service." @@ -530,18 +530,18 @@ class Bot: message, None).to_event(self.keys) send_event(evt, client=self.client, dvm_config=dvm_config) - def answer_nip89(nostr_event, index, giftwrap, sender): + async def answer_nip89(nostr_event, index, giftwrap, sender): info = print_dvm_info(self.client, index) if info is None: info = "No NIP89 Info found for " + self.dvm_config.SUPPORTED_DVMS[index].NAME time.sleep(2.0) if giftwrap: - self.client.send_sealed_msg(PublicKey.parse(sender), info, None) + await self.client.send_private_msg(PublicKey.parse(sender), info, None) else: evt = EventBuilder.encrypted_direct_msg(self.keys, nostr_event.author(), info, None).to_event(self.keys) - send_event(evt, client=self.client, dvm_config=dvm_config) + await send_event(evt, client=self.client, dvm_config=dvm_config) def build_params(decrypted_text, author, index): tags = [] @@ -699,11 +699,11 @@ class Bot: return None - await self.client.handle_notifications(NotificationHandler()) + asyncio.create_task(self.client.handle_notifications(NotificationHandler())) try: while True: - time.sleep(1.0) + await asyncio.sleep(1.0) except KeyboardInterrupt: print('Stay weird!') os.kill(os.getpid(), signal.SIGTERM) diff --git a/nostr_dvm/dvm.py b/nostr_dvm/dvm.py index 58391e9..45f67d1 100644 --- a/nostr_dvm/dvm.py +++ b/nostr_dvm/dvm.py @@ -2,6 +2,7 @@ import asyncio import json import os import subprocess +import threading from datetime import timedelta from sys import platform @@ -36,6 +37,8 @@ class DVM: jobs_on_hold_list: list def __init__(self, dvm_config, admin_config=None): + + asyncio.run(self.run_dvm(dvm_config, admin_config)) async def run_dvm(self, dvm_config, admin_config): @@ -73,14 +76,13 @@ class DVM: await admin_make_database_updates(adminconfig=self.admin_config, dvmconfig=self.dvm_config, client=self.client) await self.client.subscribe([dvm_filter, zap_filter], None) - class NotificationHandler(HandleNotification): client = self.client dvm_config = self.dvm_config keys = self.keys async def handle(self, relay_url, subscription_id, nostr_event: Event): - + print(nostr_event.as_json()) if EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u64() <= nostr_event.kind().as_u64() <= EventDefinitions.KIND_NIP90_GENERIC.as_u64(): await handle_nip90_job_event(nostr_event) elif nostr_event.kind().as_u64() == EventDefinitions.KIND_ZAP.as_u64(): @@ -118,7 +120,7 @@ class DVM: if task_supported: # fetch or add user contacting the DVM from/to local database user = await get_or_add_user(self.dvm_config.DB, nip90_event.author().to_hex(), client=self.client, - config=self.dvm_config, skip_meta=False) + config=self.dvm_config, skip_meta=False) # if user is blacklisted for some reason, send an error reaction and return if user.isblacklisted: await send_job_status_reaction(nip90_event, "error", client=self.client, dvm_config=self.dvm_config) @@ -135,7 +137,7 @@ class DVM: # If this is a subscription DVM and the Task is directed to us, check for active subscription if dvm_config.NIP88 is not None and p_tag_str == self.dvm_config.PUBLIC_KEY: await send_job_status_reaction(nip90_event, "subscription-required", True, amount, self.client, - "Checking Subscription Status, please wait..", self.dvm_config) + "Checking Subscription Status, please wait..", self.dvm_config) # if we stored in the database that the user has an active subscription, we don't need to check it print("User Subscription: " + str(user.subscribed) + " Current time: " + str( Timestamp.now().as_secs())) @@ -144,28 +146,30 @@ class DVM: print("User subscribed until: " + str(Timestamp.from_secs(user.subscribed).to_human_datetime())) user_has_active_subscription = True await send_job_status_reaction(nip90_event, "subscription-required", True, amount, - self.client, "User subscripton active until " + - Timestamp.from_secs(int(user.subscribed)).to_human_datetime().replace( - "Z", " ").replace("T", " ") + " GMT", self.dvm_config) + self.client, "User subscripton active until " + + Timestamp.from_secs( + int(user.subscribed)).to_human_datetime().replace( + "Z", " ").replace("T", " ") + " GMT", self.dvm_config) # otherwise we check for an active subscription by checking recipie events else: print("[" + self.dvm_config.NIP89.NAME + "] Checking Subscription status") await send_job_status_reaction(nip90_event, "subscription-required", True, amount, self.client, - "I Don't have information about subscription status, checking on the Nostr. This might take a few seconds", - self.dvm_config) + "I Don't have information about subscription status, checking on the Nostr. This might take a few seconds", + self.dvm_config) subscription_status = nip88_has_active_subscription(PublicKey.parse(user.npub), self.dvm_config.NIP88.DTAG, self.client, self.dvm_config.PUBLIC_KEY) if subscription_status["isActive"]: - await send_job_status_reaction(nip90_event, "subscription-required", True, amount, self.client, - "User subscripton active until " + Timestamp.from_secs(int( - subscription_status[ - "validUntil"])).to_human_datetime().replace("Z", - " ").replace( - "T", " ") + " GMT", - self.dvm_config) + await send_job_status_reaction(nip90_event, "subscription-required", True, amount, + self.client, + "User subscripton active until " + Timestamp.from_secs(int( + subscription_status[ + "validUntil"])).to_human_datetime().replace("Z", + " ").replace( + "T", " ") + " GMT", + self.dvm_config) print("Checked Recipe: User subscribed until: " + str( Timestamp.from_secs(int(subscription_status["validUntil"])).to_human_datetime())) user_has_active_subscription = True @@ -174,9 +178,10 @@ class DVM: self.client, self.dvm_config) else: print("No active subscription found") - await send_job_status_reaction(nip90_event, "subscription-required", True, amount, self.client, - "No active subscription found. Manage your subscription at: " + self.dvm_config.SUBSCRIPTION_MANAGEMENT, - self.dvm_config) + await send_job_status_reaction(nip90_event, "subscription-required", True, amount, + self.client, + "No active subscription found. Manage your subscription at: " + self.dvm_config.SUBSCRIPTION_MANAGEMENT, + self.dvm_config) for dvm in self.dvm_config.SUPPORTED_DVMS: if dvm.TASK == task and dvm.FIX_COST == 0 and dvm.PER_UNIT_COST == 0 and dvm_config.NIP88 is None: @@ -185,12 +190,12 @@ class DVM: cashu_redeemed = False if cashu != "": print(cashu) - cashu_redeemed, cashu_message, redeem_amount, fees = await redeem_cashu(cashu, self.dvm_config, - self.client, int(amount)) + cashu_redeemed, cashu_message, redeem_amount, fees = await redeem_cashu(cashu, self.dvm_config, + self.client, int(amount)) print(cashu_message) if cashu_message != "success": await send_job_status_reaction(nip90_event, "error", False, amount, self.client, cashu_message, - self.dvm_config) + self.dvm_config) return # if user is whitelisted or task is free, just do the job if (user.iswhitelisted or task_is_free or cashu_redeemed) and ( @@ -202,8 +207,8 @@ class DVM: if dvm_config.SEND_FEEDBACK_EVENTS: await send_job_status_reaction(nip90_event, "processing", True, 0, - content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, - client=self.client, dvm_config=self.dvm_config, user=user) + content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, + client=self.client, dvm_config=self.dvm_config, user=user) # when we reimburse users on error make sure to not send anything if it was free if user.iswhitelisted or task_is_free: @@ -230,8 +235,8 @@ class DVM: ". Starting processing.. Balance remains at: " + str(user.balance)) await send_job_status_reaction(nip90_event, "processing", True, 0, - content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, - client=self.client, dvm_config=self.dvm_config) + content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, + client=self.client, dvm_config=self.dvm_config) await do_work(nip90_event, amount) @@ -243,8 +248,8 @@ class DVM: "[" + self.dvm_config.NIP89.NAME + "] Hinting user for Subscription: " + nip90_event.id().to_hex()) await send_job_status_reaction(nip90_event, "subscription-required", - False, 0, client=self.client, - dvm_config=self.dvm_config) + False, 0, client=self.client, + dvm_config=self.dvm_config) else: bid = 0 for tag in nip90_event.tags(): @@ -258,15 +263,16 @@ class DVM: bid_offer = int(bid / 1000) if bid_offer >= int(amount): await send_job_status_reaction(nip90_event, "payment-required", False, - int(amount), # bid_offer - client=self.client, dvm_config=self.dvm_config) + int(amount), # bid_offer + client=self.client, dvm_config=self.dvm_config) else: # If there is no bid, just request server rate from user print( "[" + self.dvm_config.NIP89.NAME + "] Requesting payment for Event: " + nip90_event.id().to_hex()) await send_job_status_reaction(nip90_event, "payment-required", - False, int(amount), client=self.client, dvm_config=self.dvm_config) + False, int(amount), client=self.client, + dvm_config=self.dvm_config) @@ -282,7 +288,8 @@ class DVM: self.keys, self.dvm_config.NIP89.NAME, self.client, self.dvm_config) - user = await get_or_add_user(db=self.dvm_config.DB, npub=sender, client=self.client, config=self.dvm_config) + user = await get_or_add_user(db=self.dvm_config.DB, npub=sender, client=self.client, + config=self.dvm_config) if zapped_event is not None: if zapped_event.kind() == EventDefinitions.KIND_FEEDBACK: @@ -310,7 +317,7 @@ class DVM: print(status) if job_event.kind() == EventDefinitions.KIND_NIP88_SUBSCRIBE_EVENT: await send_job_status_reaction(job_event, "subscription-success", client=self.client, - dvm_config=self.dvm_config, user=user) + dvm_config=self.dvm_config, user=user) @@ -323,8 +330,8 @@ class DVM: if amount <= invoice_amount: print("[" + self.dvm_config.NIP89.NAME + "] Payment-request fulfilled...") await send_job_status_reaction(job_event, "processing", client=self.client, - content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, - dvm_config=self.dvm_config, user=user) + content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, + dvm_config=self.dvm_config, user=user) indices = [i for i, x in enumerate(self.job_list) if x.event == job_event] index = -1 @@ -345,8 +352,8 @@ class DVM: else: await send_job_status_reaction(job_event, "payment-rejected", - False, invoice_amount, client=self.client, - dvm_config=self.dvm_config) + False, invoice_amount, client=self.client, + dvm_config=self.dvm_config) print("[" + self.dvm_config.NIP89.NAME + "] Invoice was not paid sufficiently") elif zapped_event.kind() == EventDefinitions.KIND_NIP88_SUBSCRIBE_EVENT: print("new subscription, doing nothing") @@ -392,7 +399,7 @@ class DVM: job_ = RequiredJobToWatch(event=nevent, timestamp=Timestamp.now().as_secs()) self.jobs_on_hold_list.append(job_) await send_job_status_reaction(nevent, "chain-scheduled", True, 0, - client=client, dvm_config=dvmconfig) + client=client, dvm_config=dvmconfig) return False else: @@ -409,12 +416,12 @@ class DVM: if self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and not is_paid: await send_nostr_reply_event(data, original_event.as_json()) await send_job_status_reaction(original_event, "success", amount, - dvm_config=self.dvm_config, - ) # or payment-required, or both? + dvm_config=self.dvm_config, + ) # or payment-required, or both? elif not self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and not is_paid: await send_job_status_reaction(original_event, "success", amount, - dvm_config=self.dvm_config, - ) # or payment-required, or both? + dvm_config=self.dvm_config, + ) # or payment-required, or both? if self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and is_paid: self.job_list.remove(x) @@ -434,12 +441,12 @@ class DVM: # Zapping back by error in post-processing is a risk for the DVM because work has been done, # but maybe something with parsing/uploading failed. Try to avoid errors here as good as possible await send_job_status_reaction(original_event, "error", - content="Error in Post-processing: " + str(e), - dvm_config=self.dvm_config, - ) + content="Error in Post-processing: " + str(e), + dvm_config=self.dvm_config, + ) if amount > 0 and self.dvm_config.LNBITS_ADMIN_KEY != "": user = await get_or_add_user(self.dvm_config.DB, original_event.author().to_hex(), - client=self.client, config=self.dvm_config) + client=self.client, config=self.dvm_config) print(user.lud16 + " " + str(amount)) bolt11 = zaprequest(user.lud16, amount, "Couldn't finish job, returning sats", original_event, "", @@ -498,8 +505,8 @@ class DVM: original_event.kind().as_u64() + 1000) + " Job Response event sent: " + reply_event.as_json() + bcolors.ENDC) async def send_job_status_reaction(original_event, status, is_paid=True, amount=0, client=None, - content=None, - dvm_config=None, user=None): + content=None, + dvm_config=None, user=None): task = get_task(original_event, client=client, dvm_config=dvm_config) alt_description, reaction = build_status_reaction(status, task, amount, content, dvm_config) @@ -654,18 +661,18 @@ class DVM: print(bcolors.RED + "[" + self.dvm_config.NIP89.NAME + "] Error: " + str( e) + bcolors.ENDC) await send_job_status_reaction(job_event, "error", content=str(e), - dvm_config=self.dvm_config) + dvm_config=self.dvm_config) except Exception as e: print( bcolors.RED + "[" + self.dvm_config.NIP89.NAME + "] Error: " + str(e) + bcolors.ENDC) # we could send the exception here to the user, but maybe that's not a good idea after all. await send_job_status_reaction(job_event, "error", content=result, - dvm_config=self.dvm_config) + dvm_config=self.dvm_config) # Zapping back the user on error if amount > 0 and self.dvm_config.LNBITS_ADMIN_KEY != "": user = await get_or_add_user(self.dvm_config.DB, job_event.author().to_hex(), - client=self.client, config=self.dvm_config) + client=self.client, config=self.dvm_config) print(user.lud16 + " " + str(amount)) bolt11 = zaprequest(user.lud16, amount, "Couldn't finish job, returning sats", job_event, PublicKey.parse(user.npub), @@ -680,15 +687,16 @@ class DVM: return - await self.client.handle_notifications(NotificationHandler()) - while True: + #await self.client.handle_notifications(NotificationHandler) + asyncio.create_task(self.client.handle_notifications(NotificationHandler())) + while True: for dvm in self.dvm_config.SUPPORTED_DVMS: - scheduled_result = await dvm.schedule(self.dvm_config) + await dvm.schedule(self.dvm_config) for job in self.job_list: if job.bolt11 != "" and job.payment_hash != "" and not job.payment_hash is None and not job.is_paid: - ispaid = check_bolt11_ln_bits_is_paid(job.payment_hash, self.dvm_config) + ispaid = check_bolt11_ln_bits_is_paid(job.payment_hash, se.dvm_config) if ispaid and job.is_paid is False: print("is paid") job.is_paid = True @@ -696,9 +704,9 @@ class DVM: job.is_paid = True await send_job_status_reaction(job.event, "processing", True, 0, - content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, - client=self.client, - dvm_config=self.dvm_config) + content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, + client=self.client, + dvm_config=self.dvm_config) print("[" + self.dvm_config.NIP89.NAME + "] doing work from joblist") await do_work(job.event, amount) elif ispaid is None: # invoice expired @@ -708,8 +716,8 @@ class DVM: self.job_list.remove(job) for job in self.jobs_on_hold_list: - if await check_event_has_not_unfinished_job_input(job.event, False, client=self.client, - dvmconfig=self.dvm_config): + if await check_event_has_not_unfinished_job_input(job.event, False, client=se.client, + dvmconfig=self.dvm_config): await handle_nip90_job_event(nip90_event=job.event) try: self.jobs_on_hold_list.remove(job) @@ -719,4 +727,4 @@ class DVM: if Timestamp.now().as_secs() > job.timestamp + 60 * 20: # remove jobs to look for after 20 minutes.. self.jobs_on_hold_list.remove(job) - time.sleep(1.0) + await asyncio.sleep(1) diff --git a/nostr_dvm/interfaces/dvmtaskinterface.py b/nostr_dvm/interfaces/dvmtaskinterface.py index 5307390..e5a67a4 100644 --- a/nostr_dvm/interfaces/dvmtaskinterface.py +++ b/nostr_dvm/interfaces/dvmtaskinterface.py @@ -71,7 +71,7 @@ class DVMTaskInterface: self.admin_config = admin_config asyncio.run(self.init_dvm(name, dvm_config, nip89config, nip88config, - admin_config, options)) + admin_config, options)) async def init_dvm(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, nip88config: NIP88Config = None, admin_config: AdminConfig = None, options=None): diff --git a/nostr_dvm/subscription.py b/nostr_dvm/subscription.py index 845c03e..0f8e297 100644 --- a/nostr_dvm/subscription.py +++ b/nostr_dvm/subscription.py @@ -451,11 +451,11 @@ class Subscription: except Exception as e: print(e) - await self.client.handle_notifications(NotificationHandler()) + asyncio.create_task(self.client.handle_notifications(NotificationHandler())) try: while True: - time.sleep(60.0) + await asyncio.sleep(60.0) await check_subscriptions() except KeyboardInterrupt: print('Stay weird!') diff --git a/nostr_dvm/tasks/audiogeneration_suno_ai.py b/nostr_dvm/tasks/audiogeneration_suno_ai.py index 688dd0a..4f755d8 100644 --- a/nostr_dvm/tasks/audiogeneration_suno_ai.py +++ b/nostr_dvm/tasks/audiogeneration_suno_ai.py @@ -1,3 +1,4 @@ +import asyncio import json import os import time @@ -130,7 +131,7 @@ class AudioGenerationSonoAI(DVMTaskInterface): print(f"{data[1]['id']} ==> {data[1]['video_url']}") break # sleep 5s - time.sleep(5) + asyncio.sleep(5.0) response1 = self.get_clip(data[0]['id']) print(response1['video_url']) diff --git a/nostr_dvm/tasks/content_discovery_update_db_only.py b/nostr_dvm/tasks/content_discovery_update_db_only.py index 9af0d12..fef1ac0 100644 --- a/nostr_dvm/tasks/content_discovery_update_db_only.py +++ b/nostr_dvm/tasks/content_discovery_update_db_only.py @@ -3,7 +3,8 @@ import json import os from datetime import timedelta from nostr_sdk import Client, Timestamp, PublicKey, Tag, Keys, Options, SecretKey, NostrSigner, NostrDatabase, \ - ClientBuilder, Filter, NegentropyOptions, NegentropyDirection, init_logger, LogLevel, Event, EventId, Kind + ClientBuilder, Filter, NegentropyOptions, NegentropyDirection, init_logger, LogLevel, Event, EventId, Kind, \ + RelayLimits from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface, process_venv from nostr_dvm.utils import definitions @@ -28,7 +29,7 @@ class DicoverContentDBUpdateScheduler(DVMTaskInterface): FIX_COST: float = 0 dvm_config: DVMConfig request_form = None - last_schedule: int + last_schedule: int = 0 min_reactions = 2 db_since = 10 * 3600 db_name = "db/nostr_default_recent_notes.db" @@ -51,16 +52,6 @@ class DicoverContentDBUpdateScheduler(DVMTaskInterface): dvm_config.SCRIPT = os.path.abspath(__file__) - if self.options.get("personalized"): - self.personalized = bool(self.options.get("personalized")) - self.last_schedule = Timestamp.now().as_secs() - if self.options.get("search_list"): - self.search_list = self.options.get("search_list") - # print(self.search_list) - if self.options.get("avoid_list"): - self.avoid_list = self.options.get("avoid_list") - if self.options.get("must_list"): - self.must_list = self.options.get("must_list") if self.options.get("db_name"): self.db_name = self.options.get("db_name") if self.options.get("db_since"): @@ -130,7 +121,8 @@ class DicoverContentDBUpdateScheduler(DVMTaskInterface): return 1 async def sync_db(self): - opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_LONG_TIMEOUT))) + relaylimits = RelayLimits.disable() + opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_LONG_TIMEOUT))).relay_limits(relaylimits) sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY) keys = Keys.parse(sk.to_hex()) signer = NostrSigner.keys(keys) diff --git a/nostr_dvm/utils/database_utils.py b/nostr_dvm/utils/database_utils.py index d50e564..594078b 100644 --- a/nostr_dvm/utils/database_utils.py +++ b/nostr_dvm/utils/database_utils.py @@ -168,7 +168,7 @@ def list_db(db): print(e) -def update_user_balance(db, npub, additional_sats, client, config, giftwrap=False): +async def update_user_balance(db, npub, additional_sats, client, config, giftwrap=False): user = get_from_sql_table(db, npub) if user is None: name, nip05, lud16 = fetch_user_metadata(npub, client) @@ -192,11 +192,11 @@ def update_user_balance(db, npub, additional_sats, client, config, giftwrap=Fals new_balance) + " Sats.") if giftwrap: - client.send_sealed_msg(PublicKey.parse(npub), message, None) + await client.send_private_msg(PublicKey.parse(npub), message, None) else: evt = EventBuilder.encrypted_direct_msg(keys, PublicKey.parse(npub), message, None).to_event(keys) - send_event(evt, client=client, dvm_config=config) + await send_event(evt, client=client, dvm_config=config) def update_user_subscription(npub, subscribed_until, client, dvm_config): diff --git a/tests/discovery.py b/tests/discovery.py index f2a8577..2f40a65 100644 --- a/tests/discovery.py +++ b/tests/discovery.py @@ -31,14 +31,19 @@ use_logger = True AVOID_PAID_OUTBOX_RELAY_LIST = ["wss://nostrelay.yeghro.site", "wss://nostr.wine", "wss://filter.nostr.wine" "wss://nostr21.com", "wss://nostr.bitcoiner.social", "wss://nostr.orangepill.dev", "wss://relay.lnpay.me", "wss://relay.snort.social", "wss://relay.minds.com/nostr/v1/ws", - "wss://nostr-pub.semisol.dev", "wss://mostr.pub", "wss://minds.com", + "wss://nostr-pub.semisol.dev", "wss://mostr.pub", "wss://relay.mostr.pub", "wss://minds.com", "wss://yabu.me", "wss://relay.yozora.world", "wss://filter.nostr.wine/?global=all", "wss://eden.nostr.land", "wss://relay.orangepill.ovh", "wss://nostr.jcloud.es", "wss://af.purplerelay.com", "wss://za.purplerelay.com", "wss://relay.nostrich.land", "wss://relay.nostrplebs.com", "wss://relay.nostrich.land", "wss://rss.nos.social", "wss://atlas.nostr.land", "wss://puravida.nostr.land", "wss://nostr.inosta.cc", "wss://relay.orangepill.dev", "wss://no.str.cr", "wss://nostr.milou.lol", "wss://relay.nostr.com.au", "wss://puravida.nostr.land", "wss://atlas.nostr.land", "wss://nostr-pub.wellorder.net", "wss://eelay.current.fyi", - "wss://nostr.thesamecat.io", "wss://nostr.plebchain.org", "wss://relay.noswhere.com" + "wss://nostr.thesamecat.io", "wss://nostr.plebchain.org", "wss://relay.noswhere.com", "wss://nostr.uselessshit.co", + "wss://bitcoiner.social", "wss://relay.stoner.com", "wss://nostr.l00p.org", "wss://relay.nostr.ro", "wss://nostr.kollider.xyz", + "wss://relay.valera.co", "wss://relay.austrich.net", "wss://relay.nostrich.de", "wss://nostr.azte.co", "wss://nostr-relay.schnitzel.world", + "wss://relay.nostriches.org", "wss://happytavern.co", "wss://onlynotes.lol", "wss://offchain.pub", "wss://purplepag.es", "wss://relay.plebstr.com" + "wss://poster.place/relay", "wss://relayable.org" + ] @@ -47,7 +52,7 @@ AVOID_PAID_OUTBOX_RELAY_LIST = ["wss://nostrelay.yeghro.site", "wss://nostr.wine #print("GitHash " + git_hash) if use_logger: - init_logger(LogLevel.DEBUG) + init_logger(LogLevel.INFO) def build_db_scheduler(name, identifier, admin_config, options, image, description, update_rate=600, cost=0, @@ -540,6 +545,26 @@ def playground(): update_db=update_db) discovery_global.run() + # discovery_test_sub = content_discovery_currently_popular.build_example_subscription("Currently Popular Notes DVM (with Subscriptions)", "discovery_content_test", admin_config) + # discovery_test_sub.run() + + # Subscription Manager DVM + # subscription_config = DVMConfig() + # subscription_config.PRIVATE_KEY = check_and_set_private_key("dvm_subscription") + # npub = Keys.parse(subscription_config.PRIVATE_KEY).public_key().to_bech32() + # invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys("dvm_subscription", npub) + # subscription_config.LNBITS_INVOICE_KEY = invoice_key + # subscription_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back + # subscription_config.LNBITS_URL = os.getenv("LNBITS_HOST") + # sub_admin_config = AdminConfig() + # sub_admin_config.USERNPUBS = ["7782f93c5762538e1f7ccc5af83cd8018a528b9cd965048386ca1b75335f24c6"] #Add npubs of services that can contact the subscription handler + + # currently there is none, but add this once subscriptions are live. + # x = threading.Thread(target=Subscription, args=(Subscription(subscription_config, sub_admin_config),)) + # x.start() + + # keep_alive() + if __name__ == '__main__': diff --git a/tests/ditto.py b/tests/ditto.py index 0f1eb8b..164c4b5 100644 --- a/tests/ditto.py +++ b/tests/ditto.py @@ -1,4 +1,5 @@ import asyncio +import json from datetime import timedelta from nostr_sdk import Options, SecretKey, NostrSigner, Keys, Client, RelayOptions, Alphabet, SingleLetterTag, Filter, \ @@ -21,36 +22,36 @@ async def main(): ropts = RelayOptions().ping(False) await cli.add_relay_with_opts(options["relay"], ropts) - await cli.connect() - userkeys = [] - - ltags = ["pub.ditto.trends"] + ltags = ["#e", "pub.ditto.trends"] + itags = [str(SingleLetterTag.lowercase(Alphabet.E))] authors = [PublicKey.parse("db0e60d10b9555a39050c258d460c5c461f6d18f467aa9f62de1a728b8a891a4")] - notes_filter = Filter().kinds([Kind(1985)]).authors(authors).custom_tag(SingleLetterTag.uppercase(Alphabet.L), - ltags).custom_tag( - SingleLetterTag.uppercase(Alphabet.I), ["e"]) + notes_filter = Filter().authors(authors).custom_tag(SingleLetterTag.lowercase(Alphabet.L), ltags) - events = await cli.get_events_of([notes_filter], timedelta(seconds=5)) + events = await cli.get_events_of([notes_filter], timedelta(seconds=10)) result_list = [] if len(events) > 0: event = events[0] + print(event) result_list = [] for tag in event.tags(): + print(tag.as_vec()) if tag.as_vec()[0] == "e": + e_tag = Tag.parse(["e", tag.as_vec()[1], tag.as_vec()[2]]) result_list.append(e_tag.as_vec()) - print(tag.as_vec()) + else: print("Nothing found") # for event in events: # e_tag = Tag.parse(["e", event.id().to_hex()]) - # result_list.append(e_tag.as_vec()) + return "" await cli.shutdown() - # return json.dumps(result_list) + print(json.dumps(result_list)) + return json.dumps(result_list) asyncio.run(main()) diff --git a/tests/gui/nicegui/nostrAI_search_client.py b/tests/gui/nicegui/nostrAI_search_client.py index 4ab3b29..d8e52c2 100644 --- a/tests/gui/nicegui/nostrAI_search_client.py +++ b/tests/gui/nicegui/nostrAI_search_client.py @@ -1,3 +1,4 @@ +import asyncio import json import time from datetime import timedelta @@ -85,7 +86,7 @@ def init(): if len(events) == 0: response = False - time.sleep(1.0) + asyncio.sleep(1.0) continue else: if events[0].content() == "[]": diff --git a/tests/simplebot.py b/tests/simplebot.py index fbc833a..e3e2751 100644 --- a/tests/simplebot.py +++ b/tests/simplebot.py @@ -5,7 +5,7 @@ from nostr_sdk import Client, NostrSigner, Keys, Event, UnsignedEvent, Filter, \ HandleNotification, Timestamp, nip04_decrypt, UnwrappedGift, init_logger, LogLevel, Kind, KindEnum -async def main(): +async def test(): init_logger(LogLevel.DEBUG) # sk = SecretKey.from_bech32("nsec1ufnus6pju578ste3v90xd5m2decpuzpql2295m3sknqcjzyys9ls0qlc85") @@ -62,7 +62,7 @@ async def main(): print(f"Error during content NIP59 decryption: {e}") async def handle_msg(self, relay_url, msg): - None + var = None #await client.handle_notifications(NotificationHandler()) @@ -70,7 +70,17 @@ async def main(): asyncio.create_task(client.handle_notifications(NotificationHandler())) while True: print("lol.") - time.sleep(5) + await asyncio.sleep(5) -if __name__ == '__main__': - asyncio.run(main()) \ No newline at end of file + +async def async_input(): + while True: + print("lol") + await asyncio.sleep(5) + + +#async def main(): +# await asyncio.gather(asyncio.to_thread(async_input), test()) + +if __name__ == "__main__": + asyncio.run(test()) \ No newline at end of file diff --git a/tests/sunoai.py b/tests/sunoai.py index 97d3497..92081be 100644 --- a/tests/sunoai.py +++ b/tests/sunoai.py @@ -1,3 +1,4 @@ +import asyncio import time import requests @@ -78,7 +79,7 @@ if __name__ == '__main__': print(f"{data[1]['id']} ==> {data[1]['video_url']}") break # sleep 5s - time.sleep(5) + asyncio.sleep(1.0) response1 = get_clip(data[0]['id']) print(response1['video_url']) diff --git a/tests/test_dvm_client.py b/tests/test_dvm_client.py index 906fc52..86cfc31 100644 --- a/tests/test_dvm_client.py +++ b/tests/test_dvm_client.py @@ -1,3 +1,4 @@ +import asyncio import json import time from pathlib import Path @@ -13,7 +14,7 @@ from nostr_dvm.utils.definitions import EventDefinitions # TODO HINT: Best use this path with a previously whitelisted privkey, as zapping events is not implemented in the lib/code -def nostr_client_test_translation(input, kind, lang, sats, satsmax): +async def nostr_client_test_translation(input, kind, lang, sats, satsmax): keys = Keys.parse(check_and_set_private_key("test_client")) if kind == "text": iTag = Tag.parse(["i", input, "text"]) @@ -35,14 +36,14 @@ def nostr_client_test_translation(input, kind, lang, sats, satsmax): client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_search_profile(input): +async def nostr_client_test_search_profile(input): keys = Keys.parse(check_and_set_private_key("test_client")) iTag = Tag.parse(["i", input, "text"]) @@ -60,14 +61,14 @@ def nostr_client_test_search_profile(input): client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_image(prompt): +async def nostr_client_test_image(prompt): keys = Keys.parse(check_and_set_private_key("test_client")) iTag = Tag.parse(["i", prompt, "text"]) @@ -88,14 +89,14 @@ def nostr_client_test_image(prompt): signer = NostrSigner.keys(keys) client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_censor_filter(users): +async def nostr_client_test_censor_filter(users): keys = Keys.parse(check_and_set_private_key("test_client")) relay_list = ["wss://relay.damus.io", "wss://blastr.f7z.xyz", "wss://relayable.org", @@ -115,14 +116,14 @@ def nostr_client_test_censor_filter(users): signer = NostrSigner.keys(keys) client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_inactive_filter(user): +async def nostr_client_test_inactive_filter(user): keys = Keys.parse(check_and_set_private_key("test_client")) relay_list = ["wss://relay.damus.io", "wss://blastr.f7z.xyz", @@ -142,15 +143,15 @@ def nostr_client_test_inactive_filter(user): signer = NostrSigner.keys(keys) client = Client(signer) for relay in relay_list: - client.add_relay(relay) + await client.add_relay(relay) ropts = RelayOptions().ping(False) - client.add_relay_with_opts("wss://nostr.band", ropts) - client.connect() + await client.add_relay_with_opts("wss://nostr.band", ropts) + await client.connect() config = DVMConfig send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_tts(prompt): +async def nostr_client_test_tts(prompt): keys = Keys.parse(check_and_set_private_key("test_client")) iTag = Tag.parse(["i", prompt, "text"]) @@ -169,14 +170,14 @@ def nostr_client_test_tts(prompt): signer = NostrSigner.keys(keys) client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_disovery(user, ptag): +async def nostr_client_test_disovery(user, ptag): keys = Keys.parse(check_and_set_private_key("test_client")) relay_list = ["wss://relay.damus.io", "wss://blastr.f7z.xyz", @@ -196,16 +197,16 @@ def nostr_client_test_disovery(user, ptag): signer = NostrSigner.keys(keys) client = Client(signer) for relay in relay_list: - client.add_relay(relay) + await client.add_relay(relay) ropts = RelayOptions().ping(False) - client.add_relay_with_opts("wss://nostr.band", ropts) - client.connect() + await client.add_relay_with_opts("wss://nostr.band", ropts) + await client.connect() config = DVMConfig - send_event(event, client=client, dvm_config=config) + await send_event(event, client=client, dvm_config=config) return event.as_json() -def nostr_client_test_image_private(prompt, cashutoken): +async def nostr_client_test_image_private(prompt, cashutoken): keys = Keys.parse(check_and_set_private_key("test_client")) receiver_keys = Keys.parse(check_and_set_private_key("replicate_sdxl")) @@ -235,14 +236,14 @@ def nostr_client_test_image_private(prompt, cashutoken): signer = NostrSigner.keys(keys) client = Client(signer) for relay in relay_list: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() config = DVMConfig - send_event(nip90request, client=client, dvm_config=config) + await send_event(nip90request, client=client, dvm_config=config) return nip90request.as_json() -def nostr_client(): +async def nostr_client(): keys = Keys.parse(check_and_set_private_key("test_client")) sk = keys.secret_key() pk = keys.public_key() @@ -252,8 +253,8 @@ def nostr_client(): dvmconfig = DVMConfig() for relay in dvmconfig.RELAY_LIST: - client.add_relay(relay) - client.connect() + await client.add_relay(relay) + await client.connect() dm_zap_filter = Filter().pubkey(pk).kinds([EventDefinitions.KIND_DM, EventDefinitions.KIND_ZAP]).since( @@ -265,24 +266,24 @@ def nostr_client(): if kind not in kinds: kinds.append(kind) dvm_filter = (Filter().kinds(kinds).since(Timestamp.now())) - client.subscribe([dm_zap_filter, dvm_filter], None) + await client.subscribe([dm_zap_filter, dvm_filter], None) - # nostr_client_test_translation("This is the result of the DVM in spanish", "text", "es", 20, 20) - # nostr_client_test_translation("note1p8cx2dz5ss5gnk7c59zjydcncx6a754c0hsyakjvnw8xwlm5hymsnc23rs", "event", "es", 20,20) - # nostr_client_test_translation("44a0a8b395ade39d46b9d20038b3f0c8a11168e67c442e3ece95e4a1703e2beb", "event", "zh", 20, 20) - # nostr_client_test_image("a beautiful purple ostrich watching the sunset") - # nostr_client_test_search_profile("dontbelieve") + # await nostr_client_test_translation("This is the result of the DVM in spanish", "text", "es", 20, 20) + # await nostr_client_test_translation("note1p8cx2dz5ss5gnk7c59zjydcncx6a754c0hsyakjvnw8xwlm5hymsnc23rs", "event", "es", 20,20) + # await nostr_client_test_translation("44a0a8b395ade39d46b9d20038b3f0c8a11168e67c442e3ece95e4a1703e2beb", "event", "zh", 20, 20) + # await nostr_client_test_image("a beautiful purple ostrich watching the sunset") + # await nostr_client_test_search_profile("dontbelieve") wot = ["99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64"] - nostr_client_test_disovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "a21592a70ef9a00695efb3f7e816e17742d251559aff154b16d063a408bcd74d") - #nostr_client_test_censor_filter(wot) - #nostr_client_test_inactive_filter("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64") + await nostr_client_test_disovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "a21592a70ef9a00695efb3f7e816e17742d251559aff154b16d063a408bcd74d") + # await nostr_client_test_censor_filter(wot) + # await nostr_client_test_inactive_filter("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64") - # nostr_client_test_tts("Hello, this is a test. Mic check one, two.") + # await nostr_client_test_tts("Hello, this is a test. Mic check one, two.") # cashutoken = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MSwiQyI6IjAyNWU3ODZhOGFkMmExYTg0N2YxMzNiNGRhM2VhMGIyYWRhZGFkOTRiYzA4M2E2NWJjYjFlOTgwYTE1NGIyMDA2NCIsInNlY3JldCI6InQ1WnphMTZKMGY4UElQZ2FKTEg4V3pPck5rUjhESWhGa291LzVzZFd4S0U9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6NCwiQyI6IjAyOTQxNmZmMTY2MzU5ZWY5ZDc3MDc2MGNjZmY0YzliNTMzMzVmZTA2ZGI5YjBiZDg2Njg5Y2ZiZTIzMjVhYWUwYiIsInNlY3JldCI6IlRPNHB5WE43WlZqaFRQbnBkQ1BldWhncm44UHdUdE5WRUNYWk9MTzZtQXM9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MTYsIkMiOiIwMmRiZTA3ZjgwYmMzNzE0N2YyMDJkNTZiMGI3ZTIzZTdiNWNkYTBhNmI3Yjg3NDExZWYyOGRiZDg2NjAzNzBlMWIiLCJzZWNyZXQiOiJHYUNIdHhzeG9HM3J2WWNCc0N3V0YxbU1NVXczK0dDN1RKRnVwOHg1cURzPSJ9XSwibWludCI6Imh0dHBzOi8vbG5iaXRzLmJpdGNvaW5maXhlc3RoaXMub3JnL2Nhc2h1L2FwaS92MS9ScDlXZGdKZjlxck51a3M1eVQ2SG5rIn1dfQ==" - # nostr_client_test_image_private("a beautiful ostrich watching the sunset") + # await nostr_client_test_image_private("a beautiful ostrich watching the sunset") class NotificationHandler(HandleNotification): - def handle(self, relay_url, subscription_id, event: Event): + async def handle(self, relay_url, subscription_id, event: Event): print(f"Received new event from {relay_url}: {event.as_json()}") if event.kind().as_u64() == 7000: print("[Nostr Client]: " + event.as_json()) @@ -301,9 +302,9 @@ def nostr_client(): def handle_msg(self, relay_url, msg): return - client.handle_notifications(NotificationHandler()) + await client.handle_notifications(NotificationHandler()) while True: - time.sleep(5.0) + await asyncio.sleep(5.0) if __name__ == '__main__': @@ -315,5 +316,4 @@ if __name__ == '__main__': else: raise FileNotFoundError(f'.env file not found at {env_path} ') - nostr_dvm_thread = Thread(target=nostr_client()) - nostr_dvm_thread.start() + asyncio.run(nostr_client())