mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-03-17 21:31:52 +01:00
some more cleanup, preparations to update nostr sdk
This commit is contained in:
parent
1735a45513
commit
2286701453
@ -7,7 +7,7 @@ import pandas as pd
|
||||
import requests
|
||||
import PIL.Image as Image
|
||||
|
||||
from utils.output_utils import uploadMediaToHoster
|
||||
from utils.output_utils import upload_media_to_hoster
|
||||
|
||||
"""
|
||||
This file contains basic calling functions for ML tasks that are outsourced to nova-server
|
||||
@ -78,7 +78,7 @@ def check_nova_server_status(jobID, address):
|
||||
if content_type == "image/jpeg":
|
||||
image = Image.open(io.BytesIO(response.content))
|
||||
image.save("./outputs/image.jpg")
|
||||
result = uploadMediaToHoster("./outputs/image.jpg")
|
||||
result = upload_media_to_hoster("./outputs/image.jpg")
|
||||
os.remove("./outputs/image.jpg")
|
||||
elif content_type == 'text/plain; charset=utf-8':
|
||||
result = response.content.decode('utf-8')
|
||||
@ -95,8 +95,9 @@ def check_nova_server_status(jobID, address):
|
||||
print(result)
|
||||
with open("response.zip", "wb") as f:
|
||||
f.write(response.content)
|
||||
except:
|
||||
zf.extractall()
|
||||
except Exception as e:
|
||||
#zf.extractall()
|
||||
print(e)
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
|
192
dvm.py
192
dvm.py
@ -1,7 +1,7 @@
|
||||
from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \
|
||||
init_logger, LogLevel
|
||||
|
||||
import time
|
||||
import emoji
|
||||
|
||||
from utils.definitions import EventDefinitions, RequiredJobToWatch, JobToWatch
|
||||
from utils.dvmconfig import DVMConfig
|
||||
@ -10,8 +10,8 @@ from utils.backend_utils import get_amount_per_task, check_task_is_supported, ge
|
||||
from utils.database_utils import update_sql_table, get_from_sql_table, \
|
||||
create_sql_table, get_or_add_user, update_user_balance
|
||||
from utils.nostr_utils import get_event_by_id, get_referenced_event_by_id, send_event
|
||||
from utils.output_utils import post_process_result
|
||||
from utils.zap_utils import check_bolt11_ln_bits_is_paid, parse_bolt11_invoice, \
|
||||
from utils.output_utils import post_process_result, build_status_reaction
|
||||
from utils.zap_utils import check_bolt11_ln_bits_is_paid, parse_amount_from_bolt11_invoice, \
|
||||
check_for_zapplepay, decrypt_private_zap_message, create_bolt11_ln_bits
|
||||
|
||||
use_logger = False
|
||||
@ -81,7 +81,7 @@ class DVM:
|
||||
print(task)
|
||||
|
||||
if user.isblacklisted:
|
||||
send_job_status_reaction(nip90_event, "error", client=self.client, config=self.dvm_config)
|
||||
send_job_status_reaction(nip90_event, "error", client=self.client, dvm_config=self.dvm_config)
|
||||
print("[" + self.dvm_config.NIP89.name + "] Request by blacklisted user, skipped")
|
||||
|
||||
elif task_supported:
|
||||
@ -98,7 +98,7 @@ class DVM:
|
||||
if user.iswhitelisted or task_is_free:
|
||||
print("[" + self.dvm_config.NIP89.name + "] Free or Whitelisted for task " + task + ". Starting processing..")
|
||||
send_job_status_reaction(nip90_event, "processing", True, 0, client=self.client,
|
||||
config=self.dvm_config)
|
||||
dvm_config=self.dvm_config)
|
||||
do_work(nip90_event, is_from_bot=False)
|
||||
# otherwise send payment request
|
||||
else:
|
||||
@ -113,28 +113,28 @@ class DVM:
|
||||
if bid_offer >= amount:
|
||||
send_job_status_reaction(nip90_event, "payment-required", False,
|
||||
amount, # bid_offer
|
||||
client=self.client, config=self.dvm_config)
|
||||
client=self.client, dvm_config=self.dvm_config)
|
||||
|
||||
else: # If there is no bid, just request server rate from user
|
||||
print("[" + self.dvm_config.NIP89.name + "] Requesting payment for Event: " + nip90_event.id().to_hex())
|
||||
send_job_status_reaction(nip90_event, "payment-required",
|
||||
False, amount, client=self.client, config=self.dvm_config)
|
||||
False, amount, client=self.client, dvm_config=self.dvm_config)
|
||||
else:
|
||||
print("Task not supported on this DVM, skipping..")
|
||||
|
||||
def handle_zap(event):
|
||||
def handle_zap(zap_event):
|
||||
zapped_event = None
|
||||
invoice_amount = 0
|
||||
anon = False
|
||||
sender = event.pubkey()
|
||||
sender = zap_event.pubkey()
|
||||
print("Zap received")
|
||||
|
||||
try:
|
||||
for tag in event.tags():
|
||||
for tag in zap_event.tags():
|
||||
if tag.as_vec()[0] == 'bolt11':
|
||||
invoice_amount = parse_bolt11_invoice(tag.as_vec()[1])
|
||||
invoice_amount = parse_amount_from_bolt11_invoice(tag.as_vec()[1])
|
||||
elif tag.as_vec()[0] == 'e':
|
||||
zapped_event = get_event_by_id(tag.as_vec()[1], config=self.dvm_config)
|
||||
zapped_event = get_event_by_id(tag.as_vec()[1], client=self.client, config=self.dvm_config)
|
||||
elif tag.as_vec()[0] == 'description':
|
||||
zap_request_event = Event.from_json(tag.as_vec()[1])
|
||||
sender = check_for_zapplepay(zap_request_event.pubkey().to_hex(),
|
||||
@ -168,7 +168,7 @@ class DVM:
|
||||
if tag.as_vec()[0] == 'amount':
|
||||
amount = int(float(tag.as_vec()[1]) / 1000)
|
||||
elif tag.as_vec()[0] == 'e':
|
||||
job_event = get_event_by_id(tag.as_vec()[1], config=self.dvm_config)
|
||||
job_event = get_event_by_id(tag.as_vec()[1], client=self.client, config=self.dvm_config)
|
||||
|
||||
task_supported, task, duration = check_task_is_supported(job_event, client=self.client,
|
||||
get_duration=False,
|
||||
@ -177,7 +177,7 @@ class DVM:
|
||||
if amount <= invoice_amount:
|
||||
print("[" + self.dvm_config.NIP89.name + "] Payment-request fulfilled...")
|
||||
send_job_status_reaction(job_event, "processing", client=self.client,
|
||||
config=self.dvm_config)
|
||||
dvm_config=self.dvm_config)
|
||||
indices = [i for i, x in enumerate(self.job_list) if
|
||||
x.event_id == job_event.id().to_hex()]
|
||||
index = -1
|
||||
@ -187,8 +187,7 @@ class DVM:
|
||||
if self.job_list[index].is_processed: # If payment-required appears a processing
|
||||
self.job_list[index].is_paid = True
|
||||
check_and_return_event(self.job_list[index].result,
|
||||
str(job_event.as_json()),
|
||||
dvm_key=self.dvm_config.PRIVATE_KEY)
|
||||
str(job_event.as_json()))
|
||||
elif not (self.job_list[index]).is_processed:
|
||||
# If payment-required appears before processing
|
||||
self.job_list.pop(index)
|
||||
@ -201,7 +200,7 @@ class DVM:
|
||||
else:
|
||||
send_job_status_reaction(job_event, "payment-rejected",
|
||||
False, invoice_amount, client=self.client,
|
||||
config=self.dvm_config)
|
||||
dvm_config=self.dvm_config)
|
||||
print("[" + self.dvm_config.NIP89.name + "] Invoice was not paid sufficiently")
|
||||
|
||||
elif zapped_event.kind() in EventDefinitions.ANY_RESULT:
|
||||
@ -209,13 +208,13 @@ class DVM:
|
||||
elif not anon:
|
||||
print("Note Zap received for Bot balance: " + str(invoice_amount) + " Sats from " + str(
|
||||
user.name))
|
||||
update_user_balance(self.dvm_config.DB, sender, invoice_amount, config=self.dvm_config)
|
||||
update_user_balance(self.dvm_config.DB, sender, invoice_amount, client=self.client, config=self.dvm_config)
|
||||
|
||||
# a regular note
|
||||
elif not anon:
|
||||
print("Profile Zap received for Bot balance: " + str(invoice_amount) + " Sats from " + str(
|
||||
user.name))
|
||||
update_user_balance(self.dvm_config.DB, sender, invoice_amount, 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(f"Error during content decryption: {e}")
|
||||
@ -234,22 +233,21 @@ class DVM:
|
||||
input = tag.as_vec()[1]
|
||||
input_type = tag.as_vec()[2]
|
||||
if input_type == "job":
|
||||
evt = get_referenced_event_by_id(input, EventDefinitions.ANY_RESULT, client,
|
||||
config=dvmconfig)
|
||||
evt = get_referenced_event_by_id(event_id=input, client=client, kinds=EventDefinitions.ANY_RESULT,
|
||||
dvm_config=dvmconfig)
|
||||
if evt is None:
|
||||
if append:
|
||||
job = RequiredJobToWatch(event=nevent, timestamp=Timestamp.now().as_secs())
|
||||
self.jobs_on_hold_list.append(job)
|
||||
send_job_status_reaction(nevent, "chain-scheduled", True, 0, client=client,
|
||||
config=dvmconfig)
|
||||
dvm_config=dvmconfig)
|
||||
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def check_and_return_event(data, original_event_str: str, dvm_key=""):
|
||||
def check_and_return_event(data, original_event_str: str):
|
||||
original_event = Event.from_json(original_event_str)
|
||||
keys = Keys.from_sk_str(dvm_key)
|
||||
|
||||
for x in self.job_list:
|
||||
if x.event_id == original_event.id().to_hex():
|
||||
@ -258,63 +256,58 @@ class DVM:
|
||||
x.result = data
|
||||
x.is_processed = True
|
||||
if self.dvm_config.SHOWRESULTBEFOREPAYMENT and not is_paid:
|
||||
send_nostr_reply_event(data, original_event_str, key=keys)
|
||||
send_nostr_reply_event(data, original_event_str,)
|
||||
send_job_status_reaction(original_event, "success", amount,
|
||||
config=self.dvm_config) # or payment-required, or both?
|
||||
dvm_config=self.dvm_config) # or payment-required, or both?
|
||||
elif not self.dvm_config.SHOWRESULTBEFOREPAYMENT and not is_paid:
|
||||
send_job_status_reaction(original_event, "success", amount,
|
||||
config=self.dvm_config) # or payment-required, or both?
|
||||
dvm_config=self.dvm_config) # or payment-required, or both?
|
||||
|
||||
if self.dvm_config.SHOWRESULTBEFOREPAYMENT and is_paid:
|
||||
self.job_list.remove(x)
|
||||
elif not self.dvm_config.SHOWRESULTBEFOREPAYMENT and is_paid:
|
||||
self.job_list.remove(x)
|
||||
send_nostr_reply_event(data, original_event_str, key=keys)
|
||||
send_nostr_reply_event(data, original_event_str)
|
||||
break
|
||||
|
||||
try:
|
||||
post_processed_content = post_process_result(data, original_event)
|
||||
send_nostr_reply_event(post_processed_content, original_event_str, key=keys)
|
||||
send_nostr_reply_event(post_processed_content, original_event_str)
|
||||
except Exception as e:
|
||||
respond_to_error(e, original_event_str, False, self.dvm_config.PRIVATE_KEY)
|
||||
respond_to_error(str(e), original_event_str, False)
|
||||
|
||||
def send_nostr_reply_event(content, original_event_as_str, key=None):
|
||||
originalevent = Event.from_json(original_event_as_str)
|
||||
requesttag = Tag.parse(["request", original_event_as_str.replace("\\", "")])
|
||||
etag = Tag.parse(["e", originalevent.id().to_hex()])
|
||||
ptag = Tag.parse(["p", originalevent.pubkey().to_hex()])
|
||||
alttag = Tag.parse(["alt", "This is the result of a NIP90 DVM AI task with kind " + str(
|
||||
originalevent.kind()) + ". The task was: " + originalevent.content()])
|
||||
statustag = Tag.parse(["status", "success"])
|
||||
replytags = [requesttag, etag, ptag, alttag, statustag]
|
||||
for tag in originalevent.tags():
|
||||
def send_nostr_reply_event(content, original_event_as_str):
|
||||
original_event = Event.from_json(original_event_as_str)
|
||||
request_tag = Tag.parse(["request", original_event_as_str.replace("\\", "")])
|
||||
e_tag = Tag.parse(["e", original_event.id().to_hex()])
|
||||
p_tag = Tag.parse(["p", original_event.pubkey().to_hex()])
|
||||
alt_tag = Tag.parse(["alt", "This is the result of a NIP90 DVM AI task with kind " + str(
|
||||
original_event.kind()) + ". The task was: " + original_event.content()])
|
||||
status_tag = Tag.parse(["status", "success"])
|
||||
reply_tags = [request_tag, e_tag, p_tag, alt_tag, status_tag]
|
||||
for tag in original_event.tags():
|
||||
if tag.as_vec()[0] == "i":
|
||||
icontent = tag.as_vec()[1]
|
||||
ikind = tag.as_vec()[2]
|
||||
itag = Tag.parse(["i", icontent, ikind])
|
||||
replytags.append(itag)
|
||||
i_content = tag.as_vec()[1]
|
||||
i_kind = tag.as_vec()[2]
|
||||
i_tag = Tag.parse(["i", i_content, i_kind])
|
||||
reply_tags.append(i_tag)
|
||||
|
||||
if key is None:
|
||||
key = Keys.from_sk_str(self.dvm_config.PRIVATE_KEY)
|
||||
key = Keys.from_sk_str(self.dvm_config.PRIVATE_KEY)
|
||||
|
||||
response_kind = originalevent.kind() + 1000
|
||||
event = EventBuilder(response_kind, str(content), replytags).to_event(key)
|
||||
send_event(event, key=key)
|
||||
print("[" + self.dvm_config.NIP89.name + "]" + str(response_kind) + " Job Response event sent: " + event.as_json())
|
||||
return event.as_json()
|
||||
response_kind = original_event.kind() + 1000
|
||||
reply_event = EventBuilder(response_kind, str(content), reply_tags).to_event(key)
|
||||
send_event(reply_event, client=self.client, dvm_config=self.dvm_config)
|
||||
print("[" + self.dvm_config.NIP89.name + "]" + str(response_kind) + " Job Response event sent: " + reply_event.as_json())
|
||||
return reply_event.as_json()
|
||||
|
||||
def respond_to_error(content, originaleventstr, is_from_bot=False, dvm_key=None):
|
||||
print("ERROR")
|
||||
if dvm_key is None:
|
||||
keys = Keys.from_sk_str(self.dvm_config.PRIVATE_KEY)
|
||||
else:
|
||||
keys = Keys.from_sk_str(dvm_key)
|
||||
|
||||
original_event = Event.from_json(originaleventstr)
|
||||
def respond_to_error(content: str, original_event_as_str: str, is_from_bot=False):
|
||||
print("ERROR: " + str(content))
|
||||
keys = Keys.from_sk_str(self.dvm_config.PRIVATE_KEY)
|
||||
original_event = Event.from_json(original_event_as_str)
|
||||
sender = ""
|
||||
task = ""
|
||||
if not is_from_bot:
|
||||
send_job_status_reaction(original_event, "error", content=str(content), key=dvm_key)
|
||||
send_job_status_reaction(original_event, "error", content=content, dvm_config=self.dvm_config)
|
||||
# TODO Send Zap back
|
||||
else:
|
||||
for tag in original_event.tags():
|
||||
@ -336,46 +329,14 @@ class DVM:
|
||||
|
||||
evt = EventBuilder.new_encrypted_direct_msg(keys, PublicKey.from_hex(sender), message,
|
||||
None).to_event(keys)
|
||||
send_event(evt, key=keys)
|
||||
send_event(evt, client=self.client, dvm_config=self.dvm_config)
|
||||
|
||||
def send_job_status_reaction(original_event, status, is_paid=True, amount=0, client=None,
|
||||
content=None,
|
||||
config=None,
|
||||
key=None):
|
||||
dvmconfig = config
|
||||
alt_description = "This is a reaction to a NIP90 DVM AI task. "
|
||||
task = get_task(original_event, client=client, dvmconfig=dvmconfig)
|
||||
if status == "processing":
|
||||
alt_description = "NIP90 DVM AI task " + task + " started processing. "
|
||||
reaction = alt_description + emoji.emojize(":thumbs_up:")
|
||||
elif status == "success":
|
||||
alt_description = "NIP90 DVM AI task " + task + " finished successfully. "
|
||||
reaction = alt_description + emoji.emojize(":call_me_hand:")
|
||||
elif status == "chain-scheduled":
|
||||
alt_description = "NIP90 DVM AI task " + task + " Chain Task scheduled"
|
||||
reaction = alt_description + emoji.emojize(":thumbs_up:")
|
||||
elif status == "error":
|
||||
alt_description = "NIP90 DVM AI task " + task + " had an error. "
|
||||
if content is None:
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:")
|
||||
else:
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:") + content
|
||||
|
||||
elif status == "payment-required":
|
||||
|
||||
alt_description = "NIP90 DVM AI task " + task + " requires payment of min " + str(
|
||||
amount) + " Sats. "
|
||||
reaction = alt_description + emoji.emojize(":orange_heart:")
|
||||
|
||||
elif status == "payment-rejected":
|
||||
alt_description = "NIP90 DVM AI task " + task + " payment is below required amount of " + str(
|
||||
amount) + " Sats. "
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:")
|
||||
elif status == "user-blocked-from-service":
|
||||
alt_description = "NIP90 DVM AI task " + task + " can't be performed. User has been blocked from Service. "
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:")
|
||||
else:
|
||||
reaction = emoji.emojize(":thumbs_down:")
|
||||
dvm_config=None):
|
||||
dvm_config = dvm_config
|
||||
task = get_task(original_event, client=client, dvmconfig=dvm_config)
|
||||
alt_description, reaction = build_status_reaction(status, task, amount, content)
|
||||
|
||||
e_tag = Tag.parse(["e", original_event.id().to_hex()])
|
||||
p_tag = Tag.parse(["p", original_event.pubkey().to_hex()])
|
||||
@ -394,9 +355,9 @@ class DVM:
|
||||
payment_hash = ""
|
||||
expires = original_event.created_at().as_secs() + (60 * 60 * 24)
|
||||
if status == "payment-required" or (status == "processing" and not is_paid):
|
||||
if dvmconfig.LNBITS_INVOICE_KEY != "":
|
||||
if dvm_config.LNBITS_INVOICE_KEY != "":
|
||||
try:
|
||||
bolt11, payment_hash = create_bolt11_ln_bits(amount, dvmconfig)
|
||||
bolt11, payment_hash = create_bolt11_ln_bits(amount, dvm_config)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@ -410,22 +371,20 @@ class DVM:
|
||||
payment_hash=payment_hash,
|
||||
expires=expires, from_bot=False))
|
||||
#print(str(self.job_list))
|
||||
if status == "payment-required" or status == "payment-rejected" or (
|
||||
status == "processing" and not is_paid) or (
|
||||
status == "success" and not is_paid):
|
||||
if (status == "payment-required" or status == "payment-rejected" or (
|
||||
status == "processing" and not is_paid)
|
||||
or (status == "success" and not is_paid)):
|
||||
|
||||
if dvmconfig.LNBITS_INVOICE_KEY != "":
|
||||
if dvm_config.LNBITS_INVOICE_KEY != "":
|
||||
amount_tag = Tag.parse(["amount", str(amount * 1000), bolt11])
|
||||
else:
|
||||
amount_tag = Tag.parse(["amount", str(amount * 1000)]) # to millisats
|
||||
tags.append(amount_tag)
|
||||
if key is not None:
|
||||
keys = Keys.from_sk_str(key)
|
||||
else:
|
||||
keys = Keys.from_sk_str(dvmconfig.PRIVATE_KEY)
|
||||
|
||||
keys = Keys.from_sk_str(dvm_config.PRIVATE_KEY)
|
||||
event = EventBuilder(EventDefinitions.KIND_FEEDBACK, reaction, tags).to_event(keys)
|
||||
|
||||
send_event(event, key=keys)
|
||||
send_event(event, client=self.client, dvm_config=self.dvm_config)
|
||||
print("[" + self.dvm_config.NIP89.name + "]" + ": Sent Kind " + str(
|
||||
EventDefinitions.KIND_FEEDBACK) + " Reaction: " + status + " " + event.as_json())
|
||||
return event.as_json()
|
||||
@ -443,12 +402,11 @@ class DVM:
|
||||
request_form = dvm.create_request_form_from_nostr_event(job_event, self.client,
|
||||
self.dvm_config)
|
||||
result = dvm.process(request_form)
|
||||
check_and_return_event(result, str(job_event.as_json()),
|
||||
dvm_key=self.dvm_config.PRIVATE_KEY)
|
||||
check_and_return_event(result, str(job_event.as_json()))
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
respond_to_error(e, job_event.as_json(), is_from_bot, self.dvm_config.PRIVATE_KEY)
|
||||
respond_to_error(str(e), job_event.as_json(), is_from_bot)
|
||||
return
|
||||
|
||||
self.client.handle_notifications(NotificationHandler())
|
||||
@ -457,11 +415,11 @@ class DVM:
|
||||
if job.bolt11 != "" and job.payment_hash != "" and not job.is_paid:
|
||||
if str(check_bolt11_ln_bits_is_paid(job.payment_hash, self.dvm_config)) == "True":
|
||||
job.is_paid = True
|
||||
event = get_event_by_id(job.event_id, config=self.dvm_config)
|
||||
event = get_event_by_id(job.event_id, client=self.client, config=self.dvm_config)
|
||||
if event is not None:
|
||||
send_job_status_reaction(event, "processing", True, 0,
|
||||
client=self.client,
|
||||
config=self.dvm_config)
|
||||
dvm_config=self.dvm_config)
|
||||
print("do work from joblist")
|
||||
|
||||
do_work(event, is_from_bot=False)
|
||||
@ -469,13 +427,13 @@ class DVM:
|
||||
try:
|
||||
self.job_list.remove(job)
|
||||
except:
|
||||
continue
|
||||
print("Error removing Job from List after payment")
|
||||
|
||||
if Timestamp.now().as_secs() > job.expires:
|
||||
try:
|
||||
self.job_list.remove(job)
|
||||
except:
|
||||
continue
|
||||
print("Error removing Job from List after expiry")
|
||||
|
||||
for job in self.jobs_on_hold_list:
|
||||
if check_event_has_not_unfinished_job_input(job.event, False, client=self.client,
|
||||
@ -484,9 +442,9 @@ class DVM:
|
||||
try:
|
||||
self.jobs_on_hold_list.remove(job)
|
||||
except:
|
||||
continue
|
||||
print("Error removing Job on Hold from List after expiry")
|
||||
|
||||
if Timestamp.now().as_secs() > job.timestamp + 60 * 20: # remove jobs to look for after 20 minutes..
|
||||
self.jobs_on_hold_list.remove(job)
|
||||
|
||||
time.sleep(2.0)
|
||||
time.sleep(1.0)
|
||||
|
@ -21,7 +21,7 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
NAME: str = ""
|
||||
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
|
||||
TASK: str = "text-to-image"
|
||||
COST: int = 5
|
||||
COST: int = 50
|
||||
PK: str
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None, default_model=None, default_lora=None):
|
||||
@ -102,8 +102,6 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
if len(split) > 1:
|
||||
width = split[0]
|
||||
height = split[1]
|
||||
print(width)
|
||||
print(height)
|
||||
elif tag.as_vec()[1] == "model":
|
||||
model = tag.as_vec()[2]
|
||||
|
||||
|
@ -56,7 +56,7 @@ class TextExtractionPDF(DVMTaskInterface):
|
||||
url = input_content
|
||||
# if event contains url to pdf, we checked for a pdf link before
|
||||
elif input_type == "event":
|
||||
evt = get_event_by_id(input_content, config=dvm_config)
|
||||
evt = get_event_by_id(input_content, client=client, config=dvm_config)
|
||||
url = re.search("(?P<url>https?://[^\s]+)", evt.content()).group("url")
|
||||
|
||||
request_form["optStr"] = 'url=' + url
|
||||
|
@ -58,7 +58,7 @@ class Translation(DVMTaskInterface):
|
||||
if input_type == "event":
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == 'i':
|
||||
evt = get_event_by_id(tag.as_vec()[1], config=dvm_config)
|
||||
evt = get_event_by_id(tag.as_vec()[1], client=client, config=dvm_config)
|
||||
text = evt.content()
|
||||
break
|
||||
|
||||
@ -71,12 +71,11 @@ class Translation(DVMTaskInterface):
|
||||
elif input_type == "job":
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == 'i':
|
||||
evt = get_referenced_event_by_id(tag.as_vec()[1],
|
||||
[EventDefinitions.KIND_NIP90_RESULT_EXTRACT_TEXT,
|
||||
EventDefinitions.KIND_NIP90_RESULT_SUMMARIZE_TEXT,
|
||||
EventDefinitions.KIND_NIP90_RESULT_TRANSLATE_TEXT],
|
||||
client,
|
||||
config=dvm_config)
|
||||
evt = get_referenced_event_by_id(event_id=tag.as_vec()[1], client=client,
|
||||
kinds=[EventDefinitions.KIND_NIP90_RESULT_EXTRACT_TEXT,
|
||||
EventDefinitions.KIND_NIP90_RESULT_SUMMARIZE_TEXT,
|
||||
EventDefinitions.KIND_NIP90_RESULT_TRANSLATE_TEXT],
|
||||
dvm_config=dvm_config)
|
||||
text = evt.content()
|
||||
break
|
||||
|
||||
|
@ -7,6 +7,7 @@ from threading import Thread
|
||||
import dotenv
|
||||
from nostr_sdk import Keys, Client, Tag, EventBuilder, Filter, HandleNotification, Timestamp, nip04_decrypt
|
||||
|
||||
from utils.dvmconfig import DVMConfig
|
||||
from utils.nostr_utils import send_event
|
||||
from utils.definitions import EventDefinitions, RELAY_LIST
|
||||
|
||||
@ -36,7 +37,8 @@ def nostr_client_test_translation(input, kind, lang, sats, satsmax):
|
||||
for relay in relay_list:
|
||||
client.add_relay(relay)
|
||||
client.connect()
|
||||
send_event(event, client, keys)
|
||||
config = DVMConfig
|
||||
send_event(event, client=client, dvm_config=config)
|
||||
return event.as_json()
|
||||
|
||||
|
||||
@ -62,7 +64,8 @@ def nostr_client_test_image(prompt):
|
||||
for relay in relay_list:
|
||||
client.add_relay(relay)
|
||||
client.connect()
|
||||
send_event(event, client, keys)
|
||||
config = DVMConfig
|
||||
send_event(event, client=client, dvm_config=config)
|
||||
return event.as_json()
|
||||
|
||||
def nostr_client():
|
||||
|
@ -73,4 +73,4 @@ def admin_make_database_updates(adminconfig: AdminConfig = None, dvmconfig: DVMC
|
||||
list_db(db)
|
||||
|
||||
if rebroadcast_nip89:
|
||||
nip89_announce_tasks(dvmconfig)
|
||||
nip89_announce_tasks(dvmconfig, client=client)
|
||||
|
@ -28,7 +28,7 @@ def get_task(event, client, dvmconfig):
|
||||
else:
|
||||
return "unknown job"
|
||||
elif tag.as_vec()[2] == "event":
|
||||
evt = get_event_by_id(tag.as_vec()[1], config=dvmconfig)
|
||||
evt = get_event_by_id(tag.as_vec()[1], client=client, config=dvmconfig)
|
||||
if evt is not None:
|
||||
if evt.kind() == 1063:
|
||||
for tg in evt.tags():
|
||||
@ -65,7 +65,7 @@ def check_task_is_supported(event, client, get_duration=False, config=None):
|
||||
input_value = tag.as_vec()[1]
|
||||
input_type = tag.as_vec()[2]
|
||||
if input_type == "event":
|
||||
evt = get_event_by_id(input_value, config=dvm_config)
|
||||
evt = get_event_by_id(input_value, client=client, config=dvm_config)
|
||||
if evt is None:
|
||||
print("Event not found")
|
||||
return False, "", 0
|
||||
|
@ -155,7 +155,7 @@ def list_db(db):
|
||||
print(e)
|
||||
|
||||
|
||||
def update_user_balance(db, sender, sats, config=None):
|
||||
def update_user_balance(db, sender, sats, client, config):
|
||||
user = get_from_sql_table(db, sender)
|
||||
if user is None:
|
||||
add_to_sql_table(db, sender, (int(sats) + NEW_USER_BALANCE), False, False,
|
||||
@ -186,7 +186,7 @@ def update_user_balance(db, sender, sats, config=None):
|
||||
|
||||
evt = EventBuilder.new_encrypted_direct_msg(keys, PublicKey.from_hex(sender), message,
|
||||
None).to_event(keys)
|
||||
send_event(evt, key=keys)
|
||||
send_event(evt, client=client, dvm_config=config)
|
||||
|
||||
|
||||
def get_or_add_user(db, sender):
|
||||
|
@ -7,9 +7,7 @@ from utils import env
|
||||
|
||||
NEW_USER_BALANCE: int = 250 # Free credits for new users
|
||||
|
||||
RELAY_LIST = ["wss://relay.damus.io", "wss://nostr-pub.wellorder.net", "wss://nos.lol", "wss://nostr.wine",
|
||||
"wss://relay.nostfiles.dev", "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
"wss://relay.f7z.io"]
|
||||
|
||||
|
||||
|
||||
class EventDefinitions:
|
||||
|
@ -11,6 +11,7 @@ class DVMConfig:
|
||||
RELAY_LIST = ["wss://relay.damus.io", "wss://nostr-pub.wellorder.net", "wss://nos.lol", "wss://nostr.wine",
|
||||
"wss://relay.nostfiles.dev", "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
"wss://relay.f7z.io"]
|
||||
|
||||
RELAY_TIMEOUT = 5
|
||||
LNBITS_INVOICE_KEY = ''
|
||||
LNBITS_URL = 'https://lnbits.com'
|
||||
|
@ -1,6 +1,8 @@
|
||||
from nostr_sdk import Tag, Keys, EventBuilder
|
||||
|
||||
from utils.nostr_utils import send_event
|
||||
|
||||
|
||||
class NIP89Announcement:
|
||||
name: str
|
||||
kind: int
|
||||
@ -8,11 +10,12 @@ class NIP89Announcement:
|
||||
pk: str
|
||||
content: str
|
||||
|
||||
def nip89_announce_tasks(dvmconfig):
|
||||
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
|
||||
|
||||
def nip89_announce_tasks(dvm_config, client):
|
||||
k_tag = Tag.parse(["k", str(dvm_config.NIP89.kind)])
|
||||
d_tag = Tag.parse(["d", dvm_config.NIP89.dtag])
|
||||
keys = Keys.from_sk_str(dvm_config.NIP89.pk)
|
||||
content = dvm_config.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)
|
||||
send_event(event, client=client, dvm_config=dvm_config)
|
||||
print("Announced NIP 89 for " + dvm_config.NIP89.name)
|
||||
|
@ -1,19 +1,8 @@
|
||||
from datetime import timedelta
|
||||
from nostr_sdk import Keys, Filter, Client, Alphabet, EventId, Options
|
||||
|
||||
from utils.definitions import RELAY_LIST
|
||||
from nostr_sdk import Keys, Filter, Client, Alphabet, EventId, Options, Event
|
||||
|
||||
|
||||
def get_event_by_id(event_id, client=None, config=None):
|
||||
is_new_client = False
|
||||
if client is None:
|
||||
keys = Keys.from_sk_str(config.PRIVATE_KEY)
|
||||
client = Client(keys)
|
||||
for relay in config.RELAY_LIST:
|
||||
client.add_relay(relay)
|
||||
client.connect()
|
||||
is_new_client = True
|
||||
|
||||
def get_event_by_id(event_id: str, client: Client, config=None) -> Event | None:
|
||||
split = event_id.split(":")
|
||||
if len(split) == 3:
|
||||
id_filter = Filter().author(split[1]).custom_tag(Alphabet.D, [split[2]])
|
||||
@ -23,69 +12,44 @@ def get_event_by_id(event_id, client=None, config=None):
|
||||
event_id = EventId.from_bech32(event_id).to_hex()
|
||||
id_filter = Filter().id(event_id).limit(1)
|
||||
events = client.get_events_of([id_filter], timedelta(seconds=config.RELAY_TIMEOUT))
|
||||
if is_new_client:
|
||||
client.disconnect()
|
||||
if len(events) > 0:
|
||||
return events[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_referenced_event_by_id(event_id, kinds=None, client=None, config=None):
|
||||
if kinds is None:
|
||||
kinds = []
|
||||
is_new_client = False
|
||||
if client is None:
|
||||
keys = Keys.from_sk_str(config.PRIVATE_KEY)
|
||||
client = Client(keys)
|
||||
for relay in config.RELAY_LIST:
|
||||
client.add_relay(relay)
|
||||
client.connect()
|
||||
is_new_client = True
|
||||
def get_referenced_event_by_id(event_id, client, dvm_config, kinds) -> Event | None:
|
||||
if kinds is None:
|
||||
kinds = []
|
||||
|
||||
if len(kinds) > 0:
|
||||
job_id_filter = Filter().kinds(kinds).event(EventId.from_hex(event_id)).limit(1)
|
||||
else:
|
||||
job_id_filter = Filter().event(EventId.from_hex(event_id)).limit(1)
|
||||
|
||||
events = client.get_events_of([job_id_filter], timedelta(seconds=config.RELAY_TIMEOUT))
|
||||
events = client.get_events_of([job_id_filter], timedelta(seconds=dvm_config.RELAY_TIMEOUT))
|
||||
|
||||
if is_new_client:
|
||||
client.disconnect()
|
||||
if len(events) > 0:
|
||||
return events[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def send_event(event, client=None, key=None):
|
||||
def send_event(event: Event, client: Client, dvm_config) -> EventId:
|
||||
relays = []
|
||||
is_new_client = False
|
||||
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == 'relays':
|
||||
relays = tag.as_vec()[1].split(',')
|
||||
|
||||
if client is None:
|
||||
opts = Options().wait_for_send(False).send_timeout(timedelta(seconds=5)).skip_disconnected_relays(True)
|
||||
client = Client.with_opts(key, opts)
|
||||
for relay in RELAY_LIST:
|
||||
client.add_relay(relay)
|
||||
client.connect()
|
||||
is_new_client = True
|
||||
|
||||
for relay in relays:
|
||||
if relay not in RELAY_LIST:
|
||||
if relay not in dvm_config.RELAY_LIST:
|
||||
client.add_relay(relay)
|
||||
|
||||
event_id = client.send_event(event)
|
||||
|
||||
for relay in relays:
|
||||
if relay not in RELAY_LIST:
|
||||
if relay not in dvm_config.RELAY_LIST:
|
||||
client.remove_relay(relay)
|
||||
|
||||
if is_new_client:
|
||||
client.disconnect()
|
||||
|
||||
return event_id
|
||||
|
@ -2,6 +2,8 @@ import json
|
||||
import datetime as datetime
|
||||
import os
|
||||
from types import NoneType
|
||||
|
||||
import emoji
|
||||
import requests
|
||||
from pyupload.uploader import CatboxUploader
|
||||
|
||||
@ -109,7 +111,7 @@ Will probably need to switch to another system in the future.
|
||||
'''
|
||||
|
||||
|
||||
def uploadMediaToHoster(filepath):
|
||||
def upload_media_to_hoster(filepath: str):
|
||||
print("Uploading image: " + filepath)
|
||||
try:
|
||||
files = {'file': open(filepath, 'rb')}
|
||||
@ -144,3 +146,40 @@ def uploadMediaToHoster(filepath):
|
||||
return result
|
||||
except:
|
||||
return "Upload not possible, all hosters didn't work"
|
||||
|
||||
|
||||
def build_status_reaction(status, task, amount, content):
|
||||
alt_description = "This is a reaction to a NIP90 DVM AI task. "
|
||||
|
||||
if status == "processing":
|
||||
alt_description = "NIP90 DVM AI task " + task + " started processing. "
|
||||
reaction = alt_description + emoji.emojize(":thumbs_up:")
|
||||
elif status == "success":
|
||||
alt_description = "NIP90 DVM AI task " + task + " finished successfully. "
|
||||
reaction = alt_description + emoji.emojize(":call_me_hand:")
|
||||
elif status == "chain-scheduled":
|
||||
alt_description = "NIP90 DVM AI task " + task + " Chain Task scheduled"
|
||||
reaction = alt_description + emoji.emojize(":thumbs_up:")
|
||||
elif status == "error":
|
||||
alt_description = "NIP90 DVM AI task " + task + " had an error. "
|
||||
if content is None:
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:")
|
||||
else:
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:") + content
|
||||
|
||||
elif status == "payment-required":
|
||||
alt_description = "NIP90 DVM AI task " + task + " requires payment of min " + str(
|
||||
amount) + " Sats. "
|
||||
reaction = alt_description + emoji.emojize(":orange_heart:")
|
||||
|
||||
elif status == "payment-rejected":
|
||||
alt_description = "NIP90 DVM AI task " + task + " payment is below required amount of " + str(
|
||||
amount) + " Sats. "
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:")
|
||||
elif status == "user-blocked-from-service":
|
||||
alt_description = "NIP90 DVM AI task " + task + " can't be performed. User has been blocked from Service. "
|
||||
reaction = alt_description + emoji.emojize(":thumbs_down:")
|
||||
else:
|
||||
reaction = emoji.emojize(":thumbs_down:")
|
||||
|
||||
return alt_description, reaction
|
||||
|
@ -4,10 +4,11 @@ import json
|
||||
import requests
|
||||
from Crypto.Cipher import AES
|
||||
from bech32 import bech32_decode, convertbits
|
||||
from nostr_sdk import PublicKey, nostr_sdk
|
||||
from nostr_sdk import nostr_sdk, PublicKey, SecretKey
|
||||
from utils.dvmconfig import DVMConfig
|
||||
|
||||
|
||||
def parse_bolt11_invoice(invoice):
|
||||
def parse_amount_from_bolt11_invoice(bolt11_invoice: str) -> int:
|
||||
def get_index_of_first_letter(ip):
|
||||
index = 0
|
||||
for c in ip:
|
||||
@ -17,7 +18,7 @@ def parse_bolt11_invoice(invoice):
|
||||
index = index + 1
|
||||
return len(ip)
|
||||
|
||||
remaining_invoice = invoice[4:]
|
||||
remaining_invoice = bolt11_invoice[4:]
|
||||
index = get_index_of_first_letter(remaining_invoice)
|
||||
identifier = remaining_invoice[index]
|
||||
number_string = remaining_invoice[:index]
|
||||
@ -34,9 +35,9 @@ def parse_bolt11_invoice(invoice):
|
||||
return int(number)
|
||||
|
||||
|
||||
def create_bolt11_ln_bits(sats, config):
|
||||
def create_bolt11_ln_bits(sats: int, config: DVMConfig) -> (str, str):
|
||||
url = config.LNBITS_URL + "/api/v1/payments"
|
||||
data = {'out': False, 'amount': sats, 'memo': "Nostr-DVM"}
|
||||
data = {'out': False, 'amount': sats, 'memo': "Nostr-DVM " + config.NIP89.name}
|
||||
headers = {'X-API-Key': config.LNBITS_INVOICE_KEY, 'Content-Type': 'application/json', 'charset': 'UTF-8'}
|
||||
try:
|
||||
res = requests.post(url, json=data, headers=headers)
|
||||
@ -44,35 +45,35 @@ def create_bolt11_ln_bits(sats, config):
|
||||
return obj["payment_request"], obj["payment_hash"]
|
||||
except Exception as e:
|
||||
print("LNBITS: " + str(e))
|
||||
return None
|
||||
return None, None
|
||||
|
||||
|
||||
def check_bolt11_ln_bits_is_paid(payment_hash, config):
|
||||
def check_bolt11_ln_bits_is_paid(payment_hash: str, config: DVMConfig):
|
||||
url = config.LNBITS_URL + "/api/v1/payments/" + payment_hash
|
||||
headers = {'X-API-Key': config.LNBITS_INVOICE_KEY, 'Content-Type': 'application/json', 'charset': 'UTF-8'}
|
||||
try:
|
||||
res = requests.get(url, headers=headers)
|
||||
obj = json.loads(res.text)
|
||||
return obj["paid"]
|
||||
return obj["paid"] #TODO cast
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
|
||||
# DECRYPT ZAPS
|
||||
def check_for_zapplepay(sender, content):
|
||||
def check_for_zapplepay(pubkey_hex: str, content: str):
|
||||
try:
|
||||
# Special case Zapplepay
|
||||
if sender == PublicKey.from_bech32("npub1wxl6njlcgygduct7jkgzrvyvd9fylj4pqvll6p32h59wyetm5fxqjchcan").to_hex():
|
||||
if pubkey_hex == PublicKey.from_bech32("npub1wxl6njlcgygduct7jkgzrvyvd9fylj4pqvll6p32h59wyetm5fxqjchcan").to_hex():
|
||||
real_sender_bech32 = content.replace("From: nostr:", "")
|
||||
sender = PublicKey.from_bech32(real_sender_bech32).to_hex()
|
||||
return sender
|
||||
pubkey_hex = PublicKey.from_bech32(real_sender_bech32).to_hex()
|
||||
return pubkey_hex
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return sender
|
||||
return pubkey_hex
|
||||
|
||||
|
||||
def decrypt_private_zap_message(msg, privkey, pubkey):
|
||||
def decrypt_private_zap_message(msg: str, privkey: SecretKey, pubkey: PublicKey):
|
||||
shared_secret = nostr_sdk.generate_shared_key(privkey, pubkey)
|
||||
if len(shared_secret) != 16 and len(shared_secret) != 32:
|
||||
return "invalid shared secret size"
|
||||
|
Loading…
x
Reference in New Issue
Block a user