This commit is contained in:
Believethehype
2023-12-16 00:42:06 +01:00
parent dca65f2f7d
commit 6792fbc7dd
17 changed files with 385 additions and 212 deletions

1
.gitignore vendored
View File

@@ -173,3 +173,4 @@ db/*
backends/nserver/venv backends/nserver/venv
backends/nserver/cache backends/nserver/cache
backends/nserver/modules/image_upscale/weights backends/nserver/modules/image_upscale/weights
cache/venvs/

View File

@@ -1,5 +1,9 @@
import importlib
import json import json
import os
import subprocess
from datetime import timedelta from datetime import timedelta
from pathlib import Path
from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \ from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \
init_logger, LogLevel, Options, nip04_encrypt init_logger, LogLevel, Options, nip04_encrypt
@@ -323,7 +327,8 @@ class DVM:
except Exception as e: except Exception as e:
# Zapping back by error in post-processing is a risk for the DVM because work has been done, # 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 # but maybe something with parsing/uploading failed. Try to avoid errors here as good as possible
send_job_status_reaction(original_event, "error", content="Error in Post-processing: " + str(e), send_job_status_reaction(original_event, "error",
content="Error in Post-processing: " + str(e),
dvm_config=self.dvm_config, dvm_config=self.dvm_config,
) )
if amount > 0 and self.dvm_config.LNBITS_ADMIN_KEY != "": if amount > 0 and self.dvm_config.LNBITS_ADMIN_KEY != "":
@@ -466,11 +471,24 @@ class DVM:
for dvm in self.dvm_config.SUPPORTED_DVMS: for dvm in self.dvm_config.SUPPORTED_DVMS:
try: try:
if task == dvm.TASK: if task == dvm.TASK:
request_form = dvm.create_request_from_nostr_event(job_event, self.client,
self.dvm_config) request_form = dvm.create_request_from_nostr_event(job_event, self.client, self.dvm_config)
result = dvm.process(request_form) python_bin = (r'cache/venvs/' + os.path.basename(dvm_config.SCRIPT).split(".py")[0]
+ "/bin/python")
subprocess.run([python_bin, dvm_config.SCRIPT,
'--request', json.dumps(request_form),
'--identifier', dvm_config.IDENTIFIER,
'--output', 'output.txt'])
print("Finished processing, loading data..")
with open(os.path.abspath('output.txt')) as f:
result = f.readlines()[0]
print(result)
#f.close()
os.remove(os.path.abspath('output.txt'))
try: try:
post_processed = dvm.post_process(result, job_event) post_processed = dvm.post_process(str(result), job_event)
send_nostr_reply_event(post_processed, job_event.as_json()) send_nostr_reply_event(post_processed, job_event.as_json())
except Exception as e: except Exception as e:
send_job_status_reaction(job_event, "error", content=str(e), send_job_status_reaction(job_event, "error", content=str(e),
@@ -495,7 +513,6 @@ class DVM:
except Exception as e: except Exception as e:
print(e) print(e)
return return
self.client.handle_notifications(NotificationHandler()) self.client.handle_notifications(NotificationHandler())

View File

@@ -1,18 +1,16 @@
import json import json
import os import os
import subprocess import subprocess
from subprocess import run
import sys import sys
from threading import Thread from threading import Thread
from venv import create
from nostr_sdk import Keys from nostr_sdk import Keys
from nostr_dvm.dvm import DVM from nostr_dvm.dvm import DVM
from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.admin_utils import AdminConfig
from nostr_dvm.utils.dvmconfig import DVMConfig from nostr_dvm.utils.dvmconfig import DVMConfig
from nostr_dvm.utils.nip89_utils import NIP89Config from nostr_dvm.utils.nip89_utils import NIP89Config
from nostr_dvm.utils.nostr_utils import check_and_set_private_key
from nostr_dvm.utils.output_utils import post_process_result from nostr_dvm.utils.output_utils import post_process_result
from nostr_dvm.utils.zap_utils import check_and_set_ln_bits_keys
class DVMTaskInterface: class DVMTaskInterface:
@@ -30,11 +28,13 @@ class DVMTaskInterface:
admin_config: AdminConfig admin_config: AdminConfig
dependencies = [] dependencies = []
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None,
options=None, task=None): options=None, task=None):
self.init(name, dvm_config, admin_config, nip89config, task) self.init(name, dvm_config, admin_config, nip89config, task)
self.options = options self.options = options
self.install_dependencies(self.dependencies) self.make_venv(dvm_config)
def init(self, name, dvm_config, admin_config=None, nip89config=None, task=None): def init(self, name, dvm_config, admin_config=None, nip89config=None, task=None):
self.NAME = name self.NAME = name
@@ -58,6 +58,16 @@ class DVMTaskInterface:
self.dvm_config = dvm_config self.dvm_config = dvm_config
self.admin_config = admin_config self.admin_config = admin_config
def make_venv(self, dvm_config):
if dvm_config.SCRIPT != "":
dir = r'cache/venvs/' + os.path.basename(dvm_config.SCRIPT).split(".py")[0]
if not os.path.isdir(dir):
print(dir)
create(dir, with_pip=True, upgrade_deps=True)
for (module, package) in self.dependencies:
print("Installing Module: " + module)
run(["bin/pip", "install", package], cwd=dir)
def run(self): def run(self):
nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config]) nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config])
nostr_dvm_thread.start() nostr_dvm_thread.start()
@@ -87,16 +97,6 @@ class DVMTaskInterface:
"""Post-process the data and return the result Use default function, if not overwritten""" """Post-process the data and return the result Use default function, if not overwritten"""
return post_process_result(result, event) return post_process_result(result, event)
def install_dependencies(self, packages):
import pip
for module, package in packages:
try:
__import__(module)
except ImportError:
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
@staticmethod @staticmethod
def set_options(request_form): def set_options(request_form):
print("Setting options...") print("Setting options...")
@@ -105,3 +105,25 @@ class DVMTaskInterface:
opts = json.loads(request_form["options"]) opts = json.loads(request_form["options"])
print(opts) print(opts)
return dict(opts) return dict(opts)
@staticmethod
def process_args():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--request', dest='request')
parser.add_argument('--identifier', dest='identifier')
parser.add_argument('--output', dest='output')
args = parser.parse_args()
return args
@staticmethod
def write_output(result, output):
with open(os.path.abspath(output), 'w') as f:
f.write(result)
#f.close()
def process_venv(self):
pass
if __name__ == '__main__':
process_venv()

View File

@@ -27,9 +27,11 @@ class AdvancedSearch(DVMTaskInterface):
TASK: str = "search-content" TASK: str = "search-content"
FIX_COST: float = 0 FIX_COST: float = 0
dvm_config: DVMConfig dvm_config: DVMConfig
dependencies = [("nostr-dvm", "nostr-dvm")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -177,19 +179,28 @@ def build_example(name, identifier, admin_config):
admin_config=admin_config) admin_config=admin_config)
if __name__ == '__main__': def process_venv():
env_path = Path('.env') args = DVMTaskInterface.process_args()
if env_path.is_file(): dvm_config = build_default_config(args.identifier)
print(f'loading environment from {env_path.resolve()}') dvm = AdvancedSearch(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
dotenv.load_dotenv(env_path, verbose=True, override=True) result = dvm.process(json.loads(args.request))
else: DVMTaskInterface.write_output(result, args.output)
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() #if __name__ == '__main__':
admin_config.REBROADCAST_NIP89 = False # process_venv()
admin_config.UPDATE_PROFILE = False
dvm = build_example("Advanced Nostr Search", "discovery_content_search", admin_config)
dvm.run()
keep_alive() #if env_path.is_file():
# print(f'loading environment from {env_path.resolve()}')
# dotenv.load_dotenv(env_path, verbose=True, override=True)
#else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
#
#admin_config = AdminConfig()
#admin_config.REBROADCAST_NIP89 = False
#admin_config.UPDATE_PROFILE = False
#dvm = build_example("Advanced Nostr Search", "discovery_content_search", admin_config)
#dvm.run()
#keep_alive()

View File

@@ -1,4 +1,5 @@
import json import json
import os
from pathlib import Path from pathlib import Path
import dotenv import dotenv
@@ -30,6 +31,7 @@ class MediaConverter(DVMTaskInterface):
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -106,20 +108,28 @@ def build_example(name, identifier, admin_config):
return MediaConverter(name=name, dvm_config=dvm_config, nip89config=nip89config, return MediaConverter(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config) admin_config=admin_config)
def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = MediaConverter(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
if __name__ == '__main__': #if __name__ == '__main__':
env_path = Path('.env') # process_venv()
if env_path.is_file():
print(f'loading environment from {env_path.resolve()}')
dotenv.load_dotenv(env_path, verbose=True, override=True)
else:
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() #env_path = Path('.env')
admin_config.REBROADCAST_NIP89 = False #if env_path.is_file():
admin_config.UPDATE_PROFILE = False # print(f'loading environment from {env_path.resolve()}')
# dotenv.load_dotenv(env_path, verbose=True, override=True)
#else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
dvm = build_example("Media Bringer", "media_converter", admin_config) #admin_config = AdminConfig()
dvm.run() #admin_config.REBROADCAST_NIP89 = False
#admin_config.UPDATE_PROFILE = False
keep_alive() #dvm = build_example("Media Bringer", "media_converter", admin_config)
#dvm.run()
#keep_alive()

View File

@@ -33,6 +33,7 @@ class DiscoverInactiveFollows(DVMTaskInterface):
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -198,19 +199,26 @@ def build_example(name, identifier, admin_config):
return DiscoverInactiveFollows(name=name, dvm_config=dvm_config, nip89config=nip89config, return DiscoverInactiveFollows(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config) admin_config=admin_config)
def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = DiscoverInactiveFollows(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
if __name__ == '__main__': #if __name__ == '__main__':
env_path = Path('.env') # process_venv()
if env_path.is_file(): #env_path = Path('.env')
print(f'loading environment from {env_path.resolve()}') #if env_path.is_file():
dotenv.load_dotenv(env_path, verbose=True, override=True) # print(f'loading environment from {env_path.resolve()}')
else: # dotenv.load_dotenv(env_path, verbose=True, override=True)
raise FileNotFoundError(f'.env file not found at {env_path} ') #else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() #admin_config = AdminConfig()
admin_config.REBROADCAST_NIP89 = False #admin_config.REBROADCAST_NIP89 = False
admin_config.UPDATE_PROFILE = False #admin_config.UPDATE_PROFILE = False
dvm = build_example("Bygones", "discovery_inactive_follows", admin_config) #dvm = build_example("Bygones", "discovery_inactive_follows", admin_config)
dvm.run() #dvm.run()
keep_alive() #keep_alive()

View File

@@ -1,5 +1,6 @@
import json import json
import os import os
import time
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
@@ -28,10 +29,12 @@ class ImageGenerationDALLE(DVMTaskInterface):
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
TASK: str = "text-to-image" TASK: str = "text-to-image"
FIX_COST: float = 120 FIX_COST: float = 120
dependencies = [("openai", "openai==1.3.5")] dependencies = [("nostr-dvm", "nostr-dvm"),
("openai", "openai==1.3.5")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -107,6 +110,7 @@ class ImageGenerationDALLE(DVMTaskInterface):
n=int(options['number']), n=int(options['number']),
) )
image_url = response.data[0].url image_url = response.data[0].url
# rehost the result instead of relying on the openai link # rehost the result instead of relying on the openai link
response = requests.get(image_url) response = requests.get(image_url)
@@ -151,18 +155,31 @@ def build_example(name, identifier, admin_config):
return ImageGenerationDALLE(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config) return ImageGenerationDALLE(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config)
if __name__ == '__main__': def process_venv():
env_path = Path('.env') args = DVMTaskInterface.process_args()
if env_path.is_file(): dvm_config = build_default_config(args.identifier)
print(f'loading environment from {env_path.resolve()}') dvm = ImageGenerationDALLE(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
dotenv.load_dotenv(env_path, verbose=True, override=True) result = ""
else: while result == "":
raise FileNotFoundError(f'.env file not found at {env_path} ') result = dvm.process(json.loads(args.request))
time.sleep(10)
admin_config = AdminConfig()
admin_config.REBROADCAST_NIP89 = False
admin_config.UPDATE_PROFILE = False
dvm = build_example("Dall-E 3", "dalle3", admin_config)
dvm.run()
keep_alive() DVMTaskInterface.write_output(result, args.output)
#if __name__ == '__main__':
# process_venv()
#env_path = Path('.env')
#if env_path.is_file():
# print(f'loading environment from {env_path.resolve()}')
# dotenv.load_dotenv(env_path, verbose=True, override=True)
#else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
#admin_config = AdminConfig()
#admin_config.REBROADCAST_NIP89 = False
#admin_config.UPDATE_PROFILE = False
#dvm = build_example("Dall-E 3", "dalle3", admin_config)
#dvm.run()
#keep_alive()

View File

@@ -1,15 +1,11 @@
import json import json
import os import os
from io import BytesIO from io import BytesIO
from pathlib import Path
import dotenv
import requests import requests
from PIL import Image from PIL import Image
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.admin_utils import AdminConfig
from nostr_dvm.utils.backend_utils import keep_alive
from nostr_dvm.utils.definitions import EventDefinitions from nostr_dvm.utils.definitions import EventDefinitions
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
@@ -29,10 +25,12 @@ class ImageGenerationReplicateSDXL(DVMTaskInterface):
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
TASK: str = "text-to-image" TASK: str = "text-to-image"
FIX_COST: float = 120 FIX_COST: float = 120
dependencies = [("replicate", "replicate==0.21.1")] dependencies = [("nostr-dvm", "nostr-dvm"),
("replicate", "replicate==0.21.1")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -147,18 +145,26 @@ def build_example(name, identifier, admin_config):
admin_config=admin_config) admin_config=admin_config)
if __name__ == '__main__': def process_venv():
env_path = Path('.env') args = DVMTaskInterface.process_args()
if env_path.is_file(): dvm_config = build_default_config(args.identifier)
print(f'loading environment from {env_path.resolve()}') dvm = ImageGenerationReplicateSDXL(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
dotenv.load_dotenv(env_path, verbose=True, override=True) result = dvm.process(json.loads(args.request))
else: DVMTaskInterface.write_output(result, args.output)
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() #if __name__ == '__main__':
admin_config.REBROADCAST_NIP89 = False # process_venv()
admin_config.UPDATE_PROFILE = False #env_path = Path('.env')
dvm = build_example("Stable Diffusion XL", "replicate_sdxl", admin_config) #if env_path.is_file():
dvm.run() # print(f'loading environment from {env_path.resolve()}')
# dotenv.load_dotenv(env_path, verbose=True, override=True)
#else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
keep_alive() #admin_config = AdminConfig()
#admin_config.REBROADCAST_NIP89 = False
#admin_config.UPDATE_PROFILE = False
#dvm = build_example("Stable Diffusion XL", "replicate_sdxl", admin_config)
#dvm.run()
#keep_alive()

View File

@@ -27,10 +27,13 @@ class SpeechToTextGoogle(DVMTaskInterface):
TASK: str = "speech-to-text" TASK: str = "speech-to-text"
FIX_COST: float = 10 FIX_COST: float = 10
PER_UNIT_COST: float = 0.1 PER_UNIT_COST: float = 0.1
dependencies = [("speech_recognition", "SpeechRecognition==3.10.0")] dependencies = [("nostr-dvm", "nostr-dvm"),
("speech_recognition", "SpeechRecognition==3.10.0")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
if options is None: if options is None:
options = {} options = {}
@@ -155,20 +158,26 @@ def build_example(name, identifier, admin_config):
return SpeechToTextGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config, return SpeechToTextGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config, options=options) admin_config=admin_config, options=options)
def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = SpeechToTextGoogle(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
if __name__ == '__main__': #if __name__ == '__main__':
env_path = Path('.env') # env_path = Path('.env')
if env_path.is_file(): # if env_path.is_file():
print(f'loading environment from {env_path.resolve()}') # print(f'loading environment from {env_path.resolve()}')
dotenv.load_dotenv(env_path, verbose=True, override=True) # dotenv.load_dotenv(env_path, verbose=True, override=True)
else: # else:
raise FileNotFoundError(f'.env file not found at {env_path} ') # raise FileNotFoundError(f'.env file not found at {env_path} ')
#
# admin_config = AdminConfig()
# admin_config.REBROADCAST_NIP89 = False
# admin_config.UPDATE_PROFILE = False
# dvm = build_example("Transcriptor", "speech_recognition", admin_config)
# dvm.run()
admin_config = AdminConfig() # keep_alive()
admin_config.REBROADCAST_NIP89 = False
admin_config.UPDATE_PROFILE = False
dvm = build_example("Transcriptor", "speech_recognition", admin_config)
dvm.run()
keep_alive()

View File

@@ -26,11 +26,13 @@ class TextExtractionPDF(DVMTaskInterface):
KIND: int = EventDefinitions.KIND_NIP90_EXTRACT_TEXT KIND: int = EventDefinitions.KIND_NIP90_EXTRACT_TEXT
TASK: str = "pdf-to-text" TASK: str = "pdf-to-text"
FIX_COST: float = 0 FIX_COST: float = 0
dependencies = [("pypdf", "pypdf==3.17.1")] dependencies = [("nostr-dvm", "nostr-dvm"),
("pypdf", "pypdf==3.17.1")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
@@ -116,19 +118,26 @@ def build_example(name, identifier, admin_config):
return TextExtractionPDF(name=name, dvm_config=dvm_config, nip89config=nip89config, return TextExtractionPDF(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config) admin_config=admin_config)
def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = TextExtractionPDF(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
if __name__ == '__main__':
env_path = Path('.env')
if env_path.is_file():
print(f'loading environment from {env_path.resolve()}')
dotenv.load_dotenv(env_path, verbose=True, override=True)
else:
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() #if __name__ == '__main__':
admin_config.REBROADCAST_NIP89 = False # env_path = Path('.env')
admin_config.UPDATE_PROFILE = False # if env_path.is_file():
dvm = build_example("PDF Extractor", "pdf_extractor", admin_config) # print(f'loading environment from {env_path.resolve()}')
dvm.run() # dotenv.load_dotenv(env_path, verbose=True, override=True)
# else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
keep_alive() # admin_config = AdminConfig()
# admin_config.REBROADCAST_NIP89 = False
# admin_config.UPDATE_PROFILE = False
# dvm = build_example("PDF Extractor", "pdf_extractor", admin_config)
# dvm.run()
# keep_alive()

View File

@@ -24,10 +24,12 @@ class TextGenerationOLLAMA(DVMTaskInterface):
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_TEXT KIND: int = EventDefinitions.KIND_NIP90_GENERATE_TEXT
TASK: str = "text-to-text" TASK: str = "text-to-text"
FIX_COST: float = 0 FIX_COST: float = 0
dependencies = [("litellm", "litellm==1.12.3")] dependencies = [("nostr-dvm", "nostr-dvm"),
("litellm", "litellm==1.12.3")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
@@ -125,19 +127,27 @@ def build_example(name, identifier, admin_config):
return TextGenerationOLLAMA(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config, options=options) return TextGenerationOLLAMA(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config, options=options)
if __name__ == '__main__': def process_venv():
env_path = Path('.env') args = DVMTaskInterface.process_args()
if env_path.is_file(): dvm_config = build_default_config(args.identifier)
print(f'loading environment from {env_path.resolve()}') dvm = TextGenerationOLLAMA(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
dotenv.load_dotenv(env_path, verbose=True, override=True) result = dvm.process(json.loads(args.request))
else: DVMTaskInterface.write_output(result, args.output)
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig()
admin_config.REBROADCAST_NIP89 = False
admin_config.UPDATE_PROFILE = False
dvm = build_example("LLM", "llmlite", admin_config) #if __name__ == '__main__':
dvm.run() # env_path = Path('.env')
# if env_path.is_file():
# print(f'loading environment from {env_path.resolve()}')
# dotenv.load_dotenv(env_path, verbose=True, override=True)
# else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
#
# admin_config = AdminConfig()
# admin_config.REBROADCAST_NIP89 = False
# admin_config.UPDATE_PROFILE = False
#
# dvm = build_example("LLM", "llmlite", admin_config)
# dvm.run()
keep_alive() # keep_alive()

View File

@@ -1,4 +1,5 @@
import json import json
import os
from pathlib import Path from pathlib import Path
import dotenv import dotenv
@@ -25,10 +26,12 @@ class TranslationGoogle(DVMTaskInterface):
KIND: int = EventDefinitions.KIND_NIP90_TRANSLATE_TEXT KIND: int = EventDefinitions.KIND_NIP90_TRANSLATE_TEXT
TASK: str = "translation" TASK: str = "translation"
FIX_COST: float = 0 FIX_COST: float = 0
dependencies = [("translatepy", "translatepy==2.3")] dependencies = [("nostr-dvm", "nostr-dvm"),
("translatepy", "translatepy==2.3")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -141,18 +144,31 @@ def build_example(name, identifier, admin_config):
return TranslationGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config) return TranslationGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config)
if __name__ == '__main__':
env_path = Path('.env')
if env_path.is_file():
print(f'loading environment from {env_path.resolve()}')
dotenv.load_dotenv(env_path, verbose=True, override=True)
else:
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig()
admin_config.REBROADCAST_NIP89 = False
admin_config.UPDATE_PROFILE = False
dvm = build_example("Google Translator", "google_translator", admin_config)
dvm.run()
keep_alive() def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = TranslationGoogle(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
#if __name__ == '__main__':
#process_venv()
#env_path = Path('.env')
#if env_path.is_file():
# print(f'loading environment from {env_path.resolve()}')
# dotenv.load_dotenv(env_path, verbose=True, override=True)
#else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
#admin_config = AdminConfig()
#admin_config.REBROADCAST_NIP89 = False
#admin_config.UPDATE_PROFILE = False
#dvm = build_example("Google Translator", "google_translator", admin_config)
#dvm.run()
#keep_alive()

View File

@@ -13,7 +13,6 @@ from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
from nostr_dvm.utils.nostr_utils import get_referenced_event_by_id, get_event_by_id from nostr_dvm.utils.nostr_utils import get_referenced_event_by_id, get_event_by_id
""" """
This File contains a Module to call Libre Translate Services This File contains a Module to call Libre Translate Services
@@ -32,6 +31,7 @@ class TranslationLibre(DVMTaskInterface):
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None, task=None): admin_config: AdminConfig = None, options=None, task=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options, task) super().__init__(name, dvm_config, nip89config, admin_config, options, task)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -81,9 +81,9 @@ class TranslationLibre(DVMTaskInterface):
def process(self, request_form): def process(self, request_form):
options = DVMTaskInterface.set_options(request_form) options = DVMTaskInterface.set_options(request_form)
request = { request = {
"q": options["text"], "q": options["text"],
"source": "auto", "source": "auto",
"target": options["language"] "target": options["language"]
} }
if options["libre_api_key"] != "": if options["libre_api_key"] != "":
request["api_key"] = options["libre_api_key"] request["api_key"] = options["libre_api_key"]
@@ -95,10 +95,10 @@ class TranslationLibre(DVMTaskInterface):
reply = json.loads(response.text) reply = json.loads(response.text)
if reply.get("translatedText"): if reply.get("translatedText"):
translated_text = reply['translatedText'] translated_text = reply['translatedText']
#untested # untested
#confidence = reply["detectedLanguage"]['confidence'] # confidence = reply["detectedLanguage"]['confidence']
#language = reply["detectedLanguage"]['language'] # language = reply["detectedLanguage"]['language']
#print(translated_text + "language: " + language + "conf: " + confidence) # print(translated_text + "language: " + language + "conf: " + confidence)
else: else:
return response.text return response.text
@@ -125,12 +125,18 @@ def build_example(name, identifier, admin_config):
"nip90Params": { "nip90Params": {
"language": { "language": {
"required": False, "required": False,
"values": ["en", "az", "be", "bg", "bn", "bs", "ca", "ceb", "co", "cs", "cy", "da", "de", "el", "eo", "es", "values": ["en", "az", "be", "bg", "bn", "bs", "ca", "ceb", "co", "cs", "cy", "da", "de", "el", "eo",
"et", "eu", "fa", "fi", "fr", "fy", "ga", "gd", "gl", "gu", "ha", "haw", "hi", "hmn", "hr", "ht", "es",
"hu", "hy", "id", "ig", "is", "it", "he", "ja", "jv", "ka", "kk", "km", "kn", "ko", "ku", "ky", "et", "eu", "fa", "fi", "fr", "fy", "ga", "gd", "gl", "gu", "ha", "haw", "hi", "hmn", "hr",
"la", "lb", "lo", "lt", "lv", "mg", "mi", "mk", "ml", "mn", "mr", "ms", "mt", "my", "ne", "nl", "ht",
"no", "ny", "or", "pa", "pl", "ps", "pt", "ro", "ru", "sd", "si", "sk", "sl", "sm", "sn", "so", "hu", "hy", "id", "ig", "is", "it", "he", "ja", "jv", "ka", "kk", "km", "kn", "ko", "ku",
"sq", "sr", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "tl", "tr", "ug", "uk", "ur", "uz", "ky",
"la", "lb", "lo", "lt", "lv", "mg", "mi", "mk", "ml", "mn", "mr", "ms", "mt", "my", "ne",
"nl",
"no", "ny", "or", "pa", "pl", "ps", "pt", "ro", "ru", "sd", "si", "sk", "sl", "sm", "sn",
"so",
"sq", "sr", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "tl", "tr", "ug", "uk", "ur",
"uz",
"vi", "xh", "yi", "yo", "zh", "zu"] "vi", "xh", "yi", "yo", "zh", "zu"]
} }
} }
@@ -143,18 +149,25 @@ def build_example(name, identifier, admin_config):
admin_config=admin_config, options=options) admin_config=admin_config, options=options)
if __name__ == '__main__': def process_venv():
env_path = Path('.env') args = DVMTaskInterface.process_args()
if env_path.is_file(): dvm_config = build_default_config(args.identifier)
print(f'loading environment from {env_path.resolve()}') dvm = TranslationLibre(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
dotenv.load_dotenv(env_path, verbose=True, override=True) result = dvm.process(json.loads(args.request))
else: DVMTaskInterface.write_output(result, args.output)
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() # if __name__ == '__main__':
admin_config.REBROADCAST_NIP89 = False # env_path = Path('.env')
admin_config.UPDATE_PROFILE = False # if env_path.is_file():
dvm = build_example("Libre Translator", "libre_translator", admin_config) # print(f'loading environment from {env_path.resolve()}')
dvm.run() # dotenv.load_dotenv(env_path, verbose=True, override=True)
# else:
keep_alive() # raise FileNotFoundError(f'.env file not found at {env_path} ')
#
# admin_config = AdminConfig()
# admin_config.REBROADCAST_NIP89 = False
# admin_config.UPDATE_PROFILE = False
# dvm = build_example("Libre Translator", "libre_translator", admin_config)
# dvm.run()
#
# keep_alive()

View File

@@ -29,6 +29,7 @@ class TrendingNotesNostrBand(DVMTaskInterface):
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
@@ -117,20 +118,26 @@ def build_example(name, identifier, admin_config):
return TrendingNotesNostrBand(name=name, dvm_config=dvm_config, nip89config=nip89config, return TrendingNotesNostrBand(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config) admin_config=admin_config)
def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = TrendingNotesNostrBand(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
if __name__ == '__main__': #if __name__ == '__main__':
env_path = Path('.env') # env_path = Path('.env')
if env_path.is_file(): # if env_path.is_file():
print(f'loading environment from {env_path.resolve()}') # print(f'loading environment from {env_path.resolve()}')
dotenv.load_dotenv(env_path, verbose=True, override=True) # dotenv.load_dotenv(env_path, verbose=True, override=True)
else: # else:
raise FileNotFoundError(f'.env file not found at {env_path} ') # raise FileNotFoundError(f'.env file not found at {env_path} ')
#
admin_config = AdminConfig() # admin_config = AdminConfig()
admin_config.REBROADCAST_NIP89 = False # admin_config.REBROADCAST_NIP89 = False
admin_config.UPDATE_PROFILE = False # admin_config.UPDATE_PROFILE = False
#
dvm = build_example("Trending Notes on Nostr.band", "trending_notes_nostrband", admin_config) # dvm = build_example("Trending Notes on Nostr.band", "trending_notes_nostrband", admin_config)
dvm.run() # dvm.run()
#
keep_alive() # keep_alive()

View File

@@ -1,5 +1,6 @@
import json import json
import os import os
import subprocess
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
@@ -30,12 +31,18 @@ class VideoGenerationReplicateSVD(DVMTaskInterface):
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_VIDEO KIND: int = EventDefinitions.KIND_NIP90_GENERATE_VIDEO
TASK: str = "image-to-video" TASK: str = "image-to-video"
FIX_COST: float = 120 FIX_COST: float = 120
dependencies = [("replicate", "replicate==0.21.1")] dependencies = [("nostr-dvm", "nostr-dvm"),
("replicate", "replicate==0.21.1")]
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
admin_config: AdminConfig = None, options=None): admin_config: AdminConfig = None, options=None):
dvm_config.SCRIPT = os.path.abspath(__file__)
print(dvm_config.SCRIPT)
super().__init__(name, dvm_config, nip89config, admin_config, options) super().__init__(name, dvm_config, nip89config, admin_config, options)
def is_input_supported(self, tags): def is_input_supported(self, tags):
for tag in tags: for tag in tags:
if tag.as_vec()[0] == 'i': if tag.as_vec()[0] == 'i':
@@ -134,20 +141,27 @@ def build_example(name, identifier, admin_config):
return VideoGenerationReplicateSVD(name=name, dvm_config=dvm_config, nip89config=nip89config, return VideoGenerationReplicateSVD(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config) admin_config=admin_config)
def process_venv():
args = DVMTaskInterface.process_args()
dvm_config = build_default_config(args.identifier)
dvm = VideoGenerationReplicateSVD(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
result = dvm.process(json.loads(args.request))
DVMTaskInterface.write_output(result, args.output)
if __name__ == '__main__':
env_path = Path('.env')
if env_path.is_file():
print(f'loading environment from {env_path.resolve()}')
dotenv.load_dotenv(env_path, verbose=True, override=True)
else:
raise FileNotFoundError(f'.env file not found at {env_path} ')
admin_config = AdminConfig() #if __name__ == '__main__':
admin_config.REBROADCAST_NIP89 = False # env_path = Path('.env')
admin_config.UPDATE_PROFILE = False # if env_path.is_file():
# print(f'loading environment from {env_path.resolve()}')
dvm = build_example("Stable Video Diffusion", "replicate_svd", admin_config) # dotenv.load_dotenv(env_path, verbose=True, override=True)
dvm.run() # else:
# raise FileNotFoundError(f'.env file not found at {env_path} ')
keep_alive() #
# admin_config = AdminConfig()
# admin_config.REBROADCAST_NIP89 = False
# admin_config.UPDATE_PROFILE = False
#
# dvm = build_example("Stable Video Diffusion", "replicate_svd", admin_config)
# dvm.run()
#
# keep_alive()

View File

@@ -27,6 +27,8 @@ class DVMConfig:
LNBITS_ADMIN_KEY = '' # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users. LNBITS_ADMIN_KEY = '' # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users.
LNBITS_URL = 'https://lnbits.com' LNBITS_URL = 'https://lnbits.com'
LN_ADDRESS = '' LN_ADDRESS = ''
SCRIPT = ''
IDENTIFIER = ''
DB: str DB: str
NEW_USER_BALANCE: int = 0 # Free credits for new users NEW_USER_BALANCE: int = 0 # Free credits for new users
NIP89: NIP89Config NIP89: NIP89Config
@@ -36,6 +38,7 @@ class DVMConfig:
def build_default_config(identifier): def build_default_config(identifier):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.IDENTIFIER = identifier
npub = Keys.from_sk_str(dvm_config.PRIVATE_KEY).public_key().to_bech32() npub = Keys.from_sk_str(dvm_config.PRIVATE_KEY).public_key().to_bech32()
invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub) invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub)
dvm_config.LNBITS_INVOICE_KEY = invoice_key dvm_config.LNBITS_INVOICE_KEY = invoice_key

View File

@@ -69,7 +69,7 @@ def nostr_client_test_image(prompt):
def nostr_client_test_image_private(prompt, cashutoken): def nostr_client_test_image_private(prompt, cashutoken):
keys = Keys.from_sk_str(check_and_set_private_key("test_client")) keys = Keys.from_sk_str(check_and_set_private_key("test_client"))
receiver_keys = Keys.from_sk_str(check_and_set_private_key("sketcher")) receiver_keys = Keys.from_sk_str(check_and_set_private_key("replicate_sdxl"))
# TODO more advanced logic, more parsing, params etc, just very basic test functions for now # TODO more advanced logic, more parsing, params etc, just very basic test functions for now
@@ -125,13 +125,13 @@ def nostr_client():
client.subscribe([dm_zap_filter, dvm_filter]) client.subscribe([dm_zap_filter, dvm_filter])
#nostr_client_test_translation("This is the result of the DVM in spanish", "text", "es", 20, 20) #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("note1p8cx2dz5ss5gnk7c59zjydcncx6a754c0hsyakjvnw8xwlm5hymsnc23rs", "event", "es", 20,20)
#nostr_client_test_translation("44a0a8b395ade39d46b9d20038b3f0c8a11168e67c442e3ece95e4a1703e2beb", "event", "zh", 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_image("a beautiful purple ostrich watching the sunset")
#cashutoken = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MSwiQyI6IjAyNWU3ODZhOGFkMmExYTg0N2YxMzNiNGRhM2VhMGIyYWRhZGFkOTRiYzA4M2E2NWJjYjFlOTgwYTE1NGIyMDA2NCIsInNlY3JldCI6InQ1WnphMTZKMGY4UElQZ2FKTEg4V3pPck5rUjhESWhGa291LzVzZFd4S0U9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6NCwiQyI6IjAyOTQxNmZmMTY2MzU5ZWY5ZDc3MDc2MGNjZmY0YzliNTMzMzVmZTA2ZGI5YjBiZDg2Njg5Y2ZiZTIzMjVhYWUwYiIsInNlY3JldCI6IlRPNHB5WE43WlZqaFRQbnBkQ1BldWhncm44UHdUdE5WRUNYWk9MTzZtQXM9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MTYsIkMiOiIwMmRiZTA3ZjgwYmMzNzE0N2YyMDJkNTZiMGI3ZTIzZTdiNWNkYTBhNmI3Yjg3NDExZWYyOGRiZDg2NjAzNzBlMWIiLCJzZWNyZXQiOiJHYUNIdHhzeG9HM3J2WWNCc0N3V0YxbU1NVXczK0dDN1RKRnVwOHg1cURzPSJ9XSwibWludCI6Imh0dHBzOi8vbG5iaXRzLmJpdGNvaW5maXhlc3RoaXMub3JnL2Nhc2h1L2FwaS92MS9ScDlXZGdKZjlxck51a3M1eVQ2SG5rIn1dfQ==" #cashutoken = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MSwiQyI6IjAyNWU3ODZhOGFkMmExYTg0N2YxMzNiNGRhM2VhMGIyYWRhZGFkOTRiYzA4M2E2NWJjYjFlOTgwYTE1NGIyMDA2NCIsInNlY3JldCI6InQ1WnphMTZKMGY4UElQZ2FKTEg4V3pPck5rUjhESWhGa291LzVzZFd4S0U9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6NCwiQyI6IjAyOTQxNmZmMTY2MzU5ZWY5ZDc3MDc2MGNjZmY0YzliNTMzMzVmZTA2ZGI5YjBiZDg2Njg5Y2ZiZTIzMjVhYWUwYiIsInNlY3JldCI6IlRPNHB5WE43WlZqaFRQbnBkQ1BldWhncm44UHdUdE5WRUNYWk9MTzZtQXM9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MTYsIkMiOiIwMmRiZTA3ZjgwYmMzNzE0N2YyMDJkNTZiMGI3ZTIzZTdiNWNkYTBhNmI3Yjg3NDExZWYyOGRiZDg2NjAzNzBlMWIiLCJzZWNyZXQiOiJHYUNIdHhzeG9HM3J2WWNCc0N3V0YxbU1NVXczK0dDN1RKRnVwOHg1cURzPSJ9XSwibWludCI6Imh0dHBzOi8vbG5iaXRzLmJpdGNvaW5maXhlc3RoaXMub3JnL2Nhc2h1L2FwaS92MS9ScDlXZGdKZjlxck51a3M1eVQ2SG5rIn1dfQ=="
#nostr_client_test_image_private("a beautiful ostrich watching the sunset", cashutoken ) #nostr_client_test_image_private("a beautiful ostrich watching the sunset")
class NotificationHandler(HandleNotification): class NotificationHandler(HandleNotification):
def handle(self, relay_url, event): def handle(self, relay_url, event):
print(f"Received new event from {relay_url}: {event.as_json()}") print(f"Received new event from {relay_url}: {event.as_json()}")