move set_options to class, improve print messages, colored print messages

This commit is contained in:
Believethehype 2024-05-31 10:27:18 +02:00
parent b8cd322150
commit c26db73650
35 changed files with 188 additions and 176 deletions

View File

@ -22,6 +22,7 @@ from nostr_dvm.utils.output_utils import build_status_reaction
from nostr_dvm.utils.zap_utils import check_bolt11_ln_bits_is_paid, create_bolt11_ln_bits, parse_zap_event_tags, \
parse_amount_from_bolt11_invoice, zaprequest, pay_bolt11_ln_bits, create_bolt11_lud16
from nostr_dvm.utils.cashu_utils import redeem_cashu
from nostr_dvm.utils.print import bcolors
class DVM:
@ -47,9 +48,10 @@ class DVM:
self.job_list = []
self.jobs_on_hold_list = []
pk = self.keys.public_key()
print("Nostr DVM public key: " + str(pk.to_bech32()) + " Hex: " + str(pk.to_hex()) + " Supported DVM tasks: " +
', '.join(p.NAME + ":" + p.TASK for p in self.dvm_config.SUPPORTED_DVMS) + "\n")
print(bcolors.GREEN + "[" + self.dvm_config.NIP89.NAME + "] " + "Nostr DVM public key: " + str(
pk.to_bech32()) + " Hex: " +
str(pk.to_hex()) + " Supported DVM tasks: " +
', '.join(p.NAME + ":" + p.TASK for p in self.dvm_config.SUPPORTED_DVMS) + bcolors.ENDC)
for relay in self.dvm_config.RELAY_LIST:
self.client.add_relay(relay)
@ -88,7 +90,7 @@ class DVM:
# if event is encrypted, but we can't decrypt it (e.g. because its directed to someone else), return
if nip90_event is None:
return
task_is_free = False
user_has_active_subscription = False
cashu = ""
@ -104,7 +106,6 @@ class DVM:
print("[" + self.dvm_config.NIP89.NAME + "] No public request, also not addressed to me.")
return
# check if task is supported by the current DVM
task_supported, task = check_task_is_supported(nip90_event, client=self.client,
config=self.dvm_config)
@ -119,17 +120,16 @@ class DVM:
print("[" + self.dvm_config.NIP89.NAME + "] Request by blacklisted user, skipped")
return
print("[" + self.dvm_config.NIP89.NAME + "] Received new Request: " + task + " from " + user.name)
print(bcolors.MAGENTA + "[" + self.dvm_config.NIP89.NAME + "] Received new Request: " + task + " from " + user.name + bcolors.ENDC)
duration = input_data_file_duration(nip90_event, dvm_config=self.dvm_config, client=self.client)
amount = get_amount_per_task(task, self.dvm_config, duration)
if amount is None:
return
# If this is a subscription DVM and the Task is directed to us, check for active subscription
if dvm_config.NIP88 is not None and p_tag_str == self.dvm_config.PUBLIC_KEY:
send_job_status_reaction(nip90_event, "subscription-required", True, amount, self.client,
"Checking Subscription Status, please wait..",self.dvm_config)
"Checking Subscription Status, please wait..", self.dvm_config)
# if we stored in the database that the user has an active subscription, we don't need to check it
print("User Subscription: " + str(user.subscribed) + " Current time: " + str(
Timestamp.now().as_secs()))
@ -139,7 +139,8 @@ class DVM:
user_has_active_subscription = True
send_job_status_reaction(nip90_event, "subscription-required", True, amount,
self.client, "User subscripton active until " +
Timestamp.from_secs(int(user.subscribed)).to_human_datetime().replace("Z", " ").replace("T", " ") + " GMT", self.dvm_config)
Timestamp.from_secs(int(user.subscribed)).to_human_datetime().replace(
"Z", " ").replace("T", " ") + " GMT", self.dvm_config)
# otherwise we check for an active subscription by checking recipie events
else:
print("[" + self.dvm_config.NIP89.NAME + "] Checking Subscription status")
@ -153,7 +154,11 @@ class DVM:
if subscription_status["isActive"]:
send_job_status_reaction(nip90_event, "subscription-required", True, amount, self.client,
"User subscripton active until " + Timestamp.from_secs(int(subscription_status["validUntil"])).to_human_datetime().replace("Z", " ").replace("T", " ") + " GMT",
"User subscripton active until " + Timestamp.from_secs(int(
subscription_status[
"validUntil"])).to_human_datetime().replace("Z",
" ").replace(
"T", " ") + " GMT",
self.dvm_config)
print("Checked Recipe: User subscribed until: " + str(
Timestamp.from_secs(int(subscription_status["validUntil"])).to_human_datetime()))
@ -349,12 +354,12 @@ class DVM:
# update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client,
# config=self.dvm_config)
# a regular note
# a regular note
elif not anon and dvm_config.NIP88 is None:
print("[" + self.dvm_config.NIP89.NAME + "] Profile Zap received for DVM balance: " +
str(invoice_amount) + " Sats from " + str(user.name))
# update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client,
# config=self.dvm_config)
# update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client,
# config=self.dvm_config)
except Exception as e:
print("[" + self.dvm_config.NIP89.NAME + "] Error during content decryption: " + str(e))
@ -472,8 +477,9 @@ class DVM:
self.keys)
send_event(reply_event, client=self.client, dvm_config=self.dvm_config)
print("[" + self.dvm_config.NIP89.NAME + "] " + str(
original_event.kind().as_u64() + 1000) + " Job Response event sent: " + reply_event.as_json())
print(bcolors.GREEN + "[" + self.dvm_config.NIP89.NAME + "] " + str(
original_event.kind().as_u64() + 1000) + " Job Response event sent: " + reply_event.as_json() + bcolors.ENDC)
def send_job_status_reaction(original_event, status, is_paid=True, amount=0, client=None,
content=None,
@ -503,7 +509,6 @@ class DVM:
else:
reply_tags.append(p_tag)
if status == "success" or status == "error": #
for x in self.job_list:
if x.event == original_event:
@ -572,8 +577,9 @@ class DVM:
keys = Keys.parse(dvm_config.PRIVATE_KEY)
reaction_event = EventBuilder(EventDefinitions.KIND_FEEDBACK, str(content), reply_tags).to_event(keys)
send_event(reaction_event, client=self.client, dvm_config=self.dvm_config)
print("[" + self.dvm_config.NIP89.NAME + "]" + ": Sent Kind " + str(
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + status + " " + reaction_event.as_json())
print(bcolors.YELLOW + "[" + self.dvm_config.NIP89.NAME + "]" + " Sent Kind " + str(
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + status + " " + reaction_event.as_json() + bcolors.ENDC)
return reaction_event.as_json()
def do_work(job_event, amount):
@ -618,11 +624,13 @@ class DVM:
post_processed = dvm.post_process(result, job_event)
send_nostr_reply_event(post_processed, job_event.as_json())
except Exception as e:
print(e)
print(bcolors.RED + "[" + self.dvm_config.NIP89.NAME + "] Error: " + str(e) + bcolors.ENDC)
send_job_status_reaction(job_event, "error", content=str(e),
dvm_config=self.dvm_config)
except Exception as e:
print(e)
print(
bcolors.RED + "[" + self.dvm_config.NIP89.NAME + "] Error: " + str(e) + bcolors.ENDC)
# we could send the exception here to the user, but maybe that's not a good idea after all.
send_job_status_reaction(job_event, "error", content=result,
dvm_config=self.dvm_config)

View File

@ -123,13 +123,13 @@ class DVMTaskInterface:
"""Post-process the data and return the result Use default function, if not overwritten"""
return post_process_result(result, event)
@staticmethod
def set_options(request_form):
print("Setting options...")
def set_options(self, request_form):
print("[" + self.dvm_config.NIP89.NAME + "] " + "Setting options...")
opts = []
if request_form.get("options"):
opts = json.loads(request_form["options"])
print(opts)
print("[" + self.dvm_config.NIP89.NAME + "] " + str(opts))
return dict(opts)
@staticmethod

View File

@ -87,7 +87,7 @@ class AdvancedSearch(DVMTaskInterface):
def process(self, request_form):
from nostr_sdk import Filter
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT)))
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)

View File

@ -89,7 +89,7 @@ class AdvancedSearchWine(DVMTaskInterface):
def process(self, request_form):
from nostr_sdk import Filter
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
userkeys = []
for user in options["users"]:
tag = Tag.parse(user)

View File

@ -58,7 +58,6 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
if self.logger:
init_logger(LogLevel.DEBUG)
if self.dvm_config.UPDATE_DATABASE:
self.sync_db()
@ -76,7 +75,6 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
def create_request_from_nostr_event(self, event, client=None, dvm_config=None):
self.dvm_config = dvm_config
print(self.dvm_config.PRIVATE_KEY)
request_form = {"jobID": event.id().to_hex()}
@ -111,13 +109,11 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
from types import SimpleNamespace
ns = SimpleNamespace()
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
database = NostrDatabase.sqlite(self.db_name)
cli = ClientBuilder().database(database).build()
# Negentropy reconciliation
# Query events from database
timestamp_hour_ago = Timestamp.now().as_secs() - self.db_since
@ -125,6 +121,8 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
filter1 = Filter().kind(definitions.EventDefinitions.KIND_NOTE).since(since)
events = cli.database().query([filter1])
print("[" + self.dvm_config.NIP89.NAME + "] Considering " + str(len(events)) + " Events")
ns.finallist = {}
for event in events:
if event.created_at().as_secs() > timestamp_hour_ago:
@ -138,7 +136,6 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
result_list = []
finallist_sorted = sorted(ns.finallist.items(), key=lambda x: x[1], reverse=True)[:int(options["max_results"])]
for entry in finallist_sorted:
# print(EventId.parse(entry[0]).to_bech32() + "/" + EventId.parse(entry[0]).to_hex() + ": " + str(entry[1]))
e_tag = Tag.parse(["e", entry[0]])
result_list.append(e_tag.as_vec())
@ -167,7 +164,7 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
try:
self.result = self.calculate_result(self.request_form)
except Exception as e:
print("EXCEPTION: "+ e)
print("EXCEPTION: " + str(e))
return 1
def sync_db(self):
@ -191,21 +188,22 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
definitions.EventDefinitions.KIND_ZAP]).since(lasthour) # Notes, reactions, zaps
# filter = Filter().author(keys.public_key())
print("[" + self.dvm_config.IDENTIFIER + "] Syncing notes of the last " + str(
print("[" + self.dvm_config.NIP89.NAME + "] Syncing notes of the last " + str(
self.db_since) + " seconds.. this might take a while..")
dbopts = NegentropyOptions().direction(NegentropyDirection.DOWN)
cli.reconcile(filter1, dbopts)
database.delete(Filter().until(Timestamp.from_secs(
Timestamp.now().as_secs() - self.db_since))) # Clear old events so db doesnt get too full.
filter_delete = Filter().until(Timestamp.from_secs(Timestamp.now().as_secs() - self.db_since))
database.delete(filter_delete) # Clear old events so db doesn't get too full.
print(
"[" + self.dvm_config.IDENTIFIER + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
"[" + self.dvm_config.NIP89.NAME + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
# 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, options, cost=0, update_rate=180, processing_msg=None, update_db=True):
def build_example(name, identifier, admin_config, options, cost=0, update_rate=180, processing_msg=None,
update_db=True):
dvm_config = build_default_config(identifier)
dvm_config.USE_OWN_VENV = False
dvm_config.SHOWLOG = True
@ -244,14 +242,15 @@ def build_example(name, identifier, admin_config, options, cost=0, update_rate=
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"])
nip89config.CONTENT = json.dumps(nip89info)
#admin_config.UPDATE_PROFILE = False
#admin_config.REBROADCAST_NIP89 = False
# admin_config.UPDATE_PROFILE = False
# admin_config.REBROADCAST_NIP89 = False
return DicoverContentCurrentlyPopular(name=name, dvm_config=dvm_config, nip89config=nip89config,
admin_config=admin_config, options=options)
def build_example_subscription(name, identifier, admin_config, options, update_rate=180, processing_msg=None, update_db=True):
def build_example_subscription(name, identifier, admin_config, options, update_rate=180, processing_msg=None,
update_db=True):
dvm_config = build_default_config(identifier)
dvm_config.USE_OWN_VENV = False
dvm_config.SHOWLOG = True
@ -301,9 +300,9 @@ def build_example_subscription(name, identifier, admin_config, options, update_r
nip88config.PERK2DESC = "Support NostrDVM & NostrSDK development"
nip88config.PAYMENT_VERIFIER_PUBKEY = "5b5c045ecdf66fb540bdf2049fe0ef7f1a566fa427a4fe50d400a011b65a3a7e"
#admin_config.UPDATE_PROFILE = False
#admin_config.REBROADCAST_NIP89 = False
#admin_config.REBROADCAST_NIP88 = False
# admin_config.UPDATE_PROFILE = False
# admin_config.REBROADCAST_NIP89 = False
# admin_config.REBROADCAST_NIP88 = False
# admin_config.FETCH_NIP88 = True
# admin_config.EVENTID = ""

View File

@ -58,7 +58,6 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
if self.logger:
init_logger(LogLevel.DEBUG)
print("UPDATEDB: " + str(self.dvm_config.UPDATE_DATABASE))
if self.dvm_config.UPDATE_DATABASE:
self.sync_db()
@ -76,7 +75,6 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
def create_request_from_nostr_event(self, event, client=None, dvm_config=None):
self.dvm_config = dvm_config
print(self.dvm_config.PRIVATE_KEY)
request_form = {"jobID": event.id().to_hex()}
@ -110,7 +108,7 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
from types import SimpleNamespace
ns = SimpleNamespace()
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
database = NostrDatabase.sqlite(self.db_name)
cli = ClientBuilder().database(database).build()
@ -122,6 +120,8 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
filter1 = Filter().kind(definitions.EventDefinitions.KIND_NOTE).since(since)
events = cli.database().query([filter1])
print("[" + self.dvm_config.NIP89.NAME + "] Considering " + str(len(events)) + " Events")
ns.finallist = {}
for event in events:
if event.created_at().as_secs() > timestamp_hour_ago:
@ -198,15 +198,15 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
definitions.EventDefinitions.KIND_ZAP]).since(lasthour) # Notes, reactions, zaps
# filter = Filter().author(keys.public_key())
print("[" + self.dvm_config.IDENTIFIER + "] Syncing notes of the last " + str(
print("[" + self.dvm_config.NIP89.NAME + "] Syncing notes of the last " + str(
self.db_since) + " seconds.. this might take a while..")
dbopts = NegentropyOptions().direction(NegentropyDirection.DOWN)
cli.reconcile(filter1, dbopts)
database.delete(Filter().until(Timestamp.from_secs(
Timestamp.now().as_secs() - self.db_since))) # Clear old events so db doesnt get too full.
filter_delete = Filter().until(Timestamp.from_secs(Timestamp.now().as_secs() - self.db_since))
database.delete(filter_delete) # Clear old events so db doesn't get too full.
print(
"[" + self.dvm_config.IDENTIFIER + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
"[" + self.dvm_config.NIP89.NAME + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
# We build an example here that we can call by either calling this file directly from the main directory,

View File

@ -65,7 +65,6 @@ class DicoverContentCurrentlyPopularFollowers(DVMTaskInterface):
def create_request_from_nostr_event(self, event: Event, client=None, dvm_config=None):
self.dvm_config = dvm_config
print(self.dvm_config.PRIVATE_KEY)
request_form = {"jobID": event.id().to_hex()}
@ -95,7 +94,7 @@ class DicoverContentCurrentlyPopularFollowers(DVMTaskInterface):
from types import SimpleNamespace
ns = SimpleNamespace()
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
relaylimits = RelayLimits.disable()
opts = (
@ -143,6 +142,7 @@ class DicoverContentCurrentlyPopularFollowers(DVMTaskInterface):
filter1 = Filter().kind(definitions.EventDefinitions.KIND_NOTE).authors(followings).since(since)
events = cli.database().query([filter1])
print("[" + self.dvm_config.NIP89.NAME + "] Considering " + str(len(events)) + " Events")
ns.finallist = {}
for event in events:
@ -207,15 +207,14 @@ class DicoverContentCurrentlyPopularFollowers(DVMTaskInterface):
definitions.EventDefinitions.KIND_ZAP]).since(lasthour) # Notes, reactions, zaps
# filter = Filter().author(keys.public_key())
print("[" + self.dvm_config.IDENTIFIER + "] Syncing notes of the last " + str(
print("[" + self.dvm_config.NIP89.NAME + "] Syncing notes of the last " + str(
self.db_since) + " seconds.. this might take a while..")
dbopts = NegentropyOptions().direction(NegentropyDirection.DOWN)
cli.reconcile(filter1, dbopts)
database.delete(Filter().until(Timestamp.from_secs(
Timestamp.now().as_secs() - self.db_since))) # Clear old events so db doesnt get too full.
filter_delete = Filter().until(Timestamp.from_secs(Timestamp.now().as_secs() - self.db_since))
database.delete(filter_delete) # Clear old events so db doesn't get too full.
print(
"[" + self.dvm_config.IDENTIFIER + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
"[" + self.dvm_config.NIP89.NAME + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
# We build an example here that we can call by either calling this file directly from the main directory,

View File

@ -89,8 +89,6 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
def create_request_from_nostr_event(self, event, client=None, dvm_config=None):
self.dvm_config = dvm_config
print(self.dvm_config.PRIVATE_KEY)
request_form = {"jobID": event.id().to_hex()}
# default values
@ -135,28 +133,18 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
from types import SimpleNamespace
ns = SimpleNamespace()
options = DVMTaskInterface.set_options(request_form)
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT)))
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
keys = Keys.parse(sk.to_hex())
signer = NostrSigner.keys(keys)
options = self.set_options(request_form)
database = NostrDatabase.sqlite(self.db_name)
cli = ClientBuilder().database(database).build()
# cli.add_relay("wss://relay.damus.io")
# cli.connect()
# Negentropy reconciliation
# Query events from database
timestamp_since = Timestamp.now().as_secs() - self.db_since
since = Timestamp.from_secs(timestamp_since)
filter1 = Filter().kind(definitions.EventDefinitions.KIND_NOTE).since(since)
events = cli.database().query([filter1])
print(len(events))
print("[" + self.dvm_config.NIP89.NAME + "] Considering " + str(len(events)) + " Events")
ns.final_list = {}
for event in events:
@ -197,7 +185,7 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
return 1
def sync_db(self):
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT)))
opts = (Options().wait_for_send(True).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT)))
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
keys = Keys.parse(sk.to_hex())
signer = NostrSigner.keys(keys)
@ -207,7 +195,6 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
cli.add_relay("wss://relay.damus.io")
cli.add_relay("wss://nostr.oxtr.dev")
cli.add_relay("wss://nostr21.com")
cli.connect()
timestamp_since = Timestamp.now().as_secs() - self.db_since
@ -217,15 +204,15 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
EventDefinitions.KIND_LONGFORM]).since(since) # Notes, reactions, zaps
# filter = Filter().author(keys.public_key())
print("[" + self.dvm_config.IDENTIFIER + "] Syncing notes of the last " + str(
print("[" + self.dvm_config.NIP89.NAME + "] Syncing notes of the last " + str(
self.db_since) + " seconds.. this might take a while..")
dbopts = NegentropyOptions().direction(NegentropyDirection.DOWN)
cli.reconcile(filter1, dbopts)
database.delete(Filter().until(Timestamp.from_secs(
Timestamp.now().as_secs() - self.db_since))) # Clear old events so db doesn't get too full.
filter_delete = Filter().until(Timestamp.from_secs(Timestamp.now().as_secs() - self.db_since))
database.delete(filter_delete) # Clear old events so db doesn't get too full.
print(
"[" + self.dvm_config.IDENTIFIER + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
"[" + self.dvm_config.NIP89.NAME + "] Done Syncing Notes of the last " + str(self.db_since) + " seconds..")
# We build an example here that we can call by either calling this file directly from the main directory,

View File

@ -73,7 +73,7 @@ class MediaConverter(DVMTaskInterface):
return request_form
def process(self, request_form):
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
url = upload_media_to_hoster(options["filepath"])
return url

View File

@ -77,7 +77,7 @@ class DiscoveryBotFarms(DVMTaskInterface):
def process(self, request_form):
from nostr_sdk import Filter
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT)))
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)

View File

@ -89,7 +89,7 @@ class DiscoverReports(DVMTaskInterface):
cli.connect()
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
step = 20
pubkeys = []

View File

@ -88,7 +88,7 @@ class DiscoverInactiveFollows(DVMTaskInterface):
cli.connect()
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
step = 20
followers_filter = Filter().author(PublicKey.parse(options["user"])).kind(Kind(3))

View File

@ -78,7 +78,7 @@ class DiscoverNonFollowers(DVMTaskInterface):
cli.connect()
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
step = 20
followers_filter = Filter().author(PublicKey.from_hex(options["user"])).kind(Kind(3))

View File

@ -68,7 +68,7 @@ class TrendingNotesNostrBand(DVMTaskInterface):
return request_form
def process(self, request_form):
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
import requests

View File

@ -96,7 +96,7 @@ class ImageGenerationDALLE(DVMTaskInterface):
def process(self, request_form):
try:
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
from openai import OpenAI
client = OpenAI()

View File

@ -93,7 +93,7 @@ class ImageGenerationReplicateSDXL(DVMTaskInterface):
def process(self, request_form):
try:
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
import replicate
width = int(options["size"].split("x")[0])

View File

@ -99,7 +99,7 @@ class ImageGenerationMLX(DVMTaskInterface):
try:
import mlx.core as mx
from nostr_dvm.backends.mlx.modules.stable_diffusion import StableDiffusion
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
sd = StableDiffusion()
cfg_weight = 7.5

View File

@ -78,7 +78,7 @@ class SearchUser(DVMTaskInterface):
def process(self, request_form):
from nostr_sdk import Filter
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=self.dvm_config.RELAY_TIMEOUT)))
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)

View File

@ -104,7 +104,7 @@ class TextSummarizationHuggingChat(DVMTaskInterface):
cookies = sign.login()
sign.saveCookiesToDir(cookie_path_dir)
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
try:
chatbot = hugchat.ChatBot(cookies=cookies.get_dict()) # or cookie_path="usercookies/<email>.json"

View File

@ -97,7 +97,7 @@ class SummarizationUnleashedChat(DVMTaskInterface):
from openai import OpenAI
temp_open_ai_api_key = os.environ["OPENAI_API_KEY"]
os.environ["OPENAI_API_KEY"] = os.getenv("UNLEASHED_API_KEY")
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
try:
client = OpenAI(

View File

@ -112,7 +112,7 @@ class SpeechToTextGoogle(DVMTaskInterface):
api_key = self.options['api_key']
else:
api_key = None
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
# Speech recognition instance
asr = sr.Recognizer()
with sr.AudioFile(options["filepath"]) as source:

View File

@ -74,7 +74,7 @@ class TextExtractionPDF(DVMTaskInterface):
from pathlib import Path
import requests
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
try:
file_path = Path('temp.pdf')

View File

@ -71,7 +71,7 @@ class TextGenerationHuggingChat(DVMTaskInterface):
sign.saveCookiesToDir(cookie_path_dir)
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
try:
chatbot = hugchat.ChatBot(cookies=cookies.get_dict()) # or cookie_path="usercookies/<email>.json"

View File

@ -71,7 +71,7 @@ class TextGenerationLLMLite(DVMTaskInterface):
def process(self, request_form):
from litellm import completion
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
try:
if options["model"].startswith("ollama"):

View File

@ -64,7 +64,7 @@ class TextGenerationUnleashedChat(DVMTaskInterface):
from openai import OpenAI
temp_open_ai_api_key = os.environ["OPENAI_API_KEY"]
os.environ["OPENAI_API_KEY"] = os.getenv("UNLEASHED_API_KEY")
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
try:
client = OpenAI(

View File

@ -106,7 +106,7 @@ class TextToSpeech(DVMTaskInterface):
def process(self, request_form):
import torch
from TTS.api import TTS
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
device = "cuda" if torch.cuda.is_available() else "cpu"
# else "mps" if torch.backends.mps.is_available() \

View File

@ -80,7 +80,7 @@ class TranslationGoogle(DVMTaskInterface):
def process(self, request_form):
from translatepy.translators.google import GoogleTranslate
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
gtranslate = GoogleTranslate()
length = len(options["text"])

View File

@ -78,7 +78,7 @@ class TranslationLibre(DVMTaskInterface):
return request_form
def process(self, request_form):
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
request = {
"q": options["text"],
"source": "auto",

View File

@ -81,7 +81,7 @@ class VideoGenerationReplicateSVD(DVMTaskInterface):
def process(self, request_form):
try:
options = DVMTaskInterface.set_options(request_form)
options = self.set_options(request_form)
print(options["url"])
response = requests.get(options["url"])
image = Image.open(BytesIO(response.content)).convert("RGB")

View File

@ -177,7 +177,8 @@ def nip88_announce_tier(dvm_config, client):
event = EventBuilder(EventDefinitions.KIND_NIP88_TIER_EVENT, content, tags).to_event(keys)
annotier_id = send_event(event, client=client, dvm_config=dvm_config)
print("Announced NIP 88 Tier for " + dvm_config.NIP89.NAME)
print("[" + dvm_config.NAME + "] Announced NIP 88 Tier for " + dvm_config.NIP89.NAME)
return annotier_id
# Relay and payment-verification

View File

@ -8,6 +8,7 @@ from nostr_sdk import Tag, Keys, EventBuilder, Filter, Alphabet, PublicKey, Clie
from nostr_dvm.utils.definitions import EventDefinitions
from nostr_dvm.utils.nostr_utils import send_event
from nostr_dvm.utils.print import bcolors
class NIP89Config:
@ -31,7 +32,9 @@ def nip89_announce_tasks(dvm_config, client):
content = dvm_config.NIP89.CONTENT
event = EventBuilder(EventDefinitions.KIND_ANNOUNCEMENT, content, [k_tag, d_tag]).to_event(keys)
send_event(event, client=client, dvm_config=dvm_config)
print("Announced NIP 89 for " + dvm_config.NIP89.NAME)
print(bcolors.BLUE + "[" + dvm_config.NIP89.NAME + "] Announced NIP 89 for " + dvm_config.NIP89.NAME + bcolors.ENDC)
def fetch_nip89_parameters_for_deletion(keys, eventid, client, dvmconfig, pow=False):

View File

@ -211,8 +211,7 @@ def update_profile(dvm_config, client, lud16=""):
.set_lud16(lud16) \
.set_nip05(lud16)
# .set_banner("https://example.com/banner.png") \
print(f"Setting profile metadata for {keys.public_key().to_bech32()}...")
print("[" + dvm_config.NIP89.NAME + "] Setting profile metadata for " + keys.public_key().to_bech32() + "...")
print(metadata.as_json())
client.set_metadata(metadata)

15
nostr_dvm/utils/print.py Normal file
View File

@ -0,0 +1,15 @@
class bcolors:
HEADER = '\033[95m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
RED = '\033[91m'
GREEN = '\033[92m'
BLUE = '\033[94m'
CYAN = '\033[96m'
WHITE = '\033[97m'
YELLOW = '\033[93m'
MAGENTA = '\033[95m'
GREY = '\033[90m'
BLACK = '\033[90m'
DEFAULT = '\033[99m'

View File

@ -1,6 +1,6 @@
from setuptools import setup, find_packages
VERSION = '0.5.1'
VERSION = '0.5.2'
DESCRIPTION = 'A framework to build and run Nostr NIP90 Data Vending Machines'
LONG_DESCRIPTION = ('A framework to build and run Nostr NIP90 Data Vending Machines. See the github repository for more information')
@ -13,7 +13,7 @@ setup(
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
packages=find_packages(include=['nostr_dvm', 'nostr_dvm.*']),
#nostr-sdk==0.13.0a2.dev0
install_requires=["nostr-sdk==0.12.0",
"bech32",
"pycryptodome==3.20.0",

View File

@ -231,76 +231,6 @@ def playground():
custom_processing_msg=custom_processing_msg)
trending_nb.run()
# Popular top zapped
admin_config_top_zaps = AdminConfig()
admin_config_top_zaps.REBROADCAST_NIP89 = rebbroadcast_NIP89
admin_config_top_zaps.UPDATE_PROFILE = False
custom_processing_msg = ["Looking for most zapped notes", "Let's see which notes people currently zap..",
"Let's find valuable notes. #value4value"]
update_db = False
options_top_zapped = {
"db_name": "db/nostr_recent_notes.db",
"db_since": 60 * 60 * 4, # 4h since gmt,
}
cost = 0
image = "https://image.nostr.build/c6879f458252641d04d0aa65fd7f1e005a4f7362fd407467306edc2f4acdb113.jpg"
discovery_topzaps = build_example_top_zapped("Top Zapped notes",
"discovery_content_top_zaps",
admin_config=admin_config_top_zaps,
options=options_top_zapped,
image=image,
cost=cost,
update_rate=global_update_rate,
processing_msg=custom_processing_msg,
update_db=update_db)
discovery_topzaps.run()
# Popular Garden&Plants
admin_config_plants = AdminConfig()
admin_config_plants.REBROADCAST_NIP89 = rebbroadcast_NIP89
admin_config_plants.UPDATE_PROFILE = False
# admin_config_plants.DELETE_NIP89 = True
# admin_config_plants.PRIVKEY = "430bacf525a2f6efd6db1f049eb7c04e0c0314182ef1c17df39f46fe66416ddf"
# admin_config_plants.EVENTID = "f42adb15f4c67b884d58b09084907d94471d1a54185dce0217a69111c703aa14"
# admin_config_plants.POW = True
options_plants = {
"search_list": ["garden", "gardening", "nature", " plants ", " plant ", " herb ", " herbs " " pine ",
"homesteading", "rosemary", "chicken", "🪻", "🌿", "☘️", "🌲", "flower", "forest", "watering",
"permies", "planting", "farm", "vegetable", "fruit", " grass ", "sunshine",
"#flowerstr", "#bloomscrolling", "#treestr", "#plantstr", "touchgrass", ],
"avoid_list": ["porn", "smoke", "nsfw", "bitcoin", "bolt12", "bolt11", "github", "currency", "utxo",
"encryption", "government", "airpod", "ipad", "iphone", "android", "warren",
"moderna", "pfizer", "corona", "socialism",
"murder", "tax", "engagement", "hodlers", "hodl", "gdp", "global markets", "crypto", "wherostr",
"presidency", "dollar", "asset", "microsoft", "amazon", "billionaire", "ceo", "industry",
"white house", "blocks", "streaming", "summary", "wealth", "beef", "cunt", "nigger", "business",
"retail", "bakery", "synth", "slaughterhouse", "hamas", "dog days", "ww3", "socialmedia",
"nintendo", "signature", "deepfake", "congressman", "cypherpunk", "minister", "dissentwatch",
"inkblot", "covid", "robot", "pandemic", "bethesda", "zap farming", " defi ", " minister ",
"nostr-hotter-site", " ai ", "palestine", "https://boards.4chan", "https://techcrunch.com",
"https://screenrant.com"],
"db_name": "db/nostr_recent_notes.db",
"db_since": 12 * 60 * 60, # 12h since gmt
"personalized": False,
"logger": False}
image = "https://image.nostr.build/a816f3f5e98e91e8a47d50f4cd7a2c17545f556d9bb0a6086a659b9abdf7ab68.jpg"
description = "I show recent notes about plants and gardening"
custom_processing_msg = ["Finding the best notes for you.. #blooming", "Looking for some positivity.. #touchgrass",
"Looking for #goodvibes..", "All I do is #blooming.."]
update_db = False
cost = 0
discovery_test_sub = build_example_topic("Garden & Growth", "discovery_content_garden",
admin_config_plants, options_plants,
image=image,
description=description,
update_rate=global_update_rate,
cost=cost,
processing_msg=custom_processing_msg,
update_db=update_db)
discovery_test_sub.run()
# Popular Animals (Fluffy frens)
admin_config_animals = AdminConfig()
@ -358,6 +288,77 @@ def playground():
discovery_animals.run()
# Popular Garden&Plants
admin_config_plants = AdminConfig()
admin_config_plants.REBROADCAST_NIP89 = rebbroadcast_NIP89
admin_config_plants.UPDATE_PROFILE = False
# admin_config_plants.DELETE_NIP89 = True
# admin_config_plants.PRIVKEY = "430bacf525a2f6efd6db1f049eb7c04e0c0314182ef1c17df39f46fe66416ddf"
# admin_config_plants.EVENTID = "f42adb15f4c67b884d58b09084907d94471d1a54185dce0217a69111c703aa14"
# admin_config_plants.POW = True
options_plants = {
"search_list": ["garden", "gardening", "nature", " plants ", " plant ", " herb ", " herbs " " pine ",
"homesteading", "rosemary", "chicken", "🪻", "🌿", "☘️", "🌲", "flower", "forest", "watering",
"permies", "planting", "farm", "vegetable", "fruit", " grass ", "sunshine",
"#flowerstr", "#bloomscrolling", "#treestr", "#plantstr", "touchgrass", ],
"avoid_list": ["porn", "smoke", "nsfw", "bitcoin", "bolt12", "bolt11", "github", "currency", "utxo",
"encryption", "government", "airpod", "ipad", "iphone", "android", "warren",
"moderna", "pfizer", "corona", "socialism",
"murder", "tax", "engagement", "hodlers", "hodl", "gdp", "global markets", "crypto", "wherostr",
"presidency", "dollar", "asset", "microsoft", "amazon", "billionaire", "ceo", "industry",
"white house", "blocks", "streaming", "summary", "wealth", "beef", "cunt", "nigger", "business",
"retail", "bakery", "synth", "slaughterhouse", "hamas", "dog days", "ww3", "socialmedia",
"nintendo", "signature", "deepfake", "congressman", "cypherpunk", "minister", "dissentwatch",
"inkblot", "covid", "robot", "pandemic", "bethesda", "zap farming", " defi ", " minister ",
"nostr-hotter-site", " ai ", "palestine", "https://boards.4chan", "https://techcrunch.com",
"https://screenrant.com"],
"db_name": "db/nostr_recent_notes.db",
"db_since": 12 * 60 * 60, # 12h since gmt
"personalized": False,
"logger": False}
image = "https://image.nostr.build/a816f3f5e98e91e8a47d50f4cd7a2c17545f556d9bb0a6086a659b9abdf7ab68.jpg"
description = "I show recent notes about plants and gardening"
custom_processing_msg = ["Finding the best notes for you.. #blooming", "Looking for some positivity.. #touchgrass",
"Looking for #goodvibes..", "All I do is #blooming.."]
update_db = False
cost = 0
discovery_test_sub = build_example_topic("Garden & Growth", "discovery_content_garden",
admin_config_plants, options_plants,
image=image,
description=description,
update_rate=global_update_rate,
cost=cost,
processing_msg=custom_processing_msg,
update_db=update_db)
discovery_test_sub.run()
# Popular top zapped
admin_config_top_zaps = AdminConfig()
admin_config_top_zaps.REBROADCAST_NIP89 = rebbroadcast_NIP89
admin_config_top_zaps.UPDATE_PROFILE = False
custom_processing_msg = ["Looking for most zapped notes", "Let's see which notes people currently zap..",
"Let's find valuable notes. #value4value"]
update_db = False
options_top_zapped = {
"db_name": "db/nostr_recent_notes.db",
"db_since": 60 * 60 * 4, # 4h since gmt,
}
cost = 0
image = "https://image.nostr.build/c6879f458252641d04d0aa65fd7f1e005a4f7362fd407467306edc2f4acdb113.jpg"
discovery_topzaps = build_example_top_zapped("Top Zapped notes",
"discovery_content_top_zaps",
admin_config=admin_config_top_zaps,
options=options_top_zapped,
image=image,
cost=cost,
update_rate=global_update_rate,
processing_msg=custom_processing_msg,
update_db=update_db)
discovery_topzaps.run()
# Popular Followers
admin_config_followers = AdminConfig()
admin_config_followers.REBROADCAST_NIP89 = rebbroadcast_NIP89