From 6792fbc7dd0b0cb68a734c99fa8b44c1746e8684 Mon Sep 17 00:00:00 2001 From: Believethehype Date: Sat, 16 Dec 2023 00:42:06 +0100 Subject: [PATCH 1/2] update --- .gitignore | 1 + nostr_dvm/dvm.py | 29 ++++++-- nostr_dvm/interfaces/dvmtaskinterface.py | 52 +++++++++----- nostr_dvm/tasks/advanced_search.py | 37 ++++++---- nostr_dvm/tasks/convert_media.py | 36 ++++++---- nostr_dvm/tasks/discovery_inactive_follows.py | 34 ++++++---- .../tasks/imagegeneration_openai_dalle.py | 45 +++++++++---- .../tasks/imagegeneration_replicate_sdxl.py | 42 +++++++----- nostr_dvm/tasks/textextraction_google.py | 39 ++++++----- nostr_dvm/tasks/textextraction_pdf.py | 37 ++++++---- nostr_dvm/tasks/textgeneration_llmlite.py | 38 +++++++---- nostr_dvm/tasks/translation_google.py | 44 ++++++++---- nostr_dvm/tasks/translation_libretranslate.py | 67 +++++++++++-------- nostr_dvm/tasks/trending_notes_nostrband.py | 39 ++++++----- .../tasks/videogeneration_replicate_svd.py | 46 ++++++++----- nostr_dvm/utils/dvmconfig.py | 3 + tests/test_dvm_client.py | 8 +-- 17 files changed, 385 insertions(+), 212 deletions(-) diff --git a/.gitignore b/.gitignore index 54c9476..5bb30f3 100644 --- a/.gitignore +++ b/.gitignore @@ -173,3 +173,4 @@ db/* backends/nserver/venv backends/nserver/cache backends/nserver/modules/image_upscale/weights +cache/venvs/ diff --git a/nostr_dvm/dvm.py b/nostr_dvm/dvm.py index 91ede4e..27c09ca 100644 --- a/nostr_dvm/dvm.py +++ b/nostr_dvm/dvm.py @@ -1,5 +1,9 @@ +import importlib import json +import os +import subprocess from datetime import timedelta +from pathlib import Path from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \ init_logger, LogLevel, Options, nip04_encrypt @@ -323,7 +327,8 @@ class DVM: except Exception as e: # 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 - 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, ) if amount > 0 and self.dvm_config.LNBITS_ADMIN_KEY != "": @@ -466,11 +471,24 @@ class DVM: for dvm in self.dvm_config.SUPPORTED_DVMS: try: if task == dvm.TASK: - request_form = dvm.create_request_from_nostr_event(job_event, self.client, - self.dvm_config) - result = dvm.process(request_form) + + request_form = dvm.create_request_from_nostr_event(job_event, self.client, self.dvm_config) + 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: - 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()) except Exception as e: send_job_status_reaction(job_event, "error", content=str(e), @@ -495,7 +513,6 @@ class DVM: except Exception as e: print(e) - return self.client.handle_notifications(NotificationHandler()) diff --git a/nostr_dvm/interfaces/dvmtaskinterface.py b/nostr_dvm/interfaces/dvmtaskinterface.py index 8525f6f..83125d7 100644 --- a/nostr_dvm/interfaces/dvmtaskinterface.py +++ b/nostr_dvm/interfaces/dvmtaskinterface.py @@ -1,18 +1,16 @@ import json import os import subprocess +from subprocess import run import sys from threading import Thread - +from venv import create from nostr_sdk import Keys - from nostr_dvm.dvm import DVM from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.dvmconfig import DVMConfig 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.zap_utils import check_and_set_ln_bits_keys class DVMTaskInterface: @@ -30,11 +28,13 @@ class DVMTaskInterface: admin_config: AdminConfig dependencies = [] + def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, options=None, task=None): self.init(name, dvm_config, admin_config, nip89config, task) 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): self.NAME = name @@ -58,6 +58,16 @@ class DVMTaskInterface: self.dvm_config = dvm_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): nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config]) nostr_dvm_thread.start() @@ -87,16 +97,6 @@ class DVMTaskInterface: """Post-process the data and return the result Use default function, if not overwritten""" 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 def set_options(request_form): print("Setting options...") @@ -105,3 +105,25 @@ class DVMTaskInterface: opts = json.loads(request_form["options"]) print(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() diff --git a/nostr_dvm/tasks/advanced_search.py b/nostr_dvm/tasks/advanced_search.py index 793d304..7bd2816 100644 --- a/nostr_dvm/tasks/advanced_search.py +++ b/nostr_dvm/tasks/advanced_search.py @@ -27,9 +27,11 @@ class AdvancedSearch(DVMTaskInterface): TASK: str = "search-content" FIX_COST: float = 0 dvm_config: DVMConfig + dependencies = [("nostr-dvm", "nostr-dvm")] def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) def is_input_supported(self, tags): @@ -177,19 +179,28 @@ def build_example(name, identifier, admin_config): 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} ') +def process_venv(): + args = DVMTaskInterface.process_args() + dvm_config = build_default_config(args.identifier) + dvm = AdvancedSearch(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None) + result = dvm.process(json.loads(args.request)) + DVMTaskInterface.write_output(result, args.output) - admin_config = AdminConfig() - admin_config.REBROADCAST_NIP89 = False - admin_config.UPDATE_PROFILE = False +#if __name__ == '__main__': +# process_venv() - 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() diff --git a/nostr_dvm/tasks/convert_media.py b/nostr_dvm/tasks/convert_media.py index ef1666c..20ff106 100644 --- a/nostr_dvm/tasks/convert_media.py +++ b/nostr_dvm/tasks/convert_media.py @@ -1,4 +1,5 @@ import json +import os from pathlib import Path import dotenv @@ -30,6 +31,7 @@ class MediaConverter(DVMTaskInterface): def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) 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, 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__': - 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} ') +#if __name__ == '__main__': +# process_venv() - admin_config = AdminConfig() - admin_config.REBROADCAST_NIP89 = False - admin_config.UPDATE_PROFILE = False + #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} ') - dvm = build_example("Media Bringer", "media_converter", admin_config) - dvm.run() + #admin_config = AdminConfig() + #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() diff --git a/nostr_dvm/tasks/discovery_inactive_follows.py b/nostr_dvm/tasks/discovery_inactive_follows.py index 08a0aeb..6a52df5 100644 --- a/nostr_dvm/tasks/discovery_inactive_follows.py +++ b/nostr_dvm/tasks/discovery_inactive_follows.py @@ -33,6 +33,7 @@ class DiscoverInactiveFollows(DVMTaskInterface): def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) 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, 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__': - 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} ') +#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("Bygones", "discovery_inactive_follows", admin_config) - dvm.run() + #admin_config = AdminConfig() + #admin_config.REBROADCAST_NIP89 = False + #admin_config.UPDATE_PROFILE = False + #dvm = build_example("Bygones", "discovery_inactive_follows", admin_config) + #dvm.run() - keep_alive() + #keep_alive() diff --git a/nostr_dvm/tasks/imagegeneration_openai_dalle.py b/nostr_dvm/tasks/imagegeneration_openai_dalle.py index 920bfa0..3412784 100644 --- a/nostr_dvm/tasks/imagegeneration_openai_dalle.py +++ b/nostr_dvm/tasks/imagegeneration_openai_dalle.py @@ -1,5 +1,6 @@ import json import os +import time from io import BytesIO from pathlib import Path @@ -28,10 +29,12 @@ class ImageGenerationDALLE(DVMTaskInterface): KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE TASK: str = "text-to-image" 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, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) def is_input_supported(self, tags): @@ -107,6 +110,7 @@ class ImageGenerationDALLE(DVMTaskInterface): n=int(options['number']), ) + image_url = response.data[0].url # rehost the result instead of relying on the openai link 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) -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} ') +def process_venv(): + args = DVMTaskInterface.process_args() + dvm_config = build_default_config(args.identifier) + dvm = ImageGenerationDALLE(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None) + result = "" + while result == "": + 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() diff --git a/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py b/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py index 480d0ba..0aa7ab0 100644 --- a/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py +++ b/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py @@ -1,15 +1,11 @@ import json import os from io import BytesIO -from pathlib import Path - -import dotenv import requests from PIL import Image from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface 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.dvmconfig import DVMConfig, build_default_config 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 TASK: str = "text-to-image" 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, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) def is_input_supported(self, tags): @@ -147,18 +145,26 @@ def build_example(name, identifier, admin_config): 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} ') +def process_venv(): + args = DVMTaskInterface.process_args() + dvm_config = build_default_config(args.identifier) + dvm = ImageGenerationReplicateSDXL(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None) + result = dvm.process(json.loads(args.request)) + DVMTaskInterface.write_output(result, args.output) - 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() +#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} ') - 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() diff --git a/nostr_dvm/tasks/textextraction_google.py b/nostr_dvm/tasks/textextraction_google.py index cbae2c3..2c24ef7 100644 --- a/nostr_dvm/tasks/textextraction_google.py +++ b/nostr_dvm/tasks/textextraction_google.py @@ -27,10 +27,13 @@ class SpeechToTextGoogle(DVMTaskInterface): TASK: str = "speech-to-text" FIX_COST: float = 10 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, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) if options is None: options = {} @@ -155,20 +158,26 @@ def build_example(name, identifier, admin_config): return SpeechToTextGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config, 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__': - 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} ') +#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("Transcriptor", "speech_recognition", admin_config) +# dvm.run() - admin_config = AdminConfig() - admin_config.REBROADCAST_NIP89 = False - admin_config.UPDATE_PROFILE = False - dvm = build_example("Transcriptor", "speech_recognition", admin_config) - dvm.run() - - keep_alive() + # keep_alive() diff --git a/nostr_dvm/tasks/textextraction_pdf.py b/nostr_dvm/tasks/textextraction_pdf.py index e9062cf..8101840 100644 --- a/nostr_dvm/tasks/textextraction_pdf.py +++ b/nostr_dvm/tasks/textextraction_pdf.py @@ -26,11 +26,13 @@ class TextExtractionPDF(DVMTaskInterface): KIND: int = EventDefinitions.KIND_NIP90_EXTRACT_TEXT TASK: str = "pdf-to-text" 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, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) 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, 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() - admin_config.REBROADCAST_NIP89 = False - admin_config.UPDATE_PROFILE = False - dvm = build_example("PDF Extractor", "pdf_extractor", admin_config) - dvm.run() +#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} ') - 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() diff --git a/nostr_dvm/tasks/textgeneration_llmlite.py b/nostr_dvm/tasks/textgeneration_llmlite.py index 0a692e7..38090d7 100644 --- a/nostr_dvm/tasks/textgeneration_llmlite.py +++ b/nostr_dvm/tasks/textgeneration_llmlite.py @@ -24,10 +24,12 @@ class TextGenerationOLLAMA(DVMTaskInterface): KIND: int = EventDefinitions.KIND_NIP90_GENERATE_TEXT TASK: str = "text-to-text" 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, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) 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) -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} ') +def process_venv(): + args = DVMTaskInterface.process_args() + dvm_config = build_default_config(args.identifier) + dvm = TextGenerationOLLAMA(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None) + result = dvm.process(json.loads(args.request)) + DVMTaskInterface.write_output(result, args.output) - admin_config = AdminConfig() - admin_config.REBROADCAST_NIP89 = False - admin_config.UPDATE_PROFILE = False - dvm = build_example("LLM", "llmlite", admin_config) - dvm.run() +#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("LLM", "llmlite", admin_config) +# dvm.run() - keep_alive() +# keep_alive() diff --git a/nostr_dvm/tasks/translation_google.py b/nostr_dvm/tasks/translation_google.py index 642cf49..e9bcee7 100644 --- a/nostr_dvm/tasks/translation_google.py +++ b/nostr_dvm/tasks/translation_google.py @@ -1,4 +1,5 @@ import json +import os from pathlib import Path import dotenv @@ -25,10 +26,12 @@ class TranslationGoogle(DVMTaskInterface): KIND: int = EventDefinitions.KIND_NIP90_TRANSLATE_TEXT TASK: str = "translation" 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, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) 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) -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() diff --git a/nostr_dvm/tasks/translation_libretranslate.py b/nostr_dvm/tasks/translation_libretranslate.py index 55ab201..9a89c3b 100644 --- a/nostr_dvm/tasks/translation_libretranslate.py +++ b/nostr_dvm/tasks/translation_libretranslate.py @@ -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.nostr_utils import get_referenced_event_by_id, get_event_by_id - """ 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, 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) def is_input_supported(self, tags): @@ -81,9 +81,9 @@ class TranslationLibre(DVMTaskInterface): def process(self, request_form): options = DVMTaskInterface.set_options(request_form) request = { - "q": options["text"], + "q": options["text"], "source": "auto", - "target": options["language"] + "target": options["language"] } if options["libre_api_key"] != "": request["api_key"] = options["libre_api_key"] @@ -95,10 +95,10 @@ class TranslationLibre(DVMTaskInterface): reply = json.loads(response.text) if reply.get("translatedText"): translated_text = reply['translatedText'] - #untested - #confidence = reply["detectedLanguage"]['confidence'] - #language = reply["detectedLanguage"]['language'] - #print(translated_text + "language: " + language + "conf: " + confidence) + # untested + # confidence = reply["detectedLanguage"]['confidence'] + # language = reply["detectedLanguage"]['language'] + # print(translated_text + "language: " + language + "conf: " + confidence) else: return response.text @@ -125,12 +125,18 @@ def build_example(name, identifier, admin_config): "nip90Params": { "language": { "required": False, - "values": ["en", "az", "be", "bg", "bn", "bs", "ca", "ceb", "co", "cs", "cy", "da", "de", "el", "eo", "es", - "et", "eu", "fa", "fi", "fr", "fy", "ga", "gd", "gl", "gu", "ha", "haw", "hi", "hmn", "hr", "ht", - "hu", "hy", "id", "ig", "is", "it", "he", "ja", "jv", "ka", "kk", "km", "kn", "ko", "ku", "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", + "values": ["en", "az", "be", "bg", "bn", "bs", "ca", "ceb", "co", "cs", "cy", "da", "de", "el", "eo", + "es", + "et", "eu", "fa", "fi", "fr", "fy", "ga", "gd", "gl", "gu", "ha", "haw", "hi", "hmn", "hr", + "ht", + "hu", "hy", "id", "ig", "is", "it", "he", "ja", "jv", "ka", "kk", "km", "kn", "ko", "ku", + "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"] } } @@ -143,18 +149,25 @@ def build_example(name, identifier, admin_config): admin_config=admin_config, options=options) -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} ') +def process_venv(): + args = DVMTaskInterface.process_args() + dvm_config = build_default_config(args.identifier) + dvm = TranslationLibre(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None) + result = dvm.process(json.loads(args.request)) + DVMTaskInterface.write_output(result, args.output) - 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() +# 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("Libre Translator", "libre_translator", admin_config) +# dvm.run() +# +# keep_alive() diff --git a/nostr_dvm/tasks/trending_notes_nostrband.py b/nostr_dvm/tasks/trending_notes_nostrband.py index 480de1f..b915ed7 100644 --- a/nostr_dvm/tasks/trending_notes_nostrband.py +++ b/nostr_dvm/tasks/trending_notes_nostrband.py @@ -29,6 +29,7 @@ class TrendingNotesNostrBand(DVMTaskInterface): def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) super().__init__(name, dvm_config, nip89config, admin_config, options) 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, 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__': - 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("Trending Notes on Nostr.band", "trending_notes_nostrband", admin_config) - dvm.run() - - keep_alive() +#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("Trending Notes on Nostr.band", "trending_notes_nostrband", admin_config) +# dvm.run() +# +# keep_alive() diff --git a/nostr_dvm/tasks/videogeneration_replicate_svd.py b/nostr_dvm/tasks/videogeneration_replicate_svd.py index 9114446..7bf2fe8 100644 --- a/nostr_dvm/tasks/videogeneration_replicate_svd.py +++ b/nostr_dvm/tasks/videogeneration_replicate_svd.py @@ -1,5 +1,6 @@ import json import os +import subprocess from io import BytesIO from pathlib import Path @@ -30,12 +31,18 @@ class VideoGenerationReplicateSVD(DVMTaskInterface): KIND: int = EventDefinitions.KIND_NIP90_GENERATE_VIDEO TASK: str = "image-to-video" 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, 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) + + + def is_input_supported(self, tags): for tag in tags: 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, 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() - admin_config.REBROADCAST_NIP89 = False - admin_config.UPDATE_PROFILE = False - - dvm = build_example("Stable Video Diffusion", "replicate_svd", admin_config) - dvm.run() - - keep_alive() +#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("Stable Video Diffusion", "replicate_svd", admin_config) +# dvm.run() +# +# keep_alive() diff --git a/nostr_dvm/utils/dvmconfig.py b/nostr_dvm/utils/dvmconfig.py index f43cde4..976cd74 100644 --- a/nostr_dvm/utils/dvmconfig.py +++ b/nostr_dvm/utils/dvmconfig.py @@ -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_URL = 'https://lnbits.com' LN_ADDRESS = '' + SCRIPT = '' + IDENTIFIER = '' DB: str NEW_USER_BALANCE: int = 0 # Free credits for new users NIP89: NIP89Config @@ -36,6 +38,7 @@ class DVMConfig: def build_default_config(identifier): dvm_config = DVMConfig() 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() invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub) dvm_config.LNBITS_INVOICE_KEY = invoice_key diff --git a/tests/test_dvm_client.py b/tests/test_dvm_client.py index 298066e..7a5dd35 100644 --- a/tests/test_dvm_client.py +++ b/tests/test_dvm_client.py @@ -69,7 +69,7 @@ def nostr_client_test_image(prompt): def nostr_client_test_image_private(prompt, cashutoken): 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 @@ -125,13 +125,13 @@ def nostr_client(): 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("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_image("a beautiful purple ostrich watching the sunset") + nostr_client_test_image("a beautiful purple ostrich watching the sunset") #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): def handle(self, relay_url, event): print(f"Received new event from {relay_url}: {event.as_json()}") From f2c7aa3c1e32d06755c80dc4198550a9a89aff4c Mon Sep 17 00:00:00 2001 From: Believethehype Date: Sun, 17 Dec 2023 14:38:58 +0100 Subject: [PATCH 2/2] option to use venv or not per module, added tts --- .gitignore | 1 + main.py | 7 +- nostr_dvm/dvm.py | 28 ++-- nostr_dvm/interfaces/dvmtaskinterface.py | 39 ++--- nostr_dvm/tasks/advanced_search.py | 24 +--- nostr_dvm/tasks/convert_media.py | 27 +--- nostr_dvm/tasks/discovery_inactive_follows.py | 21 +-- .../tasks/imagegeneration_openai_dalle.py | 22 +-- .../tasks/imagegeneration_replicate_sdxl.py | 19 +-- nostr_dvm/tasks/textextraction_google.py | 17 +-- nostr_dvm/tasks/textextraction_pdf.py | 17 +-- nostr_dvm/tasks/textgeneration_llmlite.py | 18 +-- nostr_dvm/tasks/texttospeech.py | 136 ++++++++++++++++++ nostr_dvm/tasks/translation_google.py | 20 +-- nostr_dvm/tasks/translation_libretranslate.py | 17 +-- nostr_dvm/tasks/trending_notes_nostrband.py | 18 +-- .../tasks/videogeneration_replicate_svd.py | 19 +-- nostr_dvm/utils/definitions.py | 24 ++-- nostr_dvm/utils/dvmconfig.py | 3 +- requirements.txt | 107 -------------- tests/test_dvm_client.py | 27 +++- 21 files changed, 247 insertions(+), 364 deletions(-) create mode 100644 nostr_dvm/tasks/texttospeech.py delete mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index 5bb30f3..c2338a8 100644 --- a/.gitignore +++ b/.gitignore @@ -174,3 +174,4 @@ backends/nserver/venv backends/nserver/cache backends/nserver/modules/image_upscale/weights cache/venvs/ +cache/input.wav diff --git a/main.py b/main.py index 79355cf..facadab 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ import dotenv from nostr_dvm.bot import Bot from nostr_dvm.tasks import videogeneration_replicate_svd, imagegeneration_replicate_sdxl, textgeneration_llmlite, \ trending_notes_nostrband, discovery_inactive_follows, translation_google, textextraction_pdf, \ - translation_libretranslate, textextraction_google, convert_media, imagegeneration_openai_dalle + translation_libretranslate, textextraction_google, convert_media, imagegeneration_openai_dalle, texttospeech from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.backend_utils import keep_alive from nostr_dvm.utils.definitions import EventDefinitions @@ -133,6 +133,11 @@ def playground(): ollama = textgeneration_llmlite.build_example("LLM", "llmlite", admin_config) bot_config.SUPPORTED_DVMS.append(ollama) ollama.run() + + tts = texttospeech.build_example("Text To Speech Test", "tts", admin_config) + bot_config.SUPPORTED_DVMS.append(tts) + tts.run() + # Run the bot Bot(bot_config) # Keep the main function alive for libraries that require it, like openai diff --git a/nostr_dvm/dvm.py b/nostr_dvm/dvm.py index 27c09ca..32f899f 100644 --- a/nostr_dvm/dvm.py +++ b/nostr_dvm/dvm.py @@ -473,20 +473,24 @@ class DVM: if task == dvm.TASK: request_form = dvm.create_request_from_nostr_event(job_event, self.client, self.dvm_config) - 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..") + if dvm_config.USE_OWN_VENV: + python_bin = (r'cache/venvs/' + os.path.basename(dvm_config.SCRIPT).split(".py")[0] + + "/bin/python") + retcode = subprocess.call([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')) + with open(os.path.abspath('output.txt')) as f: + result = f.readlines()[0] + print(result) + #f.close() + os.remove(os.path.abspath('output.txt')) + else: #Some components might have issues with running code in otuside venv. + # We install locally in these cases for now + result = dvm.process(request_form) try: post_processed = dvm.post_process(str(result), job_event) send_nostr_reply_event(post_processed, job_event.as_json()) diff --git a/nostr_dvm/interfaces/dvmtaskinterface.py b/nostr_dvm/interfaces/dvmtaskinterface.py index 83125d7..1d0d08d 100644 --- a/nostr_dvm/interfaces/dvmtaskinterface.py +++ b/nostr_dvm/interfaces/dvmtaskinterface.py @@ -9,7 +9,7 @@ from nostr_sdk import Keys from nostr_dvm.dvm import DVM from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.dvmconfig import DVMConfig -from nostr_dvm.utils.nip89_utils import NIP89Config +from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag from nostr_dvm.utils.output_utils import post_process_result @@ -28,13 +28,11 @@ class DVMTaskInterface: admin_config: AdminConfig dependencies = [] - def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, admin_config: AdminConfig = None, options=None, task=None): self.init(name, dvm_config, admin_config, nip89config, task) self.options = options - self.make_venv(dvm_config) - + self.install_dependencies(dvm_config) def init(self, name, dvm_config, admin_config=None, nip89config=None, task=None): self.NAME = name @@ -58,15 +56,24 @@ class DVMTaskInterface: self.dvm_config = dvm_config self.admin_config = admin_config - def make_venv(self, dvm_config): + def install_dependencies(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) + if self.dvm_config.USE_OWN_VENV: + 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 Venv Module: " + module) + run(["bin/pip", "install", package], cwd=dir) + else: + for module, package in self.dependencies: + if module != "nostr-dvm": + try: + __import__(module) + except ImportError: + print("Installing global Module: " + module) + subprocess.check_call([sys.executable, "-m", "pip", "install", package]) def run(self): nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config]) @@ -120,10 +127,4 @@ class DVMTaskInterface: 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() + # f.close() diff --git a/nostr_dvm/tasks/advanced_search.py b/nostr_dvm/tasks/advanced_search.py index 7bd2816..217ea18 100644 --- a/nostr_dvm/tasks/advanced_search.py +++ b/nostr_dvm/tasks/advanced_search.py @@ -1,14 +1,10 @@ import json import os from datetime import timedelta -from pathlib import Path - -import dotenv from nostr_sdk import Client, Timestamp, PublicKey, Tag, Keys, Options, SecretKey from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface 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.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag @@ -186,21 +182,5 @@ def process_venv(): result = dvm.process(json.loads(args.request)) DVMTaskInterface.write_output(result, args.output) -#if __name__ == '__main__': -# 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() - #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() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/convert_media.py b/nostr_dvm/tasks/convert_media.py index 20ff106..0de9ba6 100644 --- a/nostr_dvm/tasks/convert_media.py +++ b/nostr_dvm/tasks/convert_media.py @@ -1,12 +1,7 @@ import json import os -from pathlib import Path - -import dotenv - from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface 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.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag @@ -102,8 +97,7 @@ def build_example(name, identifier, admin_config): } nip89config = NIP89Config() - nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"]) - nip89config.CONTENT = json.dumps(nip89info) + return MediaConverter(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config) @@ -115,21 +109,6 @@ def process_venv(): 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("Media Bringer", "media_converter", admin_config) - #dvm.run() - - #keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/discovery_inactive_follows.py b/nostr_dvm/tasks/discovery_inactive_follows.py index 6a52df5..961380e 100644 --- a/nostr_dvm/tasks/discovery_inactive_follows.py +++ b/nostr_dvm/tasks/discovery_inactive_follows.py @@ -1,15 +1,12 @@ import json import os from datetime import timedelta -from pathlib import Path from threading import Thread -import dotenv from nostr_sdk import Client, Timestamp, PublicKey, Tag, Keys, Options from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface 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.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag @@ -206,19 +203,5 @@ def process_venv(): 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("Bygones", "discovery_inactive_follows", admin_config) - #dvm.run() - - #keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/imagegeneration_openai_dalle.py b/nostr_dvm/tasks/imagegeneration_openai_dalle.py index 3412784..86ebdcb 100644 --- a/nostr_dvm/tasks/imagegeneration_openai_dalle.py +++ b/nostr_dvm/tasks/imagegeneration_openai_dalle.py @@ -2,15 +2,12 @@ import json import os import time from io import BytesIO -from pathlib import Path -import dotenv import requests from PIL import Image from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface 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.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag @@ -129,6 +126,7 @@ class ImageGenerationDALLE(DVMTaskInterface): # playground or elsewhere def build_example(name, identifier, admin_config): dvm_config = build_default_config(identifier) + dvm_config.USE_OWN_VENV = True admin_config.LUD16 = dvm_config.LN_ADDRESS profit_in_sats = 10 cost_in_cent = 4.0 @@ -167,19 +165,5 @@ def process_venv(): 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() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py b/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py index 0aa7ab0..5c3cdec 100644 --- a/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py +++ b/nostr_dvm/tasks/imagegeneration_replicate_sdxl.py @@ -6,6 +6,7 @@ from PIL import Image from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface 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.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag @@ -152,19 +153,5 @@ def process_venv(): 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("Stable Diffusion XL", "replicate_sdxl", admin_config) - #dvm.run() - - #keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/textextraction_google.py b/nostr_dvm/tasks/textextraction_google.py index 2c24ef7..f5c6b69 100644 --- a/nostr_dvm/tasks/textextraction_google.py +++ b/nostr_dvm/tasks/textextraction_google.py @@ -166,18 +166,5 @@ def process_venv(): 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() -# admin_config.REBROADCAST_NIP89 = False -# admin_config.UPDATE_PROFILE = False -# dvm = build_example("Transcriptor", "speech_recognition", admin_config) -# dvm.run() - - # keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/textextraction_pdf.py b/nostr_dvm/tasks/textextraction_pdf.py index 8101840..d578299 100644 --- a/nostr_dvm/tasks/textextraction_pdf.py +++ b/nostr_dvm/tasks/textextraction_pdf.py @@ -126,18 +126,5 @@ def process_venv(): 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() -# admin_config.REBROADCAST_NIP89 = False -# admin_config.UPDATE_PROFILE = False -# dvm = build_example("PDF Extractor", "pdf_extractor", admin_config) -# dvm.run() - -# keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/textgeneration_llmlite.py b/nostr_dvm/tasks/textgeneration_llmlite.py index 38090d7..9bee4c1 100644 --- a/nostr_dvm/tasks/textgeneration_llmlite.py +++ b/nostr_dvm/tasks/textgeneration_llmlite.py @@ -135,19 +135,5 @@ def process_venv(): 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() -# admin_config.REBROADCAST_NIP89 = False -# admin_config.UPDATE_PROFILE = False -# -# dvm = build_example("LLM", "llmlite", admin_config) -# dvm.run() - -# keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/texttospeech.py b/nostr_dvm/tasks/texttospeech.py new file mode 100644 index 0000000..1e99d1a --- /dev/null +++ b/nostr_dvm/tasks/texttospeech.py @@ -0,0 +1,136 @@ +import json +import os +os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1" +from pathlib import Path + +from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface +from nostr_dvm.utils.admin_utils import AdminConfig +from nostr_dvm.utils.definitions import EventDefinitions +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.output_utils import upload_media_to_hoster + +""" +This File contains a Module to generate Audio based on an input and a voice + +Accepted Inputs: Text +Outputs: Generated Audiofile +""" + + +class TextToSpeech(DVMTaskInterface): + KIND: int = EventDefinitions.KIND_NIP90_TEXT_TO_SPEECH + TASK: str = "text-to-speech" + FIX_COST: float = 0 + dependencies = [("nostr-dvm", "nostr-dvm"), + ("TTS", "TTS==0.22.0")] + + def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, + admin_config: AdminConfig = None, options=None): + dvm_config.SCRIPT = os.path.abspath(__file__) + super().__init__(name, dvm_config, nip89config, admin_config, options) + + def is_input_supported(self, tags): + for tag in tags: + if tag.as_vec()[0] == 'i': + input_value = tag.as_vec()[1] + input_type = tag.as_vec()[2] + if input_type != "text": + return False + + return True + + def create_request_from_nostr_event(self, event, client=None, dvm_config=None): + request_form = {"jobID": event.id().to_hex() + "_" + self.NAME.replace(" ", "")} + prompt = "test" + if self.options.get("input_file") and self.options.get("input_file") != "": + input_file = self.options['input_file'] + else: + input_file = "https://media.nostr.build/av/de104e3260be636533a56fd4468b905c1eb22b226143a997aa936b011122af8a.wav" + import urllib.request + if not Path.exists(Path(r'cache/input.wav')): + urllib.request.urlretrieve(input_file, "cache/input.wav") + language = "en" + + for tag in event.tags(): + if tag.as_vec()[0] == 'i': + input_type = tag.as_vec()[2] + if input_type == "text": + prompt = tag.as_vec()[1] + if input_type == "url": + input_file = tag.as_vec()[1] + elif tag.as_vec()[0] == 'param': + param = tag.as_vec()[1] + if param == "language": # check for param type + language = tag.as_vec()[2] + + options = { + "prompt": prompt, + "input_wav": input_file, + "language": language + } + request_form['options'] = json.dumps(options) + + return request_form + + def process(self, request_form): + import torch + from TTS.api import TTS + options = DVMTaskInterface.set_options(request_form) + device = "cuda" if torch.cuda.is_available() else "cpu" + #else "mps" if torch.backends.mps.is_available() \ + + print(TTS().list_models()) + try: + tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to(device) + + tts.tts_to_file( + text=options["prompt"], + speaker_wav="cache/input.wav", language=options["language"], file_path="outputs/output.wav") + result = upload_media_to_hoster("outputs/output.wav") + return result + except Exception as e: + print("Error in Module: " + str(e)) + raise Exception(e) + + +# We build an example here that we can call by either calling this file directly from the main directory, +# or by adding it to our playground. You can call the example and adjust it to your needs or redefine it in the +# playground or elsewhere +def build_example(name, identifier, admin_config): + dvm_config = build_default_config(identifier) + admin_config.LUD16 = dvm_config.LN_ADDRESS + + options = {'input_file': ""} + + nip89info = { + "name": name, + "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg", + "about": "I Generate Speech from Text", + "encryptionSupported": True, + "cashuAccepted": True, + "nip90Params": { + "language": { + "required": False, + "values": [] + } + } + } + + nip89config = NIP89Config() + nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"]) + nip89config.CONTENT = json.dumps(nip89info) + + return TextToSpeech(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config, + options=options) + + +def process_venv(): + args = DVMTaskInterface.process_args() + dvm_config = build_default_config(args.identifier) + dvm = TextToSpeech(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() \ No newline at end of file diff --git a/nostr_dvm/tasks/translation_google.py b/nostr_dvm/tasks/translation_google.py index e9bcee7..b1f17d8 100644 --- a/nostr_dvm/tasks/translation_google.py +++ b/nostr_dvm/tasks/translation_google.py @@ -154,21 +154,5 @@ def process_venv(): 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() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/translation_libretranslate.py b/nostr_dvm/tasks/translation_libretranslate.py index 9a89c3b..c3d00c7 100644 --- a/nostr_dvm/tasks/translation_libretranslate.py +++ b/nostr_dvm/tasks/translation_libretranslate.py @@ -156,18 +156,5 @@ def process_venv(): 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() -# admin_config.REBROADCAST_NIP89 = False -# admin_config.UPDATE_PROFILE = False -# dvm = build_example("Libre Translator", "libre_translator", admin_config) -# dvm.run() -# -# keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/trending_notes_nostrband.py b/nostr_dvm/tasks/trending_notes_nostrband.py index b915ed7..20c5cd5 100644 --- a/nostr_dvm/tasks/trending_notes_nostrband.py +++ b/nostr_dvm/tasks/trending_notes_nostrband.py @@ -125,19 +125,5 @@ def process_venv(): 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() -# admin_config.REBROADCAST_NIP89 = False -# admin_config.UPDATE_PROFILE = False -# -# dvm = build_example("Trending Notes on Nostr.band", "trending_notes_nostrband", admin_config) -# dvm.run() -# -# keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/tasks/videogeneration_replicate_svd.py b/nostr_dvm/tasks/videogeneration_replicate_svd.py index 7bf2fe8..f283c1c 100644 --- a/nostr_dvm/tasks/videogeneration_replicate_svd.py +++ b/nostr_dvm/tasks/videogeneration_replicate_svd.py @@ -37,7 +37,6 @@ class VideoGenerationReplicateSVD(DVMTaskInterface): def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, 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) @@ -149,19 +148,5 @@ def process_venv(): 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() -# admin_config.REBROADCAST_NIP89 = False -# admin_config.UPDATE_PROFILE = False -# -# dvm = build_example("Stable Video Diffusion", "replicate_svd", admin_config) -# dvm.run() -# -# keep_alive() +if __name__ == '__main__': + process_venv() \ No newline at end of file diff --git a/nostr_dvm/utils/definitions.py b/nostr_dvm/utils/definitions.py index 6c3123e..5191ff0 100644 --- a/nostr_dvm/utils/definitions.py +++ b/nostr_dvm/utils/definitions.py @@ -9,27 +9,29 @@ class EventDefinitions: KIND_NIP94_METADATA = 1063 KIND_FEEDBACK = 7000 KIND_NIP90_EXTRACT_TEXT = 5000 - KIND_NIP90_RESULT_EXTRACT_TEXT = 6000 + KIND_NIP90_RESULT_EXTRACT_TEXT = KIND_NIP90_EXTRACT_TEXT + 1000 KIND_NIP90_SUMMARIZE_TEXT = 5001 - KIND_NIP90_RESULT_SUMMARIZE_TEXT = 6001 + KIND_NIP90_RESULT_SUMMARIZE_TEXT = KIND_NIP90_SUMMARIZE_TEXT + 1000 KIND_NIP90_TRANSLATE_TEXT = 5002 - KIND_NIP90_RESULT_TRANSLATE_TEXT = 6002 + KIND_NIP90_RESULT_TRANSLATE_TEXT = KIND_NIP90_TRANSLATE_TEXT + 1000 + KIND_NIP90_TEXT_TO_SPEECH = 5005 + KIND_NIP90_TEXT_TO_SPEECH_RESULT = KIND_NIP90_TEXT_TO_SPEECH + 1000 KIND_NIP90_GENERATE_TEXT = 5050 - KIND_NIP90_RESULT_GENERATE_TEXT = 6050 + KIND_NIP90_RESULT_GENERATE_TEXT = KIND_NIP90_GENERATE_TEXT + 1000 KIND_NIP90_GENERATE_IMAGE = 5100 - KIND_NIP90_RESULT_GENERATE_IMAGE = 6100 + KIND_NIP90_RESULT_GENERATE_IMAGE = KIND_NIP90_GENERATE_IMAGE + 1000 KIND_NIP90_CONVERT_VIDEO = 5200 - KIND_NIP90_RESULT_CONVERT_VIDEO = 6200 + KIND_NIP90_RESULT_CONVERT_VIDEO = KIND_NIP90_CONVERT_VIDEO + 1000 KIND_NIP90_GENERATE_VIDEO = 5202 - KIND_NIP90_RESULT_GENERATE_VIDEO = 6202 + KIND_NIP90_RESULT_GENERATE_VIDEO = KIND_NIP90_GENERATE_VIDEO + 1000 KIND_NIP90_CONTENT_DISCOVERY = 5300 - KIND_NIP90_RESULT_CONTENT_DISCOVERY = 6300 + KIND_NIP90_RESULT_CONTENT_DISCOVERY = KIND_NIP90_CONTENT_DISCOVERY + 1000 KIND_NIP90_PEOPLE_DISCOVERY = 5301 - KIND_NIP90_RESULT_PEOPLE_DISCOVERY = 6301 + KIND_NIP90_RESULT_PEOPLE_DISCOVERY = KIND_NIP90_PEOPLE_DISCOVERY + 1000 KIND_NIP90_CONTENT_SEARCH = 5302 - KIND_NIP90_RESULTS_CONTENT_SEARCH = 6302 + KIND_NIP90_RESULTS_CONTENT_SEARCH = KIND_NIP90_CONTENT_SEARCH + 1000 KIND_NIP90_GENERIC = 5999 - KIND_NIP90_RESULT_GENERIC = 6999 + KIND_NIP90_RESULT_GENERIC = KIND_NIP90_GENERIC + 1000 ANY_RESULT = [KIND_NIP90_RESULT_EXTRACT_TEXT, KIND_NIP90_RESULT_SUMMARIZE_TEXT, KIND_NIP90_RESULT_TRANSLATE_TEXT, diff --git a/nostr_dvm/utils/dvmconfig.py b/nostr_dvm/utils/dvmconfig.py index 976cd74..38d3c59 100644 --- a/nostr_dvm/utils/dvmconfig.py +++ b/nostr_dvm/utils/dvmconfig.py @@ -23,12 +23,13 @@ class DVMConfig: RELAY_TIMEOUT = 3 EXTERNAL_POST_PROCESS_TYPE = PostProcessFunctionType.NONE # Leave this on None, except the DVM is external - LNBITS_INVOICE_KEY = '' + LNBITS_INVOICE_KEY = '' # Will all automatically generated by default, or read from .env LNBITS_ADMIN_KEY = '' # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users. LNBITS_URL = 'https://lnbits.com' LN_ADDRESS = '' SCRIPT = '' IDENTIFIER = '' + USE_OWN_VENV = True # Make an own venv for each dvm's process function.Disable if you want to install packages into main venv. Only recommended if you dont want to run dvms with different dependency versions DB: str NEW_USER_BALANCE: int = 0 # Free credits for new users NIP89: NIP89Config diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 867beb6..0000000 --- a/requirements.txt +++ /dev/null @@ -1,107 +0,0 @@ -aiohttp==3.9.1 -aiosignal==1.3.1 -anyio==3.7.1 -appdirs==1.4.4 -asn1crypto==1.5.1 -async-timeout==4.0.3 -attrs==23.1.0 -base58==2.1.1 -beautifulsoup4==4.12.2 -bech32==1.2.0 -bip32==3.4 -bitarray==2.8.3 -bitstring==3.1.9 -blessed==1.20.0 -cassidy==0.1.4 -certifi==2023.7.22 -cffi==1.16.0 -charset-normalizer==3.3.2 -click==8.1.7 -coincurve==18.0.0 -cryptography==41.0.4 -decorator==4.4.2 -distro==1.8.0 -ecdsa==0.18.0 -emoji==2.8.0 -enumb==0.1.5 -environs==9.5.0 -eva-decord==0.6.1 -exceptiongroup==1.1.3 -expo==0.1.2 -fastapi==0.103.0 -ffmpegio==0.8.5 -ffmpegio-core==0.8.5 -filelock==3.13.1 -frozenlist==1.4.0 -fsspec==2023.12.1 -h11==0.14.0 -httpcore==0.18.0 -httpx==0.25.1 -huggingface-hub==0.19.4 -idna==3.4 -imageio==2.33.0 -imageio-ffmpeg==0.4.9 -importlib-metadata==6.8.0 -inquirer==3.1.3 -install==1.3.5 -instaloader==4.10.1 -Jinja2==3.1.2 -litellm==1.12.3 -lnurl==0.4.1 -loguru==0.7.2 -MarkupSafe==2.1.3 -marshmallow==3.20.1 -mediatype==0.1.6 -mnemonic==0.20 -moviepy==2.0.0.dev2 -multidict==6.0.4 -nostr-sdk==0.0.5 -numpy==1.26.2 -openai==1.3.5 -outcome==1.2.0 -packaging==23.2 -pandas==2.1.3 -Pillow==10.1.0 -pluggy==1.3.0 -proglog==0.1.10 -pycparser==2.21 -pycryptodome==3.19.0 -pycryptodomex==3.19.0 -pydantic==1.10.13 -pydantic_core==2.14.5 -pypdf==3.17.1 -python-dateutil==2.8.2 -python-dotenv==1.0.0 -python-editor==1.0.4 -pytube==15.0.0 -pytz==2023.3.post1 -PyUpload==0.1.4 -pyuseragents==1.0.5 -PyYAML==6.0.1 -readchar==4.0.5 -regex==2023.10.3 -replicate==0.21.1 -Represent==1.6.0.post0 -requests==2.31.0 -requests-toolbelt==1.0.0 -safeIO==1.2 -six==1.16.0 -sniffio==1.3.0 -socksio==1.0.0 -soupsieve==2.5 -SpeechRecognition==3.10.0 -SQLAlchemy==1.3.24 -sqlalchemy-aio==0.17.0 -starlette==0.27.0 -tiktoken==0.5.2 -tokenizers==0.15.0 -tqdm==4.66.1 -translatepy==2.3 -typing_extensions==4.8.0 -tzdata==2023.3 -urllib3==2.1.0 -uvicorn==0.23.2 -wcwidth==0.2.10 -websocket-client==1.6.4 -yarl==1.9.4 -zipp==3.17.0 \ No newline at end of file diff --git a/tests/test_dvm_client.py b/tests/test_dvm_client.py index 7a5dd35..c0e252f 100644 --- a/tests/test_dvm_client.py +++ b/tests/test_dvm_client.py @@ -65,6 +65,30 @@ def nostr_client_test_image(prompt): config = DVMConfig send_event(event, client=client, dvm_config=config) return event.as_json() +def nostr_client_test_tts(prompt): + keys = Keys.from_sk_str(check_and_set_private_key("test_client")) + + iTag = Tag.parse(["i", prompt, "text"]) + paramTag1 = Tag.parse(["param", "language", "en"]) + + + bidTag = Tag.parse(['bid', str(1000 * 1000), str(1000 * 1000)]) + relaysTag = Tag.parse(['relays', "wss://relay.damus.io", "wss://blastr.f7z.xyz", "wss://relayable.org", + "wss://nostr-pub.wellorder.net"]) + alttag = Tag.parse(["alt", "This is a NIP90 DVM AI task to generate TTSt"]) + event = EventBuilder(EventDefinitions.KIND_NIP90_TEXT_TO_SPEECH, str("Generate an Audio File."), + [iTag, paramTag1, bidTag, relaysTag, alttag]).to_event(keys) + + relay_list = ["wss://relay.damus.io", "wss://blastr.f7z.xyz", "wss://relayable.org", + "wss://nostr-pub.wellorder.net"] + + client = Client(keys) + for relay in relay_list: + client.add_relay(relay) + client.connect() + config = DVMConfig + send_event(event, client=client, dvm_config=config) + return event.as_json() def nostr_client_test_image_private(prompt, cashutoken): @@ -127,8 +151,9 @@ def nostr_client(): #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_tts("Hello, this is a test. One two three.") - nostr_client_test_image("a beautiful purple ostrich watching the sunset") #cashutoken = "cashuAeyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MSwiQyI6IjAyNWU3ODZhOGFkMmExYTg0N2YxMzNiNGRhM2VhMGIyYWRhZGFkOTRiYzA4M2E2NWJjYjFlOTgwYTE1NGIyMDA2NCIsInNlY3JldCI6InQ1WnphMTZKMGY4UElQZ2FKTEg4V3pPck5rUjhESWhGa291LzVzZFd4S0U9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6NCwiQyI6IjAyOTQxNmZmMTY2MzU5ZWY5ZDc3MDc2MGNjZmY0YzliNTMzMzVmZTA2ZGI5YjBiZDg2Njg5Y2ZiZTIzMjVhYWUwYiIsInNlY3JldCI6IlRPNHB5WE43WlZqaFRQbnBkQ1BldWhncm44UHdUdE5WRUNYWk9MTzZtQXM9In0seyJpZCI6InZxc1VRSVorb0sxOSIsImFtb3VudCI6MTYsIkMiOiIwMmRiZTA3ZjgwYmMzNzE0N2YyMDJkNTZiMGI3ZTIzZTdiNWNkYTBhNmI3Yjg3NDExZWYyOGRiZDg2NjAzNzBlMWIiLCJzZWNyZXQiOiJHYUNIdHhzeG9HM3J2WWNCc0N3V0YxbU1NVXczK0dDN1RKRnVwOHg1cURzPSJ9XSwibWludCI6Imh0dHBzOi8vbG5iaXRzLmJpdGNvaW5maXhlc3RoaXMub3JnL2Nhc2h1L2FwaS92MS9ScDlXZGdKZjlxck51a3M1eVQ2SG5rIn1dfQ==" #nostr_client_test_image_private("a beautiful ostrich watching the sunset")