diff --git a/dvm.py b/dvm.py index 9c28ac2..91071f9 100644 --- a/dvm.py +++ b/dvm.py @@ -5,7 +5,7 @@ import emoji from utils.definitions import EventDefinitions, RequiredJobToWatch, JobToWatch from utils.dvmconfig import DVMConfig -from utils.admin_utils import admin_make_database_updates +from utils.admin_utils import admin_make_database_updates, AdminConfig from utils.backend_utils import get_amount_per_task, check_task_is_supported, get_task from utils.database_utils import update_sql_table, get_from_sql_table, \ create_sql_table, get_or_add_user, update_user_balance @@ -23,14 +23,16 @@ if use_logger: class DVM: dvm_config: DVMConfig + admin_config: AdminConfig keys: Keys client: Client job_list: list jobs_on_hold_list: list - def __init__(self, config): - self.dvm_config = config - self.keys = Keys.from_sk_str(config.PRIVATE_KEY) + def __init__(self, dvmconfig, adminconfig = None): + self.dvm_config = dvmconfig + self.admin_config = adminconfig + self.keys = Keys.from_sk_str(dvmconfig.PRIVATE_KEY) self.client = Client(self.keys) self.job_list = [] self.jobs_on_hold_list = [] @@ -54,7 +56,7 @@ class DVM: self.client.subscribe([dm_zap_filter, dvm_filter]) create_sql_table(self.dvm_config.DB) - admin_make_database_updates(config=self.dvm_config, client=self.client) + admin_make_database_updates(adminconfig=self.admin_config, dvmconfig=self.dvm_config, client=self.client) class NotificationHandler(HandleNotification): client = self.client diff --git a/interfaces/dvmtaskinterface.py b/interfaces/dvmtaskinterface.py index e48df54..e5c02db 100644 --- a/interfaces/dvmtaskinterface.py +++ b/interfaces/dvmtaskinterface.py @@ -2,6 +2,7 @@ from utils.nip89_utils import NIP89Announcement class DVMTaskInterface: + NAME: str KIND: int TASK: str COST: int @@ -9,6 +10,7 @@ class DVMTaskInterface: def NIP89_announcement(self, d_tag, content): nip89 = NIP89Announcement() + nip89.name = self.NAME nip89.kind = self.KIND nip89.pk = self.PK nip89.dtag = d_tag diff --git a/main.py b/main.py index 7e65190..864a803 100644 --- a/main.py +++ b/main.py @@ -6,17 +6,23 @@ import utils.env as env from tasks.imagegenerationsdxl import ImageGenerationSDXL from tasks.textextractionpdf import TextExtractionPDF from tasks.translation import Translation +from utils.admin_utils import AdminConfig +from utils.dvmconfig import DVMConfig def run_nostr_dvm_with_local_config(): - from utils.dvmconfig import DVMConfig + #Generate a optional Admin Config, in this case, whenever we give our DVMS this config, they will (re)broadcast + # their NIP89 announcement + admin_config = AdminConfig() + admin_config.REBROADCASTNIP89 = True # Spawn the DVMs - # Add NIP89 events for each DVM (set rebroadcast = True for the next start in admin_utils) + # Add NIP89 events for each DVM # Add the dtag here or in your .env file, so you can update your dvm later and change the content as needed. # Get a dtag and the content at vendata.io - # Spawn DVM1 Kind 5000 Text Ectractor from PDFs + # Spawn DVM1 Kind 5000 Text Extractor from PDFs + dvm_config = DVMConfig() dvm_config.PRIVATE_KEY = os.getenv(env.NOSTR_PRIVATE_KEY) dvm_config.LNBITS_INVOICE_KEY = os.getenv(env.LNBITS_INVOICE_KEY) @@ -28,7 +34,7 @@ def run_nostr_dvm_with_local_config(): "/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669" ".jpg\",\"about\":\"I extract Text from pdf documents\"," "\"nip90Params\":{}}") - dvm_config.NIP89s.append(pdfextactor.NIP89_announcement(d_tag, content)) + dvm_config.NIP89 = pdfextactor.NIP89_announcement(d_tag, content) # Spawn DVM2 Kind 5002 Text Translation dvm_config = DVMConfig() @@ -37,7 +43,6 @@ def run_nostr_dvm_with_local_config(): dvm_config.LNBITS_URL = os.getenv(env.LNBITS_HOST) translator = Translation("Translator", dvm_config) - d_tag = os.getenv(env.TASK_TRANSLATION_NIP89_DTAG) content = "{\"name\":\"" + translator.NAME + ("\",\"image\":\"https://image.nostr.build" "/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669" @@ -57,7 +62,7 @@ def run_nostr_dvm_with_local_config(): "\"ta\",\"te\",\"tg\",\"th\",\"tl\",\"tr\",\"ug\",\"uk\",\"ur\"," "\"uz\",\"vi\",\"xh\",\"yi\",\"yo\",\"zh\",\"zu\"]}}}") - dvm_config.NIP89s.append(translator.NIP89_announcement(d_tag, content)) + dvm_config.NIP89 = translator.NIP89_announcement(d_tag, content) # Spawn DVM3 Kind 5100 Image Generation This one uses a specific backend called nova-server. If you want to use # it see the instructions in backends/nova_server @@ -65,25 +70,26 @@ def run_nostr_dvm_with_local_config(): dvm_config.PRIVATE_KEY = os.getenv(env.NOSTR_PRIVATE_KEY) dvm_config.LNBITS_INVOICE_KEY = os.getenv(env.LNBITS_INVOICE_KEY) dvm_config.LNBITS_URL = os.getenv(env.LNBITS_HOST) - unstableartist = ImageGenerationSDXL("Unstable Diffusion", dvm_config, "unstable") d_tag = os.getenv(env.TASK_IMAGEGENERATION_NIP89_DTAG) content = "{\"name\":\"" + unstableartist.NAME + ("\",\"image\":\"https://image.nostr.build" "/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg" "\",\"about\":\"I draw images based on a prompt with a Model called unstable diffusion.\",\"nip90Params\":{}}") - dvm_config.NIP89s.append(unstableartist.NIP89_announcement(d_tag, content)) + dvm_config.NIP89 = unstableartist.NIP89_announcement(d_tag, content) - # Spawn another Instance of text-to-image but use a different model and lora this time. + + # Spawn another Instance of text-to-image but use a different privatekey, model and lora this time. dvm_config = DVMConfig() dvm_config.PRIVATE_KEY = "73b262d31edc6ea1316dffcc7daa772651d661e6475761b7b78291482c1bf5cb" dvm_config.LNBITS_INVOICE_KEY = os.getenv(env.LNBITS_INVOICE_KEY) dvm_config.LNBITS_URL = os.getenv(env.LNBITS_HOST) - sketcher = ImageGenerationSDXL("Sketcher", dvm_config, "mohawk", "timburton") + #We add an optional AdminConfig for this one, and tell the dvm to rebroadcast its NIP89 + sketcher = ImageGenerationSDXL("Sketcher", dvm_config, admin_config, default_model="mohawk", default_lora="timburton") d_tag = os.getenv(env.TASK_IMAGEGENERATION_NIP89_DTAG2) content = "{\"name\":\"" + sketcher.NAME + ("\",\"image\":\"https://image.nostr.build" "/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg" "\",\"about\":\"I draw images based on a prompt in kind of Tim Burton style\",\"nip90Params\":{}}") - dvm_config.NIP89s.append(sketcher.NIP89_announcement(d_tag, content)) + dvm_config.NIP89 = sketcher.NIP89_announcement(d_tag, content) if __name__ == '__main__': diff --git a/tasks/imagegenerationsdxl.py b/tasks/imagegenerationsdxl.py index 24bb134..1e5199a 100644 --- a/tasks/imagegenerationsdxl.py +++ b/tasks/imagegenerationsdxl.py @@ -5,8 +5,9 @@ from threading import Thread from backends.nova_server import check_nova_server_status, send_request_to_nova_server from dvm import DVM from interfaces.dvmtaskinterface import DVMTaskInterface +from utils.admin_utils import AdminConfig from utils.definitions import EventDefinitions - +from utils.dvmconfig import DVMConfig """ This File contains a Module to transform Text input on NOVA-Server and receive results back. @@ -23,7 +24,7 @@ class ImageGenerationSDXL(DVMTaskInterface): COST: int = 5 PK: str - def __init__(self, name, dvm_config, default_model=None, default_lora=None): + def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None, default_model=None, default_lora=None): self.NAME = name dvm_config.SUPPORTED_TASKS = [self] dvm_config.DB = "db/" + self.NAME + ".db" @@ -32,7 +33,7 @@ class ImageGenerationSDXL(DVMTaskInterface): self.default_lora = default_lora dvm = DVM - nostr_dvm_thread = Thread(target=dvm, args=[dvm_config]) + nostr_dvm_thread = Thread(target=dvm, args=[dvm_config, admin_config]) nostr_dvm_thread.start() diff --git a/tasks/textextractionpdf.py b/tasks/textextractionpdf.py index 27ddc45..ba5bd94 100644 --- a/tasks/textextractionpdf.py +++ b/tasks/textextractionpdf.py @@ -4,7 +4,9 @@ from threading import Thread from dvm import DVM from interfaces.dvmtaskinterface import DVMTaskInterface +from utils.admin_utils import AdminConfig from utils.definitions import EventDefinitions +from utils.dvmconfig import DVMConfig from utils.nostr_utils import get_event_by_id """ @@ -22,14 +24,14 @@ class TextExtractionPDF(DVMTaskInterface): COST: int = 20 PK: str - def __init__(self, name, dvm_config): + def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None): self.NAME = name dvm_config.SUPPORTED_TASKS = [self] dvm_config.DB = "db/" + self.NAME + ".db" self.PK = dvm_config.PRIVATE_KEY dvm = DVM - nostr_dvm_thread = Thread(target=dvm, args=[dvm_config]) + nostr_dvm_thread = Thread(target=dvm, args=[dvm_config, admin_config]) nostr_dvm_thread.start() def is_input_supported(self, input_type, input_content): diff --git a/tasks/translation.py b/tasks/translation.py index 3e25722..afe02d1 100644 --- a/tasks/translation.py +++ b/tasks/translation.py @@ -2,7 +2,9 @@ from threading import Thread from dvm import DVM from interfaces.dvmtaskinterface import DVMTaskInterface +from utils.admin_utils import AdminConfig from utils.definitions import EventDefinitions +from utils.dvmconfig import DVMConfig from utils.nostr_utils import get_referenced_event_by_id, get_event_by_id """ @@ -20,14 +22,14 @@ class Translation(DVMTaskInterface): COST: int = 0 PK: str - def __init__(self, name, dvm_config): + def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None): self.NAME = name dvm_config.SUPPORTED_TASKS = [self] dvm_config.DB = "db/" + self.NAME + ".db" self.PK = dvm_config.PRIVATE_KEY dvm = DVM - nostr_dvm_thread = Thread(target=dvm, args=[dvm_config]) + nostr_dvm_thread = Thread(target=dvm, args=[dvm_config, admin_config]) nostr_dvm_thread.start() def is_input_supported(self, input_type, input_content): diff --git a/utils/admin_utils.py b/utils/admin_utils.py index feea351..a178daa 100644 --- a/utils/admin_utils.py +++ b/utils/admin_utils.py @@ -5,30 +5,49 @@ from nostr_sdk import Keys, EventBuilder, PublicKey from utils.database_utils import get_from_sql_table, list_db, delete_from_sql_table, update_sql_table, \ get_or_add_user, clean_db +from utils.dvmconfig import DVMConfig from utils.nip89_utils import nip89_announce_tasks from utils.nostr_utils import send_event class AdminConfig: REBROADCASTNIP89: bool = False + WHITELISTUSER: bool = False + UNWHITELISTUSER: bool = False + BLACKLISTUSER: bool = False + DELETEUSER: bool = False + LISTDATABASE: bool = False + ClEANDB: bool = False + USERNPUB: str = "" -def admin_make_database_updates(config=None, client=None): +def admin_make_database_updates(adminconfig: AdminConfig = None, dvmconfig: DVMConfig = None, client=None): # This is called on start of Server, Admin function to manually whitelist/blacklist/add balance/delete users - dvmconfig = config - db = config.DB + if adminconfig is None or dvmconfig is None: + return - rebroadcast_nip89 = False - cleandb = False - listdatabase = False - deleteuser = False - whitelistuser = False - unwhitelistuser = False - blacklistuser = False + if not isinstance(adminconfig, AdminConfig): + return + + if ((adminconfig.WHITELISTUSER is True or adminconfig.UNWHITELISTUSER is True or adminconfig.BLACKLISTUSER is True or adminconfig.DELETEUSER is True) + and adminconfig.USERNPUB == ""): + return - # publickey = PublicKey.from_bech32("npub1...").to_hex() - # use this if you have the npub - publickey = "asd123" - #use this if you have hex + db = dvmconfig.DB + + rebroadcast_nip89 = adminconfig.REBROADCASTNIP89 + cleandb = adminconfig.ClEANDB + listdatabase = adminconfig.LISTDATABASE + deleteuser = adminconfig.DELETEUSER + whitelistuser = adminconfig.WHITELISTUSER + unwhitelistuser = adminconfig.UNWHITELISTUSER + blacklistuser = adminconfig.BLACKLISTUSER + + if adminconfig.USERNPUB != "": + if str(adminconfig.USERNPUB).startswith("npub"): + publickey = PublicKey.from_bech32(adminconfig.USERNPUB).to_hex() + else: + publickey = adminconfig.USERNPUB + if whitelistuser: user = get_or_add_user(db, publickey) diff --git a/utils/dvmconfig.py b/utils/dvmconfig.py index e5804b2..3de7079 100644 --- a/utils/dvmconfig.py +++ b/utils/dvmconfig.py @@ -1,6 +1,7 @@ import os from utils import env +from utils.nip89_utils import NIP89Announcement class DVMConfig: @@ -13,10 +14,11 @@ class DVMConfig: RELAY_TIMEOUT = 5 LNBITS_INVOICE_KEY = '' LNBITS_URL = 'https://lnbits.com' - REQUIRES_NIP05: bool = False DB: str + NIP89: NIP89Announcement + REQUIRES_NIP05: bool = False SHOWRESULTBEFOREPAYMENT: bool = True # if this is true show results even when not paid right after autoprocess - NIP89s: list = [] + diff --git a/utils/nip89_utils.py b/utils/nip89_utils.py index 220e53c..65be301 100644 --- a/utils/nip89_utils.py +++ b/utils/nip89_utils.py @@ -2,18 +2,17 @@ from nostr_sdk import Tag, Keys, EventBuilder from utils.nostr_utils import send_event class NIP89Announcement: + name: str kind: int dtag: str pk: str content: str def nip89_announce_tasks(dvmconfig): - for nip89 in dvmconfig.NIP89s: - k_tag = Tag.parse(["k", str(nip89.kind)]) - d_tag = Tag.parse(["d", nip89.dtag]) - keys = Keys.from_sk_str(nip89.pk) - content = nip89.content - event = EventBuilder(31990, content, [k_tag, d_tag]).to_event(keys) - send_event(event, key=keys) - - print("Announced NIP 89") \ No newline at end of file + k_tag = Tag.parse(["k", str(dvmconfig.NIP89.kind)]) + d_tag = Tag.parse(["d", dvmconfig.NIP89.dtag]) + keys = Keys.from_sk_str(dvmconfig.NIP89.pk) + content = dvmconfig.NIP89.content + event = EventBuilder(31990, content, [k_tag, d_tag]).to_event(keys) + send_event(event, key=keys) + print("Announced NIP 89 for " + dvmconfig.NIP89.name) \ No newline at end of file