Merge branch 'main' into nserver-modules

This commit is contained in:
Believethehype 2023-12-09 23:59:10 +01:00
commit c422b18ba3
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)
# 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_ID = ""
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.
@ -14,4 +19,7 @@ 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.
# 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.py
app_deploy.py
db/Cashu/wallet.sqlite3
db/*
.idea/misc.xml
.idea/misc.xml
backends/nserver/cache/*
backends/nserver/modules/image_upscale/weights/*
backends/nserver/venv
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"`
- 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
- Run python main.py.

View File

@ -298,6 +298,7 @@ class Bot:
print("Receiver has no Lightning address")
return
try:
print(bolt11)
payment_hash = pay_bolt11_ln_bits(bolt11, self.dvm_config)
self.job_list[self.job_list.index(entry)]['is_paid'] = True
print("[" + self.NAME + "] payment_hash: " + payment_hash +
@ -366,16 +367,39 @@ class Bot:
self.keys, self.NAME,
self.client, self.dvm_config)
user = get_or_add_user(self.dvm_config.DB, sender, client=self.client, config=self.dvm_config)
if zapped_event is not None:
if not anon:
print("[" + self.NAME + "] Note Zap received for Bot 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)
etag = ""
for tag in zap_event.tags():
if tag.as_vec()[0] == "e":
etag = tag.as_vec()[1]
# a regular note
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 not anon:
print("[" + self.NAME + "] Note Zap received for Bot 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)
# a regular note
elif not anon:
print("[" + self.NAME + "] Profile Zap received for Bot balance: " + str(
invoice_amount) + " Sats from " + 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.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.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
use_logger = False
@ -115,7 +116,8 @@ class DVM:
cashu_redeemed = False
if 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)
if cashu_message != "success":
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,
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
elif p_tag_str == self.dvm_config.PUBLIC_KEY and user.balance >= int(amount):
balance = max(user.balance - int(amount), 0)
@ -147,7 +152,7 @@ class DVM:
send_job_status_reaction(nip90_event, "processing", True, 0,
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
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
self.job_list.pop(index)
print("Starting work...")
do_work(job_event)
do_work(job_event, invoice_amount)
else:
print("Job not in List, but starting work...")
do_work(job_event)
do_work(job_event, invoice_amount)
else:
send_job_status_reaction(job_event, "payment-rejected",
@ -314,17 +319,14 @@ class DVM:
task = get_task(original_event, self.client, self.dvm_config)
for dvm in self.dvm_config.SUPPORTED_DVMS:
if task == dvm.TASK:
try:
post_processed = dvm.post_process(data, original_event)
send_nostr_reply_event(post_processed, original_event.as_json())
except Exception as e:
send_job_status_reaction(original_event, "error", content=str(e),
if task == dvm.TASK:
try:
post_processed = dvm.post_process(data, original_event)
send_nostr_reply_event(post_processed, original_event.as_json())
except Exception as e:
send_job_status_reaction(original_event, "error", content=str(e),
dvm_config=self.dvm_config,
)
)
def send_nostr_reply_event(content, 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())
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)
or job_event.kind() == EventDefinitions.KIND_DM):
@ -460,14 +462,27 @@ class DVM:
send_nostr_reply_event(post_processed, job_event.as_json())
except Exception as 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:
print(e)
# 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",
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
@ -484,7 +499,8 @@ class DVM:
client=self.client,
dvm_config=self.dvm_config)
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
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.nostr_utils import check_and_set_private_key
from utils.output_utils import PostProcessFunctionType
from utils.zap_utils import check_and_set_ln_bits_keys
from nostr_sdk import Keys
def playground():
@ -26,10 +28,13 @@ def playground():
# Note this is very basic for now and still under development
bot_config = DVMConfig()
bot_config.PRIVATE_KEY = check_and_set_private_key("bot")
bot_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY")
bot_config.LNBITS_ADMIN_KEY = os.getenv("LNBITS_ADMIN_KEY") # The bot will forward zaps for us, use responsibly
npub = Keys.from_sk_str(bot_config.PRIVATE_KEY).public_key().to_bech32()
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")
# Generate an optional Admin Config, in this case, whenever we give our DVMs this config, they will (re)broadcast
# their NIP89 announcement
# 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.
admin_config = AdminConfig()
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
# 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.LUD16 = ""
# Spawn some DVMs in the playground and run them
# 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.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.zap_utils import check_and_set_ln_bits_keys
"""
This File contains a Module to search for notes
@ -143,8 +144,12 @@ class AdvancedSearch(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
# Add NIP89
nip90params = {
"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.nostr_utils import check_and_set_private_key
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
@ -87,8 +89,12 @@ class MediaConverter(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
# Add NIP89
nip90params = {
"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.nostr_utils import get_event_by_id, check_and_set_private_key
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
@ -174,8 +175,12 @@ class DiscoverInactiveFollows(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
# Add NIP89
nip90params = {
"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.nostr_utils import check_and_set_private_key
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.
@ -127,8 +128,12 @@ class ImageGenerationDALLE(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
profit_in_sats = 10
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.nostr_utils import check_and_set_private_key
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.
@ -122,8 +123,12 @@ class ImageGenerationReplicateSDXL(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
profit_in_sats = 10
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.definitions import EventDefinitions
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
@ -133,8 +135,12 @@ class SpeechToTextGoogle(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
options = {'api_key': None}
# 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

View File

@ -12,6 +12,8 @@ from utils.definitions import EventDefinitions
from utils.dvmconfig import DVMConfig
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.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
@ -96,8 +98,12 @@ class TextExtractionPDF(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
# Add NIP89
nip90params = {}
nip89info = {

View File

@ -11,6 +11,8 @@ from utils.definitions import EventDefinitions
from utils.dvmconfig import DVMConfig
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.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
@ -113,8 +115,12 @@ class TranslationGoogle(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
nip90params = {
"language": {

View File

@ -12,6 +12,8 @@ from utils.definitions import EventDefinitions
from utils.dvmconfig import DVMConfig
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.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
@ -110,8 +112,12 @@ class TranslationLibre(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
options = {'libre_end_point': os.getenv("LIBRE_TRANSLATE_ENDPOINT"),
'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.nostr_utils import check_and_set_private_key
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
@ -113,8 +114,12 @@ class VideoGenerationReplicateSVD(DVMTaskInterface):
def build_example(name, identifier, admin_config):
dvm_config = DVMConfig()
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")
admin_config.LUD16 = lnaddress
profit_in_sats = 10
cost_in_cent = 4.0
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"])
nip89config.CONTENT = json.dumps(nip89info)
# 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)

View File

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

View File

@ -1,18 +1,29 @@
# LIGHTNING/CASHU/ZAP FUNCTIONS
# LIGHTNING/ZAP FUNCTIONS
import json
import os
import urllib.parse
from pathlib import Path
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from bech32 import bech32_decode, convertbits, bech32_encode
from nostr_sdk import nostr_sdk, PublicKey, SecretKey, Event, EventBuilder, Tag, Keys
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
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):
zapped_event = None
invoice_amount = 0
@ -116,12 +127,34 @@ def create_bolt11_lud16(lud16, amount):
except:
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):
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)
res = requests.get(url, headers=headers, proxies=proxies)
obj = json.loads(res.text)
if obj.get("paid"):
return obj["paid"]
@ -264,3 +297,74 @@ def get_price_per_sat(currency):
price_currency_per_sat = 0.0004
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)