mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-09-27 13:56:38 +02:00
updated option structure
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -158,6 +158,5 @@ cython_debug/
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
nostrzaps.db
|
||||
.DS_Store
|
||||
*.db
|
||||
|
@@ -33,7 +33,7 @@ def send_request_to_nova_server(request_form, address):
|
||||
url = ('http://' + address + '/process')
|
||||
headers = {'Content-type': 'application/x-www-form-urlencoded'}
|
||||
response = requests.post(url, headers=headers, data=request_form)
|
||||
return response.content
|
||||
return response.text
|
||||
|
||||
|
||||
"""
|
||||
@@ -58,9 +58,9 @@ def check_nova_server_status(jobID, address):
|
||||
response_status = requests.post(url_status, headers=headers, data=data)
|
||||
response_log = requests.post(url_log, headers=headers, data=data)
|
||||
status = int(json.loads(response_status.text)['status'])
|
||||
|
||||
log = str(response_log.content)[length:]
|
||||
length = len(str(response_log.content))
|
||||
log_content = str(json.loads(response_log.text)['message']).replace("ERROR", "").replace("INFO", "")
|
||||
log = log_content[length:]
|
||||
length = len(log_content)
|
||||
if log != "":
|
||||
print(log + " Status: " + str(status))
|
||||
# WAITING = 0, RUNNING = 1, FINISHED = 2, ERROR = 3
|
||||
@@ -74,7 +74,7 @@ def check_nova_server_status(jobID, address):
|
||||
data = {"jobID": jobID}
|
||||
response = requests.post(url_fetch, headers=headers, data=data)
|
||||
content_type = response.headers['content-type']
|
||||
print(content_type)
|
||||
print("Content-type: " + str(content_type))
|
||||
if content_type == "image/jpeg":
|
||||
image = Image.open(io.BytesIO(response.content))
|
||||
image.save("./outputs/image.jpg")
|
||||
|
16
dvm.py
16
dvm.py
@@ -84,7 +84,7 @@ class DVM:
|
||||
print("[" + self.dvm_config.NIP89.name + "] Request by blacklisted user, skipped")
|
||||
|
||||
elif task_supported:
|
||||
print("Received new Task: " + task + " from " + user.name)
|
||||
print("[" + self.dvm_config.NIP89.name + "] Received new Task: " + task + " from " + user.name)
|
||||
amount = get_amount_per_task(task, self.dvm_config, duration)
|
||||
if amount is None:
|
||||
return
|
||||
@@ -95,11 +95,11 @@ class DVM:
|
||||
task_is_free = True
|
||||
|
||||
if user.iswhitelisted or task_is_free:
|
||||
print("[" + self.dvm_config.NIP89.name + "] Free or Whitelisted for task " + task + ". Starting processing..")
|
||||
print("[" + self.dvm_config.NIP89.name + "] Free task or Whitelisted for task " + task + ". Starting processing..")
|
||||
send_job_status_reaction(nip90_event, "processing", True, 0, client=self.client,
|
||||
dvm_config=self.dvm_config)
|
||||
do_work(nip90_event, is_from_bot=False)
|
||||
# otherwise send payment request
|
||||
|
||||
else:
|
||||
bid = 0
|
||||
for tag in nip90_event.tags():
|
||||
@@ -254,17 +254,17 @@ class DVM:
|
||||
amount = x.amount
|
||||
x.result = data
|
||||
x.is_processed = True
|
||||
if self.dvm_config.SHOWRESULTBEFOREPAYMENT and not is_paid:
|
||||
if self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and not is_paid:
|
||||
send_nostr_reply_event(data, original_event_str,)
|
||||
send_job_status_reaction(original_event, "success", amount,
|
||||
dvm_config=self.dvm_config) # or payment-required, or both?
|
||||
elif not self.dvm_config.SHOWRESULTBEFOREPAYMENT and not is_paid:
|
||||
elif not self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and not is_paid:
|
||||
send_job_status_reaction(original_event, "success", amount,
|
||||
dvm_config=self.dvm_config) # or payment-required, or both?
|
||||
|
||||
if self.dvm_config.SHOWRESULTBEFOREPAYMENT and is_paid:
|
||||
if self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and is_paid:
|
||||
self.job_list.remove(x)
|
||||
elif not self.dvm_config.SHOWRESULTBEFOREPAYMENT and is_paid:
|
||||
elif not self.dvm_config.SHOW_RESULT_BEFORE_PAYMENT and is_paid:
|
||||
self.job_list.remove(x)
|
||||
send_nostr_reply_event(data, original_event_str)
|
||||
break
|
||||
@@ -296,7 +296,7 @@ class DVM:
|
||||
response_kind = original_event.kind() + 1000
|
||||
reply_event = EventBuilder(response_kind, str(content), reply_tags).to_event(key)
|
||||
send_event(reply_event, client=self.client, dvm_config=self.dvm_config)
|
||||
print("[" + self.dvm_config.NIP89.name + "]" + str(response_kind) + " Job Response event sent: " + reply_event.as_json())
|
||||
print("[" + self.dvm_config.NIP89.name + "] " + str(response_kind) + " Job Response event sent: " + reply_event.as_json())
|
||||
return reply_event.as_json()
|
||||
|
||||
def respond_to_error(content: str, original_event_as_str: str, is_from_bot=False):
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import json
|
||||
|
||||
from utils.nip89_utils import NIP89Announcement
|
||||
|
||||
|
||||
@@ -30,13 +32,19 @@ class DVMTaskInterface:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def setOptions(request_form):
|
||||
def set_options(request_form):
|
||||
print("Setting options...")
|
||||
opts = []
|
||||
if request_form.get("optStr"):
|
||||
if request_form.get("options"):
|
||||
opts = json.loads(request_form["options"])
|
||||
print(opts)
|
||||
|
||||
# old format, deprecated, will remove
|
||||
elif request_form.get("optStr"):
|
||||
opts = []
|
||||
for k, v in [option.split("=") for option in request_form["optStr"].split(";")]:
|
||||
t = (k, v)
|
||||
opts.append(t)
|
||||
print(k + "=" + v)
|
||||
print("...done.")
|
||||
|
||||
return dict(opts)
|
||||
|
7
main.py
7
main.py
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from threading import Thread
|
||||
|
||||
import dotenv
|
||||
import utils.env as env
|
||||
@@ -14,7 +15,7 @@ def run_nostr_dvm_with_local_config():
|
||||
#Generate a optional Admin Config, in this case, whenever we give our DVMS this config, they will (re)broadcast
|
||||
# their NIP89 announcement
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCASTNIP89 = True
|
||||
admin_config.REBROADCASTNIP89 = False
|
||||
|
||||
# Spawn the DVMs
|
||||
# Add NIP89 events for each DVM
|
||||
@@ -86,7 +87,7 @@ def run_nostr_dvm_with_local_config():
|
||||
#We add an optional AdminConfig for this one, and tell the dvm to rebroadcast its NIP89
|
||||
sketcher = ImageGenerationSDXL("Sketcher", dvm_config, admin_config, default_model="mohawk", default_lora="timburton")
|
||||
d_tag = os.getenv(env.TASK_IMAGEGENERATION_NIP89_DTAG2)
|
||||
content = ("{\"name\":\"" + unstableartist.NAME + "\","
|
||||
content = ("{\"name\":\"" + sketcher.NAME + "\","
|
||||
"\"image\":\"https://image.nostr.build/229c14e440895da30de77b3ca145d66d4b04efb4027ba3c44ca147eecde891f1.jpg\","
|
||||
"\"about\":\"I draw images based on a prompt with a Model called unstable diffusion.\","
|
||||
"\"nip90Params\":{}}")
|
||||
@@ -94,6 +95,8 @@ def run_nostr_dvm_with_local_config():
|
||||
dvm_config.NIP89 = sketcher.NIP89_announcement(d_tag, content)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
env_path = Path('.env')
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
from multiprocessing.pool import ThreadPool
|
||||
from threading import Thread
|
||||
@@ -14,6 +15,8 @@ This File contains a Module to transform Text input on NOVA-Server and receive r
|
||||
|
||||
Accepted Inputs: Prompt (text)
|
||||
Outputs: An url to an Image
|
||||
Params: -model # models: juggernaut, dynavision, colossusProject, newreality, unstable
|
||||
-lora # loras (weights on top of models) voxel,
|
||||
"""
|
||||
|
||||
|
||||
@@ -24,7 +27,8 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
COST: int = 50
|
||||
PK: str
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None, default_model=None, default_lora=None):
|
||||
def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None, default_model=None,
|
||||
default_lora=None):
|
||||
self.NAME = name
|
||||
dvm_config.SUPPORTED_TASKS = [self]
|
||||
dvm_config.DB = "db/" + self.NAME + ".db"
|
||||
@@ -36,14 +40,13 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
nostr_dvm_thread = Thread(target=dvm, args=[dvm_config, admin_config])
|
||||
nostr_dvm_thread.start()
|
||||
|
||||
|
||||
def is_input_supported(self, input_type, input_content):
|
||||
if input_type != "text":
|
||||
return False
|
||||
return True
|
||||
|
||||
def create_request_form_from_nostr_event(self, event, client=None, dvm_config=None):
|
||||
request_form = {"jobID": event.id().to_hex() + "_"+ self.NAME.replace(" ", "")}
|
||||
request_form = {"jobID": event.id().to_hex() + "_" + self.NAME.replace(" ", "")}
|
||||
request_form["trainerFilePath"] = 'modules\\stablediffusionxl\\stablediffusionxl.trainer'
|
||||
|
||||
prompt = ""
|
||||
@@ -53,7 +56,6 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
else:
|
||||
model = self.default_model
|
||||
|
||||
# models: juggernautXL, dynavisionXL, colossusProjectXL, newrealityXL, unstable
|
||||
ratio_width = "1"
|
||||
ratio_height = "1"
|
||||
width = ""
|
||||
@@ -72,7 +74,7 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
prompt = tag.as_vec()[1]
|
||||
|
||||
elif tag.as_vec()[0] == 'param':
|
||||
print(tag.as_vec()[2])
|
||||
print("Param: " + tag.as_vec()[1] + ": " + tag.as_vec()[2])
|
||||
if tag.as_vec()[1] == "negative_prompt":
|
||||
negative_prompt = tag.as_vec()[2]
|
||||
elif tag.as_vec()[1] == "lora":
|
||||
@@ -91,12 +93,12 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
split = tag.as_vec()[2].split(":")
|
||||
ratio_width = split[0]
|
||||
ratio_height = split[1]
|
||||
#if size is set it will overwrite ratio.
|
||||
# if size is set it will overwrite ratio.
|
||||
elif tag.as_vec()[1] == "size":
|
||||
|
||||
if len(tag.as_vec()) > 3:
|
||||
width = (tag.as_vec()[2])
|
||||
height = (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:
|
||||
@@ -105,18 +107,39 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
elif tag.as_vec()[1] == "model":
|
||||
model = tag.as_vec()[2]
|
||||
|
||||
prompt = prompt.replace(";", ",")
|
||||
request_form['data'] = '[{"id":"input_prompt","type":"input","src":"request:text","data":"' + prompt + '","active":"True"},{"id":"negative_prompt","type":"input","src":"request:text","data":"' + negative_prompt + '","active":"True"},{"id":"output_image","type":"output","src":"request:image","active":"True"}]'
|
||||
request_form['options'] = ('[{"model":" + ' + model
|
||||
+ '","ratio":"' + str(ratio_width) + ':' + str(ratio_height)
|
||||
+ '","width":"' + str(width) + ':' + str(height)
|
||||
+ '","strength":"' + str(strength)
|
||||
+ '","guidance_scale":"' + str(guidance_scale)
|
||||
+ '","lora":"' + str(lora)
|
||||
+ '","lora_weight":"' + str(lora_weight)
|
||||
+ '"}]')
|
||||
io_input = {
|
||||
"id": "input_prompt",
|
||||
"type": "input",
|
||||
"src": "request:text",
|
||||
"data": prompt
|
||||
}
|
||||
io_negative = {
|
||||
"id": "negative_prompt",
|
||||
"type": "input",
|
||||
"src": "request:text",
|
||||
"data": negative_prompt
|
||||
}
|
||||
io_output = {
|
||||
"id": "output_image",
|
||||
"type": "output",
|
||||
"src": "request:image"
|
||||
}
|
||||
|
||||
request_form['data'] = json.dumps([io_input, io_negative, io_output])
|
||||
|
||||
options = {
|
||||
"model": model,
|
||||
"ratio": ratio_width + '-' + ratio_height,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"strength": strength,
|
||||
"guidance_scale": guidance_scale,
|
||||
"lora": lora,
|
||||
"lora_weight": lora_weight
|
||||
}
|
||||
request_form['options'] = json.dumps(options)
|
||||
|
||||
# old format, deprecated, will remove
|
||||
request_form["optStr"] = ('model=' + model + ';ratio=' + str(ratio_width) + '-' + str(ratio_height) + ';size=' +
|
||||
str(width) + '-' + str(height) + ';strength=' + str(strength) + ';guidance_scale=' +
|
||||
str(guidance_scale) + ';lora=' + lora + ';lora_weight=' + lora_weight)
|
||||
@@ -126,8 +149,9 @@ class ImageGenerationSDXL(DVMTaskInterface):
|
||||
def process(self, request_form):
|
||||
try:
|
||||
# Call the process route of NOVA-Server with our request form.
|
||||
success = send_request_to_nova_server(request_form, os.environ["NOVA_SERVER"])
|
||||
print(success)
|
||||
response = send_request_to_nova_server(request_form, os.environ["NOVA_SERVER"])
|
||||
if bool(json.loads(response)['success']):
|
||||
print("Job " + request_form['jobID'] + " sent to nova-server")
|
||||
|
||||
pool = ThreadPool(processes=1)
|
||||
thread = pool.apply_async(check_nova_server_status, (request_form['jobID'], os.environ["NOVA_SERVER"]))
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from threading import Thread
|
||||
@@ -14,6 +15,7 @@ This File contains a Module to extract Text from a PDF file locally on the DVM M
|
||||
|
||||
Accepted Inputs: Url to pdf file, Event containing an URL to a PDF file
|
||||
Outputs: Text containing the extracted contents of the PDF file
|
||||
Params: None
|
||||
"""
|
||||
|
||||
|
||||
@@ -21,7 +23,7 @@ class TextExtractionPDF(DVMTaskInterface):
|
||||
NAME: str = ""
|
||||
KIND: int = EventDefinitions.KIND_NIP90_EXTRACT_TEXT
|
||||
TASK: str = "pdf-to-text"
|
||||
COST: int = 20
|
||||
COST: int = 0
|
||||
PK: str
|
||||
|
||||
def __init__(self, name, dvm_config: DVMConfig, admin_config: AdminConfig = None):
|
||||
@@ -59,7 +61,10 @@ class TextExtractionPDF(DVMTaskInterface):
|
||||
evt = get_event_by_id(input_content, client=client, config=dvm_config)
|
||||
url = re.search("(?P<url>https?://[^\s]+)", evt.content()).group("url")
|
||||
|
||||
request_form["optStr"] = 'url=' + url
|
||||
options = {
|
||||
"url": url,
|
||||
}
|
||||
request_form['options'] = json.dumps(options)
|
||||
return request_form
|
||||
|
||||
def process(self, request_form):
|
||||
@@ -67,7 +72,7 @@ class TextExtractionPDF(DVMTaskInterface):
|
||||
from pathlib import Path
|
||||
import requests
|
||||
|
||||
options = DVMTaskInterface.setOptions(request_form)
|
||||
options = DVMTaskInterface.set_options(request_form)
|
||||
|
||||
try:
|
||||
file_path = Path('temp.pdf')
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
from threading import Thread
|
||||
|
||||
from dvm import DVM
|
||||
@@ -12,6 +13,7 @@ This File contains a Module to call Google Translate Services locally on the DVM
|
||||
|
||||
Accepted Inputs: Text, Events, Jobs (Text Extraction, Summary, Translation)
|
||||
Outputs: Text containing the Translation in the desired language.
|
||||
Params: -language The target language
|
||||
"""
|
||||
|
||||
|
||||
@@ -79,15 +81,18 @@ class Translation(DVMTaskInterface):
|
||||
text = evt.content()
|
||||
break
|
||||
|
||||
request_form["optStr"] = ('translation_lang=' + translation_lang + ';text=' +
|
||||
text.replace('\U0001f919', "").replace("=", "equals").
|
||||
replace(";", ","))
|
||||
options = {
|
||||
"text": text,
|
||||
"language": translation_lang
|
||||
}
|
||||
request_form['options'] = json.dumps(options)
|
||||
|
||||
return request_form
|
||||
|
||||
def process(self, request_form):
|
||||
from translatepy.translators.google import GoogleTranslate
|
||||
|
||||
options = DVMTaskInterface.setOptions(request_form)
|
||||
options = DVMTaskInterface.set_options(request_form)
|
||||
gtranslate = GoogleTranslate()
|
||||
length = len(options["text"])
|
||||
|
||||
@@ -98,7 +103,7 @@ class Translation(DVMTaskInterface):
|
||||
text_part = options["text"][step:step + 5000]
|
||||
step = step + 5000
|
||||
try:
|
||||
translated_text_part = str(gtranslate.translate(text_part, options["translation_lang"]))
|
||||
translated_text_part = str(gtranslate.translate(text_part, options["language"]))
|
||||
print("Translated Text part:\n\n " + translated_text_part)
|
||||
except Exception as e:
|
||||
raise Exception(e)
|
||||
@@ -108,7 +113,7 @@ class Translation(DVMTaskInterface):
|
||||
if step < length:
|
||||
text_part = options["text"][step:length]
|
||||
try:
|
||||
translated_text_part = str(gtranslate.translate(text_part, options["translation_lang"]))
|
||||
translated_text_part = str(gtranslate.translate(text_part, options["language"]))
|
||||
print("Translated Text part:\n " + translated_text_part)
|
||||
except Exception as e:
|
||||
raise Exception(e)
|
||||
|
@@ -9,7 +9,7 @@ from nostr_sdk import Keys, Client, Tag, EventBuilder, Filter, HandleNotificatio
|
||||
|
||||
from utils.dvmconfig import DVMConfig
|
||||
from utils.nostr_utils import send_event
|
||||
from utils.definitions import EventDefinitions, RELAY_LIST
|
||||
from utils.definitions import EventDefinitions
|
||||
|
||||
import utils.env as env
|
||||
|
||||
@@ -74,7 +74,8 @@ def nostr_client():
|
||||
pk = keys.public_key()
|
||||
print(f"Nostr Client public key: {pk.to_bech32()}, Hex: {pk.to_hex()} ")
|
||||
client = Client(keys)
|
||||
for relay in RELAY_LIST:
|
||||
dvmconfig = DVMConfig()
|
||||
for relay in dvmconfig.RELAY_LIST:
|
||||
client.add_relay(relay)
|
||||
client.connect()
|
||||
|
||||
@@ -85,7 +86,7 @@ def nostr_client():
|
||||
EventDefinitions.KIND_FEEDBACK]).since(Timestamp.now())) # public events
|
||||
client.subscribe([dm_zap_filter, dvm_filter])
|
||||
|
||||
# nostr_client_test_translation("This is the result of the DVM in spanish", "text", "es", 20, 20)
|
||||
#nostr_client_test_translation("This is the result of the DVM in spanish", "text", "es", 20, 20)
|
||||
#nostr_client_test_translation("note1p8cx2dz5ss5gnk7c59zjydcncx6a754c0hsyakjvnw8xwlm5hymsnc23rs", "event", "es", 20,20)
|
||||
#nostr_client_test_translation("44a0a8b395ade39d46b9d20038b3f0c8a11168e67c442e3ece95e4a1703e2beb", "event", "zh", 20, 20)
|
||||
|
||||
|
@@ -198,7 +198,6 @@ def get_or_add_user(db, npub, client):
|
||||
add_to_sql_table(db, npub, NEW_USER_BALANCE, False, False, nip05,
|
||||
lud16, name, Timestamp.now().as_secs())
|
||||
user = get_from_sql_table(db, npub)
|
||||
print(user)
|
||||
else:
|
||||
# update Name, Nip05 and lud16 lnaddress
|
||||
user.name, user.nip05, user.lud16 = fetch_user_metadata(npub, client)
|
||||
|
@@ -19,7 +19,7 @@ class DVMConfig:
|
||||
NIP89: NIP89Announcement
|
||||
|
||||
REQUIRES_NIP05: bool = False
|
||||
SHOWRESULTBEFOREPAYMENT: bool = True # if this is true show results even when not paid right after autoprocess
|
||||
SHOW_RESULT_BEFORE_PAYMENT: bool = True # if this is true show results even when not paid right after autoprocess
|
||||
|
||||
|
||||
|
||||
|
@@ -15,12 +15,11 @@ Post process results to either given output format or a Nostr readable plain tex
|
||||
|
||||
|
||||
def post_process_result(anno, original_event):
|
||||
print("post-processing...")
|
||||
print("Post-processing...")
|
||||
if isinstance(anno, pandas.DataFrame): # if input is an anno we parse it to required output format
|
||||
for tag in original_event.tags():
|
||||
print(tag.as_vec()[0])
|
||||
if tag.as_vec()[0] == "output":
|
||||
print("HAS OUTPUT TAG")
|
||||
output_format = tag.as_vec()[1]
|
||||
print("requested output is " + str(tag.as_vec()[1]) + "...")
|
||||
try:
|
||||
|
Reference in New Issue
Block a user