diff --git a/.env_example b/.env_example
index 1e7b65b..aaa3c46 100644
--- a/.env_example
+++ b/.env_example
@@ -9,6 +9,7 @@ LNBITS_HOST = "https://lnbits.com"
OPENAI_API_KEY = "" # Enter your OpenAI API Key to use DVMs with OpenAI services
LIBRE_TRANSLATE_ENDPOINT = "" # Url to LibreTranslate Endpoint e.g. https://libretranslate.com
LIBRE_TRANSLATE_API_KEY = "" # API Key, if required (You can host your own instance where you don't need it)
+REPLICATE_API_TOKEN = "" #API Key to run models on replicate.com
# 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.
diff --git a/.gitignore b/.gitignore
index ff37a51..4f1d54f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -167,3 +167,5 @@ app_deploy.py
app.py
app_deploy.py
db/Cashu/wallet.sqlite3
+.idea/misc.xml
+.idea/misc.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 8b60158..3ce312c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/main.py b/main.py
index ae440f1..f5adac5 100644
--- a/main.py
+++ b/main.py
@@ -15,6 +15,7 @@ import tasks.textextraction_pdf as textextraction_pdf
import tasks.textextraction_google as textextraction_google
import tasks.translation_google as translation_google
import tasks.translation_libretranslate as translation_libretranslate
+from tasks import imagegeneration_replicate
from utils.admin_utils import AdminConfig
from utils.backend_utils import keep_alive
@@ -75,6 +76,12 @@ def playground():
bot_config.SUPPORTED_DVMS.append(dalle)
dalle.run()
+ if os.getenv("REPLICATE_API_TOKEN") is not None and os.getenv("REPLICATE_API_TOKEN") != "":
+ sdxlreplicate = imagegeneration_replicate.build_example("Stable Diffusion XL", "replicate_sdxl", admin_config)
+ bot_config.SUPPORTED_DVMS.append(sdxlreplicate)
+ sdxlreplicate.run()
+
+
#Let's define a function so we can add external DVMs to our bot, we will instanciate it afterwards
diff --git a/tasks/imagegeneration_openai_dalle.py b/tasks/imagegeneration_openai_dalle.py
index 6017060..5b02fbc 100644
--- a/tasks/imagegeneration_openai_dalle.py
+++ b/tasks/imagegeneration_openai_dalle.py
@@ -18,12 +18,10 @@ from utils.output_utils import upload_media_to_hoster
from utils.zap_utils import get_price_per_sat
"""
-This File contains a Module to transform Text input on NOVA-Server and receive results back.
+This File contains a Module to transform Text input on OpenAI's servers with DALLE-3 and receive results back.
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,
"""
diff --git a/tasks/imagegeneration_replicate.py b/tasks/imagegeneration_replicate.py
new file mode 100644
index 0000000..ca47178
--- /dev/null
+++ b/tasks/imagegeneration_replicate.py
@@ -0,0 +1,170 @@
+import json
+import os
+from io import BytesIO
+from pathlib import Path
+
+import dotenv
+import requests
+from PIL import Image
+
+from interfaces.dvmtaskinterface import DVMTaskInterface
+from utils.admin_utils import AdminConfig
+from utils.backend_utils import keep_alive
+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 check_and_set_private_key
+from utils.output_utils import upload_media_to_hoster
+from utils.zap_utils import get_price_per_sat
+
+"""
+This File contains a Module to transform Text input on NOVA-Server and receive results back.
+
+Accepted Inputs: Prompt (text)
+Outputs: An url to an Image
+Params:
+"""
+
+
+class ImageGenerationReplicate(DVMTaskInterface):
+ KIND: int = EventDefinitions.KIND_NIP90_GENERATE_IMAGE
+ TASK: str = "text-to-image"
+ FIX_COST: float = 120
+
+ def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config,
+ admin_config: AdminConfig = None, options=None):
+ 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:
+ options = DVMTaskInterface.set_options(request_form)
+
+ import replicate
+ width = int(options["size"].split("x")[0])
+ height = int(options["size"].split("x")[1])
+ output = replicate.run(
+ "stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b",
+ input={"prompt": options["prompt"],
+ "width": width,
+ "height": height,
+ "disable_safety_checker": True}
+ )
+ print(output[0])
+ response = requests.get(output[0])
+ image = Image.open(BytesIO(response.content)).convert("RGB")
+ 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 = DVMConfig()
+ dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
+ dvm_config.LNBITS_INVOICE_KEY = os.getenv("LNBITS_INVOICE_KEY")
+ dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
+ profit_in_sats = 10
+ dvm_config.FIX_COST = int(((4.0 / (get_price_per_sat("USD") * 100)) + profit_in_sats))
+
+ nip90params = {
+ "size": {
+ "required": False,
+ "values": ["1024:1024", "1024x1792", "1792x1024"]
+ }
+ }
+ nip89info = {
+ "name": name,
+ "image": "https://image.nostr.build/c33ca6fc4cc038ca4adb46fdfdfda34951656f87ee364ef59095bae1495ce669.jpg",
+ "about": "I use Replicate to run StableDiffusion XL",
+ "encryptionSupported": True,
+ "cashuAccepted": True,
+ "nip90Params": nip90params
+ }
+
+
+ nip89config = NIP89Config()
+ nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY,
+ nip89info["image"])
+ nip89config.CONTENT = json.dumps(nip89info)
+ # We add an optional AdminConfig for this one, and tell the dvm to rebroadcast its NIP89
+ return ImageGenerationReplicate(name=name, dvm_config=dvm_config, nip89config=nip89config, admin_config=admin_config)
+
+
+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
+ admin_config.LUD16 = ""
+
+ dvm = build_example("Stable Diffusion XL", "replicate_sdxl", admin_config)
+ dvm.run()
+
+ keep_alive()
diff --git a/tasks/textextraction_google.py b/tasks/textextraction_google.py
index c48d786..fe47b86 100644
--- a/tasks/textextraction_google.py
+++ b/tasks/textextraction_google.py
@@ -6,7 +6,6 @@ from pathlib import Path
import dotenv
-from backends.nova_server import check_nova_server_status, send_request_to_nova_server, send_file_to_nova_server
from interfaces.dvmtaskinterface import DVMTaskInterface
from utils.admin_utils import AdminConfig
from utils.backend_utils import keep_alive