mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-11-18 10:07:36 +01:00
Merge branch 'main' into backends-nserver
This commit is contained in:
@@ -43,9 +43,6 @@ def send_file_to_server(filepath, address):
|
||||
|
||||
return result
|
||||
|
||||
# headers = {'Content-type': 'application/x-www-form-urlencoded'}
|
||||
|
||||
|
||||
"""
|
||||
check_n_server_status(request_form, address)
|
||||
Function that requests the status of the current process with the jobID (we use the Nostr event as jobID).
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import importlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \
|
||||
init_logger, LogLevel, Options, nip04_encrypt
|
||||
@@ -323,7 +327,8 @@ class DVM:
|
||||
except Exception as e:
|
||||
# Zapping back by error in post-processing is a risk for the DVM because work has been done,
|
||||
# but maybe something with parsing/uploading failed. Try to avoid errors here as good as possible
|
||||
send_job_status_reaction(original_event, "error", content="Error in Post-processing: " + str(e),
|
||||
send_job_status_reaction(original_event, "error",
|
||||
content="Error in Post-processing: " + str(e),
|
||||
dvm_config=self.dvm_config,
|
||||
)
|
||||
if amount > 0 and self.dvm_config.LNBITS_ADMIN_KEY != "":
|
||||
@@ -466,11 +471,30 @@ class DVM:
|
||||
for dvm in self.dvm_config.SUPPORTED_DVMS:
|
||||
try:
|
||||
if task == dvm.TASK:
|
||||
request_form = dvm.create_request_from_nostr_event(job_event, self.client,
|
||||
self.dvm_config)
|
||||
result = dvm.process(request_form)
|
||||
|
||||
request_form = dvm.create_request_from_nostr_event(job_event, self.client, self.dvm_config)
|
||||
|
||||
if dvm_config.USE_OWN_VENV:
|
||||
python_bin = (r'cache/venvs/' + os.path.basename(dvm_config.SCRIPT).split(".py")[0]
|
||||
+ "/bin/python")
|
||||
retcode = subprocess.call([python_bin, dvm_config.SCRIPT,
|
||||
'--request', json.dumps(request_form),
|
||||
'--identifier', dvm_config.IDENTIFIER,
|
||||
'--output', 'output.txt'])
|
||||
print("Finished processing, loading data..")
|
||||
|
||||
with open(os.path.abspath('output.txt')) as f:
|
||||
resultall = f.readlines()
|
||||
result = ""
|
||||
for line in resultall:
|
||||
if line != '\n':
|
||||
result += line
|
||||
os.remove(os.path.abspath('output.txt'))
|
||||
else: #Some components might have issues with running code in otuside venv.
|
||||
# We install locally in these cases for now
|
||||
result = dvm.process(request_form)
|
||||
try:
|
||||
post_processed = dvm.post_process(result, job_event)
|
||||
post_processed = dvm.post_process(str(result), job_event)
|
||||
send_nostr_reply_event(post_processed, job_event.as_json())
|
||||
except Exception as e:
|
||||
send_job_status_reaction(job_event, "error", content=str(e),
|
||||
@@ -495,7 +519,6 @@ class DVM:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
return
|
||||
|
||||
self.client.handle_notifications(NotificationHandler())
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from subprocess import run
|
||||
import sys
|
||||
from threading import Thread
|
||||
|
||||
from venv import create
|
||||
from nostr_sdk import Keys
|
||||
|
||||
from nostr_dvm.dvm import DVM
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config
|
||||
from nostr_dvm.utils.nostr_utils import check_and_set_private_key
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.output_utils import post_process_result
|
||||
from nostr_dvm.utils.zap_utils import check_and_set_ln_bits_keys
|
||||
|
||||
|
||||
class DVMTaskInterface:
|
||||
@@ -34,7 +32,7 @@ class DVMTaskInterface:
|
||||
options=None, task=None):
|
||||
self.init(name, dvm_config, admin_config, nip89config, task)
|
||||
self.options = options
|
||||
self.install_dependencies(self.dependencies)
|
||||
self.install_dependencies(dvm_config)
|
||||
|
||||
def init(self, name, dvm_config, admin_config=None, nip89config=None, task=None):
|
||||
self.NAME = name
|
||||
@@ -58,6 +56,27 @@ class DVMTaskInterface:
|
||||
self.dvm_config = dvm_config
|
||||
self.admin_config = admin_config
|
||||
|
||||
def install_dependencies(self, dvm_config):
|
||||
if dvm_config.SCRIPT != "":
|
||||
if self.dvm_config.USE_OWN_VENV:
|
||||
|
||||
dir = r'cache/venvs/' + os.path.basename(dvm_config.SCRIPT).split(".py")[0]
|
||||
if not os.path.isdir(dir):
|
||||
print(dir)
|
||||
create(dir, with_pip=True, upgrade_deps=True)
|
||||
self.dependencies.append(("nostr-dvm", "nostr-dvm"))
|
||||
for (module, package) in self.dependencies:
|
||||
print("Installing Venv Module: " + module)
|
||||
run(["bin/pip", "install", "--force-reinstall", package], cwd=dir)
|
||||
else:
|
||||
for module, package in self.dependencies:
|
||||
if module != "nostr-dvm":
|
||||
try:
|
||||
__import__(module)
|
||||
except ImportError:
|
||||
print("Installing global Module: " + module)
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
||||
|
||||
def run(self):
|
||||
nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config])
|
||||
nostr_dvm_thread.start()
|
||||
@@ -87,16 +106,6 @@ class DVMTaskInterface:
|
||||
"""Post-process the data and return the result Use default function, if not overwritten"""
|
||||
return post_process_result(result, event)
|
||||
|
||||
def install_dependencies(self, packages):
|
||||
import pip
|
||||
for module, package in packages:
|
||||
try:
|
||||
__import__(module)
|
||||
except ImportError:
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def set_options(request_form):
|
||||
print("Setting options...")
|
||||
@@ -105,3 +114,19 @@ class DVMTaskInterface:
|
||||
opts = json.loads(request_form["options"])
|
||||
print(opts)
|
||||
return dict(opts)
|
||||
|
||||
@staticmethod
|
||||
def process_args():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--request', dest='request')
|
||||
parser.add_argument('--identifier', dest='identifier')
|
||||
parser.add_argument('--output', dest='output')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
@staticmethod
|
||||
def write_output(result, output):
|
||||
with open(os.path.abspath(output), 'w') as f:
|
||||
f.write(result)
|
||||
# f.close()
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import json
|
||||
import os
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
from nostr_sdk import Client, Timestamp, PublicKey, Tag, Keys, Options, SecretKey
|
||||
|
||||
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.backend_utils import keep_alive
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
@@ -27,9 +23,11 @@ class AdvancedSearch(DVMTaskInterface):
|
||||
TASK: str = "search-content"
|
||||
FIX_COST: float = 0
|
||||
dvm_config: DVMConfig
|
||||
dependencies = [("nostr-dvm", "nostr-dvm")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -177,19 +175,12 @@ def build_example(name, identifier, admin_config):
|
||||
admin_config=admin_config)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = AdvancedSearch(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
|
||||
dvm = build_example("Advanced Nostr Search", "discovery_content_search", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -1,14 +1,10 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
|
||||
import os
|
||||
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.backend_utils import keep_alive
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config
|
||||
from nostr_dvm.utils.mediasource_utils import organize_input_media_data
|
||||
from nostr_dvm.utils.output_utils import upload_media_to_hoster
|
||||
|
||||
@@ -30,6 +26,7 @@ class MediaConverter(DVMTaskInterface):
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -92,7 +89,7 @@ def build_example(name, identifier, admin_config):
|
||||
"encryptionSupported": True,
|
||||
"cashuAccepted": True,
|
||||
"nip90Params": {
|
||||
"media_format": {
|
||||
"format": {
|
||||
"required": False,
|
||||
"values": ["video/mp4", "audio/mp3"]
|
||||
}
|
||||
@@ -100,26 +97,18 @@ def build_example(name, identifier, admin_config):
|
||||
}
|
||||
|
||||
nip89config = NIP89Config()
|
||||
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"])
|
||||
nip89config.CONTENT = json.dumps(nip89info)
|
||||
|
||||
|
||||
return MediaConverter(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config)
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = MediaConverter(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
|
||||
dvm = build_example("Media Bringer", "media_converter", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -1,15 +1,12 @@
|
||||
import json
|
||||
import os
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
from threading import Thread
|
||||
|
||||
import dotenv
|
||||
from nostr_sdk import Client, Timestamp, PublicKey, Tag, Keys, Options
|
||||
|
||||
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.backend_utils import keep_alive
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
@@ -33,6 +30,7 @@ class DiscoverInactiveFollows(DVMTaskInterface):
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -198,19 +196,12 @@ def build_example(name, identifier, admin_config):
|
||||
return DiscoverInactiveFollows(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config)
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = DiscoverInactiveFollows(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("Bygones", "discovery_inactive_follows", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
186
nostr_dvm/tasks/imagegeneration_mlx.py
Normal file
186
nostr_dvm/tasks/imagegeneration_mlx.py
Normal file
@@ -0,0 +1,186 @@
|
||||
import json
|
||||
import os
|
||||
from PIL import Image
|
||||
from tqdm import tqdm
|
||||
|
||||
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.output_utils import upload_media_to_hoster
|
||||
from nostr_dvm.utils.zap_utils import get_price_per_sat
|
||||
|
||||
"""
|
||||
This File contains a Module to generate an Image on replicate and receive results back.
|
||||
|
||||
Accepted Inputs: Prompt (text)
|
||||
Outputs: An url to an Image
|
||||
Params:
|
||||
"""
|
||||
|
||||
|
||||
class ImageGenerationMLX(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
|
||||
TASK: str = "text-to-image"
|
||||
FIX_COST: float = 120
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("mlx", "mlx"),
|
||||
("safetensors", "safetensors"),
|
||||
("huggingface-hub", "huggingface-hub"),
|
||||
("regex", "regex"),
|
||||
("tqdm", "tqdm"),
|
||||
]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
for tag in tags:
|
||||
if tag.as_vec()[0] == 'i':
|
||||
input_value = tag.as_vec()[1]
|
||||
input_type = tag.as_vec()[2]
|
||||
if input_type != "text":
|
||||
return False
|
||||
|
||||
elif tag.as_vec()[0] == 'output':
|
||||
output = tag.as_vec()[1]
|
||||
if (output == "" or
|
||||
not (output == "image/png" or "image/jpg"
|
||||
or output == "image/png;format=url" or output == "image/jpg;format=url")):
|
||||
print("Output format not supported, skipping..")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def create_request_from_nostr_event(self, event, client=None, dvm_config=None):
|
||||
request_form = {"jobID": event.id().to_hex() + "_" + self.NAME.replace(" ", "")}
|
||||
prompt = ""
|
||||
width = "1024"
|
||||
height = "1024"
|
||||
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == 'i':
|
||||
input_type = tag.as_vec()[2]
|
||||
if input_type == "text":
|
||||
prompt = tag.as_vec()[1]
|
||||
|
||||
elif tag.as_vec()[0] == 'param':
|
||||
print("Param: " + tag.as_vec()[1] + ": " + tag.as_vec()[2])
|
||||
if tag.as_vec()[1] == "size":
|
||||
if len(tag.as_vec()) > 3:
|
||||
width = (tag.as_vec()[2])
|
||||
height = (tag.as_vec()[3])
|
||||
elif len(tag.as_vec()) == 3:
|
||||
split = tag.as_vec()[2].split("x")
|
||||
if len(split) > 1:
|
||||
width = split[0]
|
||||
height = split[1]
|
||||
elif tag.as_vec()[1] == "model":
|
||||
model = tag.as_vec()[2]
|
||||
elif tag.as_vec()[1] == "quality":
|
||||
quality = tag.as_vec()[2]
|
||||
|
||||
options = {
|
||||
"prompt": prompt,
|
||||
"size": width + "x" + height,
|
||||
"number": 1
|
||||
}
|
||||
request_form['options'] = json.dumps(options)
|
||||
|
||||
return request_form
|
||||
|
||||
def process(self, request_form):
|
||||
try:
|
||||
import mlx.core as mx
|
||||
from backends.mlx.stable_diffusion import StableDiffusion
|
||||
options = DVMTaskInterface.set_options(request_form)
|
||||
|
||||
sd = StableDiffusion()
|
||||
cfg_weight = 7.5
|
||||
batchsize = 1
|
||||
n_rows = 1
|
||||
steps = 50
|
||||
n_images = options["number"]
|
||||
|
||||
# Generate the latent vectors using diffusion
|
||||
latents = sd.generate_latents(
|
||||
options["prompt"],
|
||||
n_images=n_images,
|
||||
cfg_weight=cfg_weight,
|
||||
num_steps=steps,
|
||||
negative_text="",
|
||||
)
|
||||
for x_t in tqdm(latents, total=steps):
|
||||
mx.simplify(x_t)
|
||||
mx.simplify(x_t)
|
||||
mx.eval(x_t)
|
||||
|
||||
# Decode them into images
|
||||
decoded = []
|
||||
for i in tqdm(range(0, 1, batchsize)):
|
||||
decoded.append(sd.decode(x_t[i: i + batchsize]))
|
||||
mx.eval(decoded[-1])
|
||||
|
||||
# Arrange them on a grid
|
||||
x = mx.concatenate(decoded, axis=0)
|
||||
x = mx.pad(x, [(0, 0), (8, 8), (8, 8), (0, 0)])
|
||||
B, H, W, C = x.shape
|
||||
x = x.reshape(n_rows, B // n_rows, H, W, C).transpose(0, 2, 1, 3, 4)
|
||||
x = x.reshape(n_rows * H, B // n_rows * W, C)
|
||||
x = (x * 255).astype(mx.uint8)
|
||||
|
||||
# Save them to disc
|
||||
image = Image.fromarray(x.__array__())
|
||||
image.save("./outputs/image.jpg")
|
||||
result = upload_media_to_hoster("./outputs/image.jpg")
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print("Error in Module")
|
||||
raise Exception(e)
|
||||
|
||||
|
||||
# We build an example here that we can call by either calling this file directly from the main directory,
|
||||
# or by adding it to our playground. You can call the example and adjust it to your needs or redefine it in the
|
||||
# playground or elsewhere
|
||||
def build_example(name, identifier, admin_config):
|
||||
dvm_config = build_default_config(identifier)
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
profit_in_sats = 10
|
||||
dvm_config.FIX_COST = int(((4.0 / (get_price_per_sat("USD") * 100)) + profit_in_sats))
|
||||
|
||||
nip89info = {
|
||||
"name": name,
|
||||
"image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg",
|
||||
"about": "I use Replicate to run StableDiffusion XL",
|
||||
"encryptionSupported": True,
|
||||
"cashuAccepted": True,
|
||||
"nip90Params": {
|
||||
"size": {
|
||||
"required": False,
|
||||
"values": ["1024:1024", "1024x1792", "1792x1024"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nip89config = NIP89Config()
|
||||
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"])
|
||||
nip89config.CONTENT = json.dumps(nip89info)
|
||||
|
||||
return ImageGenerationMLX(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = ImageGenerationMLX(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
process_venv()
|
||||
@@ -1,15 +1,13 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.backend_utils import keep_alive
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
@@ -28,10 +26,12 @@ class ImageGenerationDALLE(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
|
||||
TASK: str = "text-to-image"
|
||||
FIX_COST: float = 120
|
||||
dependencies = [("openai", "openai==1.3.5")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("openai", "openai==1.3.5")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -107,6 +107,7 @@ class ImageGenerationDALLE(DVMTaskInterface):
|
||||
n=int(options['number']),
|
||||
)
|
||||
|
||||
|
||||
image_url = response.data[0].url
|
||||
# rehost the result instead of relying on the openai link
|
||||
response = requests.get(image_url)
|
||||
@@ -125,6 +126,7 @@ class ImageGenerationDALLE(DVMTaskInterface):
|
||||
# playground or elsewhere
|
||||
def build_example(name, identifier, admin_config):
|
||||
dvm_config = build_default_config(identifier)
|
||||
dvm_config.USE_OWN_VENV = True
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
profit_in_sats = 10
|
||||
cost_in_cent = 4.0
|
||||
@@ -151,18 +153,17 @@ def build_example(name, identifier, admin_config):
|
||||
return ImageGenerationDALLE(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = ImageGenerationDALLE(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = ""
|
||||
while result == "":
|
||||
result = dvm.process(json.loads(args.request))
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("Dall-E 3", "dalle3", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -1,9 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
@@ -29,10 +26,12 @@ class ImageGenerationReplicateSDXL(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
|
||||
TASK: str = "text-to-image"
|
||||
FIX_COST: float = 120
|
||||
dependencies = [("replicate", "replicate==0.21.1")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("replicate", "replicate==0.21.1")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -147,18 +146,12 @@ def build_example(name, identifier, admin_config):
|
||||
admin_config=admin_config)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = ImageGenerationReplicateSDXL(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("Stable Diffusion XL", "replicate_sdxl", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -27,10 +27,13 @@ class SpeechToTextGoogle(DVMTaskInterface):
|
||||
TASK: str = "speech-to-text"
|
||||
FIX_COST: float = 10
|
||||
PER_UNIT_COST: float = 0.1
|
||||
dependencies = [("speech_recognition", "SpeechRecognition==3.10.0")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("speech_recognition", "SpeechRecognition==3.10.0")]
|
||||
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
if options is None:
|
||||
options = {}
|
||||
@@ -155,20 +158,13 @@ def build_example(name, identifier, admin_config):
|
||||
|
||||
return SpeechToTextGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config, options=options)
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = SpeechToTextGoogle(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("Transcriptor", "speech_recognition", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -26,11 +26,13 @@ class TextExtractionPDF(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_EXTRACT_TEXT
|
||||
TASK: str = "pdf-to-text"
|
||||
FIX_COST: float = 0
|
||||
dependencies = [("pypdf", "pypdf==3.17.1")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("pypdf", "pypdf==3.17.1")]
|
||||
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
|
||||
@@ -116,19 +118,13 @@ def build_example(name, identifier, admin_config):
|
||||
return TextExtractionPDF(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config)
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = TextExtractionPDF(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("PDF Extractor", "pdf_extractor", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -20,14 +20,16 @@ Outputs: Generated text
|
||||
"""
|
||||
|
||||
|
||||
class TextGenerationOLLAMA(DVMTaskInterface):
|
||||
class TextGenerationLLMLite(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_TEXT
|
||||
TASK: str = "text-to-text"
|
||||
FIX_COST: float = 0
|
||||
dependencies = [("litellm", "litellm==1.12.3")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("litellm", "litellm==1.12.3")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
|
||||
@@ -78,7 +80,8 @@ class TextGenerationOLLAMA(DVMTaskInterface):
|
||||
response = completion(
|
||||
model=options["model"],
|
||||
messages=[{"content": options["prompt"], "role": "user"}],
|
||||
api_base=options["server"]
|
||||
api_base=options["server"],
|
||||
stream=False
|
||||
)
|
||||
print(response.choices[0].message.content)
|
||||
return response.choices[0].message.content
|
||||
@@ -110,34 +113,23 @@ def build_example(name, identifier, admin_config):
|
||||
"about": "I use a LLM connected via OLLAMA",
|
||||
"encryptionSupported": True,
|
||||
"cashuAccepted": True,
|
||||
"nip90Params": {
|
||||
"size": {
|
||||
"required": False,
|
||||
"values": ["1024:1024", "1024x1792", "1792x1024"]
|
||||
}
|
||||
}
|
||||
"nip90Params": {}
|
||||
}
|
||||
|
||||
nip89config = NIP89Config()
|
||||
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"])
|
||||
nip89config.CONTENT = json.dumps(nip89info)
|
||||
|
||||
return TextGenerationOLLAMA(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config, options=options)
|
||||
return TextGenerationLLMLite(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config, options=options)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = TextGenerationLLMLite(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
|
||||
dvm = build_example("LLM", "llmlite", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
138
nostr_dvm/tasks/texttospeech.py
Normal file
138
nostr_dvm/tasks/texttospeech.py
Normal file
@@ -0,0 +1,138 @@
|
||||
import json
|
||||
import os
|
||||
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
|
||||
from pathlib import Path
|
||||
import urllib.request
|
||||
|
||||
from nostr_dvm.interfaces.dvmtaskinterface import DVMTaskInterface
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.output_utils import upload_media_to_hoster
|
||||
|
||||
"""
|
||||
This File contains a Module to generate Audio based on an input and a voice
|
||||
|
||||
Accepted Inputs: Text
|
||||
Outputs: Generated Audiofile
|
||||
"""
|
||||
|
||||
|
||||
class TextToSpeech(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_TEXT_TO_SPEECH
|
||||
TASK: str = "text-to-speech"
|
||||
FIX_COST: float = 200
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("TTS", "TTS==0.22.0")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
for tag in tags:
|
||||
if tag.as_vec()[0] == 'i':
|
||||
input_value = tag.as_vec()[1]
|
||||
input_type = tag.as_vec()[2]
|
||||
if input_type != "text":
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def create_request_from_nostr_event(self, event, client=None, dvm_config=None):
|
||||
request_form = {"jobID": event.id().to_hex() + "_" + self.NAME.replace(" ", "")}
|
||||
prompt = "test"
|
||||
if self.options.get("input_file") and self.options.get("input_file") != "":
|
||||
input_file = self.options['input_file']
|
||||
else:
|
||||
if not Path.exists(Path('cache/input.wav')):
|
||||
input_file_url = "https://media.nostr.build/av/de104e3260be636533a56fd4468b905c1eb22b226143a997aa936b011122af8a.wav"
|
||||
urllib.request.urlretrieve(input_file_url, "cache/input.wav")
|
||||
input_file = "cache/input.wav"
|
||||
language = "en"
|
||||
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == 'i':
|
||||
input_type = tag.as_vec()[2]
|
||||
if input_type == "text":
|
||||
prompt = tag.as_vec()[1]
|
||||
if input_type == "url":
|
||||
input_file = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == 'param':
|
||||
param = tag.as_vec()[1]
|
||||
if param == "language": # check for param type
|
||||
language = tag.as_vec()[2]
|
||||
|
||||
options = {
|
||||
"prompt": prompt,
|
||||
"input_wav": input_file,
|
||||
"language": language
|
||||
}
|
||||
request_form['options'] = json.dumps(options)
|
||||
|
||||
return request_form
|
||||
|
||||
def process(self, request_form):
|
||||
import torch
|
||||
from TTS.api import TTS
|
||||
options = DVMTaskInterface.set_options(request_form)
|
||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
#else "mps" if torch.backends.mps.is_available() \
|
||||
|
||||
print(TTS().list_models())
|
||||
try:
|
||||
tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to(device)
|
||||
|
||||
tts.tts_to_file(
|
||||
text=options["prompt"],
|
||||
speaker_wav=options["input_wav"], language=options["language"], file_path="outputs/output.wav")
|
||||
result = upload_media_to_hoster("outputs/output.wav")
|
||||
return result
|
||||
except Exception as e:
|
||||
print("Error in Module: " + str(e))
|
||||
raise Exception(e)
|
||||
|
||||
|
||||
# We build an example here that we can call by either calling this file directly from the main directory,
|
||||
# or by adding it to our playground. You can call the example and adjust it to your needs or redefine it in the
|
||||
# playground or elsewhere
|
||||
def build_example(name, identifier, admin_config):
|
||||
dvm_config = build_default_config(identifier)
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
#use an alternative local wav file you want to use for cloning
|
||||
options = {'input_file': ""}
|
||||
|
||||
nip89info = {
|
||||
"name": name,
|
||||
"image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg",
|
||||
"about": "I Generate Speech from Text",
|
||||
"encryptionSupported": True,
|
||||
"cashuAccepted": True,
|
||||
"nip90Params": {
|
||||
"language": {
|
||||
"required": False,
|
||||
"values": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nip89config = NIP89Config()
|
||||
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["image"])
|
||||
nip89config.CONTENT = json.dumps(nip89info)
|
||||
|
||||
return TextToSpeech(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config,
|
||||
options=options)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = TextToSpeech(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
process_venv()
|
||||
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
@@ -25,10 +26,12 @@ class TranslationGoogle(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_TRANSLATE_TEXT
|
||||
TASK: str = "translation"
|
||||
FIX_COST: float = 0
|
||||
dependencies = [("translatepy", "translatepy==2.3")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("translatepy", "translatepy==2.3")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -141,18 +144,15 @@ def build_example(name, identifier, admin_config):
|
||||
|
||||
return TranslationGoogle(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config)
|
||||
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = TranslationGoogle(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("Google Translator", "google_translator", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -13,7 +13,6 @@ from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.nostr_utils import get_referenced_event_by_id, get_event_by_id
|
||||
|
||||
|
||||
"""
|
||||
This File contains a Module to call Libre Translate Services
|
||||
|
||||
@@ -32,6 +31,7 @@ class TranslationLibre(DVMTaskInterface):
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None, task=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options, task)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -81,9 +81,9 @@ class TranslationLibre(DVMTaskInterface):
|
||||
def process(self, request_form):
|
||||
options = DVMTaskInterface.set_options(request_form)
|
||||
request = {
|
||||
"q": options["text"],
|
||||
"q": options["text"],
|
||||
"source": "auto",
|
||||
"target": options["language"]
|
||||
"target": options["language"]
|
||||
}
|
||||
if options["libre_api_key"] != "":
|
||||
request["api_key"] = options["libre_api_key"]
|
||||
@@ -95,10 +95,10 @@ class TranslationLibre(DVMTaskInterface):
|
||||
reply = json.loads(response.text)
|
||||
if reply.get("translatedText"):
|
||||
translated_text = reply['translatedText']
|
||||
#untested
|
||||
#confidence = reply["detectedLanguage"]['confidence']
|
||||
#language = reply["detectedLanguage"]['language']
|
||||
#print(translated_text + "language: " + language + "conf: " + confidence)
|
||||
# untested
|
||||
# confidence = reply["detectedLanguage"]['confidence']
|
||||
# language = reply["detectedLanguage"]['language']
|
||||
# print(translated_text + "language: " + language + "conf: " + confidence)
|
||||
else:
|
||||
return response.text
|
||||
|
||||
@@ -125,12 +125,18 @@ def build_example(name, identifier, admin_config):
|
||||
"nip90Params": {
|
||||
"language": {
|
||||
"required": False,
|
||||
"values": ["en", "az", "be", "bg", "bn", "bs", "ca", "ceb", "co", "cs", "cy", "da", "de", "el", "eo", "es",
|
||||
"et", "eu", "fa", "fi", "fr", "fy", "ga", "gd", "gl", "gu", "ha", "haw", "hi", "hmn", "hr", "ht",
|
||||
"hu", "hy", "id", "ig", "is", "it", "he", "ja", "jv", "ka", "kk", "km", "kn", "ko", "ku", "ky",
|
||||
"la", "lb", "lo", "lt", "lv", "mg", "mi", "mk", "ml", "mn", "mr", "ms", "mt", "my", "ne", "nl",
|
||||
"no", "ny", "or", "pa", "pl", "ps", "pt", "ro", "ru", "sd", "si", "sk", "sl", "sm", "sn", "so",
|
||||
"sq", "sr", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "tl", "tr", "ug", "uk", "ur", "uz",
|
||||
"values": ["en", "az", "be", "bg", "bn", "bs", "ca", "ceb", "co", "cs", "cy", "da", "de", "el", "eo",
|
||||
"es",
|
||||
"et", "eu", "fa", "fi", "fr", "fy", "ga", "gd", "gl", "gu", "ha", "haw", "hi", "hmn", "hr",
|
||||
"ht",
|
||||
"hu", "hy", "id", "ig", "is", "it", "he", "ja", "jv", "ka", "kk", "km", "kn", "ko", "ku",
|
||||
"ky",
|
||||
"la", "lb", "lo", "lt", "lv", "mg", "mi", "mk", "ml", "mn", "mr", "ms", "mt", "my", "ne",
|
||||
"nl",
|
||||
"no", "ny", "or", "pa", "pl", "ps", "pt", "ro", "ru", "sd", "si", "sk", "sl", "sm", "sn",
|
||||
"so",
|
||||
"sq", "sr", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "tl", "tr", "ug", "uk", "ur",
|
||||
"uz",
|
||||
"vi", "xh", "yi", "yo", "zh", "zu"]
|
||||
}
|
||||
}
|
||||
@@ -143,18 +149,12 @@ def build_example(name, identifier, admin_config):
|
||||
admin_config=admin_config, options=options)
|
||||
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = TranslationLibre(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
dvm = build_example("Libre Translator", "libre_translator", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -29,6 +29,7 @@ class TrendingNotesNostrBand(DVMTaskInterface):
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
@@ -117,20 +118,12 @@ def build_example(name, identifier, admin_config):
|
||||
return TrendingNotesNostrBand(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config)
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = TrendingNotesNostrBand(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
|
||||
dvm = build_example("Trending Notes on Nostr.band", "trending_notes_nostrband", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
@@ -30,12 +31,17 @@ class VideoGenerationReplicateSVD(DVMTaskInterface):
|
||||
KIND: int = EventDefinitions.KIND_NIP90_GENERATE_VIDEO
|
||||
TASK: str = "image-to-video"
|
||||
FIX_COST: float = 120
|
||||
dependencies = [("replicate", "replicate==0.21.1")]
|
||||
dependencies = [("nostr-dvm", "nostr-dvm"),
|
||||
("replicate", "replicate==0.21.1")]
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
|
||||
admin_config: AdminConfig = None, options=None):
|
||||
dvm_config.SCRIPT = os.path.abspath(__file__)
|
||||
super().__init__(name, dvm_config, nip89config, admin_config, options)
|
||||
|
||||
|
||||
|
||||
|
||||
def is_input_supported(self, tags):
|
||||
for tag in tags:
|
||||
if tag.as_vec()[0] == 'i':
|
||||
@@ -134,20 +140,13 @@ def build_example(name, identifier, admin_config):
|
||||
return VideoGenerationReplicateSVD(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config)
|
||||
|
||||
def process_venv():
|
||||
args = DVMTaskInterface.process_args()
|
||||
dvm_config = build_default_config(args.identifier)
|
||||
dvm = VideoGenerationReplicateSVD(name="", dvm_config=dvm_config, nip89config=NIP89Config(), admin_config=None)
|
||||
result = dvm.process(json.loads(args.request))
|
||||
DVMTaskInterface.write_output(result, args.output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = False
|
||||
admin_config.UPDATE_PROFILE = False
|
||||
|
||||
dvm = build_example("Stable Video Diffusion", "replicate_svd", admin_config)
|
||||
dvm.run()
|
||||
|
||||
keep_alive()
|
||||
process_venv()
|
||||
@@ -26,8 +26,10 @@ class User:
|
||||
def create_sql_table(db):
|
||||
try:
|
||||
import os
|
||||
if not os.path.exists(r'.\db'):
|
||||
os.makedirs(r'.\db')
|
||||
if not os.path.exists(r'db'):
|
||||
os.makedirs(r'db')
|
||||
if not os.path.exists(r'outputs'):
|
||||
os.makedirs(r'outputs')
|
||||
con = sqlite3.connect(db)
|
||||
cur = con.cursor()
|
||||
cur.execute(""" CREATE TABLE IF NOT EXISTS users (
|
||||
|
||||
@@ -9,27 +9,29 @@ class EventDefinitions:
|
||||
KIND_NIP94_METADATA = 1063
|
||||
KIND_FEEDBACK = 7000
|
||||
KIND_NIP90_EXTRACT_TEXT = 5000
|
||||
KIND_NIP90_RESULT_EXTRACT_TEXT = 6000
|
||||
KIND_NIP90_RESULT_EXTRACT_TEXT = KIND_NIP90_EXTRACT_TEXT + 1000
|
||||
KIND_NIP90_SUMMARIZE_TEXT = 5001
|
||||
KIND_NIP90_RESULT_SUMMARIZE_TEXT = 6001
|
||||
KIND_NIP90_RESULT_SUMMARIZE_TEXT = KIND_NIP90_SUMMARIZE_TEXT + 1000
|
||||
KIND_NIP90_TRANSLATE_TEXT = 5002
|
||||
KIND_NIP90_RESULT_TRANSLATE_TEXT = 6002
|
||||
KIND_NIP90_RESULT_TRANSLATE_TEXT = KIND_NIP90_TRANSLATE_TEXT + 1000
|
||||
KIND_NIP90_TEXT_TO_SPEECH = 5005
|
||||
KIND_NIP90_RESULT_TEXT_TO_SPEECH = KIND_NIP90_TEXT_TO_SPEECH + 1000
|
||||
KIND_NIP90_GENERATE_TEXT = 5050
|
||||
KIND_NIP90_RESULT_GENERATE_TEXT = 6050
|
||||
KIND_NIP90_RESULT_GENERATE_TEXT = KIND_NIP90_GENERATE_TEXT + 1000
|
||||
KIND_NIP90_GENERATE_IMAGE = 5100
|
||||
KIND_NIP90_RESULT_GENERATE_IMAGE = 6100
|
||||
KIND_NIP90_RESULT_GENERATE_IMAGE = KIND_NIP90_GENERATE_IMAGE + 1000
|
||||
KIND_NIP90_CONVERT_VIDEO = 5200
|
||||
KIND_NIP90_RESULT_CONVERT_VIDEO = 6200
|
||||
KIND_NIP90_RESULT_CONVERT_VIDEO = KIND_NIP90_CONVERT_VIDEO + 1000
|
||||
KIND_NIP90_GENERATE_VIDEO = 5202
|
||||
KIND_NIP90_RESULT_GENERATE_VIDEO = 6202
|
||||
KIND_NIP90_RESULT_GENERATE_VIDEO = KIND_NIP90_GENERATE_VIDEO + 1000
|
||||
KIND_NIP90_CONTENT_DISCOVERY = 5300
|
||||
KIND_NIP90_RESULT_CONTENT_DISCOVERY = 6300
|
||||
KIND_NIP90_RESULT_CONTENT_DISCOVERY = KIND_NIP90_CONTENT_DISCOVERY + 1000
|
||||
KIND_NIP90_PEOPLE_DISCOVERY = 5301
|
||||
KIND_NIP90_RESULT_PEOPLE_DISCOVERY = 6301
|
||||
KIND_NIP90_RESULT_PEOPLE_DISCOVERY = KIND_NIP90_PEOPLE_DISCOVERY + 1000
|
||||
KIND_NIP90_CONTENT_SEARCH = 5302
|
||||
KIND_NIP90_RESULTS_CONTENT_SEARCH = 6302
|
||||
KIND_NIP90_RESULTS_CONTENT_SEARCH = KIND_NIP90_CONTENT_SEARCH + 1000
|
||||
KIND_NIP90_GENERIC = 5999
|
||||
KIND_NIP90_RESULT_GENERIC = 6999
|
||||
KIND_NIP90_RESULT_GENERIC = KIND_NIP90_GENERIC + 1000
|
||||
ANY_RESULT = [KIND_NIP90_RESULT_EXTRACT_TEXT,
|
||||
KIND_NIP90_RESULT_SUMMARIZE_TEXT,
|
||||
KIND_NIP90_RESULT_TRANSLATE_TEXT,
|
||||
|
||||
@@ -23,10 +23,13 @@ class DVMConfig:
|
||||
|
||||
RELAY_TIMEOUT = 3
|
||||
EXTERNAL_POST_PROCESS_TYPE = PostProcessFunctionType.NONE # Leave this on None, except the DVM is external
|
||||
LNBITS_INVOICE_KEY = ''
|
||||
LNBITS_INVOICE_KEY = '' # Will all automatically generated by default, or read from .env
|
||||
LNBITS_ADMIN_KEY = '' # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users.
|
||||
LNBITS_URL = 'https://lnbits.com'
|
||||
LN_ADDRESS = ''
|
||||
SCRIPT = ''
|
||||
IDENTIFIER = ''
|
||||
USE_OWN_VENV = True # Make an own venv for each dvm's process function.Disable if you want to install packages into main venv. Only recommended if you dont want to run dvms with different dependency versions
|
||||
DB: str
|
||||
NEW_USER_BALANCE: int = 0 # Free credits for new users
|
||||
NIP89: NIP89Config
|
||||
@@ -36,6 +39,7 @@ class DVMConfig:
|
||||
def build_default_config(identifier):
|
||||
dvm_config = DVMConfig()
|
||||
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
|
||||
dvm_config.IDENTIFIER = identifier
|
||||
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
|
||||
|
||||
@@ -6,10 +6,12 @@ import ffmpegio
|
||||
from decord import AudioReader, cpu
|
||||
import requests
|
||||
from nostr_dvm.utils.nostr_utils import get_event_by_id
|
||||
from nostr_dvm.utils.scrapper.media_scrapper import OvercastDownload, XitterDownload, TiktokDownloadAll, \
|
||||
InstagramDownload, YouTubeDownload
|
||||
|
||||
|
||||
def input_data_file_duration(event, dvm_config, client, start=0, end=0):
|
||||
#print("[" + dvm_config.NIP89.NAME + "] Getting Duration of the Media file..")
|
||||
# print("[" + dvm_config.NIP89.NAME + "] Getting Duration of the Media file..")
|
||||
input_value = ""
|
||||
input_type = ""
|
||||
for tag in event.tags():
|
||||
@@ -18,7 +20,7 @@ def input_data_file_duration(event, dvm_config, client, start=0, end=0):
|
||||
input_type = tag.as_vec()[2]
|
||||
|
||||
if input_type == "text":
|
||||
#For now, ingore length of any text, just return 1.
|
||||
# For now, ignore length of any text, just return 1.
|
||||
return 1
|
||||
|
||||
if input_type == "event": # NIP94 event
|
||||
@@ -52,7 +54,8 @@ def input_data_file_duration(event, dvm_config, client, start=0, end=0):
|
||||
return 1
|
||||
|
||||
|
||||
def organize_input_media_data(input_value, input_type, start, end, dvm_config, client, process=True, media_format="audio/mp3") -> str:
|
||||
def organize_input_media_data(input_value, input_type, start, end, dvm_config, client, process=True,
|
||||
media_format="audio/mp3") -> str:
|
||||
if input_type == "event": # NIP94 event
|
||||
evt = get_event_by_id(input_value, client=client, config=dvm_config)
|
||||
if evt is not None:
|
||||
@@ -209,7 +212,7 @@ def get_overcast(input_value, start, end):
|
||||
print("Found overcast.fm Link.. downloading")
|
||||
start_time = start
|
||||
end_time = end
|
||||
downloadOvercast(input_value, filename)
|
||||
download_overcast(input_value, filename)
|
||||
finaltag = str(input_value).replace("https://overcast.fm/", "").split('/')
|
||||
if start == 0.0:
|
||||
if len(finaltag) > 1:
|
||||
@@ -227,7 +230,7 @@ def get_overcast(input_value, start, end):
|
||||
def get_TikTok(input_value, start, end):
|
||||
filepath = os.path.abspath(os.curdir + r'/outputs/')
|
||||
try:
|
||||
filename = downloadTikTok(input_value, filepath)
|
||||
filename = download_tik_tok(input_value, filepath)
|
||||
print(filename)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -238,7 +241,7 @@ def get_TikTok(input_value, start, end):
|
||||
def get_Instagram(input_value, start, end):
|
||||
filepath = os.path.abspath(os.curdir + r'/outputs/')
|
||||
try:
|
||||
filename = downloadInstagram(input_value, filepath)
|
||||
filename = download_instagram(input_value, filepath)
|
||||
print(filename)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -250,7 +253,7 @@ def get_Twitter(input_value, start, end):
|
||||
filepath = os.path.abspath(os.curdir) + r'/outputs/'
|
||||
cleanlink = str(input_value).replace("twitter.com", "x.com")
|
||||
try:
|
||||
filename = downloadTwitter(cleanlink, filepath)
|
||||
filename = download_twitter(cleanlink, filepath)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return "", start, end
|
||||
@@ -259,12 +262,13 @@ def get_Twitter(input_value, start, end):
|
||||
|
||||
def get_youtube(input_value, start, end, audioonly=True):
|
||||
filepath = os.path.abspath(os.curdir) + r'/outputs/'
|
||||
print(filepath)
|
||||
filename = ""
|
||||
try:
|
||||
filename = downloadYouTube(input_value, filepath, audioonly)
|
||||
filename = download_youtube(input_value, filepath, audioonly)
|
||||
|
||||
except Exception as e:
|
||||
print("Youtube" + str(e))
|
||||
print("Youtube " + str(e))
|
||||
return filename, start, end
|
||||
try:
|
||||
o = urlparse(input_value)
|
||||
@@ -331,31 +335,25 @@ def get_media_link(url) -> (str, str):
|
||||
return None, None
|
||||
|
||||
|
||||
def downloadOvercast(source_url, target_location):
|
||||
from scrapper.media_scrapper import OvercastDownload
|
||||
def download_overcast(source_url, target_location):
|
||||
result = OvercastDownload(source_url, target_location)
|
||||
return result
|
||||
|
||||
|
||||
def downloadTwitter(videourl, path):
|
||||
from scrapper.media_scrapper import XitterDownload
|
||||
def download_twitter(videourl, path):
|
||||
result = XitterDownload(videourl, path + "x.mp4")
|
||||
return result
|
||||
|
||||
|
||||
def downloadTikTok(videourl, path):
|
||||
from scrapper.media_scrapper import TiktokDownloadAll
|
||||
def download_tik_tok(videourl, path):
|
||||
result = TiktokDownloadAll([videourl], path)
|
||||
return result
|
||||
|
||||
|
||||
def downloadInstagram(videourl, path):
|
||||
from scrapper.media_scrapper import InstagramDownload
|
||||
def download_instagram(videourl, path):
|
||||
result = InstagramDownload(videourl, "insta", path)
|
||||
return result
|
||||
|
||||
|
||||
def downloadYouTube(link, path, audioonly=True):
|
||||
from scrapper.media_scrapper import YouTubeDownload
|
||||
result = YouTubeDownload(link, path, audio_only=audioonly)
|
||||
return result
|
||||
def download_youtube(link, path, audioonly=True):
|
||||
return YouTubeDownload(link, path, audio_only=audioonly)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from dvm import DVM
|
||||
@@ -18,7 +18,15 @@ def XitterDownload(source_url, target_location):
|
||||
features, variables = request_details["features"], request_details["variables"]
|
||||
|
||||
def get_tokens(tweet_url):
|
||||
html = requests.get(tweet_url)
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0",
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "de,en-US;q=0.7,en;q=0.3",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"TE": "trailers",
|
||||
}
|
||||
|
||||
html = requests.get(tweet_url, headers=headers)
|
||||
|
||||
assert (
|
||||
html.status_code == 200
|
||||
@@ -34,7 +42,6 @@ def XitterDownload(source_url, target_location):
|
||||
), f"Failed to find main.js file. If you are using the correct Twitter URL this suggests a bug in the script. Please open a GitHub issue and copy and paste this message. Tweet url: {tweet_url}"
|
||||
|
||||
mainjs_url = mainjs_url[0]
|
||||
|
||||
mainjs = requests.get(mainjs_url)
|
||||
|
||||
assert (
|
||||
@@ -80,9 +87,11 @@ def XitterDownload(source_url, target_location):
|
||||
variables["tweetId"] = tweet_id
|
||||
|
||||
return f"https://twitter.com/i/api/graphql/0hWvDhmW8YQ-S_ib3azIrw/TweetResultByRestId?variables={urllib.parse.quote(json.dumps(variables))}&features={urllib.parse.quote(json.dumps(features))}"
|
||||
# return f"https://api.twitter.com/graphql/ncDeACNGIApPMaqGVuF_rw/TweetResultByRestId?variables={urllib.parse.quote(json.dumps(variables))}&features={urllib.parse.quote(json.dumps(features))}"
|
||||
|
||||
def get_tweet_details(tweet_url, guest_token, bearer_token):
|
||||
tweet_id = re.findall(r"(?<=status/)\d+", tweet_url)
|
||||
|
||||
assert (
|
||||
tweet_id is not None and len(tweet_id) == 1
|
||||
), f"Could not parse tweet id from your url. Make sure you are using the correct url. If you are, then file a GitHub issue and copy and paste this message. Tweet url: {tweet_url}"
|
||||
@@ -172,7 +181,7 @@ def XitterDownload(source_url, target_location):
|
||||
pattern = (
|
||||
r'"expanded_url"\s*:\s*"https://x\.com/[^/]+/status/'
|
||||
+ sid
|
||||
+ '/[^"]+",\s*"id_str"\s*:\s*"\d+",'
|
||||
+ r'/[^"]+",\s*"id_str"\s*:\s*"\d+",'
|
||||
)
|
||||
matches = re.findall(pattern, j)
|
||||
if len(matches) > 0:
|
||||
@@ -240,17 +249,49 @@ def XitterDownload(source_url, target_location):
|
||||
urls = [x["url"] for x in results.values()]
|
||||
urls += container_matches
|
||||
return urls
|
||||
|
||||
return [x["url"] for x in results.values()]
|
||||
|
||||
def extract_mp4_fmp4(j):
|
||||
"""
|
||||
Extract the URL of the MP4 video from the detailed information of the tweet.
|
||||
Returns a list of URLs, tweet IDs, and resolution information (dictionary type)
|
||||
and a list of tweet IDs as return values.
|
||||
"""
|
||||
|
||||
# Empty list to store tweet IDs
|
||||
tweet_id_list = []
|
||||
mp4_info_dict_list = []
|
||||
amplitude_pattern = re.compile(
|
||||
r"(https://video.twimg.com/amplify_video/(\d+)/vid/(avc1/)(\d+x\d+)/[^.]+.mp4\?tag=\d+)"
|
||||
)
|
||||
ext_tw_pattern = re.compile(
|
||||
r"(https://video.twimg.com/ext_tw_video/(\d+)/pu/vid/(avc1/)?(\d+x\d+)/[^.]+.mp4\?tag=\d+)"
|
||||
)
|
||||
tweet_video_pattern = re.compile(r'https://video.twimg.com/tweet_video/[^"]+')
|
||||
container_pattern = re.compile(r'https://video.twimg.com/[^"]*container=fmp4')
|
||||
|
||||
matches = amplitude_pattern.findall(j)
|
||||
matches += ext_tw_pattern.findall(j)
|
||||
container_matches = container_pattern.findall(j)
|
||||
tweet_video_url_list = tweet_video_pattern.findall(j)
|
||||
|
||||
for match in matches:
|
||||
url, tweet_id, _, resolution = match
|
||||
tweet_id_list.append(int(tweet_id))
|
||||
mp4_info_dict_list.append({"resolution": resolution, "url": url})
|
||||
|
||||
tweet_id_list = list(dict.fromkeys(tweet_id_list))
|
||||
|
||||
if len(container_matches) > 0:
|
||||
for url in container_matches:
|
||||
mp4_info_dict_list.append({"url": url})
|
||||
|
||||
return tweet_id_list, mp4_info_dict_list, tweet_video_url_list
|
||||
|
||||
def download_parts(url, output_filename):
|
||||
resp = requests.get(url, stream=True)
|
||||
|
||||
# container begins with / ends with fmp4 and has a resolution in it we want to capture
|
||||
pattern = re.compile(r"(/[^\n]*/(\d+x\d+)/[^\n]*container=fmp4)")
|
||||
|
||||
matches = pattern.findall(resp.text)
|
||||
|
||||
max_res = 0
|
||||
max_res_url = None
|
||||
|
||||
@@ -301,12 +342,9 @@ def XitterDownload(source_url, target_location):
|
||||
|
||||
def repost_check(j, exclude_replies=True):
|
||||
try:
|
||||
# This line extract the index of the first reply
|
||||
reply_index = j.index('"conversationthread-')
|
||||
except ValueError:
|
||||
# If there are no replies we use the enrire response data length
|
||||
reply_index = len(j)
|
||||
# We truncate the response data to exclude replies
|
||||
if exclude_replies:
|
||||
j = j[0:reply_index]
|
||||
|
||||
@@ -360,6 +398,7 @@ def XitterDownload(source_url, target_location):
|
||||
bearer_token, guest_token = get_tokens(tweet_url)
|
||||
resp = get_tweet_details(tweet_url, guest_token, bearer_token)
|
||||
mp4s = extract_mp4s(resp.text, tweet_url, target_all_videos)
|
||||
|
||||
if target_all_videos:
|
||||
video_counter = 1
|
||||
original_urls = repost_check(resp.text, exclude_replies=False)
|
||||
@@ -377,6 +416,7 @@ def XitterDownload(source_url, target_location):
|
||||
download_parts(mp4, output_file)
|
||||
|
||||
else:
|
||||
# use a stream to download the file
|
||||
r = requests.get(mp4, stream=True)
|
||||
with open(output_file, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=1024):
|
||||
@@ -475,7 +515,7 @@ def TiktokDownloadAll(linkList, path) -> str:
|
||||
for i in linkList:
|
||||
try:
|
||||
data['url'] = i
|
||||
result = TikTokDownload(cookies, headers, data, "tiktok", path) # str(linkList.index(i))
|
||||
result = TikTokDownload(cookies, headers, data, "tiktok", path) # str(linkList.index(i))
|
||||
return result
|
||||
except IndexError:
|
||||
parseDict = getDict()
|
||||
|
||||
@@ -9,12 +9,12 @@ 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 nostr_dvm.utils.nostr_utils import get_event_by_id, check_and_decrypt_own_tags
|
||||
import lnurl
|
||||
from hashlib import sha256
|
||||
import dotenv
|
||||
|
||||
|
||||
# TODO tor connection to lnbits
|
||||
# proxies = {
|
||||
# 'http': 'socks5h://127.0.0.1:9050',
|
||||
@@ -23,6 +23,7 @@ import dotenv
|
||||
|
||||
proxies = {}
|
||||
|
||||
|
||||
def parse_zap_event_tags(zap_event, keys, name, client, config):
|
||||
zapped_event = None
|
||||
invoice_amount = 0
|
||||
@@ -126,10 +127,11 @@ 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
|
||||
return "","","","", "failed"
|
||||
data = {
|
||||
'admin_id': os.getenv("LNBITS_ADMIN_ID"),
|
||||
'wallet_name': name,
|
||||
@@ -144,9 +146,11 @@ def create_lnbits_account(name):
|
||||
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"
|
||||
return walletjson['wallets'][0]['inkey'], walletjson['wallets'][0]['adminkey'], walletjson['wallets'][0][
|
||||
'id'], walletjson['id'], "success"
|
||||
except:
|
||||
print("error creating wallet")
|
||||
return "", "", "", "", "failed"
|
||||
|
||||
|
||||
def check_bolt11_ln_bits_is_paid(payment_hash: str, config):
|
||||
@@ -278,9 +282,6 @@ def zap(lud16: str, amount: int, content, zapped_event: Event, keys, dvm_config,
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def get_price_per_sat(currency):
|
||||
import requests
|
||||
|
||||
@@ -298,13 +299,7 @@ def get_price_per_sat(currency):
|
||||
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,
|
||||
@@ -314,10 +309,9 @@ def make_ln_address_nostdress(identifier, npub, pin, nostdressdomain):
|
||||
'key': os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()),
|
||||
'pin': pin,
|
||||
'npub': npub,
|
||||
'currentname': " "
|
||||
'currentname': " "
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
url = "https://" + nostdressdomain + "/api/easy/"
|
||||
res = requests.post(url, data=data)
|
||||
@@ -330,8 +324,8 @@ def make_ln_address_nostdress(identifier, npub, pin, nostdressdomain):
|
||||
print(e)
|
||||
return "", ""
|
||||
|
||||
def check_and_set_ln_bits_keys(identifier, npub):
|
||||
|
||||
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)
|
||||
@@ -341,7 +335,7 @@ def check_and_set_ln_bits_keys(identifier, npub):
|
||||
|
||||
lnaddress = ""
|
||||
pin = ""
|
||||
if os.getenv("NOSTDRESS_DOMAIN"):
|
||||
if os.getenv("NOSTDRESS_DOMAIN") and success != "failed":
|
||||
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)
|
||||
@@ -356,14 +350,8 @@ def check_and_set_ln_bits_keys(identifier, npub):
|
||||
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)
|
||||
|
||||
|
||||
dotenv.set_key(env_path, value, oskey)
|
||||
Reference in New Issue
Block a user