import os import signal import time import requests from nostr_sdk import Event from nostr_dvm.utils.definitions import EventDefinitions from nostr_dvm.utils.mediasource_utils import check_source_type, media_source from nostr_dvm.utils.nostr_utils import get_event_by_id, get_referenced_event_by_id async def get_task(event, client, dvm_config): try: if event.kind() == EventDefinitions.KIND_NIP90_GENERIC: # use this for events that have no id yet, inclufr j tag for tag in event.tags().to_vec(): if tag.as_vec()[0] == 'j': return tag.as_vec()[1] else: return "unknown job: " + event.as_json() elif event.kind() == EventDefinitions.KIND_DM: # dm for tag in event.tags().to_vec(): if tag.as_vec()[0] == 'j': return tag.as_vec()[1] else: return "unknown job: " + event.as_json() # This looks a bit more complicated, but we do several tasks for text-extraction in the future elif event.kind() == EventDefinitions.KIND_NIP90_EXTRACT_TEXT: for tag in event.tags().to_vec(): if tag.as_vec()[0] == "i": if tag.as_vec()[2] == "url": file_type = check_url_is_readable(tag.as_vec()[1]) print(file_type) if file_type == "pdf": return "pdf-to-text" elif file_type == "audio" or file_type == "video": return "speech-to-text" elif file_type == "image": return "image-to-text" else: return "unknown job" elif tag.as_vec()[2] == "event": evt = await get_event_by_id(tag.as_vec()[1], client=client, config=dvm_config) if evt is not None: if evt.kind() == 1063: for tg in evt.tags().to_vec(): if tg.as_vec()[0] == 'url': file_type = check_url_is_readable(tg.as_vec()[1]) if file_type == "pdf": return "pdf-to-text" elif file_type == "audio" or file_type == "video": return "speech-to-text" else: return "unknown job" else: return "unknown type" else: return "unknown job" elif event.kind() == EventDefinitions.KIND_NIP90_GENERATE_IMAGE: has_image_tag = False has_text_tag = False for tag in event.tags().to_vec(): if tag.as_vec()[0] == "i": if tag.as_vec()[2] == "url": file_type = check_url_is_readable(tag.as_vec()[1]) if file_type == "image": has_image_tag = True print("found image tag") elif tag.as_vec()[2] == "job": evt = await get_referenced_event_by_id(event_id=tag.as_vec()[1], kinds= [EventDefinitions.KIND_NIP90_RESULT_EXTRACT_TEXT, EventDefinitions.KIND_NIP90_RESULT_TRANSLATE_TEXT, EventDefinitions.KIND_NIP90_RESULT_SUMMARIZE_TEXT], client=client, dvm_config=dvm_config) if evt is not None: file_type = check_url_is_readable(evt.content()) if file_type == "image": has_image_tag = True elif tag.as_vec()[2] == "text": has_text_tag = True if has_image_tag: return "image-to-image" elif has_text_tag and not has_image_tag: return "text-to-image" # TODO if a task can consist of multiple inputs add them here # This is not ideal. Maybe such events should have their own kind # else if kind is supported, simply return task else: for dvm in dvm_config.SUPPORTED_DVMS: if dvm.KIND.as_u16() == event.kind().as_u16(): return dvm.TASK except Exception as e: print("Get task: " + str(e)) return "unknown type" def is_input_supported_generic(tags, client, dvm_config) -> bool: # Handle malformed tags, missing events etc here. try: for tag in tags: if tag.as_vec()[0] == 'i': if len(tag.as_vec()) < 3: print("Job Event missing/malformed i tag, skipping..") return False else: input_value = tag.as_vec()[1] input_type = tag.as_vec()[2] # if input_type == "event": # evt = get_event_by_id(input_value, client=client, config=dvm_config) # if evt is None: # print("Event not found") # return False # TODO check_url_is_readable might be more relevant per task in the future # if input_type == 'url' and check_url_is_readable(input_value) is None: # print("Url not readable / supported") # return False return True except Exception as e: print("Generic input check: " + str(e)) async def check_task_is_supported(event: Event, client, config=None): try: dvm_config = config # Check for generic issues, event maformed, referenced event not found etc.. if not is_input_supported_generic(event.tags().to_vec(), client, dvm_config): return False, "" # See if current dvm supports the task task = await get_task(event, client=client, dvm_config=dvm_config) # if task not in (x.TASK for x in dvm_config.SUPPORTED_DVMS) and not task == "generic": # return False, task # See if current dvm can handle input for given task for dvm in dvm_config.SUPPORTED_DVMS: if dvm.TASK == task: if not await dvm.is_input_supported(event.tags().to_vec(), client, config): return False, task return True, task except Exception as e: print("Check task: " + str(e)) def check_url_is_readable(url): if not str(url).startswith("http"): return None source = check_source_type(url) type = media_source(source) if type == "url": # If link is comaptible with one of these file formats, move on. req = requests.get(url) content_type = req.headers['content-type'] if content_type == 'audio/x-wav' or str(url).endswith(".wav") or content_type == 'audio/mpeg' or str( url).endswith( ".mp3") or content_type == 'audio/ogg' or str(url).endswith(".ogg"): return "audio" elif (content_type == 'image/png' or str(url).endswith(".png") or content_type == 'image/jpg' or str( url).endswith( ".jpg") or content_type == 'image/jpeg' or str(url).endswith(".jpeg") or content_type == 'image/png' or str(url).endswith(".png")): return "image" elif content_type == 'video/mp4' or str(url).endswith(".mp4") or content_type == 'video/avi' or str( url).endswith( ".avi") or content_type == 'video/mov' or str(url).endswith(".mov"): return "video" elif (str(url)).endswith(".pdf"): return "pdf" else: return type # Otherwise we will not offer to do the job. return None def get_amount_per_task(task, dvm_config, duration=1): # duration is either static 1 (for images etc) or in seconds by default (e.g. audio/video) for dvm in dvm_config.SUPPORTED_DVMS: # this is currently just one if dvm.TASK == task or dvm.TASK == "generic": amount = dvm.FIX_COST + (dvm.PER_UNIT_COST * duration) return amount else: print("[" + dvm_config.SUPPORTED_DVMS[ 0].NAME + "] Task " + task + " is currently not supported by this instance, skipping") return None