Merge branch 'main' into nserver-modules

This commit is contained in:
Believethehype
2023-12-09 23:59:10 +01:00
18 changed files with 275 additions and 57 deletions

View File

@@ -1,8 +1,13 @@
# Optional LNBITS options to create invoices (if empty, it will use the lud16 from profile) # Optional LNBITS options to create invoices (if empty, it will use the lud16 from profile)
# Admin Key is (only) required for bot or if any payments should be made # Admin Key is (only) required for bot or if any payments should be made
LNBITS_INVOICE_KEY = ""
#Create an account with a lnbits instance of your choice, add the admin key and id here. This account will be used to create a new lnbits wallet for each dvm/bot
LNBITS_ADMIN_KEY = "" # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users. Keep this secret and use responsibly. LNBITS_ADMIN_KEY = "" # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users. Keep this secret and use responsibly.
LNBITS_ADMIN_ID = ""
LNBITS_HOST = "https://lnbits.com" LNBITS_HOST = "https://lnbits.com"
# In order to create a zappable lightning address, host nostdress on your domain or use this preinstalled domain.
# We will use the api to create and manage zapable lightning addresses
NOSTDRESS_DOMAIN = "nostrdvm.com"
#Backend Specific Options for tasks that require them. A DVM needing these should only be started if these are set. #Backend Specific Options for tasks that require them. A DVM needing these should only be started if these are set.
@@ -15,3 +20,6 @@ N_SERVER = "" # Enter the address of a n-server instance, locally or on a machi
# We will automatically create dtags and private keys based on the identifier variable in main. # We will automatically create dtags and private keys based on the identifier variable in main.
# If your DVM already has a dtag and private key you can replace it here before publishing the DTAG to not create a new one. # If your DVM already has a dtag and private key you can replace it here before publishing the DTAG to not create a new one.
# The name and NIP90 info of the DVM can be changed but the identifier must stay the same in order to not create a different dtag. # The name and NIP90 info of the DVM can be changed but the identifier must stay the same in order to not create a different dtag.
# We will also create new wallets on the given lnbits instance for each dvm. If you want to use an existing wallet, you can replace the parameters here as well.
# Make sure you backup this file to keep access to your wallets

8
.gitignore vendored
View File

@@ -166,8 +166,10 @@ outputs
app_deploy.py app_deploy.py
app.py app.py
app_deploy.py app_deploy.py
db/Cashu/wallet.sqlite3
db/*
.idea/misc.xml .idea/misc.xml
.idea/misc.xml .idea/misc.xml
backends/nserver/cache/* backends/nserver/venv
backends/nserver/modules/image_upscale/weights/* backends/nserver/cache
backends/nserver/modules/image_upscale/weights

View File

@@ -11,7 +11,7 @@ This means the project is in alpha status, interfaces might still change/break a
Create a new venv by running `"python -m venv venv"` Create a new venv by running `"python -m venv venv"`
- Place .env file (based on .env_example) in main folder. - Place .env file (based on .env_example) in main folder.
- the feamework will automatically create keys for your dvms in this file. - the framework will automatically create keys for your dvms in this file.
- Install requirements.txt - Install requirements.txt
- Run python main.py. - Run python main.py.

View File

@@ -298,6 +298,7 @@ class Bot:
print("Receiver has no Lightning address") print("Receiver has no Lightning address")
return return
try: try:
print(bolt11)
payment_hash = pay_bolt11_ln_bits(bolt11, self.dvm_config) payment_hash = pay_bolt11_ln_bits(bolt11, self.dvm_config)
self.job_list[self.job_list.index(entry)]['is_paid'] = True self.job_list[self.job_list.index(entry)]['is_paid'] = True
print("[" + self.NAME + "] payment_hash: " + payment_hash + print("[" + self.NAME + "] payment_hash: " + payment_hash +
@@ -366,7 +367,30 @@ class Bot:
self.keys, self.NAME, self.keys, self.NAME,
self.client, self.dvm_config) self.client, self.dvm_config)
etag = ""
for tag in zap_event.tags():
if tag.as_vec()[0] == "e":
etag = tag.as_vec()[1]
user = get_or_add_user(self.dvm_config.DB, sender, client=self.client, config=self.dvm_config) user = get_or_add_user(self.dvm_config.DB, sender, client=self.client, config=self.dvm_config)
entry = next((x for x in self.job_list if x['event_id'] == etag), None)
print(entry)
#print(entry['dvm_key'])
# print(str(zapped_event.pubkey().to_hex()))
# print(str(zap_event.pubkey().to_hex()))
print(sender)
if entry is not None and entry['is_paid'] is True and entry['dvm_key'] == sender:
# if we get a bolt11, we pay and move on
user = get_or_add_user(db=self.dvm_config.DB, npub=entry["npub"],
client=self.client, config=self.dvm_config)
print("HELLO: " + user.name)
sender = user.npub
#print(zap_event.as_json())
if zapped_event is not None: if zapped_event is not None:
if not anon: if not anon:
print("[" + self.NAME + "] Note Zap received for Bot balance: " + str( print("[" + self.NAME + "] Note Zap received for Bot balance: " + str(

View File

@@ -15,7 +15,8 @@ from utils.database_utils import create_sql_table, get_or_add_user, update_user_
from utils.mediasource_utils import input_data_file_duration from utils.mediasource_utils import input_data_file_duration
from utils.nostr_utils import get_event_by_id, get_referenced_event_by_id, send_event, check_and_decrypt_tags from utils.nostr_utils import get_event_by_id, get_referenced_event_by_id, send_event, check_and_decrypt_tags
from utils.output_utils import build_status_reaction from utils.output_utils import build_status_reaction
from utils.zap_utils import check_bolt11_ln_bits_is_paid, create_bolt11_ln_bits, parse_zap_event_tags from utils.zap_utils import check_bolt11_ln_bits_is_paid, create_bolt11_ln_bits, parse_zap_event_tags, \
parse_amount_from_bolt11_invoice, zap, pay_bolt11_ln_bits
from utils.cashu_utils import redeem_cashu from utils.cashu_utils import redeem_cashu
use_logger = False use_logger = False
@@ -115,7 +116,8 @@ class DVM:
cashu_redeemed = False cashu_redeemed = False
if cashu != "": if cashu != "":
print(cashu) print(cashu)
cashu_redeemed, cashu_message, redeem_amount, fees = redeem_cashu(cashu, self.dvm_config, self.client, int(amount)) cashu_redeemed, cashu_message, redeem_amount, fees = redeem_cashu(cashu, self.dvm_config,
self.client, int(amount))
print(cashu_message) print(cashu_message)
if cashu_message != "success": if cashu_message != "success":
send_job_status_reaction(nip90_event, "error", False, amount, self.client, cashu_message, send_job_status_reaction(nip90_event, "error", False, amount, self.client, cashu_message,
@@ -131,7 +133,10 @@ class DVM:
send_job_status_reaction(nip90_event, "processing", True, 0, send_job_status_reaction(nip90_event, "processing", True, 0,
client=self.client, dvm_config=self.dvm_config) client=self.client, dvm_config=self.dvm_config)
do_work(nip90_event) # when we reimburse users on error make sure to not send anything if it was free
if user.iswhitelisted or task_is_free:
amount = 0
do_work(nip90_event, amount)
# if task is directed to us via p tag and user has balance, do the job and update balance # if task is directed to us via p tag and user has balance, do the job and update balance
elif p_tag_str == self.dvm_config.PUBLIC_KEY and user.balance >= int(amount): elif p_tag_str == self.dvm_config.PUBLIC_KEY and user.balance >= int(amount):
balance = max(user.balance - int(amount), 0) balance = max(user.balance - int(amount), 0)
@@ -147,7 +152,7 @@ class DVM:
send_job_status_reaction(nip90_event, "processing", True, 0, send_job_status_reaction(nip90_event, "processing", True, 0,
client=self.client, dvm_config=self.dvm_config) client=self.client, dvm_config=self.dvm_config)
do_work(nip90_event) do_work(nip90_event, amount)
# else send a payment required event to user # else send a payment required event to user
elif p_tag_str == "" or p_tag_str == self.dvm_config.PUBLIC_KEY: elif p_tag_str == "" or p_tag_str == self.dvm_config.PUBLIC_KEY:
@@ -228,10 +233,10 @@ class DVM:
# If payment-required appears before processing # If payment-required appears before processing
self.job_list.pop(index) self.job_list.pop(index)
print("Starting work...") print("Starting work...")
do_work(job_event) do_work(job_event, invoice_amount)
else: else:
print("Job not in List, but starting work...") print("Job not in List, but starting work...")
do_work(job_event) do_work(job_event, invoice_amount)
else: else:
send_job_status_reaction(job_event, "payment-rejected", send_job_status_reaction(job_event, "payment-rejected",
@@ -321,10 +326,7 @@ class DVM:
except Exception as e: except Exception as e:
send_job_status_reaction(original_event, "error", content=str(e), send_job_status_reaction(original_event, "error", content=str(e),
dvm_config=self.dvm_config, dvm_config=self.dvm_config,
) )
def send_nostr_reply_event(content, original_event_as_str): def send_nostr_reply_event(content, original_event_as_str):
original_event = Event.from_json(original_event_as_str) original_event = Event.from_json(original_event_as_str)
@@ -443,7 +445,7 @@ class DVM:
EventDefinitions.KIND_FEEDBACK) + " Reaction: " + status + " " + reaction_event.as_json()) EventDefinitions.KIND_FEEDBACK) + " Reaction: " + status + " " + reaction_event.as_json())
return reaction_event.as_json() return reaction_event.as_json()
def do_work(job_event): def do_work(job_event, amount):
if ((EventDefinitions.KIND_NIP90_EXTRACT_TEXT <= job_event.kind() <= EventDefinitions.KIND_NIP90_GENERIC) if ((EventDefinitions.KIND_NIP90_EXTRACT_TEXT <= job_event.kind() <= EventDefinitions.KIND_NIP90_GENERIC)
or job_event.kind() == EventDefinitions.KIND_DM): or job_event.kind() == EventDefinitions.KIND_DM):
@@ -460,14 +462,27 @@ class DVM:
send_nostr_reply_event(post_processed, job_event.as_json()) send_nostr_reply_event(post_processed, job_event.as_json())
except Exception as e: except Exception as e:
send_job_status_reaction(job_event, "error", content=str(e), send_job_status_reaction(job_event, "error", content=str(e),
dvm_config=self.dvm_config, dvm_config=self.dvm_config)
)
except Exception as e: except Exception as e:
print(e) print(e)
# we could send the exception here to the user, but maybe that's not a good idea after all. # 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="An error occurred", send_job_status_reaction(job_event, "error", content="An error occurred",
dvm_config=self.dvm_config) dvm_config=self.dvm_config)
# TODO send sats back on error # Zapping back the user on error
if amount > 0:
user = get_or_add_user(self.dvm_config.DB, job_event.pubkey().to_hex(),
client=self.client, config=self.dvm_config)
print(user.lud16 + " " + str(amount))
bolt11 = zap(user.lud16, amount, "Couldn't finish job, returning sats", job_event,
self.keys, self.dvm_config, zaptype="private")
if bolt11 is None:
print("Receiver has no Lightning address, can't zap back.")
return
try:
payment_hash = pay_bolt11_ln_bits(bolt11, self.dvm_config)
except Exception as e:
print(e)
return return
@@ -484,7 +499,8 @@ class DVM:
client=self.client, client=self.client,
dvm_config=self.dvm_config) dvm_config=self.dvm_config)
print("[" + self.dvm_config.NIP89.NAME + "] doing work from joblist") print("[" + self.dvm_config.NIP89.NAME + "] doing work from joblist")
do_work(job.event) amount = parse_amount_from_bolt11_invoice(job.bolt11)
do_work(job.event, amount)
elif ispaid is None: # invoice expired elif ispaid is None: # invoice expired
self.job_list.remove(job) self.job_list.remove(job)

14
main.py
View File

@@ -19,6 +19,8 @@ from utils.dvmconfig import DVMConfig
from utils.external_dvm_utils import build_external_dvm from utils.external_dvm_utils import build_external_dvm
from utils.nostr_utils import check_and_set_private_key from utils.nostr_utils import check_and_set_private_key
from utils.output_utils import PostProcessFunctionType from utils.output_utils import PostProcessFunctionType
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
def playground(): def playground():
@@ -26,10 +28,13 @@ def playground():
# Note this is very basic for now and still under development # Note this is very basic for now and still under development
bot_config = DVMConfig() bot_config = DVMConfig()
bot_config.PRIVATE_KEY = check_and_set_private_key("bot") bot_config.PRIVATE_KEY = check_and_set_private_key("bot")
bot_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") npub = Keys.from_sk_str(bot_config.PRIVATE_KEY).public_key().to_bech32()
bot_config.LNBITS_ADMIN_KEY = os.getenv("LNBITS_ADMIN_KEY") # The bot will forward zaps for us, use responsibly invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys("bot", npub)
bot_config.LNBITS_INVOICE_KEY = invoice_key
bot_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
bot_config.LNBITS_URL = os.getenv("LNBITS_HOST") bot_config.LNBITS_URL = os.getenv("LNBITS_HOST")
# Generate an optional Admin Config, in this case, whenever we give our DVMs this config, they will (re)broadcast # Generate an optional Admin Config, in this case, whenever we give our DVMs this config, they will (re)broadcast
# their NIP89 announcement # their NIP89 announcement
# You can create individual admins configs and hand them over when initializing the dvm, # You can create individual admins configs and hand them over when initializing the dvm,
@@ -37,10 +42,13 @@ def playground():
# If you use this global config, options will be set for all dvms that use it. # If you use this global config, options will be set for all dvms that use it.
admin_config = AdminConfig() admin_config = AdminConfig()
admin_config.REBROADCAST_NIP89 = False admin_config.REBROADCAST_NIP89 = False
admin_config.LUD16 = lnaddress
# Set rebroadcast to true once you have set your NIP89 descriptions and d tags. You only need to rebroadcast once you # Set rebroadcast to true once you have set your NIP89 descriptions and d tags. You only need to rebroadcast once you
# want to update your NIP89 descriptions # want to update your NIP89 descriptions
# Update the DVMs (not the bot) profile. For example after you updated the NIP89 or the lnaddress, you can automatically update profiles here.
admin_config.UPDATE_PROFILE = False admin_config.UPDATE_PROFILE = False
admin_config.LUD16 = ""
# Spawn some DVMs in the playground and run them # Spawn some DVMs in the playground and run them
# You can add arbitrary DVMs there and instantiate them here # You can add arbitrary DVMs there and instantiate them here

View File

@@ -17,6 +17,7 @@ from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import get_event_by_id, check_and_set_private_key from utils.nostr_utils import get_event_by_id, check_and_set_private_key
from utils.output_utils import post_process_list_to_users, post_process_list_to_events from utils.output_utils import post_process_list_to_users, post_process_list_to_events
from utils.zap_utils import check_and_set_ln_bits_keys
""" """
This File contains a Module to search for notes This File contains a Module to search for notes
@@ -143,8 +144,12 @@ class AdvancedSearch(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
# Add NIP89 # Add NIP89
nip90params = { nip90params = {
"user": { "user": {

View File

@@ -15,6 +15,8 @@ from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.mediasource_utils import organize_input_media_data from utils.mediasource_utils import organize_input_media_data
from utils.nostr_utils import check_and_set_private_key from utils.nostr_utils import check_and_set_private_key
from utils.output_utils import upload_media_to_hoster from utils.output_utils import upload_media_to_hoster
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to call Google Translate Services locally on the DVM Machine This File contains a Module to call Google Translate Services locally on the DVM Machine
@@ -87,8 +89,12 @@ class MediaConverter(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
# Add NIP89 # Add NIP89
nip90params = { nip90params = {
"media_format": { "media_format": {

View File

@@ -17,6 +17,7 @@ from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import get_event_by_id, check_and_set_private_key from utils.nostr_utils import get_event_by_id, check_and_set_private_key
from utils.output_utils import post_process_list_to_users from utils.output_utils import post_process_list_to_users
from utils.zap_utils import check_and_set_ln_bits_keys
""" """
This File contains a Module to find inactive follows for a user on nostr This File contains a Module to find inactive follows for a user on nostr
@@ -174,8 +175,12 @@ class DiscoverInactiveFollows(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
# Add NIP89 # Add NIP89
nip90params = { nip90params = {
"user": { "user": {

View File

@@ -15,7 +15,8 @@ from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import check_and_set_private_key from utils.nostr_utils import check_and_set_private_key
from utils.output_utils import upload_media_to_hoster from utils.output_utils import upload_media_to_hoster
from utils.zap_utils import get_price_per_sat from utils.zap_utils import get_price_per_sat, check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to transform Text input on OpenAI's servers with DALLE-3 and receive results back. This File contains a Module to transform Text input on OpenAI's servers with DALLE-3 and receive results back.
@@ -127,8 +128,12 @@ class ImageGenerationDALLE(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
profit_in_sats = 10 profit_in_sats = 10
dvm_config.FIX_COST = int(((4.0 / (get_price_per_sat("USD") * 100)) + profit_in_sats)) dvm_config.FIX_COST = int(((4.0 / (get_price_per_sat("USD") * 100)) + profit_in_sats))

View File

@@ -15,7 +15,8 @@ from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import check_and_set_private_key from utils.nostr_utils import check_and_set_private_key
from utils.output_utils import upload_media_to_hoster from utils.output_utils import upload_media_to_hoster
from utils.zap_utils import get_price_per_sat from utils.zap_utils import get_price_per_sat, check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to transform Text input on NOVA-Server and receive results back. This File contains a Module to transform Text input on NOVA-Server and receive results back.
@@ -122,8 +123,12 @@ class ImageGenerationReplicateSDXL(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
profit_in_sats = 10 profit_in_sats = 10
dvm_config.FIX_COST = int(((4.0 / (get_price_per_sat("USD") * 100)) + profit_in_sats)) dvm_config.FIX_COST = int(((4.0 / (get_price_per_sat("USD") * 100)) + profit_in_sats))

View File

@@ -14,6 +14,8 @@ from utils.mediasource_utils import organize_input_media_data
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.definitions import EventDefinitions from utils.definitions import EventDefinitions
from utils.nostr_utils import check_and_set_private_key from utils.nostr_utils import check_and_set_private_key
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to transform a media file input on Google Cloud This File contains a Module to transform a media file input on Google Cloud
@@ -133,8 +135,12 @@ class SpeechToTextGoogle(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
options = {'api_key': None} options = {'api_key': None}
# A module might have options it can be initialized with, here we set a default model, and the server # A module might have options it can be initialized with, here we set a default model, and the server
# address it should use. These parameters can be freely defined in the task component # address it should use. These parameters can be freely defined in the task component

View File

@@ -12,6 +12,8 @@ from utils.definitions import EventDefinitions
from utils.dvmconfig import DVMConfig from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import get_event_by_id, check_and_set_private_key from utils.nostr_utils import get_event_by_id, check_and_set_private_key
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to extract Text from a PDF file locally on the DVM Machine This File contains a Module to extract Text from a PDF file locally on the DVM Machine
@@ -96,8 +98,12 @@ class TextExtractionPDF(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
# Add NIP89 # Add NIP89
nip90params = {} nip90params = {}
nip89info = { nip89info = {

View File

@@ -11,6 +11,8 @@ from utils.definitions import EventDefinitions
from utils.dvmconfig import DVMConfig from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import get_referenced_event_by_id, get_event_by_id, check_and_set_private_key from utils.nostr_utils import get_referenced_event_by_id, get_event_by_id, check_and_set_private_key
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to call Google Translate Services locally on the DVM Machine This File contains a Module to call Google Translate Services locally on the DVM Machine
@@ -113,8 +115,12 @@ class TranslationGoogle(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
nip90params = { nip90params = {
"language": { "language": {

View File

@@ -12,6 +12,8 @@ from utils.definitions import EventDefinitions
from utils.dvmconfig import DVMConfig from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import get_referenced_event_by_id, get_event_by_id, check_and_set_private_key from utils.nostr_utils import get_referenced_event_by_id, get_event_by_id, check_and_set_private_key
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to call Google Translate Services locally on the DVM Machine This File contains a Module to call Google Translate Services locally on the DVM Machine
@@ -110,8 +112,12 @@ class TranslationLibre(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
options = {'libre_end_point': os.getenv("LIBRE_TRANSLATE_ENDPOINT"), options = {'libre_end_point': os.getenv("LIBRE_TRANSLATE_ENDPOINT"),
'libre_api_key': os.getenv("LIBRE_TRANSLATE_API_KEY")} 'libre_api_key': os.getenv("LIBRE_TRANSLATE_API_KEY")}

View File

@@ -16,7 +16,8 @@ from utils.dvmconfig import DVMConfig
from utils.nip89_utils import NIP89Config, check_and_set_d_tag from utils.nip89_utils import NIP89Config, check_and_set_d_tag
from utils.nostr_utils import check_and_set_private_key from utils.nostr_utils import check_and_set_private_key
from utils.output_utils import upload_media_to_hoster from utils.output_utils import upload_media_to_hoster
from utils.zap_utils import get_price_per_sat from utils.zap_utils import get_price_per_sat, check_and_set_ln_bits_keys
from nostr_sdk import Keys
""" """
This File contains a Module to transform an image to a short video clip using Stable Video Diffusion with replicate This File contains a Module to transform an image to a short video clip using Stable Video Diffusion with replicate
@@ -113,8 +114,12 @@ class VideoGenerationReplicateSVD(DVMTaskInterface):
def build_example(name, identifier, admin_config): def build_example(name, identifier, admin_config):
dvm_config = DVMConfig() dvm_config = DVMConfig()
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier) dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY") 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
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST") dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
admin_config.LUD16 = lnaddress
profit_in_sats = 10 profit_in_sats = 10
cost_in_cent = 4.0 cost_in_cent = 4.0
dvm_config.FIX_COST = int(((cost_in_cent / (get_price_per_sat("USD") * 100)) + profit_in_sats)) dvm_config.FIX_COST = int(((cost_in_cent / (get_price_per_sat("USD") * 100)) + profit_in_sats))
@@ -136,6 +141,7 @@ def build_example(name, identifier, admin_config):
nip89info["image"]) nip89info["image"])
nip89config.CONTENT = json.dumps(nip89info) nip89config.CONTENT = json.dumps(nip89info)
# We add an optional AdminConfig for this one, and tell the dvm to rebroadcast its NIP89 # We add an optional AdminConfig for this one, and tell the dvm to rebroadcast its NIP89
return VideoGenerationReplicateSVD(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config) return VideoGenerationReplicateSVD(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config)

View File

@@ -150,9 +150,9 @@ def update_profile(dvm_config, client, lud16=""):
.set_display_name(name) \ .set_display_name(name) \
.set_about(about) \ .set_about(about) \
.set_picture(image) \ .set_picture(image) \
.set_lud16(lud16) .set_lud16(lud16) \
.set_nip05(lud16)
# .set_banner("https://example.com/banner.png") \ # .set_banner("https://example.com/banner.png") \
# .set_nip05("username@example.com") \
print(f"Setting profile metadata for {keys.public_key().to_bech32()}...") print(f"Setting profile metadata for {keys.public_key().to_bech32()}...")
print(metadata.as_json()) print(metadata.as_json())

View File

@@ -1,18 +1,29 @@
# LIGHTNING/CASHU/ZAP FUNCTIONS # LIGHTNING/ZAP FUNCTIONS
import json import json
import os import os
import urllib.parse import urllib.parse
from pathlib import Path
import requests import requests
from Crypto.Cipher import AES from Crypto.Cipher import AES
from Crypto.Util.Padding import pad from Crypto.Util.Padding import pad
from bech32 import bech32_decode, convertbits, bech32_encode from bech32 import bech32_decode, convertbits, bech32_encode
from nostr_sdk import nostr_sdk, PublicKey, SecretKey, Event, EventBuilder, Tag, Keys from nostr_sdk import nostr_sdk, PublicKey, SecretKey, Event, EventBuilder, Tag, Keys
from utils.dvmconfig import DVMConfig from utils.dvmconfig import DVMConfig
from utils.nostr_utils import get_event_by_id, check_and_decrypt_own_tags from utils.nostr_utils import get_event_by_id, check_and_decrypt_own_tags, update_profile
import lnurl import lnurl
from hashlib import sha256 from hashlib import sha256
import dotenv
# TODO tor connection to lnbits
# proxies = {
# 'http': 'socks5h://127.0.0.1:9050',
# 'https': 'socks5h://127.0.0.1:9050'
# }
proxies = {}
def parse_zap_event_tags(zap_event, keys, name, client, config): def parse_zap_event_tags(zap_event, keys, name, client, config):
zapped_event = None zapped_event = None
invoice_amount = 0 invoice_amount = 0
@@ -116,12 +127,34 @@ def create_bolt11_lud16(lud16, amount):
except: except:
return None return None
def create_lnbits_account(name):
if os.getenv("LNBITS_ADMIN_ID") is None or os.getenv("LNBITS_ADMIN_ID") == "":
print("No admin id set, no wallet created.")
return
data = {
'admin_id': os.getenv("LNBITS_ADMIN_ID"),
'wallet_name': name,
'user_name': name,
}
try:
json_object = json.dumps(data)
url = os.getenv("LNBITS_HOST") + '/usermanager/api/v1/users'
print(url)
headers = {'X-API-Key': os.getenv("LNBITS_ADMIN_KEY"), 'Content-Type': 'application/json', 'charset': 'UTF-8'}
r = requests.post(url, data=json_object, headers=headers, proxies=proxies)
walletjson = json.loads(r.text)
print(walletjson)
if walletjson.get("wallets"):
return walletjson['wallets'][0]['inkey'], walletjson['wallets'][0]['adminkey'], walletjson['wallets'][0]['id'], walletjson['id'], "success"
except:
print("error creating wallet")
def check_bolt11_ln_bits_is_paid(payment_hash: str, config: DVMConfig): def check_bolt11_ln_bits_is_paid(payment_hash: str, config: DVMConfig):
url = config.LNBITS_URL + "/api/v1/payments/" + payment_hash url = config.LNBITS_URL + "/api/v1/payments/" + payment_hash
headers = {'X-API-Key': config.LNBITS_INVOICE_KEY, 'Content-Type': 'application/json', 'charset': 'UTF-8'} headers = {'X-API-Key': config.LNBITS_INVOICE_KEY, 'Content-Type': 'application/json', 'charset': 'UTF-8'}
try: try:
res = requests.get(url, headers=headers) res = requests.get(url, headers=headers, proxies=proxies)
obj = json.loads(res.text) obj = json.loads(res.text)
if obj.get("paid"): if obj.get("paid"):
return obj["paid"] return obj["paid"]
@@ -264,3 +297,74 @@ def get_price_per_sat(currency):
price_currency_per_sat = 0.0004 price_currency_per_sat = 0.0004
return price_currency_per_sat return price_currency_per_sat
def make_ln_address_nostdress(identifier, npub, pin, nostdressdomain):
#env_path = Path('.env')
#if env_path.is_file():
# dotenv.load_dotenv(env_path, verbose=True, override=True)
print(os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()))
data = {
'name': identifier,
'domain': nostdressdomain,
'kind': "lnbits",
'host': os.getenv("LNBITS_HOST"),
'key': os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()),
'pin': pin,
'npub': npub,
'currentname': " "
}
try:
url = "https://" + nostdressdomain + "/api/easy/"
res = requests.post(url, data=data)
print(res.text)
obj = json.loads(res.text)
if obj.get("ok"):
return identifier + "@" + nostdressdomain, obj["pin"]
except Exception as e:
print(e)
return "", ""
def check_and_set_ln_bits_keys(identifier, npub):
if not os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()):
invoicekey, adminkey, walletid, userid, success = create_lnbits_account(identifier)
add_key_to_env_file("LNBITS_INVOICE_KEY_" + identifier.upper(), invoicekey)
add_key_to_env_file("LNBITS_ADMIN_KEY_" + identifier.upper(), adminkey)
add_key_to_env_file("LNBITS_USER_ID_" + identifier.upper(), userid)
add_key_to_env_file("LNBITS_WALLET_ID_" + identifier.upper(), userid)
lnaddress = ""
pin = ""
if os.getenv("NOSTDRESS_DOMAIN"):
print(os.getenv("NOSTDRESS_DOMAIN"))
lnaddress, pin = make_ln_address_nostdress(identifier, npub, " ", os.getenv("NOSTDRESS_DOMAIN"))
add_key_to_env_file("LNADDRESS_" + identifier.upper(), lnaddress)
add_key_to_env_file("LNADDRESS_PIN_" + identifier.upper(), pin)
return invoicekey, adminkey, userid, walletid, lnaddress
else:
return (os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()),
os.getenv("LNBITS_ADMIN_KEY_" + identifier.upper()),
os.getenv("LNBITS_USER_ID_" + identifier.upper()),
os.getenv("LNBITS_WALLET_ID_" + identifier.upper()),
os.getenv("LNADDRESS_" + identifier.upper()))
def add_key_to_env_file(value, oskey):
env_path = Path('.env')
if env_path.is_file():
dotenv.load_dotenv(env_path, verbose=True, override=True)
dotenv.set_key(env_path, value, oskey)