mirror of
https://github.com/aljazceru/nostrdvm.git
synced 2026-02-21 22:24:22 +01:00
@@ -3,7 +3,7 @@
|
||||
|
||||
#Create an account with a lnbits instance of your choice, add the admin key and id here. This account will be used to create a new lnbits wallet for each dvm/bot
|
||||
LNBITS_ADMIN_KEY = "" # In order to pay invoices, e.g. from the bot to DVMs, or reimburse users. Keep this secret and use responsibly.
|
||||
LNBITS_ADMIN_ID = ""
|
||||
LNBITS_WALLET_ID = ""
|
||||
LNBITS_HOST = "https://demo.lnbits.com/"
|
||||
# In order to create a zappable lightning address, host nostdress on your domain or use this preinstalled domain.
|
||||
# We will use the api to create and manage zapable lightning addresses
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -191,3 +191,4 @@ tests/db/Cashu/wallet.sqlite3
|
||||
tests/pagerank/index_map_99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64.json
|
||||
tests/pagerank/network_graph_99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64.json
|
||||
tests/test_data/wallet_mint_api/wallet.sqlite3
|
||||
.env_bkp2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Create an account with a lnbits instance of your choice, add the admin key and id here. This account will be used to create a new lnbits wallet for each dvm/bot
|
||||
LNBITS_ADMIN_KEY = ""
|
||||
LNBITS_ADMIN_ID = ""
|
||||
LNBITS_WALLET_ID = ""
|
||||
LNBITS_HOST = "https://lnbits.com" #Use your own/a trusted instance ideally.
|
||||
# In order to create a zappable lightning address, host nostdress on your domain or use this preinstalled domain.
|
||||
# We will use the api to create and manage zapable lightning addresses
|
||||
|
||||
@@ -9,7 +9,7 @@ Projects in this folder contain ready-to-use DVMs. To tun the DVM following the
|
||||
Create a new venv in this directory by opening the terminal here, or navigate to this directory and type: `"python -m venv venv"`
|
||||
- Place .env file (based on .env_example) in this folder.
|
||||
- Recommended but optional:
|
||||
- Create a `LNbits` account on an accessible instance of your choice, enter one account's id and admin key (this account will create other accounts for the dvms) Open the .env file and enter this info to `LNBITS_ADMIN_KEY`, `LNBITS_ADMIN_ID`, `LNBITS_HOST`.
|
||||
- Create a `LNbits` account on an accessible instance of your choice, enter one account's id and admin key (this account will create other accounts for the dvms) Open the .env file and enter this info to `LNBITS_ADMIN_KEY`, `LNBITS_WALLET_ID`, `LNBITS_HOST`.
|
||||
- If you are running an own instance of `Nostdress` enter `NOSTDRESS_DOMAIN` or use the default one.
|
||||
- Activate the venv with
|
||||
- MacOS/Linux: source ./venv/bin/activate
|
||||
|
||||
@@ -65,7 +65,7 @@ async def nostr_client():
|
||||
print(f"Received new event from {relay_url}: {event.as_json()}")
|
||||
if event.kind() == 7000:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
elif 6000 < event.kind().as_u64() < 6999:
|
||||
elif 6000 < event.kind().as_u16() < 6999:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
print("[Nostr Client]: " + event.content())
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Create an account with a lnbits instance of your choice, add the admin key and id here. This account will be used to create a new lnbits wallet for each dvm/bot
|
||||
LNBITS_ADMIN_KEY = ""
|
||||
LNBITS_ADMIN_ID = ""
|
||||
LNBITS_WALLET_ID = ""
|
||||
LNBITS_HOST = "https://lnbits.com" #Use your own/a trusted instance ideally.
|
||||
# In order to create a zappable lightning address, host nostdress on your domain or use this preinstalled domain.
|
||||
# We will use the api to create and manage zapable lightning addresses
|
||||
|
||||
@@ -9,7 +9,7 @@ Projects in this folder contain ready-to-use DVMs. To tun the DVM following the
|
||||
Create a new venv in this directory by opening the terminal here, or navigate to this directory and type: `"python -m venv venv"`
|
||||
- Place .env file (based on .env_example) in this folder.
|
||||
- Recommended but optional:
|
||||
- Create a `LNbits` account on an accessible instance of your choice, enter one account's id and admin key (this account will create other accounts for the dvms) Open the .env file and enter this info to `LNBITS_ADMIN_KEY`, `LNBITS_ADMIN_ID`, `LNBITS_HOST`.
|
||||
- Create a `LNbits` account on an accessible instance of your choice, enter one account's id and admin key (this account will create other accounts for the dvms) Open the .env file and enter this info to `LNBITS_ADMIN_KEY`, `LNBITS_WALLET_ID`, `LNBITS_HOST`.
|
||||
- If you are running an own instance of `Nostdress` enter `NOSTDRESS_DOMAIN` or use the default one.
|
||||
- Activate the venv with
|
||||
- MacOS/Linux: source ./venv/bin/activate
|
||||
|
||||
@@ -71,7 +71,7 @@ async def nostr_client():
|
||||
print(f"Received new event from {relay_url}: {event.as_json()}")
|
||||
if event.kind() == 7000:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
elif 6000 < event.kind().as_u64() < 6999:
|
||||
elif 6000 < event.kind().as_u16() < 6999:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
print("[Nostr Client]: " + event.content())
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Create an account with a lnbits instance of your choice, add the admin key and id here. This account will be used to create a new lnbits wallet for each dvm/bot
|
||||
LNBITS_ADMIN_KEY = ""
|
||||
LNBITS_ADMIN_ID = ""
|
||||
LNBITS_WALLET_ID = ""
|
||||
LNBITS_HOST = "https://lnbits.com" #Use your own/a trusted instance ideally.
|
||||
# In order to create a zappable lightning address, host nostdress on your domain or use this preinstalled domain.
|
||||
# We will use the api to create and manage zapable lightning addresses
|
||||
|
||||
@@ -9,7 +9,7 @@ Projects in this folder contain ready-to-use DVMs. To tun the DVM following the
|
||||
Create a new venv in this directory by opening the terminal here, or navigate to this directory and type: `"python -m venv venv"`
|
||||
- Place .env file (based on .env_example) in this folder.
|
||||
- Recommended but optional:
|
||||
- Create a `LNbits` account on an accessible instance of your choice, enter one account's id and admin key (this account will create other accounts for the dvms) Open the .env file and enter this info to `LNBITS_ADMIN_KEY`, `LNBITS_ADMIN_ID`, `LNBITS_HOST`.
|
||||
- Create a `LNbits` account on an accessible instance of your choice, enter one account's id and admin key (this account will create other accounts for the dvms) Open the .env file and enter this info to `LNBITS_ADMIN_KEY`, `LNBITS_WALLET_ID`, `LNBITS_HOST`.
|
||||
- If you are running an own instance of `Nostdress` enter `NOSTDRESS_DOMAIN` or use the default one.
|
||||
- Activate the venv with
|
||||
- MacOS/Linux: source ./venv/bin/activate
|
||||
|
||||
@@ -70,7 +70,7 @@ async def nostr_client():
|
||||
print(f"Received new event from {relay_url}: {event.as_json()}")
|
||||
if event.kind() == 7000:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
elif 6000 < event.kind().as_u64() < 6999:
|
||||
elif 6000 < event.kind().as_u16() < 6999:
|
||||
print("[Nostr Client " + event.author().to_bech32() + "]: " + event.as_json())
|
||||
print("[Nostr Client " + event.author().to_bech32() + "]: " + event.content())
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class Bot:
|
||||
kinds = [EventDefinitions.KIND_NIP90_GENERIC, EventDefinitions.KIND_FEEDBACK]
|
||||
for dvm in self.dvm_config.SUPPORTED_DVMS:
|
||||
if dvm.KIND not in kinds:
|
||||
kinds.append(Kind(dvm.KIND.as_u64() + 1000))
|
||||
kinds.append(Kind(dvm.KIND.as_u16() + 1000))
|
||||
dvm_filter = (Filter().kinds(kinds).since(Timestamp.now()))
|
||||
|
||||
await self.client.subscribe([zap_filter, dm_filter, nip17_filter, dvm_filter], None)
|
||||
@@ -82,8 +82,8 @@ class Bot:
|
||||
keys = self.keys
|
||||
|
||||
async def handle(self, relay_url, subscription_id, nostr_event):
|
||||
if (EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u64() + 1000 <= nostr_event.kind().as_u64()
|
||||
<= EventDefinitions.KIND_NIP90_GENERIC.as_u64() + 1000):
|
||||
if (EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u16() + 1000 <= nostr_event.kind().as_u16()
|
||||
<= EventDefinitions.KIND_NIP90_GENERIC.as_u16() + 1000):
|
||||
await handle_nip90_response_event(nostr_event)
|
||||
elif nostr_event.kind() == EventDefinitions.KIND_FEEDBACK:
|
||||
await handle_nip90_feedback(nostr_event)
|
||||
@@ -459,7 +459,7 @@ class Bot:
|
||||
return
|
||||
|
||||
dvms = [x for x in self.dvm_config.SUPPORTED_DVMS if
|
||||
x.PUBLIC_KEY == nostr_event.author().to_hex() and x.KIND.as_u64() == nostr_event.kind().as_u64() - 1000]
|
||||
x.PUBLIC_KEY == nostr_event.author().to_hex() and x.KIND.as_u16() == nostr_event.kind().as_u16() - 1000]
|
||||
if len(dvms) > 0:
|
||||
dvm = dvms[0]
|
||||
if dvm.dvm_config.EXTERNAL_POST_PROCESS_TYPE != PostProcessFunctionType.NONE:
|
||||
|
||||
@@ -91,11 +91,11 @@ class DVM:
|
||||
async def handle(self, relay_url, subscription_id, nostr_event: Event):
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
print(nostr_event.as_json())
|
||||
if EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u64() <= nostr_event.kind().as_u64() <= EventDefinitions.KIND_NIP90_GENERIC.as_u64():
|
||||
if EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u16() <= nostr_event.kind().as_u16() <= EventDefinitions.KIND_NIP90_GENERIC.as_u16():
|
||||
await handle_nip90_job_event(nostr_event)
|
||||
elif nostr_event.kind().as_u64() == EventDefinitions.KIND_ZAP.as_u64():
|
||||
elif nostr_event.kind().as_u16() == EventDefinitions.KIND_ZAP.as_u16():
|
||||
await handle_zap(nostr_event)
|
||||
elif nostr_event.kind().as_u64() == EventDefinitions.KIND_NIP61_NUT_ZAP.as_u64():
|
||||
elif nostr_event.kind().as_u16() == EventDefinitions.KIND_NIP61_NUT_ZAP.as_u16():
|
||||
await handle_nutzap(nostr_event)
|
||||
|
||||
async def handle_msg(self, relay_url, msg):
|
||||
@@ -139,7 +139,7 @@ class DVM:
|
||||
return
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.INFO.value:
|
||||
print(
|
||||
bcolors.MAGENTA + "[" + self.dvm_config.NIP89.NAME + "] Received new Request: " + task + " from " + user.name + " (" + user.npub + ")" + bcolors.ENDC)
|
||||
bcolors.MAGENTA + "[" + self.dvm_config.NIP89.NAME + "] Received new Request: " + task + " from " + user.name + " (" + PublicKey.parse(user.npub).to_bech32() + ")" + bcolors.ENDC)
|
||||
duration = await input_data_file_duration(nip90_event, dvm_config=self.dvm_config, client=self.client)
|
||||
amount = get_amount_per_task(task, self.dvm_config, duration)
|
||||
if amount is None:
|
||||
@@ -575,7 +575,7 @@ class DVM:
|
||||
e_tag = Tag.parse(["e", original_event.id().to_hex()])
|
||||
p_tag = Tag.parse(["p", original_event.author().to_hex()])
|
||||
alt_tag = Tag.parse(["alt", "This is the result of a NIP90 DVM AI task with kind " + str(
|
||||
original_event.kind().as_u64()) + ". The task was: " + original_event.content()])
|
||||
original_event.kind().as_u16()) + ". The task was: " + original_event.content()])
|
||||
status_tag = Tag.parse(["status", "success"])
|
||||
reply_tags = [request_tag, e_tag, p_tag, alt_tag, status_tag]
|
||||
|
||||
@@ -607,17 +607,17 @@ class DVM:
|
||||
content = nip04_encrypt(self.keys.secret_key(), PublicKey.from_hex(original_event.author().to_hex()),
|
||||
content)
|
||||
|
||||
reply_event = EventBuilder(Kind(original_event.kind().as_u64() + 1000), str(content), reply_tags).to_event(
|
||||
reply_event = EventBuilder(Kind(original_event.kind().as_u16() + 1000), str(content), reply_tags).to_event(
|
||||
self.keys)
|
||||
|
||||
# send_event(reply_event, client=self.client, dvm_config=self.dvm_config)
|
||||
await send_event_outbox(reply_event, client=self.client, dvm_config=self.dvm_config)
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
print(bcolors.GREEN + "[" + self.dvm_config.NIP89.NAME + "] " + str(
|
||||
original_event.kind().as_u64() + 1000) + " Job Response event sent: " + reply_event.as_json() + bcolors.ENDC)
|
||||
original_event.kind().as_u16() + 1000) + " Job Response event sent: " + reply_event.as_json() + bcolors.ENDC)
|
||||
elif self.dvm_config.LOGLEVEL.value >= LogLevel.INFO.value:
|
||||
print(bcolors.GREEN + "[" + self.dvm_config.NIP89.NAME + "] " + str(
|
||||
original_event.kind().as_u64() + 1000) + " Job Response event sent: " + reply_event.id().to_hex() + bcolors.ENDC)
|
||||
original_event.kind().as_u16() + 1000) + " Job Response event sent: " + reply_event.id().to_hex() + bcolors.ENDC)
|
||||
|
||||
async def send_job_status_reaction(original_event, status, is_paid=True, amount=0, client=None,
|
||||
content=None,
|
||||
@@ -729,10 +729,10 @@ class DVM:
|
||||
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
print(bcolors.YELLOW + "[" + self.dvm_config.NIP89.NAME + "]" + " Sent Kind " + str(
|
||||
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + status + " " + reaction_event.as_json() + bcolors.ENDC)
|
||||
EventDefinitions.KIND_FEEDBACK.as_u16()) + " Reaction: " + status + " " + reaction_event.as_json() + bcolors.ENDC)
|
||||
elif self.dvm_config.LOGLEVEL.value >= LogLevel.INFO.value:
|
||||
print(bcolors.YELLOW + "[" + self.dvm_config.NIP89.NAME + "]" + " Sent Kind " + str(
|
||||
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + status + " " + reaction_event.id().to_hex() + bcolors.ENDC)
|
||||
EventDefinitions.KIND_FEEDBACK.as_u16()) + " Reaction: " + status + " " + reaction_event.id().to_hex() + bcolors.ENDC)
|
||||
|
||||
return reaction_event.as_json()
|
||||
|
||||
@@ -779,8 +779,8 @@ class DVM:
|
||||
|
||||
async def do_work(job_event, amount):
|
||||
if ((
|
||||
EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u64() <= job_event.kind().as_u64() <= EventDefinitions.KIND_NIP90_GENERIC.as_u64())
|
||||
or job_event.kind().as_u64() == EventDefinitions.KIND_DM.as_u64()):
|
||||
EventDefinitions.KIND_NIP90_EXTRACT_TEXT.as_u16() <= job_event.kind().as_u16() <= EventDefinitions.KIND_NIP90_GENERIC.as_u16())
|
||||
or job_event.kind().as_u16() == EventDefinitions.KIND_DM.as_u16()):
|
||||
|
||||
task = await get_task(job_event, client=self.client, dvm_config=self.dvm_config)
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ class Subscription:
|
||||
reaction_event = EventBuilder(EventDefinitions.KIND_FEEDBACK, str(content), reply_tags).to_event(keys)
|
||||
await send_event(reaction_event, client=self.client, dvm_config=self.dvm_config)
|
||||
print("[" + self.dvm_config.NIP89.NAME + "]" + ": Sent Kind " + str(
|
||||
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + "success" + " " + reaction_event.as_json())
|
||||
EventDefinitions.KIND_FEEDBACK.as_u16()) + " Reaction: " + "success" + " " + reaction_event.as_json())
|
||||
|
||||
async def pay_zap_split(nwc, overall_amount, zaps, tier, unit="msats"):
|
||||
overallsplit = 0
|
||||
|
||||
@@ -112,7 +112,7 @@ class DicoverContentLatestLongForm(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
#print(self.db_name)
|
||||
cli = ClientBuilder().database(database).signer(signer).opts(opts).build()
|
||||
await cli.connect()
|
||||
@@ -178,7 +178,7 @@ class DicoverContentLatestLongForm(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -112,7 +112,7 @@ class DicoverContentLatestWiki(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
#print(self.db_name)
|
||||
cli = ClientBuilder().database(database).signer(signer).opts(opts).build()
|
||||
await cli.connect()
|
||||
@@ -178,7 +178,7 @@ class DicoverContentLatestWiki(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -109,7 +109,7 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
|
||||
ns = SimpleNamespace()
|
||||
|
||||
options = self.set_options(request_form)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
|
||||
timestamp_since = Timestamp.now().as_secs() - self.db_since
|
||||
since = Timestamp.from_secs(timestamp_since)
|
||||
@@ -175,7 +175,7 @@ class DicoverContentCurrentlyPopular(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -115,7 +115,7 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
|
||||
#keys = Keys.parse(sk.to_hex())
|
||||
#signer = NostrSigner.keys(keys)
|
||||
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
#cli = ClientBuilder().database(database).signer(signer).opts(opts).build()
|
||||
|
||||
#await cli.connect()
|
||||
@@ -230,7 +230,7 @@ class DicoverContentCurrentlyPopularZaps(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -101,7 +101,7 @@ class DicoverContentCurrentlyPopularFollowers(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().database(database).signer(signer).opts(opts).build()
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
await cli.add_relay(relay)
|
||||
@@ -199,7 +199,7 @@ class DicoverContentCurrentlyPopularFollowers(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -112,7 +112,7 @@ class DicoverContentCurrentlyPopularGallery(DVMTaskInterface):
|
||||
ns = SimpleNamespace()
|
||||
|
||||
options = self.set_options(request_form)
|
||||
databasegallery = await NostrDatabase.sqlite(self.db_name)
|
||||
databasegallery = NostrDatabase.lmdb(self.db_name)
|
||||
|
||||
timestamp_since = Timestamp.now().as_secs() - self.db_since
|
||||
since = Timestamp.from_secs(timestamp_since)
|
||||
@@ -250,7 +250,7 @@ class DicoverContentCurrentlyPopularGallery(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -106,6 +106,7 @@ class DicoverContentCurrentlyPopularMostr(DVMTaskInterface):
|
||||
from nostr_sdk import Filter
|
||||
from types import SimpleNamespace
|
||||
|
||||
|
||||
ns = SimpleNamespace()
|
||||
options = self.set_options(request_form)
|
||||
|
||||
@@ -114,9 +115,17 @@ class DicoverContentCurrentlyPopularMostr(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
|
||||
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
try:
|
||||
await database.delete(Filter().until(Timestamp.from_secs(
|
||||
Timestamp.now().as_secs() - self.db_since)))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
|
||||
timestamp_since = Timestamp.now().as_secs() - self.db_since
|
||||
since = Timestamp.from_secs(timestamp_since)
|
||||
|
||||
@@ -153,6 +162,7 @@ class DicoverContentCurrentlyPopularMostr(DVMTaskInterface):
|
||||
# await cli.shutdown()
|
||||
return json.dumps(result_list)
|
||||
|
||||
|
||||
async def post_process(self, result, event):
|
||||
"""Overwrite the interface function to return a social client readable format, if requested"""
|
||||
for tag in event.tags():
|
||||
@@ -183,7 +193,7 @@ class DicoverContentCurrentlyPopularMostr(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
@@ -221,7 +231,7 @@ class DicoverContentCurrentlyPopularMostr(DVMTaskInterface):
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# Do not delete profiles
|
||||
await cli.database().delete(Filter().kinds([EventDefinitions.KIND_NOTE, EventDefinitions.KIND_ZAP, EventDefinitions.KIND_REPOST, EventDefinitions.KIND_REACTION]).until(Timestamp.from_secs(
|
||||
await cli.database().delete(Filter().until(Timestamp.from_secs(
|
||||
Timestamp.now().as_secs() - self.db_since))) # Clear old events so db doesn't get too full.
|
||||
await cli.shutdown()
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
|
||||
@@ -146,7 +146,7 @@ class DicoverContentCurrentlyPopularNonFollowers(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
if self.database is None:
|
||||
self.database = await NostrDatabase.sqlite(self.db_name)
|
||||
self.database = NostrDatabase.lmdb(self.db_name)
|
||||
|
||||
cli = ClientBuilder().database(self.database).signer(signer).opts(opts).build()
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
@@ -230,7 +230,7 @@ class DicoverContentCurrentlyPopularNonFollowers(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -93,6 +93,7 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
|
||||
|
||||
# default values
|
||||
max_results = 200
|
||||
user = event.author().to_hex()
|
||||
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == 'i':
|
||||
@@ -101,6 +102,8 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
|
||||
param = tag.as_vec()[1]
|
||||
if param == "max_results": # check for param type
|
||||
max_results = int(tag.as_vec()[2])
|
||||
elif param == "user": # check for param type
|
||||
user = (tag.as_vec()[2])
|
||||
elif param == "search_list": # check for param type
|
||||
self.search_list = str(tag.as_vec()[2]).split(",")
|
||||
print(self.search_list)
|
||||
@@ -113,6 +116,8 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
|
||||
|
||||
options = {
|
||||
"max_results": max_results,
|
||||
"request_event_id": event.id().to_hex(),
|
||||
"request_event_author": event.author().to_hex()
|
||||
}
|
||||
request_form['options'] = json.dumps(options)
|
||||
self.request_form = request_form
|
||||
@@ -144,29 +149,34 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
|
||||
|
||||
options = self.set_options(request_form)
|
||||
if self.database is None:
|
||||
self.database = await NostrDatabase.sqlite(self.db_name)
|
||||
self.database = NostrDatabase.lmdb(self.db_name)
|
||||
|
||||
timestamp_since = Timestamp.now().as_secs() - self.db_since
|
||||
since = Timestamp.from_secs(timestamp_since)
|
||||
|
||||
filter1 = Filter().kind(definitions.EventDefinitions.KIND_NOTE).since(since)
|
||||
filters = []
|
||||
for word in self.search_list:
|
||||
filter = Filter().kind(definitions.EventDefinitions.KIND_NOTE).since(since).search(word)
|
||||
filters.append(filter)
|
||||
|
||||
events = await self.database.query([filter1])
|
||||
|
||||
|
||||
events = await self.database.query(filters)
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
print("[" + self.dvm_config.NIP89.NAME + "] Considering " + str(len(events)) + " Events")
|
||||
ns.finallist = {}
|
||||
|
||||
for event in events:
|
||||
if all(ele in event.content().lower() for ele in self.must_list):
|
||||
if any(ele in event.content().lower() for ele in self.search_list):
|
||||
if not any(ele in event.content().lower() for ele in self.avoid_list):
|
||||
filt = Filter().kinds(
|
||||
[definitions.EventDefinitions.KIND_ZAP, definitions.EventDefinitions.KIND_REACTION,
|
||||
definitions.EventDefinitions.KIND_REPOST,
|
||||
definitions.EventDefinitions.KIND_NOTE]).event(event.id()).since(since)
|
||||
reactions = await self.database.query([filt])
|
||||
if len(reactions) >= self.min_reactions:
|
||||
ns.finallist[event.id().to_hex()] = len(reactions)
|
||||
#if any(ele in event.content().lower() for ele in self.search_list):
|
||||
if not any(ele in event.content().lower() for ele in self.avoid_list):
|
||||
filt = Filter().kinds(
|
||||
[definitions.EventDefinitions.KIND_ZAP, definitions.EventDefinitions.KIND_REACTION,
|
||||
definitions.EventDefinitions.KIND_REPOST,
|
||||
definitions.EventDefinitions.KIND_NOTE]).event(event.id()).since(since)
|
||||
reactions = await self.database.query([filt])
|
||||
if len(reactions) >= self.min_reactions:
|
||||
ns.finallist[event.id().to_hex()] = len(reactions)
|
||||
|
||||
result_list = []
|
||||
finallist_sorted = sorted(ns.finallist.items(), key=lambda x: x[1], reverse=True)[:int(options["max_results"])]
|
||||
@@ -198,7 +208,7 @@ class DicoverContentCurrentlyPopularbyTopic(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from itertools import islice
|
||||
|
||||
import networkx as nx
|
||||
from nostr_sdk import Client, Timestamp, PublicKey, Tag, Keys, Options, SecretKey, NostrSigner, NostrDatabase, \
|
||||
ClientBuilder, Filter, NegentropyOptions, NegentropyDirection, init_logger, LogLevel, Event, EventId, Kind, \
|
||||
RelayLimits
|
||||
@@ -14,7 +18,7 @@ from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip88_utils import NIP88Config, check_and_set_d_tag_nip88, check_and_set_tiereventid_nip88
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag, create_amount_tag
|
||||
from nostr_dvm.utils.output_utils import post_process_list_to_events
|
||||
|
||||
from nostr_dvm.utils.wot_utils import build_wot_network, save_network, print_results
|
||||
|
||||
"""
|
||||
This File contains a Module to update the database for content discovery dvms
|
||||
@@ -132,24 +136,49 @@ class DicoverContentDBUpdateScheduler(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
if self.database is None:
|
||||
self.database = await NostrDatabase.sqlite(self.db_name)
|
||||
self.database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(self.database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
await cli.add_relay(relay)
|
||||
|
||||
|
||||
await cli.connect()
|
||||
|
||||
|
||||
if self.dvm_config.WOT_FILTERING:
|
||||
print("Calculating WOT for " + str(self.dvm_config.WOT_BASED_ON_NPUBS))
|
||||
filtering = cli.filtering()
|
||||
index_map, G = await build_wot_network(self.dvm_config.WOT_BASED_ON_NPUBS, depth=self.dvm_config.WOT_DEPTH, max_batch=500, max_time_request=10)
|
||||
|
||||
# Do we actually need pagerank here?
|
||||
#print('computing global pagerank...')
|
||||
#tic = time.time()
|
||||
#p_G = nx.pagerank(G, tol=1e-12)
|
||||
# print("network after pagerank: " + str(len(p_G)))
|
||||
|
||||
wot_keys = []
|
||||
for item in islice(G, len(G)):
|
||||
key = next((PublicKey.parse(pubkey) for pubkey, id in index_map.items() if id == item),
|
||||
None)
|
||||
wot_keys.append(key)
|
||||
|
||||
#toc = time.time()
|
||||
#print(f'finished in {toc - tic} seconds')
|
||||
await filtering.add_public_keys(wot_keys)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Mute public key
|
||||
await cli.mute_public_keys(self.dvm_config.MUTE)
|
||||
#await cli. (self.dvm_config.MUTE)
|
||||
|
||||
timestamp_since = Timestamp.now().as_secs() - self.db_since
|
||||
since = Timestamp.from_secs(timestamp_since)
|
||||
|
||||
filter1 = Filter().kinds([definitions.EventDefinitions.KIND_NOTE, definitions.EventDefinitions.KIND_REACTION,
|
||||
definitions.EventDefinitions.KIND_ZAP]).since(since) # Notes, reactions, zaps
|
||||
definitions.EventDefinitions.KIND_ZAP]).since(since) # Notes, reactions, zaps
|
||||
|
||||
# filter = Filter().author(keys.public_key())
|
||||
if self.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
|
||||
@@ -77,7 +77,7 @@ class DiscoveryBotFarms(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
|
||||
database = await NostrDatabase.sqlite("db/nostr_profiles.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_profiles.db")
|
||||
cli = ClientBuilder().database(database).signer(signer).opts(opts).build()
|
||||
|
||||
await cli.add_relay("wss://relay.damus.io")
|
||||
@@ -137,7 +137,7 @@ class DiscoveryBotFarms(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite("db/nostr_profiles.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_profiles.db")
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
await cli.add_relay("wss://relay.damus.io")
|
||||
|
||||
@@ -51,9 +51,8 @@ class GenericDVM(DVMTaskInterface):
|
||||
|
||||
request_form = {"jobID": event.id().to_hex()}
|
||||
|
||||
self.options["user"] = user
|
||||
self.options["request_event_id"] = event.id().to_hex()
|
||||
self.options["request_event_author"] = event.author().to_hex()
|
||||
self.options["request_event_author"] = user
|
||||
if prompt != "":
|
||||
self.options["input"] = prompt
|
||||
request_form['options'] = json.dumps(self.options)
|
||||
|
||||
@@ -19,7 +19,7 @@ from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config
|
||||
from nostr_dvm.utils.nip88_utils import NIP88Config, check_and_set_d_tag_nip88, check_and_set_tiereventid_nip88
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag, create_amount_tag
|
||||
from nostr_dvm.utils.output_utils import post_process_list_to_events, post_process_list_to_users
|
||||
from nostr_dvm.utils.wot_utils import build_network_from, save_network, load_network, print_results, \
|
||||
from nostr_dvm.utils.wot_utils import build_wot_network, save_network, load_network, print_results, \
|
||||
convert_index_to_hex
|
||||
|
||||
"""
|
||||
@@ -141,7 +141,7 @@ class DiscoverPeopleMyWOT(DVMTaskInterface):
|
||||
#hop1
|
||||
user_id = PublicKey.parse(options["user"]).to_hex()
|
||||
|
||||
index_map, G = await build_network_from(options["user"], depth=int(options["hops"]), max_batch=500, max_time_request=10)
|
||||
index_map, G = await build_wot_network(options["user"], depth=int(options["hops"]), max_batch=500, max_time_request=10)
|
||||
if use_files:
|
||||
save_network(index_map, G, options["user"])
|
||||
|
||||
@@ -217,7 +217,7 @@ class DiscoverPeopleMyWOT(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
@@ -257,7 +257,7 @@ async def analyse_users(user_ids=None, dunbar=100000000):
|
||||
print(npub)
|
||||
print(e)
|
||||
|
||||
database = await NostrDatabase.sqlite("db/nostr_followlists.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_followlists.db")
|
||||
followers_filter = Filter().authors(user_keys).kind(Kind(3))
|
||||
followers = await database.query([followers_filter])
|
||||
allfriends = []
|
||||
|
||||
@@ -215,7 +215,7 @@ class DiscoverPeopleWOT(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
for relay in self.dvm_config.RECONCILE_DB_RELAY_LIST:
|
||||
@@ -255,7 +255,7 @@ async def analyse_users(user_ids=None, dunbar=100000000):
|
||||
print(npub)
|
||||
print(e)
|
||||
|
||||
database = await NostrDatabase.sqlite("db/nostr_followlists.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_followlists.db")
|
||||
followers_filter = Filter().authors(user_keys).kind(Kind(3))
|
||||
followers = await database.query([followers_filter])
|
||||
allfriends = []
|
||||
|
||||
@@ -83,7 +83,7 @@ class SearchUser(DVMTaskInterface):
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().database(database).signer(signer).opts(opts).build()
|
||||
|
||||
await cli.add_relay(self.relay)
|
||||
@@ -143,7 +143,7 @@ class SearchUser(DVMTaskInterface):
|
||||
sk = SecretKey.from_hex(self.dvm_config.PRIVATE_KEY)
|
||||
keys = Keys.parse(sk.to_hex())
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite(self.db_name)
|
||||
database = NostrDatabase.lmdb(self.db_name)
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
await cli.add_relay(self.relay)
|
||||
|
||||
@@ -92,7 +92,7 @@ async def get_task(event, client, dvm_config):
|
||||
else:
|
||||
|
||||
for dvm in dvm_config.SUPPORTED_DVMS:
|
||||
if dvm.KIND.as_u64() == event.kind().as_u64():
|
||||
if dvm.KIND.as_u16() == event.kind().as_u16():
|
||||
return dvm.TASK
|
||||
except Exception as e:
|
||||
print("Get task: " + str(e))
|
||||
|
||||
@@ -20,30 +20,16 @@ class DVMConfig:
|
||||
"wss://relay.nostr.net"
|
||||
]
|
||||
|
||||
RECONCILE_DB_RELAY_LIST = ["wss://relay.damus.io", "wss://nostr21.com",
|
||||
"wss://nostr.oxtr.dev",
|
||||
"wss://relay.nostr.net" , "wss://relay.primal.net"] #, "wss://relay.snort.social"]
|
||||
RECONCILE_DB_RELAY_LIST = ["wss://relay.damus.io", "wss://nostr.oxtr.dev",
|
||||
"wss://relay.nostr.net" , "wss://relay.primal.net"]
|
||||
|
||||
# Straight Censorship (reply guy spam)
|
||||
MUTE = [PublicKey.parse("npub1x5vhtx7j2prvueeenwf7tmesrzmuzc50zs0aakgd75v5c30ekj3s5zjckj"),
|
||||
PublicKey.parse("npub1l03urys27uet2u6wq6u90rnzf7kv5c3wfu3cyndqz9lq75g46c5q0wkpsj"),
|
||||
PublicKey.parse("npub17g7qhlu4caefd88vateedm9wau9ys6xt6jhjcfu2kqyw9xmnucxs5d6crj"),
|
||||
PublicKey.parse("npub1epwccahqndqhseh6q02seu40cqa2ghk3u9tvu92yh4hd6lmxg33spwzujc"),
|
||||
PublicKey.parse("npub1v0kgu3hymtd4fw9zrlem6l74c3cwl8jdqentt4qsxrrzan6paxaqkkf6dr"),
|
||||
PublicKey.parse("npub1y8teqt2jay2ulww87wlmpe97gxhjqvhva60jv3ghp8emgk2da3psc2x7lt"),
|
||||
PublicKey.parse("npub1drz9ts6esv22vplg9vunajwhts4ecaxvusmpxwy8yy683ejnzfnqvfvtk9"),
|
||||
PublicKey.parse("npub1af5hgjkjpdqavpu3xqz092xjrvrpr3nzfftp4pgh4nez635hznas7m0vvn"),
|
||||
PublicKey.parse("npub1rwxfxn33mmt9fe66qwg25lm9pm3nwtj5za5qm5cpqjsxlhk3dtsqkmunfe"),
|
||||
PublicKey.parse("npub1l6y4l424ggvstc8a40n5c4rf8wwt5hlt5vuhn4dzvx9xf0eff9uqnc2fuw"),
|
||||
PublicKey.parse("npub1q57y985vcazhx87naj5qhdyxxmtrrqakfq7lmvhxppvduqpfkesq3n46e8"),
|
||||
PublicKey.parse("npub1dryv50m3rl6cx6ajeakmh3ygz83vjcdf6cga99yllmfx9ugqa04st0nk3w"),
|
||||
PublicKey.parse("npub1xh3n3q2cp2wf9r66mmzmkyunyj8cf5r8aszsvwtdld6upqjmkxcsxgejsd"),
|
||||
PublicKey.parse("npub1cek65lcyks0jjwx4y47c0zxmx8y22zn7zmhxktfjr32h2z5wtgeqn70vjc"),
|
||||
PublicKey.parse("npub1y2v5mqw32m7n8mz4wpypcy7wt0t4hg93g67qw0fuyspjdspk0etqm0xx9y"),
|
||||
PublicKey.parse("npub1cfgr520quxl8p74f5r3u5snt05dxyshfk88tcm5tuj78ypkdhgyqcpxkx2"),
|
||||
PublicKey.parse("npub1620alhm0dyn063wlrlp6r8xzxlzdk9pp94xfag99gghj92wentlq23t6rz"),
|
||||
|
||||
]
|
||||
WOT_FILTERING = False
|
||||
WOT_BASED_ON_NPUBS = ["99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64",
|
||||
"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
|
||||
"3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24"
|
||||
]
|
||||
WOT_DEPTH = 2
|
||||
|
||||
|
||||
AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
@@ -91,7 +77,7 @@ def build_default_config(identifier):
|
||||
dvm_config.PRIVATE_KEY = check_and_set_private_key(identifier)
|
||||
dvm_config.IDENTIFIER = identifier
|
||||
npub = Keys.parse(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)
|
||||
invoice_key, admin_key, wallet_id, lnaddress = check_and_set_ln_bits_keys(identifier, npub)
|
||||
dvm_config.LNBITS_INVOICE_KEY = invoice_key
|
||||
dvm_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
|
||||
dvm_config.LNBITS_URL = os.getenv("LNBITS_HOST")
|
||||
|
||||
@@ -16,7 +16,7 @@ async def nip65_announce_relays(dvm_config, client):
|
||||
content = ""
|
||||
|
||||
event = EventBuilder(EventDefinitions.KIND_RELAY_ANNOUNCEMENT, content, tags).to_event(keys)
|
||||
eventid = await send_event(event, client=client, dvm_config=dvm_config, blastr=True)
|
||||
eventid = await send_event(event, client=client, dvm_config=dvm_config)
|
||||
if (eventid is not None):
|
||||
print(
|
||||
bcolors.BLUE + "[" + dvm_config.NIP89.NAME + "] Announced NIP 65 for " + dvm_config.NIP89.NAME + " (EventID: " + str(
|
||||
|
||||
@@ -26,7 +26,7 @@ def nip89_create_d_tag(name, pubkey, image):
|
||||
|
||||
|
||||
async def nip89_announce_tasks(dvm_config, client):
|
||||
k_tag = Tag.parse(["k", str(dvm_config.NIP89.KIND.as_u64())])
|
||||
k_tag = Tag.parse(["k", str(dvm_config.NIP89.KIND.as_u16())])
|
||||
d_tag = Tag.parse(["d", dvm_config.NIP89.DTAG])
|
||||
keys = Keys.parse(dvm_config.NIP89.PK)
|
||||
content = dvm_config.NIP89.CONTENT
|
||||
@@ -65,7 +65,7 @@ async def fetch_nip89_parameters_for_deletion(keys, eventid, client, dvmconfig,
|
||||
async def nip89_delete_announcement(eid: str, keys: Keys, dtag: str, client: Client, config):
|
||||
e_tag = Tag.parse(["e", eid])
|
||||
a_tag = Tag.parse(
|
||||
["a", str(EventDefinitions.KIND_ANNOUNCEMENT.as_u64()) + ":" + keys.public_key().to_hex() + ":" + dtag])
|
||||
["a", str(EventDefinitions.KIND_ANNOUNCEMENT.as_u16()) + ":" + keys.public_key().to_hex() + ":" + dtag])
|
||||
event = EventBuilder(Kind(5), "", [e_tag, a_tag]).to_event(keys)
|
||||
print(f"POW event: {event.as_json()}")
|
||||
await send_event(event, client, config)
|
||||
@@ -73,8 +73,8 @@ async def nip89_delete_announcement(eid: str, keys: Keys, dtag: str, client: Cli
|
||||
async def nip89_delete_announcement_pow(eid: str, keys: Keys, dtag: str, client: Client, config):
|
||||
e_tag = Tag.parse(["e", eid])
|
||||
a_tag = Tag.parse(
|
||||
["a", str(EventDefinitions.KIND_ANNOUNCEMENT.as_u64()) + ":" + keys.public_key().to_hex() + ":" + dtag])
|
||||
event = EventBuilder(Kind(5), "", [e_tag, a_tag]).to_pow_event(keys, 28)
|
||||
["a", str(EventDefinitions.KIND_ANNOUNCEMENT.as_u16()) + ":" + keys.public_key().to_hex() + ":" + dtag])
|
||||
event = EventBuilder(Kind(5), "", [e_tag, a_tag]).pow(28).to_event(keys)
|
||||
print(f"POW event: {event.as_json()}")
|
||||
await send_event(event, client, config)
|
||||
|
||||
@@ -91,7 +91,7 @@ async def nip89_fetch_all_dvms(client):
|
||||
|
||||
|
||||
async def nip89_fetch_events_pubkey(client, pubkey, kind):
|
||||
ktags = [str(kind.as_u64())]
|
||||
ktags = [str(kind.as_u16())]
|
||||
nip89filter = (Filter().kind(EventDefinitions.KIND_ANNOUNCEMENT).author(PublicKey.parse(pubkey)).
|
||||
custom_tag(SingleLetterTag.lowercase(Alphabet.K), ktags))
|
||||
events = await client.get_events_of([nip89filter], relay_timeout)
|
||||
|
||||
@@ -234,13 +234,15 @@ async def send_event_outbox(event: Event, client, dvm_config) -> EventId:
|
||||
# 5. Fallback, if we couldn't send the event to any relay, we try to send to generic relays instead.
|
||||
if event_id is None:
|
||||
for relay in relays:
|
||||
await outboxclient.remove_relay(relay)
|
||||
try:
|
||||
await outboxclient.remove_relay(relay)
|
||||
except:
|
||||
print("Error removing relay: " + relay)
|
||||
|
||||
|
||||
relays = await get_main_relays(event, client, dvm_config)
|
||||
for relay in relays:
|
||||
opts = RelayOptions().ping(False)
|
||||
await outboxclient.add_relay_with_opts(relay, opts)
|
||||
await outboxclient.add_relay(relay)
|
||||
try:
|
||||
await outboxclient.connect()
|
||||
event_id = await outboxclient.send_event(event)
|
||||
@@ -256,7 +258,7 @@ async def send_event_outbox(event: Event, client, dvm_config) -> EventId:
|
||||
|
||||
|
||||
|
||||
async def send_event(event: Event, client: Client, dvm_config, blastr=False):
|
||||
async def send_event(event: Event, client: Client, dvm_config):
|
||||
try:
|
||||
relays = []
|
||||
for tag in event.tags():
|
||||
@@ -275,11 +277,8 @@ async def send_event(event: Event, client: Client, dvm_config, blastr=False):
|
||||
if relay not in dvm_config.RELAY_LIST:
|
||||
await client.add_relay(relay)
|
||||
|
||||
#if blastr:
|
||||
# client.add_relay("wss://nostr.mutinywallet.com")
|
||||
try:
|
||||
event_id = await client.send_event(event)
|
||||
#event_id = output.id
|
||||
except Exception as e:
|
||||
print(e)
|
||||
event_id = None
|
||||
@@ -288,8 +287,6 @@ async def send_event(event: Event, client: Client, dvm_config, blastr=False):
|
||||
if relay not in dvm_config.RELAY_LIST:
|
||||
if relay not in dvm_config.RELAY_LIST:
|
||||
await client.remove_relay(relay)
|
||||
#if blastr:
|
||||
# client.remove_relay("wss://nostr.mutinywallet.com")
|
||||
return event_id
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -360,6 +357,24 @@ def check_and_decrypt_own_tags(event, dvm_config):
|
||||
return event
|
||||
|
||||
|
||||
async def update_profile_lnaddress(private_key, dvm_config, lud16="",):
|
||||
keys = Keys.parse(private_key)
|
||||
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=5))
|
||||
.skip_disconnected_relays(True))
|
||||
|
||||
signer = NostrSigner.keys(keys)
|
||||
client = Client.with_opts(signer, opts)
|
||||
for relay in dvm_config.RELAY_LIST:
|
||||
await client.add_relay(relay)
|
||||
await client.connect()
|
||||
|
||||
metadata = Metadata() \
|
||||
.set_lud16(lud16) \
|
||||
.set_nip05(lud16)
|
||||
|
||||
await client.set_metadata(metadata)
|
||||
|
||||
|
||||
async def update_profile(dvm_config, client, lud16=""):
|
||||
keys = Keys.parse(dvm_config.PRIVATE_KEY)
|
||||
try:
|
||||
|
||||
@@ -6,7 +6,7 @@ from datetime import timedelta
|
||||
|
||||
import requests
|
||||
from nostr_dvm.utils.database_utils import fetch_user_metadata
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
from nostr_dvm.utils.definitions import EventDefinitions, relay_timeout, relay_timeout_long
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig
|
||||
from nostr_dvm.utils.nostr_utils import check_and_set_private_key
|
||||
from nostr_dvm.utils.zap_utils import pay_bolt11_ln_bits, zaprequest
|
||||
@@ -14,6 +14,7 @@ from nostr_sdk import Tag, Keys, nip44_encrypt, nip44_decrypt, Nip44Version, Eve
|
||||
EventId, nip04_decrypt, nip04_encrypt, Options, NostrSigner, PublicKey, init_logger, LogLevel, Metadata
|
||||
from nostr_dvm.utils.print import bcolors
|
||||
|
||||
|
||||
class NutWallet(object):
|
||||
def __init__(self):
|
||||
self.name: str = "NutWallet"
|
||||
@@ -28,7 +29,7 @@ class NutWallet(object):
|
||||
self.a: str = ""
|
||||
self.legacy_encryption: bool = False # Use Nip04 instead of Nip44, for reasons, turn to False ASAP.
|
||||
self.trust_unknown_mints: bool = False
|
||||
self.missing_balance_strategy: str = "mint" #swap to use existing tokens from other mints (fees!) or mint to mint from lightning
|
||||
self.missing_balance_strategy: str = "mint" #none to do nothing until manually minted, mint to mint from lightning or swap to use existing tokens from other mints (fees!) (not working yet!)
|
||||
|
||||
|
||||
class NutMint(object):
|
||||
@@ -46,7 +47,6 @@ class NutMint(object):
|
||||
return balance
|
||||
|
||||
|
||||
|
||||
class NutZapWallet:
|
||||
|
||||
async def client_connect(self, relay_list):
|
||||
@@ -72,8 +72,8 @@ class NutZapWallet:
|
||||
new_nut_wallet.description = description
|
||||
new_nut_wallet.mints = mint_urls
|
||||
new_nut_wallet.relays = relays
|
||||
new_nut_wallet.d = "wallet" # sha256(str(new_nut_wallet.name + new_nut_wallet.description).encode('utf-8')).hexdigest()[:16]
|
||||
new_nut_wallet.a = str(Kind(7375).as_u64()) + ":" + keys.public_key().to_hex() + ":" + new_nut_wallet.d
|
||||
new_nut_wallet.d = "wallet"
|
||||
new_nut_wallet.a = str(Kind(7375).as_u16()) + ":" + keys.public_key().to_hex() + ":" + new_nut_wallet.d
|
||||
print("Creating Wallet..")
|
||||
send_response_id = await self.create_or_update_nut_wallet_event(new_nut_wallet, client, keys)
|
||||
|
||||
@@ -120,7 +120,8 @@ class NutZapWallet:
|
||||
nut_wallet = None
|
||||
|
||||
wallet_filter = Filter().kind(EventDefinitions.KIND_NUT_WALLET).author(keys.public_key())
|
||||
wallets = await client.get_events_of([wallet_filter], timedelta(10))
|
||||
#relay_timeout = EventSource.relays(timedelta(seconds=10))
|
||||
wallets = await client.get_events_of([wallet_filter], relay_timeout_long)
|
||||
|
||||
if len(wallets) > 0:
|
||||
|
||||
@@ -194,7 +195,8 @@ class NutZapWallet:
|
||||
|
||||
# Now all proof events
|
||||
proof_filter = Filter().kind(Kind(7375)).author(keys.public_key())
|
||||
proof_events = await client.get_events_of([proof_filter], timedelta(5))
|
||||
#relay_timeout = EventSource.relays(timedelta(seconds=5))
|
||||
proof_events = await client.get_events_of([proof_filter], relay_timeout)
|
||||
|
||||
latest_proof_sec = 0
|
||||
latest_proof_event_id = EventId
|
||||
@@ -247,7 +249,7 @@ class NutZapWallet:
|
||||
nut_proof.amount = proof['amount']
|
||||
nut_proof.C = proof['C']
|
||||
nut_mint.proofs.append(nut_proof)
|
||||
#print(proof)
|
||||
# print(proof)
|
||||
|
||||
mints = [x for x in nut_wallet.nutmints if x.mint_url == mint_url]
|
||||
if len(mints) == 0:
|
||||
@@ -347,8 +349,8 @@ class NutZapWallet:
|
||||
"secret": proof['secret'],
|
||||
"C": proof['C']
|
||||
}
|
||||
#print("Mint proofs:")
|
||||
#print(proof)
|
||||
# print("Mint proofs:")
|
||||
# print(proof)
|
||||
new_proofs.append(proofjson)
|
||||
old_event_id = mint.previous_event_id
|
||||
|
||||
@@ -447,7 +449,8 @@ class NutZapWallet:
|
||||
|
||||
async def fetch_mint_info_event(self, pubkey, client):
|
||||
mint_info_filter = Filter().kind(Kind(10019)).author(PublicKey.parse(pubkey))
|
||||
preferences = await client.get_events_of([mint_info_filter], timedelta(5))
|
||||
#relay_timeout = EventSource.relays(timedelta(seconds=5))
|
||||
preferences = await client.get_events_of([mint_info_filter], relay_timeout)
|
||||
mints = []
|
||||
relays = []
|
||||
pubkey = ""
|
||||
@@ -517,21 +520,23 @@ class NutZapWallet:
|
||||
|
||||
return await self.update_nut_wallet(nut_wallet, [mint_url], client, keys)
|
||||
|
||||
|
||||
async def handle_low_balance_on_mint(self, nut_wallet, outgoing_mint_url, mint, amount, client, keys):
|
||||
async def handle_low_balance_on_mint(self, nut_wallet, mint_to_send, mint, amount, client, keys):
|
||||
|
||||
required_amount = amount - mint.available_balance()
|
||||
|
||||
if nut_wallet.missing_balance_strategy == "mint":
|
||||
await self.mint_cashu(nut_wallet, outgoing_mint_url, client, keys, required_amount)
|
||||
await self.mint_cashu(nut_wallet, mint_to_send, client, keys, required_amount)
|
||||
|
||||
elif nut_wallet.missing_balance_strategy == "swap":
|
||||
for nutmint in nut_wallet.nutmints:
|
||||
estimated_fees = 3
|
||||
if nutmint.available_balance() > required_amount+estimated_fees:
|
||||
await self.swap(required_amount, nutmint.mint_url, outgoing_mint_url)
|
||||
if nutmint.available_balance() > required_amount + estimated_fees:
|
||||
print(nutmint.mint_url)
|
||||
await self.swap(required_amount, mint_to_send, nutmint.mint_url, nut_wallet)
|
||||
break
|
||||
|
||||
|
||||
else:
|
||||
print(bcolors.RED + "[" + nut_wallet.name + "] Not enough Balance on Mint, mint some tokens first. " + str(
|
||||
amount) + " " + nut_wallet.unit + bcolors.ENDC)
|
||||
|
||||
async def send_nut_zap(self, amount, comment, nut_wallet: NutWallet, zapped_event, zapped_user, client: Client,
|
||||
keys: Keys):
|
||||
@@ -562,7 +567,6 @@ class NutZapWallet:
|
||||
if mint.available_balance() < amount:
|
||||
await self.handle_low_balance_on_mint(nut_wallet, mint_url, mint, amount, client, keys)
|
||||
|
||||
|
||||
# If that's not the case, iterate over the recipents mints and try to mint there. This might be a bit dangerous as not all mints might give cashu, so loss of ln is possible
|
||||
if mint_url is None:
|
||||
if nut_wallet.trust_unknown_mints:
|
||||
@@ -687,39 +691,39 @@ class NutZapWallet:
|
||||
from cashu.wallet.wallet import Wallet
|
||||
from cashu.core.base import Proof
|
||||
from cashu.core.crypto.keys import PrivateKey
|
||||
|
||||
proofs = []
|
||||
mint_url = ""
|
||||
amount = 0
|
||||
unit = "sat"
|
||||
zapped_user = ""
|
||||
zapped_event = ""
|
||||
sender = event.author().to_hex()
|
||||
message = event.content()
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == "proof":
|
||||
proof_json = json.loads(tag.as_vec()[1])
|
||||
proof = Proof().from_dict(proof_json)
|
||||
proofs.append(proof)
|
||||
elif tag.as_vec()[0] == "u":
|
||||
mint_url = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == "amount":
|
||||
amount = int(tag.as_vec()[1])
|
||||
elif tag.as_vec()[0] == "unit":
|
||||
unit = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == "p":
|
||||
zapped_user = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == "e":
|
||||
zapped_event = tag.as_vec()[1]
|
||||
|
||||
cashu_wallet = await Wallet.with_db(
|
||||
url=mint_url,
|
||||
db="db/Receiver",
|
||||
name="receiver",
|
||||
)
|
||||
cashu_wallet.private_key = PrivateKey(bytes.fromhex(nut_wallet.privkey), raw=True)
|
||||
await cashu_wallet.load_mint()
|
||||
try:
|
||||
proofs = []
|
||||
mint_url = ""
|
||||
amount = 0
|
||||
unit = "sat"
|
||||
zapped_user = ""
|
||||
zapped_event = ""
|
||||
sender = event.author().to_hex()
|
||||
message = event.content()
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == "proof":
|
||||
proof_json = json.loads(tag.as_vec()[1])
|
||||
proof = Proof().from_dict(proof_json)
|
||||
proofs.append(proof)
|
||||
elif tag.as_vec()[0] == "u":
|
||||
mint_url = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == "amount":
|
||||
amount = int(tag.as_vec()[1])
|
||||
elif tag.as_vec()[0] == "unit":
|
||||
unit = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == "p":
|
||||
zapped_user = tag.as_vec()[1]
|
||||
elif tag.as_vec()[0] == "e":
|
||||
zapped_event = tag.as_vec()[1]
|
||||
|
||||
cashu_wallet = await Wallet.with_db(
|
||||
url=mint_url,
|
||||
db="db/Receiver",
|
||||
name="receiver",
|
||||
)
|
||||
cashu_wallet.private_key = PrivateKey(bytes.fromhex(nut_wallet.privkey), raw=True)
|
||||
await cashu_wallet.load_mint()
|
||||
|
||||
new_proofs, _ = await cashu_wallet.redeem(proofs)
|
||||
mint = self.get_mint(nut_wallet, mint_url)
|
||||
print(mint.proofs)
|
||||
@@ -735,7 +739,6 @@ class NutZapWallet:
|
||||
print(bcolors.RED + str(e) + bcolors.ENDC)
|
||||
return None, message, sender
|
||||
|
||||
|
||||
async def melt_cashu(self, nut_wallet, mint_url, total_amount, client, keys, lud16=None, npub=None):
|
||||
from cashu.wallet.wallet import Wallet
|
||||
mint = self.get_mint(nut_wallet, mint_url)
|
||||
@@ -774,35 +777,43 @@ class NutZapWallet:
|
||||
total_amount - estimated_fees) + " (Fees: " + str(estimated_fees) + ") " + nut_wallet.unit
|
||||
+ bcolors.ENDC)
|
||||
|
||||
async def swap(self, amountinsats, outgoing_mint_url, incoming_mint_url):
|
||||
async def swap(self, amountinsats, incoming_mint_url, outgoing_mint_url, nut_wallet):
|
||||
#TODO this doesn't seem to work yet.
|
||||
from cashu.wallet.cli.cli_helpers import print_mint_balances
|
||||
from cashu.wallet.wallet import Wallet
|
||||
# print("Select the mint to swap from:")
|
||||
# outgoing_wallet = await get_mint_wallet(ctx, force_select=True)
|
||||
from cashu.core.crypto.keys import PrivateKey
|
||||
|
||||
|
||||
outgoing_mint = self.get_mint(nut_wallet, outgoing_mint_url)
|
||||
|
||||
outgoing_wallet = await Wallet.with_db(
|
||||
url=outgoing_mint_url,
|
||||
db="db/Sender",
|
||||
name="sender",
|
||||
db="db/Cashu",
|
||||
name="outgoing",
|
||||
)
|
||||
outgoing_wallet.private_key = PrivateKey(bytes.fromhex(nut_wallet.privkey), raw=True)
|
||||
await outgoing_wallet.load_mint()
|
||||
outgoing_wallet.proofs = outgoing_mint.proofs
|
||||
|
||||
print("Select the mint to swap to:")
|
||||
# incoming_wallet = await get_mint_wallet(ctx, force_select=True)
|
||||
print(outgoing_wallet.available_balance)
|
||||
|
||||
|
||||
incoming_mint = self.get_mint(nut_wallet, incoming_mint_url)
|
||||
incoming_wallet = await Wallet.with_db(
|
||||
url=incoming_mint_url,
|
||||
db="db/Receiver",
|
||||
name="reeciver",
|
||||
db="db/Cashu",
|
||||
name="incoming",
|
||||
)
|
||||
|
||||
incoming_wallet.private_key = PrivateKey(bytes.fromhex(nut_wallet.privkey), raw=True)
|
||||
await incoming_wallet.load_mint()
|
||||
await outgoing_wallet.load_mint()
|
||||
incoming_wallet.proofs = incoming_mint.proofs
|
||||
|
||||
|
||||
|
||||
if incoming_wallet.url == outgoing_wallet.url:
|
||||
raise Exception("mints for swap have to be different")
|
||||
|
||||
print("Incoming Mint units: " + incoming_wallet.unit.name)
|
||||
|
||||
assert amountinsats > 0, "amount is not positive"
|
||||
|
||||
# request invoice from incoming mint
|
||||
@@ -816,9 +827,13 @@ class NutZapWallet:
|
||||
send_proofs, fees = await outgoing_wallet.select_to_send(
|
||||
outgoing_wallet.proofs, total_amount, set_reserved=True
|
||||
)
|
||||
await outgoing_wallet.melt(
|
||||
send_proofs, invoice.bolt11, quote.fee_reserve, quote.quote
|
||||
)
|
||||
|
||||
try:
|
||||
await outgoing_wallet.melt(
|
||||
proofs=send_proofs, invoice=invoice.bolt11, fee_reserve_sat=quote.fee_reserve, quote_id=quote.quote
|
||||
)
|
||||
except:
|
||||
print("anyways..")
|
||||
|
||||
# mint token in incoming mint
|
||||
await incoming_wallet.mint(amountinsats, id=invoice.id)
|
||||
|
||||
@@ -318,9 +318,9 @@ async def send_job_status_reaction(original_event_id_hex, original_event_author_
|
||||
|
||||
if dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
print(bcolors.YELLOW + "[" + dvm_config.NIP89.NAME + "]" + " Sent Kind " + str(
|
||||
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + status + " " + reaction_event.as_json() + bcolors.ENDC)
|
||||
EventDefinitions.KIND_FEEDBACK.as_u16()) + " Reaction: " + status + " " + reaction_event.as_json() + bcolors.ENDC)
|
||||
elif dvm_config.LOGLEVEL.value >= LogLevel.INFO.value:
|
||||
print(bcolors.YELLOW + "[" + dvm_config.NIP89.NAME + "]" + " Sent Kind " + str(
|
||||
EventDefinitions.KIND_FEEDBACK.as_u64()) + " Reaction: " + status + " " + reaction_event.id().to_hex() + bcolors.ENDC)
|
||||
EventDefinitions.KIND_FEEDBACK.as_u16()) + " Reaction: " + status + " " + reaction_event.id().to_hex() + bcolors.ENDC)
|
||||
|
||||
return reaction_event.as_json()
|
||||
68
nostr_dvm/utils/reaction_utils.py
Normal file
68
nostr_dvm/utils/reaction_utils.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import asyncio
|
||||
|
||||
from nostr_sdk import Tag, Keys, EventBuilder, Kind, NostrSigner, Client
|
||||
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig
|
||||
from nostr_dvm.utils.nostr_utils import send_event, check_and_set_private_key
|
||||
from nostr_dvm.utils.print import bcolors
|
||||
|
||||
|
||||
async def create_reaction(keys, title, dtag):
|
||||
d_tag = Tag.parse(["d", dtag])
|
||||
title_tag = Tag.parse(["title", title])
|
||||
|
||||
emoji_tags = []
|
||||
|
||||
# add more if you want
|
||||
name = "ThugAmy"
|
||||
url = "https://image.nostr.build/ccc229cbe11f5a13a1cc7fd24e13ac53fc78f287ecce0d9a674807e2e20f6fd5.png"
|
||||
emoji_tag1 = Tag.parse(["emoji", name, url])
|
||||
emoji_tags.append(emoji_tag1)
|
||||
|
||||
|
||||
|
||||
keys = Keys.parse(keys)
|
||||
content = ""
|
||||
event = EventBuilder(Kind(30030), content, [d_tag, title_tag] + emoji_tags).to_event(keys)
|
||||
|
||||
signer = NostrSigner.keys(keys)
|
||||
client = Client(signer)
|
||||
# We add the relays we defined above and told our DVM we would want to receive events to.
|
||||
for relay in DVMConfig().RELAY_LIST:
|
||||
await client.add_relay(relay)
|
||||
# We connect the client
|
||||
await client.connect()
|
||||
|
||||
eventid = await send_event(event, client=client, dvm_config=DVMConfig())
|
||||
|
||||
print(
|
||||
bcolors.BLUE + "[" + "Reaction" + "] Announced (" + eventid.id.to_nostr_uri() +
|
||||
" Hex: " + eventid.id.to_hex() + ")" + bcolors.ENDC)
|
||||
|
||||
|
||||
async def delete_reaction(keys, eid: str, dtag: str):
|
||||
keys = Keys.parse(keys)
|
||||
e_tag = Tag.parse(["e", eid])
|
||||
a_tag = Tag.parse(
|
||||
["a", "30030:" + keys.public_key().to_hex() + ":" + dtag])
|
||||
event = EventBuilder(Kind(5), "", [e_tag, a_tag]).to_event(keys)
|
||||
|
||||
signer = NostrSigner.keys(keys)
|
||||
client = Client(signer)
|
||||
# We add the relays we defined above and told our DVM we would want to receive events to.
|
||||
for relay in DVMConfig().RELAY_LIST:
|
||||
await client.add_relay(relay)
|
||||
# We connect the client
|
||||
await client.connect()
|
||||
|
||||
eventid = await send_event(event, client, DVMConfig())
|
||||
print(
|
||||
bcolors.BLUE + "[" + "Reaction" + "] deleted (" + eventid.id.to_nostr_uri() +
|
||||
" Hex: " + eventid.id.to_hex() + ")" + bcolors.ENDC)
|
||||
|
||||
|
||||
keys = check_and_set_private_key("test_client")
|
||||
eventid = "da05cefc512ad43363f84131343f5d2a80303ea3b9368b9ad7f010e07db37d90"
|
||||
|
||||
asyncio.run(create_reaction(keys=keys, title="ThugAmy", dtag="ThugAmy"))
|
||||
#asyncio.run(delete_reaction(keys=keys, eid=eventid, dtag="ThugAmy"))
|
||||
@@ -93,7 +93,7 @@ async def get_following(pks, max_time_request=10, newer_than_time=None):
|
||||
return following
|
||||
|
||||
|
||||
async def build_network_from(seed_pks, depth=2, max_batch=500, max_time_request=10):
|
||||
async def build_wot_network(seed_pks, depth=2, max_batch=500, max_time_request=10):
|
||||
if not seed_pks:
|
||||
print('Error: seed_pks cannot be empty')
|
||||
return
|
||||
@@ -636,5 +636,5 @@ async def convert_index_to_hex(graph, index_map, show_results_num):
|
||||
def test():
|
||||
# WARNING, DEPENDING ON DEPTH THIS TAKES LONG
|
||||
user = '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'
|
||||
index_map, network_graph = asyncio.run(build_network_from(user, depth=2, max_batch=500, max_time_request=10))
|
||||
index_map, network_graph = asyncio.run(build_wot_network(user, depth=2, max_batch=500, max_time_request=10))
|
||||
save_network(index_map, network_graph, user)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# LIGHTNING/ZAP FUNCTIONS
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
|
||||
@@ -12,7 +14,8 @@ from bech32 import bech32_decode, convertbits, bech32_encode
|
||||
from nostr_sdk import PublicKey, SecretKey, Event, EventBuilder, Tag, Keys, generate_shared_key, Kind, \
|
||||
Timestamp
|
||||
|
||||
from nostr_dvm.utils.nostr_utils import get_event_by_id, check_and_decrypt_own_tags
|
||||
from nostr_dvm.utils.nostr_utils import get_event_by_id, check_and_decrypt_own_tags, update_profile, \
|
||||
update_profile_lnaddress
|
||||
from hashlib import sha256
|
||||
import dotenv
|
||||
|
||||
@@ -51,7 +54,7 @@ async def parse_zap_event_tags(zap_event, keys, name, client, config):
|
||||
keys.secret_key(),
|
||||
zap_request_event.author())
|
||||
decrypted_private_event = Event.from_json(decrypted_content)
|
||||
if decrypted_private_event.kind().as_u64() == 9733:
|
||||
if decrypted_private_event.kind().as_u16() == 9733:
|
||||
sender = decrypted_private_event.author().to_hex()
|
||||
message = decrypted_private_event.content()
|
||||
# if message != "":
|
||||
@@ -132,11 +135,11 @@ def create_bolt11_lud16(lud16, amount):
|
||||
|
||||
|
||||
def create_lnbits_account(name):
|
||||
if os.getenv("LNBITS_ADMIN_ID") is None or os.getenv("LNBITS_ADMIN_ID") == "":
|
||||
if os.getenv("LNBITS_WALLET_ID") is None or os.getenv("LNBITS_WALLET_ID") == "":
|
||||
print("No admin id set, no wallet created.")
|
||||
return "", "", "", "", "failed"
|
||||
data = {
|
||||
'admin_id': os.getenv("LNBITS_ADMIN_ID"),
|
||||
'admin_id': os.getenv("LNBITS_WALLET_ID"),
|
||||
'wallet_name': name,
|
||||
'user_name': name,
|
||||
}
|
||||
@@ -347,20 +350,26 @@ def get_price_per_sat(currency):
|
||||
|
||||
return price_currency_per_sat
|
||||
|
||||
def randomword(length):
|
||||
letters = string.ascii_lowercase
|
||||
return ''.join(random.choice(letters) for i in range(length))
|
||||
|
||||
def make_ln_address_nostdress(identifier, npub, pin, nostdressdomain, newname = " ", currentname=" "):
|
||||
|
||||
if newname == " ":
|
||||
newname = identifier
|
||||
|
||||
def make_ln_address_nostdress(identifier, npub, pin, nostdressdomain):
|
||||
print(os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()))
|
||||
data = {
|
||||
'name': identifier,
|
||||
'name': newname,
|
||||
'domain': nostdressdomain,
|
||||
'kind': "lnbits",
|
||||
'host': os.getenv("LNBITS_HOST"),
|
||||
'key': os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()),
|
||||
'pin': pin,
|
||||
'npub': npub,
|
||||
'currentname': " "
|
||||
'currentname': currentname
|
||||
}
|
||||
|
||||
try:
|
||||
url = "https://" + nostdressdomain + "/api/easy/"
|
||||
res = requests.post(url, data=data)
|
||||
@@ -368,10 +377,22 @@ def make_ln_address_nostdress(identifier, npub, pin, nostdressdomain):
|
||||
obj = json.loads(res.text)
|
||||
|
||||
if obj.get("ok"):
|
||||
return identifier + "@" + nostdressdomain, obj["pin"]
|
||||
return data["name"] + "@" + nostdressdomain, obj["pin"]
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return "", ""
|
||||
print("Creating random name..")
|
||||
data["name"] = data["name"] + "_" + randomword(10)
|
||||
try:
|
||||
url = "https://" + nostdressdomain + "/api/easy/"
|
||||
res = requests.post(url, data=data)
|
||||
print(res.text)
|
||||
obj = json.loads(res.text)
|
||||
|
||||
if obj.get("ok"):
|
||||
return data["name"] + "@" + nostdressdomain, obj["pin"]
|
||||
|
||||
except Exception as e:
|
||||
return "", ""
|
||||
|
||||
|
||||
def check_and_set_ln_bits_keys(identifier, npub):
|
||||
@@ -379,26 +400,36 @@ def check_and_set_ln_bits_keys(identifier, npub):
|
||||
invoicekey, adminkey, walletid, userid, success = create_lnbits_account(identifier)
|
||||
add_key_to_env_file("LNBITS_INVOICE_KEY_" + identifier.upper(), invoicekey)
|
||||
add_key_to_env_file("LNBITS_ADMIN_KEY_" + identifier.upper(), adminkey)
|
||||
add_key_to_env_file("LNBITS_USER_ID_" + identifier.upper(), userid)
|
||||
add_key_to_env_file("LNBITS_WALLET_ID_" + identifier.upper(), userid)
|
||||
|
||||
lnaddress = ""
|
||||
pin = ""
|
||||
if os.getenv("NOSTDRESS_DOMAIN") and success != "failed":
|
||||
print(os.getenv("NOSTDRESS_DOMAIN"))
|
||||
lnaddress, pin = make_ln_address_nostdress(identifier, npub, " ", os.getenv("NOSTDRESS_DOMAIN"))
|
||||
lnaddress, pin = make_ln_address_nostdress(identifier, npub, " ", os.getenv("NOSTDRESS_DOMAIN"), identifier)
|
||||
add_key_to_env_file("LNADDRESS_" + identifier.upper(), lnaddress)
|
||||
add_key_to_env_file("LNADDRESS_PIN_" + identifier.upper(), pin)
|
||||
|
||||
return invoicekey, adminkey, userid, walletid, lnaddress
|
||||
return invoicekey, adminkey, walletid, lnaddress
|
||||
else:
|
||||
return (os.getenv("LNBITS_INVOICE_KEY_" + identifier.upper()),
|
||||
os.getenv("LNBITS_ADMIN_KEY_" + identifier.upper()),
|
||||
os.getenv("LNBITS_USER_ID_" + identifier.upper()),
|
||||
os.getenv("LNBITS_WALLET_ID_" + identifier.upper()),
|
||||
os.getenv("LNADDRESS_" + identifier.upper()))
|
||||
|
||||
|
||||
async def change_ln_address(identifier, new_identifier, dvm_config, updateprofile=False):
|
||||
previous_identifier = os.getenv("LNADDRESS_" + identifier.upper()).split("@")[0]
|
||||
pin = os.getenv("LNADDRESS_PIN_" + identifier.upper())
|
||||
npub = Keys.parse(os.getenv("DVM_PRIVATE_KEY_" + identifier.upper())).public_key().to_hex()
|
||||
lnaddress, pin = make_ln_address_nostdress(identifier, npub, pin, os.getenv("NOSTDRESS_DOMAIN"), new_identifier, currentname=previous_identifier)
|
||||
add_key_to_env_file("LNADDRESS_" + identifier.upper(), lnaddress)
|
||||
add_key_to_env_file("LNADDRESS_PIN_" + identifier.upper(), pin)
|
||||
print("changed lnaddress")
|
||||
if updateprofile:
|
||||
private_key = os.getenv("DVM_PRIVATE_KEY_" + identifier.upper())
|
||||
await update_profile_lnaddress(private_key, dvm_config, lud16=lnaddress)
|
||||
|
||||
def add_key_to_env_file(value, oskey):
|
||||
env_path = Path('.env')
|
||||
if env_path.is_file():
|
||||
|
||||
4
setup.py
4
setup.py
@@ -1,6 +1,6 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
VERSION = '0.8.20'
|
||||
VERSION = '0.8.21'
|
||||
DESCRIPTION = 'A framework to build and run Nostr NIP90 Data Vending Machines'
|
||||
LONG_DESCRIPTION = ('A framework to build and run Nostr NIP90 Data Vending Machines. See the github repository for more information')
|
||||
|
||||
@@ -14,7 +14,7 @@ setup(
|
||||
long_description=LONG_DESCRIPTION,
|
||||
packages=find_packages(include=['nostr_dvm', 'nostr_dvm.*']),
|
||||
|
||||
install_requires=["nostr-sdk==0.34.0",
|
||||
install_requires=["nostr-sdk==0.35.0",
|
||||
"bech32==1.2.0",
|
||||
"pycryptodome==3.20.0",
|
||||
"yt-dlp==2024.5.27",
|
||||
|
||||
@@ -8,7 +8,7 @@ print(keys.public_key().to_bech32())
|
||||
|
||||
async def reconcile_db():
|
||||
# Create/open SQLite database
|
||||
database = await NostrDatabase.sqlite("nostr.db")
|
||||
database = NostrDatabase.lmdb("nostr.db")
|
||||
|
||||
# NOT AVAILABLE ON WINDOWS AT THE MOMENT!
|
||||
# Create/open nostrdb database
|
||||
@@ -28,7 +28,7 @@ async def reconcile_db():
|
||||
await do_some_work()
|
||||
|
||||
async def do_some_work():
|
||||
database = await NostrDatabase.sqlite("nostr.db")
|
||||
database = NostrDatabase.lmdb("nostr.db")
|
||||
f = Filter().author(keys.public_key()).limit(10)
|
||||
events = await database.query([f])
|
||||
|
||||
|
||||
@@ -37,12 +37,12 @@ rebroadcast_NIP65_Relay_List = True
|
||||
update_profile = False
|
||||
|
||||
global_update_rate = 180 # set this high on first sync so db can fully sync before another process trys to.
|
||||
use_logger = False
|
||||
use_logger = True
|
||||
log_level = LogLevel.INFO
|
||||
|
||||
|
||||
RECONCILE_DB_RELAY_LIST = [ "wss://relay.damus.io", "wss://relay.primal.net", "wss://nostr.oxtr.dev"]
|
||||
|
||||
RECONCILE_DB_RELAY_LIST = [ "wss://relay.nostr.net", "wss://relay.damus.io", "wss://nostr.oxtr.dev"]
|
||||
RELAY_LIST = ["wss://relay.primal.net",
|
||||
"wss://nostr.mom", "wss://nostr.oxtr.dev",
|
||||
"wss://relay.nostr.net"
|
||||
@@ -63,6 +63,7 @@ def build_db_scheduler(name, identifier, admin_config, options, image, descripti
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.DATABASE = database
|
||||
dvm_config.WOT_FILTERING = True
|
||||
|
||||
# Activate these to use a subscription based model instead
|
||||
# dvm_config.SUBSCRIPTION_REQUIRED = True
|
||||
@@ -147,11 +148,9 @@ def build_example_nostrband(name, identifier, admin_config, image, about, custom
|
||||
dvm_config.USE_OWN_VENV = False
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = custom_processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.LOGLEVEL = LogLevel.INFO
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
# Add NIP89
|
||||
|
||||
@@ -288,11 +287,9 @@ def build_example_topic(name, identifier, admin_config, options, image, descript
|
||||
dvm_config.LOGLEVEL = LogLevel.INFO
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.DATABASE = database
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -326,21 +323,15 @@ def build_example_topic(name, identifier, admin_config, options, image, descript
|
||||
def build_example_popular(name, identifier, admin_config, options, image, cost=0, update_rate=180, processing_msg=None,
|
||||
update_db=True, database=None):
|
||||
dvm_config = build_default_config(identifier)
|
||||
dvm_config.USE_OWN_VENV = False
|
||||
dvm_config.LOGLEVEL = LogLevel.INFO
|
||||
# dvm_config.SHOWLOG = True
|
||||
dvm_config.SCHEDULE_UPDATES_SECONDS = update_rate # Every 10 minutes
|
||||
dvm_config.UPDATE_DATABASE = update_db
|
||||
dvm_config.FIX_COST = cost
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
#"wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.DATABASE = database
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -381,10 +372,8 @@ def build_example_popular_followers(name, identifier, admin_config, options, ima
|
||||
dvm_config.FIX_COST = cost
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -427,11 +416,12 @@ def build_example_popular_non_followers(name, identifier, admin_config, options,
|
||||
dvm_config.UPDATE_DATABASE = update_db
|
||||
dvm_config.DATABASE = database
|
||||
# Activate these to use a subscription based model instead
|
||||
dvm_config.FIX_COST = cost
|
||||
dvm_config.FIX_COST = 10
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.SUBSCRIPTION_REQUIRED = True
|
||||
dvm_config.SUBSCRIPTION_REQUIRED = False
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
admin_config.REBROADCAST_NIP88 = False
|
||||
#admin_config.REBROADCAST_NIP89 = True
|
||||
@@ -446,8 +436,8 @@ def build_example_popular_non_followers(name, identifier, admin_config, options,
|
||||
"lud16": dvm_config.LN_ADDRESS,
|
||||
"encryptionSupported": True,
|
||||
"cashuAccepted": True,
|
||||
"subscription": True,
|
||||
"personalized": False,
|
||||
"subscription": False,
|
||||
"personalized": True,
|
||||
"nip90Params": {
|
||||
"max_results": {
|
||||
"required": False,
|
||||
@@ -479,7 +469,7 @@ def build_example_popular_non_followers(name, identifier, admin_config, options,
|
||||
admin_config.PRIVKEY = dvm_config.PRIVATE_KEY
|
||||
|
||||
return DicoverContentCurrentlyPopularNonFollowers(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
nip88config=nip88config,
|
||||
#nip88config=nip88config,
|
||||
admin_config=admin_config,
|
||||
options=options)
|
||||
|
||||
@@ -497,11 +487,9 @@ def build_example_top_zapped(name, identifier, admin_config, options, image, cos
|
||||
dvm_config.FIX_COST = cost
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.DATABASE = database
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -544,17 +532,13 @@ def build_example_mostr(name, identifier, admin_config, options, image, cost=0,
|
||||
# dvm_config.SHOWLOG = True
|
||||
dvm_config.SCHEDULE_UPDATES_SECONDS = update_rate # Every 10 minutes
|
||||
dvm_config.UPDATE_DATABASE = update_db
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = ["wss://nfrelay.app/?user=activitypub"]
|
||||
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -594,12 +578,9 @@ def build_example_oneperfollow(name, identifier, admin_config, options, image, c
|
||||
dvm_config.UPDATE_DATABASE = False
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
dvm_config.RELAY_LIST = ["wss://relay.damus.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg", "wss://relay.primal.net"]
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -630,7 +611,7 @@ def build_example_oneperfollow(name, identifier, admin_config, options, image, c
|
||||
|
||||
|
||||
async def init_db(database):
|
||||
return await NostrDatabase.sqlite(database)
|
||||
return NostrDatabase.lmdb(database)
|
||||
|
||||
def playground():
|
||||
|
||||
@@ -640,7 +621,7 @@ def playground():
|
||||
admin_config_db_scheduler= AdminConfig()
|
||||
options_animal = {
|
||||
"db_name": main_db,
|
||||
"db_since": 12 * 60 * 60, # 48h since gmt,
|
||||
"db_since": 48 * 60 * 60, # 48h since gmt,
|
||||
"personalized": False,
|
||||
"logger": False}
|
||||
image = ""
|
||||
@@ -831,6 +812,34 @@ def playground():
|
||||
update_db=True)
|
||||
discovery_mostr.run()
|
||||
|
||||
# Popular Garden&Plants
|
||||
admin_config_asknostr = AdminConfig()
|
||||
admin_config_asknostr.REBROADCAST_NIP89 =rebroadcast_NIP89
|
||||
admin_config_asknostr.REBROADCAST_NIP65_RELAY_LIST = rebroadcast_NIP65_Relay_List
|
||||
admin_config_asknostr.UPDATE_PROFILE = update_profile
|
||||
options_plants = {
|
||||
"search_list": ["#asknostr"],
|
||||
"avoid_list": [],
|
||||
"db_name": "db/nostr_recent_notes.db",
|
||||
"db_since": 24 * 60 * 60, # 12h since gmt
|
||||
"personalized": False,
|
||||
"logger": False}
|
||||
|
||||
image = "https://i.nostr.build/vIixmuRacIhULsrP.png"
|
||||
description = "I show popular questions #asknostr"
|
||||
custom_processing_msg = ["Finding the best notes for you.. #asknostr"]
|
||||
update_db = False
|
||||
cost = 0
|
||||
discovery_asknostr = build_example_topic("Popular on #asknostr", "discovery_content_asknostr",
|
||||
admin_config_asknostr, options_plants,
|
||||
image=image,
|
||||
description=description,
|
||||
update_rate=global_update_rate,
|
||||
cost=cost,
|
||||
processing_msg=custom_processing_msg,
|
||||
update_db=update_db,
|
||||
database=DATABASE)
|
||||
discovery_asknostr.run()
|
||||
|
||||
# Popular Animals (Fluffy frens)
|
||||
admin_config_animals = AdminConfig()
|
||||
@@ -1049,7 +1058,7 @@ def playground():
|
||||
|
||||
options_global_popular = {
|
||||
"db_name": "db/nostr_recent_notes.db",
|
||||
"db_since": 60 * 60, # 1h since gmt,
|
||||
"db_since": 60 * 60 * 1, # 1h since gmt,
|
||||
}
|
||||
cost = 0
|
||||
#image = "https://image.nostr.build/b29b6ec4bf9b6184f69d33cb44862db0d90a2dd9a506532e7ba5698af7d36210.jpg"
|
||||
@@ -1119,7 +1128,9 @@ def playground():
|
||||
subscription_config = DVMConfig()
|
||||
subscription_config.PRIVATE_KEY = check_and_set_private_key("dvm_subscription")
|
||||
npub = Keys.parse(subscription_config.PRIVATE_KEY).public_key().to_bech32()
|
||||
invoice_key, admin_key, wallet_id, user_id, lnaddress = check_and_set_ln_bits_keys("dvm_subscription", npub)
|
||||
invoice_key, admin_key, wallet_id, lnaddress = check_and_set_ln_bits_keys("dvm_subscription", npub)
|
||||
subscription_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
subscription_config.RELAY_LIST = RELAY_LIST
|
||||
subscription_config.LNBITS_INVOICE_KEY = invoice_key
|
||||
subscription_config.LNBITS_ADMIN_KEY = admin_key # The dvm might pay failed jobs back
|
||||
subscription_config.LNBITS_URL = os.getenv("LNBITS_HOST")
|
||||
|
||||
@@ -33,12 +33,7 @@ def build_example_gallery(name, identifier, admin_config, options, image, cost=0
|
||||
dvm_config.UPDATE_DATABASE = update_db
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
|
||||
@@ -37,12 +37,7 @@ def build_example_mostr(name, identifier, admin_config, options, image, cost=0,
|
||||
dvm_config.RECONCILE_DB_RELAY_LIST = ["wss://nfrelay.app/?user=activitypub"]
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
|
||||
@@ -38,11 +38,7 @@ def build_example_oneperfollow(name, identifier, admin_config, options, image, c
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
dvm_config.RELAY_LIST = ["wss://relay.damus.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg", "wss://relay.primal.net"]
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
|
||||
@@ -42,12 +42,7 @@ def build_example_wot(name, identifier, admin_config, options, image, cost=0, up
|
||||
#dvm_config.RECONCILE_DB_RELAY_LIST = RECONCILE_DB_RELAY_LIST
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
#"wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
|
||||
@@ -149,9 +149,6 @@ def build_example_nostrband(name, identifier, admin_config, image, about, custom
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.LOGLEVEL = LogLevel.INFO
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
# Add NIP89
|
||||
|
||||
@@ -289,9 +286,6 @@ def build_example_topic(name, identifier, admin_config, options, image, descript
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -331,14 +325,9 @@ def build_example_popular(name, identifier, admin_config, options, image, cost=0
|
||||
dvm_config.SCHEDULE_UPDATES_SECONDS = update_rate # Every 10 minutes
|
||||
dvm_config.UPDATE_DATABASE = update_db
|
||||
dvm_config.FIX_COST = cost
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
#"wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -380,9 +369,6 @@ def build_example_popular_followers(name, identifier, admin_config, options, ima
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -495,9 +481,6 @@ def build_example_top_zapped(name, identifier, admin_config, options, image, cos
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
dvm_config.AVOID_PAID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
#dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -545,12 +528,7 @@ def build_example_mostr(name, identifier, admin_config, options, image, cost=0,
|
||||
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg",
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
@@ -591,11 +569,7 @@ def build_example_oneperfollow(name, identifier, admin_config, options, image, c
|
||||
dvm_config.LOGLEVEL = LogLevel.DEBUG
|
||||
dvm_config.FIX_COST = cost
|
||||
dvm_config.RELAY_LIST = ["wss://relay.damus.io", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg", "wss://relay.primal.net"]
|
||||
# "wss://relay.nostr.net"]
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg
|
||||
# dvm_config.RELAY_LIST = ["wss://dvms.f7z.io",
|
||||
# "wss://nostr.mom", "wss://nostr.oxtr.dev", "wss://relay.nostr.bg"
|
||||
# ]
|
||||
admin_config.LUD16 = dvm_config.LN_ADDRESS
|
||||
|
||||
# Add NIP89
|
||||
|
||||
@@ -8,6 +8,7 @@ from duck_chat import ModelType
|
||||
from nostr_sdk import Kind, Filter, PublicKey, SecretKey, Keys, NostrSigner, RelayLimits, Options, Client, Tag, \
|
||||
LogLevel, Timestamp, NostrDatabase
|
||||
|
||||
|
||||
from nostr_dvm.tasks.generic_dvm import GenericDVM
|
||||
from nostr_dvm.utils import definitions
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
@@ -50,13 +51,13 @@ def playground(announce=False):
|
||||
dvm_config = build_default_config(identifier)
|
||||
dvm_config.KIND = Kind(kind) # Manually set the Kind Number (see data-vending-machines.org)
|
||||
dvm_config.CUSTOM_PROCESSING_MESSAGE = "Creating a personalized feed based on the topics you write about. This might take a moment."
|
||||
dvm_config.FIX_COST = 10
|
||||
dvm_config.FIX_COST = 0
|
||||
|
||||
|
||||
admin_config.DELETE_NIP89 = True
|
||||
admin_config.POW = True
|
||||
admin_config.EVENTID = "5322b731230cf8961f8403d025722a381af9b012b5d5f6dcc09f88e160f4e4ff"
|
||||
admin_config.PRIVKEY = dvm_config.PRIVATE_KEY
|
||||
#admin_config.DELETE_NIP89 = True
|
||||
#admin_config.POW = True
|
||||
#admin_config.EVENTID = "5322b731230cf8961f8403d025722a381af9b012b5d5f6dcc09f88e160f4e4ff"
|
||||
#admin_config.PRIVKEY = dvm_config.PRIVATE_KEY
|
||||
|
||||
|
||||
# Add NIP89
|
||||
@@ -83,12 +84,10 @@ def playground(announce=False):
|
||||
admin_config=admin_config, options=options)
|
||||
|
||||
|
||||
async def process_request(request_form, prompt):
|
||||
async def process_request(options, prompt):
|
||||
result = ""
|
||||
try:
|
||||
from duck_chat import DuckChat
|
||||
options = dvm.set_options(request_form)
|
||||
result = ""
|
||||
async with DuckChat(model=ModelType.GPT4o) as chat:
|
||||
query = prompt
|
||||
result = await chat.ask_question(query)
|
||||
@@ -119,7 +118,8 @@ def playground(announce=False):
|
||||
|
||||
await cli.connect()
|
||||
#pip install -U https://github.com/mrgick/duckduckgo-chat-ai/archive/master.zip
|
||||
author = PublicKey.parse(options["user"])
|
||||
author = PublicKey.parse(options["request_event_author"])
|
||||
print(options["request_event_author"])
|
||||
filterauth = Filter().kind(definitions.EventDefinitions.KIND_NOTE).author(author).limit(100)
|
||||
|
||||
evts = await cli.get_events_of([filterauth], relay_timeout)
|
||||
@@ -128,12 +128,14 @@ def playground(announce=False):
|
||||
for event in evts:
|
||||
text = text + event.content() + ";"
|
||||
|
||||
|
||||
text = text[:6000]
|
||||
|
||||
prompt = "Only reply with the result. Here is a list of notes, seperated by ;. Find the 20 most important keywords and return them by a comma seperated list: " + text
|
||||
|
||||
#loop = asyncio.get_running_loop()
|
||||
result = asyncio.run(process_request(request_form, prompt))
|
||||
result = await process_request(options, prompt)
|
||||
print(result)
|
||||
content = "I identified these as your topics:\n\n"+result.replace(",", ", ") + "\n\nProcessing, just a few more seconds..."
|
||||
await send_job_status_reaction(original_event_id_hex=dvm.options["request_event_id"], original_event_author_hex=dvm.options["request_event_author"], client=cli, dvm_config=dvm_config, content=content)
|
||||
|
||||
@@ -144,11 +146,11 @@ def playground(announce=False):
|
||||
# result = await chat.ask_question(query)
|
||||
# result = result.replace(", ", ",")
|
||||
# print(result)
|
||||
result = ""
|
||||
|
||||
from types import SimpleNamespace
|
||||
ns = SimpleNamespace()
|
||||
|
||||
database = await NostrDatabase.sqlite("db/nostr_recent_notes.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_recent_notes.db")
|
||||
|
||||
timestamp_since = Timestamp.now().as_secs() - since
|
||||
since = Timestamp.from_secs(timestamp_since)
|
||||
@@ -159,7 +161,7 @@ def playground(announce=False):
|
||||
if dvm.dvm_config.LOGLEVEL.value >= LogLevel.DEBUG.value:
|
||||
print("[" + dvm.dvm_config.NIP89.NAME + "] Considering " + str(len(events)) + " Events")
|
||||
ns.finallist = {}
|
||||
search_list = result.split('')
|
||||
#search_list = result.split(',')
|
||||
|
||||
for event in events:
|
||||
#if all(ele in event.content().lower() for ele in []):
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Imports\n",
|
||||
"from nostr_dvm.utils.wot_utils import build_network_from, save_network, load_network, get_mc_pagerank, get_subrank, get_metadata, print_results\n",
|
||||
"from nostr_dvm.utils.wot_utils import build_wot_network, save_network, load_network, get_mc_pagerank, get_subrank, get_metadata, print_results\n",
|
||||
"import time\n",
|
||||
"import networkx as nx\n",
|
||||
"import random\n",
|
||||
@@ -85,7 +85,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"index_map, G = await build_network_from(user, depth=2, max_batch=500, max_time_request=10)\n",
|
||||
"index_map, G = await build_wot_network(user, depth=2, max_batch=500, max_time_request=10)\n",
|
||||
"if use_files:\n",
|
||||
" save_network(index_map, G, user)"
|
||||
],
|
||||
|
||||
@@ -224,7 +224,7 @@ async def nostr_client_custom_discovery(user, ptag):
|
||||
|
||||
pTag = Tag.parse(["p", ptag])
|
||||
|
||||
tags = [relaysTag, alttag, paramTag, pTag, paramTagSearch, paramTagMust, paramTagAvoid]
|
||||
tags = [relaysTag, alttag, paramTag, pTag]# paramTagSearch, paramTagMust, paramTagAvoid]
|
||||
|
||||
event = EventBuilder(EventDefinitions.KIND_NIP90_CONTENT_DISCOVERY, str("Give me content"),
|
||||
tags).to_event(keys)
|
||||
@@ -234,7 +234,7 @@ async def nostr_client_custom_discovery(user, ptag):
|
||||
for relay in relay_list:
|
||||
await client.add_relay(relay)
|
||||
ropts = RelayOptions().ping(False)
|
||||
await client.add_relay_with_opts("wss://nostr.band", ropts)
|
||||
|
||||
await client.connect()
|
||||
config = DVMConfig
|
||||
await send_event(event, client=client, dvm_config=config)
|
||||
@@ -444,18 +444,18 @@ async def nostr_client():
|
||||
# await nostr_client_test_translation("44a0a8b395ade39d46b9d20038b3f0c8a11168e67c442e3ece95e4a1703e2beb", "event", "zh", 20, 20)
|
||||
|
||||
#await nostr_client_test_image("a beautiful purple ostrich watching the sunset, eating a cashew nut")
|
||||
#await nostr_client_custom_discovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "7a63849b684d90c0de983492578b12e147e56f5d79ed6585cc64e5aa8a122744")
|
||||
await nostr_client_custom_discovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "7240284b84951cfedbc20fce26f0e3f0a36da3e9c1be85d7a06965f0d4fe25fb")
|
||||
#"a018ba05af400b52772e33162d8326fca4a167fe7b6d3cd2382e14cac2af6841"
|
||||
#await nostr_client_duckduck_test(PublicKey.parse("aa8ab5b774d47e7b29a985dd739cfdcccf93451678bf7977ba1b2e094ecd8b30").to_hex() , "How do i create a dockerfile for python 3.12")
|
||||
await nostr_client_flux_schnell("d57f1efb7582f58cade6f482d53eefa998d8082711b996aae3dc5f5527cbdd6e" , "topics")
|
||||
# await nostr_client_duckduck_test(PublicKey.parse("7a63849b684d90c0de983492578b12e147e56f5d79ed6585cc64e5aa8a122744").to_hex() , "How do i create a dockerfile for python 3.12")
|
||||
#await nostr_client_flux_schnell("d57f1efb7582f58cade6f482d53eefa998d8082711b996aae3dc5f5527cbdd6e" , "topics")
|
||||
|
||||
# await nostr_client_test_search_profile("dontbelieve")
|
||||
#wot = ["99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64"]
|
||||
# await nostr_client_test_discovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "ab6cdf12ca3ae5109416295b8cd8a53fdec3a9d54beb7a9aee0ebfb67cb4edf7")
|
||||
#await nostr_client_test_discovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "ab6cdf12ca3ae5109416295b8cd8a53fdec3a9d54beb7a9aee0ebfb67cb4edf7")
|
||||
# await nostr_client_test_discovery_gallery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64", "4add3944eb596a27a650f9b954f5ed8dfefeec6ca50473605b0fbb058dd11306")
|
||||
|
||||
# await nostr_client_test_discovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64",
|
||||
# "2cf10ff849d2769b2b021bd93a0270d03eecfd14126d07f94c6ca2269cb3f3b1")
|
||||
#await nostr_client_test_discovery("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64",
|
||||
# "7a63849b684d90c0de983492578b12e147e56f5d79ed6585cc64e5aa8a122744")
|
||||
|
||||
# await nostr_client_test_censor_filter(wot)
|
||||
# await nostr_client_test_inactive_filter("99bb5591c9116600f845107d31f9b59e2f7c7e09a1ff802e84f1d43da557ca64")
|
||||
@@ -466,6 +466,8 @@ async def nostr_client():
|
||||
# await nostr_client_test_image_private("a beautiful ostrich watching the sunset")
|
||||
|
||||
nutzap_wallet = NutZapWallet()
|
||||
|
||||
|
||||
nut_wallet = await nutzap_wallet.get_nut_wallet(client, keys)
|
||||
#dangerous, dont use this, except your wallet is messed up.
|
||||
delete = False
|
||||
@@ -486,7 +488,7 @@ async def nostr_client():
|
||||
|
||||
print(
|
||||
bcolors.BLUE + f"Received new event from {relay_url}: {event.as_json()}" + bcolors.ENDC)
|
||||
if event.kind().as_u64() == 7000:
|
||||
if event.kind().as_u16() == 7000:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
amount_sats = 0
|
||||
status = ""
|
||||
@@ -512,15 +514,15 @@ async def nostr_client():
|
||||
keys)
|
||||
|
||||
|
||||
elif 6000 < event.kind().as_u64() < 6999:
|
||||
elif 6000 < event.kind().as_u16() < 6999:
|
||||
print("[Nostr Client]: " + event.as_json())
|
||||
print("[Nostr Client]: " + event.content())
|
||||
|
||||
elif event.kind().as_u64() == 4:
|
||||
elif event.kind().as_u16() == 4:
|
||||
dec_text = nip04_decrypt(sk, event.author(), event.content())
|
||||
print("[Nostr Client]: " + f"Received new msg: {dec_text}")
|
||||
|
||||
elif event.kind().as_u64() == 9735:
|
||||
elif event.kind().as_u16() == 9735:
|
||||
print("[Nostr Client]: " + f"Received new zap:")
|
||||
print(event.as_json())
|
||||
|
||||
|
||||
@@ -163,4 +163,3 @@ if __name__ == '__main__':
|
||||
|
||||
asyncio.run(test_gallery())
|
||||
|
||||
# works
|
||||
|
||||
@@ -57,7 +57,7 @@ async def sync_db():
|
||||
opts = (Options().wait_for_send(False).send_timeout(timedelta(seconds=5)))
|
||||
keys = Keys.parse("nsec1zmzllu40a7mr7ztl78uwfwslnp0pn0pww868adl05x52d4la237s6m8qfj")
|
||||
signer = NostrSigner.keys(keys)
|
||||
database = await NostrDatabase.sqlite("db/nostr_followlists.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_followlists.db")
|
||||
cli = ClientBuilder().signer(signer).database(database).opts(opts).build()
|
||||
|
||||
await cli.add_relay("wss://relay.damus.io") # TODO ADD MORE
|
||||
@@ -86,7 +86,7 @@ async def analyse_users(user_ids=None):
|
||||
print(npub)
|
||||
print(e)
|
||||
|
||||
database = await NostrDatabase.sqlite("db/nostr_followlists.db")
|
||||
database = NostrDatabase.lmdb("db/nostr_followlists.db")
|
||||
followers_filter = Filter().authors(user_keys).kind(Kind(3))
|
||||
followers = await database.query([followers_filter])
|
||||
allfriends = []
|
||||
|
||||
122
tutorials/01_preparations.ipynb
Normal file
122
tutorials/01_preparations.ipynb
Normal file
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": "",
|
||||
"id": "1865ec9f54c7b22e"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Hello there, fellow DVM enthusiast\n",
|
||||
"This is the first of a series of tutorials on how to use nostr-dvm.\n",
|
||||
"\n",
|
||||
"Before we start, we have to make sure you have a .env file in the working directory.\n",
|
||||
"\n",
|
||||
"In order to make sure you have it and to get you started quickly, here is a small function to create an inital .env file for you. Just make sure you set the parameters in the following field:"
|
||||
],
|
||||
"id": "e1f5dcfcad069462"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"lnbits_admin_key = \"\" #TODO set your key here\n",
|
||||
"lnbits_wallet_id = \"\" #TODO set your key here\n",
|
||||
"lnbits_host= \"https://demo.lnbits.com\" #TODO you can use demo.lnbits.com, but rather use your own instance\n",
|
||||
"nostdress_domain = \"nostrdvm.com\" #TODO use your own nostdress instance, or use the default one"
|
||||
],
|
||||
"id": "2e71e7aa2ebdac50"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"LNBITS_HOST is an Lnbits instance. We'll use Lnbits to generate wallets for each DVM automatically.\n",
|
||||
"You can use the demo server, but it is highly recommended to move to your own instance,\n",
|
||||
"or an instance of someone you trust.\n",
|
||||
"\n",
|
||||
"LNBITS_ADMIN_KEY and LNBITS_WALLET_ID are the API keys you get from Lnbits. You might also want to activate the User Manager module in LNBits.\n",
|
||||
"\n",
|
||||
"NOSTDRESS_DOMAIN: You can run your own instance of Nostdress https://github.com/believethehype/nostdress, so your DVMs get their own unique zapable lightning address, or you can use the default one. Make sure that the used identifier is unique, as otherwise the lnaddress will not work, if the nostdress acount already exists\n",
|
||||
"\n",
|
||||
" By the way, if that's not your kind of thing, you don't have to set an Lnbits account. If your DVM should receive zaps somehow, make sure you manually set a valid, zappable lightning address in its profile, once we created it. In this case leave the lnbits_admin_key and lnbits_wallet_id empty\n"
|
||||
],
|
||||
"id": "bb26e7180f1d1f0"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": "The following script will make an initial .env file with the parameters set in the field above, if it doesn't exist yet.\n",
|
||||
"id": "f6b316e1cace5adc"
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-09-16T13:36:56.451990Z",
|
||||
"start_time": "2024-09-16T13:36:56.448752Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"config = \"LNBITS_ADMIN_KEY = \\\"\"+lnbits_admin_key+\"\\\"\\nLNBITS_WALLET_ID = \\\"\"+ lnbits_wallet_id +\"\\\"\\nLNBITS_HOST = \\\"\"+ lnbits_host + \"\\\"\\nNOSTDRESS_DOMAIN = \\\"\" + nostdress_domain + \"\\\"\"\n",
|
||||
"\n",
|
||||
"import os.path\n",
|
||||
"if not os.path.isfile(\".env\"):\n",
|
||||
" with open(\".env\", \"w\") as f: # Opens file and casts as f \n",
|
||||
" f.write(config) # Writing\n",
|
||||
" # File closed automatically\n",
|
||||
"else:\n",
|
||||
" print(\".env file already exists\")"
|
||||
],
|
||||
"id": "a3e16002be388215",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
".env file already exists\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 8
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": "Cool. That's it for the prepartion. Once the .env file exists we won't overwrite it here again. You can open the .env file in this folder (maybe refresh your IDE) and check if everything worked as expected",
|
||||
"id": "f4e3ed80abdad23a"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": "",
|
||||
"id": "d32b5abd00600e64"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
82
tutorials/02_run_dvm.py
Normal file
82
tutorials/02_run_dvm.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# Welcome back, this time we don't use a notebook, but we run an actual Python Script.
|
||||
# We use a GenericDVM kind to start with. Now what's this? We have many predefined tasks in the task folder, but
|
||||
# the genericDVM gives you some control for simple manipulation without caring about the tasks. Important is that
|
||||
# we set the Kind of the GenericDVM. In Line 28 you see that we give it Kind 5050 (Text generation).
|
||||
# On https://www.data-vending-machines.org/ there's an overview on all current kinds.
|
||||
# On https://github.com/nostr-protocol/data-vending-machines/ you can make a PR for your own kind, if you come up with one later.
|
||||
# Check the run_dvm function for more explanations
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
|
||||
from nostr_dvm.tasks.generic_dvm import GenericDVM
|
||||
from nostr_sdk import Kind, Keys
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.dvmconfig import build_default_config, DVMConfig
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config
|
||||
from nostr_dvm.utils.zap_utils import change_ln_address
|
||||
|
||||
|
||||
def run_dvm(identifier):
|
||||
# You have seen this one before, we did this in tutorial 2. This function will either create or load. the parameters of our DVMConfig.
|
||||
# Make sure you replace the identifier down in the main function with the one you generated in tutorial 2, or we will create a new one here.
|
||||
dvm_config = build_default_config(identifier)
|
||||
# As we will use a GenericDVM we need to give it a kind. Here we use kind 5050 (Text Generation) as we want to reply with some simple text.
|
||||
# There is a bunch of predefined DVMs in tasks that already have a kind set, but as we use the genericDVM we have to manually set it here.
|
||||
dvm_config.KIND = Kind(5050)
|
||||
|
||||
# We can set options that we can later use in our process function. They are stored in a simple JSON
|
||||
options = {
|
||||
"some_option": "#RunDVM",
|
||||
}
|
||||
# We give the DVM a human readable name
|
||||
name = "My very first DVM"
|
||||
# Next we initalize a GenericDVM with the name and the dvm_config and the options we just created, as well as
|
||||
# an empty AdminConfig() and NIP89Config(). We will check these out in later tutorials, so don't worry about them now.
|
||||
dvm = GenericDVM(name=name, dvm_config=dvm_config, options=options,
|
||||
nip89config=NIP89Config(), admin_config=AdminConfig())
|
||||
|
||||
|
||||
# Normally we would define the dvm interface as we do in the tasks folder (we will do it later in the tutorials as well,
|
||||
# but here is a small hack to quickly manipulate what our dvm will do.
|
||||
async def process(request_form):
|
||||
# First we always parse the options from our request_form, that is build internally in the create_request_from_nostr_event function.
|
||||
options = dvm.set_options(request_form)
|
||||
# We build our result we are giving back from some text
|
||||
result = "The result of the DVM is: "
|
||||
# and the option we defined above and handed over to our DVM (some_option)
|
||||
result += options["some_option"]
|
||||
print(result)
|
||||
# Then we simply return the result
|
||||
return result
|
||||
|
||||
dvm.process = process # now we simply overwrite our DVM's process function with the one we defined here.
|
||||
# and finally we run the DVM #RunDVM
|
||||
dvm.run()
|
||||
|
||||
# When the DVM is running you should see a blue message with the name and the public key in bech32 and hex format.
|
||||
# For the next exercise, copy the Hex key, and let this DVM run, you will need it :)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#We open the .env file we created before.
|
||||
env_path = Path('.env')
|
||||
if not env_path.is_file():
|
||||
with open('.env', 'w') as f:
|
||||
print("Writing new .env file")
|
||||
f.write('')
|
||||
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} ')
|
||||
|
||||
# Replace the identifier with the one from the last notebook, or a new dvmconfig will be stored
|
||||
identifier = "tutorial01"
|
||||
|
||||
# psst, you can change your lightning address here:
|
||||
#asyncio.run(change_ln_address(identifier, "test", DVMConfig(), True))
|
||||
|
||||
run_dvm(identifier)
|
||||
130
tutorials/03_client.py
Normal file
130
tutorials/03_client.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# Welcome to part 3. This actually is is a simplistic client that will interact with our DVM.
|
||||
# We will address the DVM we created in part 02, so make sure it's still running and run this Script in a new instance.
|
||||
# Copy the DVM's hex key that pops up at the beginning and replace the one down in the main function with your DVM's key.
|
||||
# This way we will tag it and it will know it should reply to us.
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from secp256k1 import PublicKey
|
||||
|
||||
from nostr_dvm.utils.dvmconfig import DVMConfig
|
||||
from nostr_dvm.utils.print import bcolors
|
||||
|
||||
import dotenv
|
||||
from nostr_sdk import Keys, Client, Tag, EventBuilder, Filter, HandleNotification, Timestamp, nip04_decrypt, \
|
||||
NostrSigner, Event, Kind, PublicKey
|
||||
from nostr_dvm.utils.nostr_utils import send_event, check_and_set_private_key
|
||||
from nostr_dvm.utils.definitions import EventDefinitions
|
||||
|
||||
|
||||
|
||||
async def nostr_client_generic_test(ptag):
|
||||
# Create or manage some private keys for our client.
|
||||
keys = Keys.parse(check_and_set_private_key("test_client"))
|
||||
|
||||
# We tell the DVM to which relays it should reply
|
||||
relay_list = ["wss://nostr.oxtr.dev", "wss://relay.primal.net"]
|
||||
relaysTag = Tag.parse(["relays"] + relay_list)
|
||||
# The alt tag is optional, and just describes what the event does.
|
||||
alttag = Tag.parse(["alt", "This is a NIP90 DVM AI task"])
|
||||
# The ptag tags the DVM we want to address. Make sure to set it down in the main function.
|
||||
pTag = Tag.parse(["p", PublicKey.parse(ptag).to_hex()])
|
||||
|
||||
# These are out tags
|
||||
tags = [relaysTag, alttag, pTag]
|
||||
|
||||
# We now send a 5050 Request (for Text Generation) with our tags. The content is optional.
|
||||
event = EventBuilder(Kind(5050), "This is a test",
|
||||
tags).to_event(keys)
|
||||
|
||||
# We create a signer with some random keys
|
||||
signer = NostrSigner.keys(keys)
|
||||
client = Client(signer)
|
||||
# We add the relays we defined above and told our DVM we would want to receive events to.
|
||||
for relay in relay_list:
|
||||
await client.add_relay(relay)
|
||||
# We connect the client
|
||||
await client.connect()
|
||||
# and send the Event.
|
||||
result = await send_event(event, client=client, dvm_config=DVMConfig())
|
||||
print(result)
|
||||
|
||||
|
||||
async def nostr_client(target_dvm_npub):
|
||||
|
||||
# This is some logic for listening to events. For example we want to see replies from the DVM.
|
||||
keys = Keys.parse(check_and_set_private_key("test_client"))
|
||||
sk = keys.secret_key()
|
||||
pk = keys.public_key()
|
||||
print(f"Nostr Client public key: {pk.to_bech32()}, Hex: {pk.to_hex()} ")
|
||||
signer = NostrSigner.keys(keys)
|
||||
client = Client(signer)
|
||||
|
||||
dvmconfig = DVMConfig()
|
||||
for relay in dvmconfig.RELAY_LIST:
|
||||
await client.add_relay(relay)
|
||||
await client.connect()
|
||||
|
||||
dm_zap_filter = Filter().pubkey(pk).kinds([EventDefinitions.KIND_DM,
|
||||
EventDefinitions.KIND_ZAP]).since(Timestamp.now())
|
||||
kinds = [EventDefinitions.KIND_NIP90_GENERIC]
|
||||
for kind in range(6000, 7001):
|
||||
if kind not in kinds:
|
||||
kinds.append(Kind(kind))
|
||||
|
||||
dvm_filter = (Filter().kinds(kinds).since(Timestamp.now()).pubkey(pk))
|
||||
await client.subscribe([dm_zap_filter, dvm_filter], None)
|
||||
|
||||
# This will send a request to the DVM
|
||||
await nostr_client_generic_test(target_dvm_npub)
|
||||
|
||||
# We listen to
|
||||
class NotificationHandler(HandleNotification):
|
||||
last_event_time = 0
|
||||
async def handle(self, relay_url, subscription_id, event: Event):
|
||||
|
||||
print(
|
||||
bcolors.BLUE + f"Received new event from {relay_url}: {event.as_json()}" + bcolors.ENDC)
|
||||
if event.kind().as_u16() == 7000:
|
||||
print(bcolors.YELLOW + "[Nostr Client]: " + event.content() + bcolors.ENDC)
|
||||
amount_sats = 0
|
||||
status = ""
|
||||
for tag in event.tags():
|
||||
if tag.as_vec()[0] == "amount":
|
||||
amount_sats = int(int(tag.as_vec()[1]) / 1000) # millisats
|
||||
if tag.as_vec()[0] == "status":
|
||||
status = tag.as_vec()[1]
|
||||
|
||||
elif 6000 < event.kind().as_u16() < 6999:
|
||||
print(bcolors.GREEN + "[Nostr Client]: " + event.content() + bcolors.ENDC)
|
||||
|
||||
elif event.kind().as_u16() == 4:
|
||||
dec_text = nip04_decrypt(sk, event.author(), event.content() )
|
||||
print("[Nostr Client]: " + f"Received new msg: {dec_text}")
|
||||
|
||||
elif event.kind().as_u16() == 9735:
|
||||
print("[Nostr Client]: " + f"Received new zap:")
|
||||
print(event.as_json())
|
||||
|
||||
async def handle_msg(self, relay_url, msg):
|
||||
return
|
||||
|
||||
asyncio.create_task(client.handle_notifications(NotificationHandler()))
|
||||
# await client.handle_notifications(NotificationHandler())
|
||||
while True:
|
||||
await asyncio.sleep(2)
|
||||
|
||||
|
||||
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} ')
|
||||
|
||||
# Replace this key with the one from your DVM from part 3.
|
||||
target_dvm_npub = "aaf3b2bda1f19651417af4b1ccc35ebb6675d718843fdc444bdca4da1c8cd2fc"
|
||||
asyncio.run(nostr_client(target_dvm_npub))
|
||||
@@ -75,8 +75,11 @@ async function generate_feed(id) {
|
||||
let tags = []
|
||||
//tags.push(["param", "max_results", "200"])
|
||||
tags.push(["param", "user", store.state.pubkey.toHex()])
|
||||
let r = store.state.relays.join(",")
|
||||
tags.push(["relays", r])
|
||||
let r = ["relays"]
|
||||
for (let relay of store.state.relays){
|
||||
r.push(relay)
|
||||
}
|
||||
tags.push(r)
|
||||
let res;
|
||||
let requestid;
|
||||
|
||||
|
||||
@@ -61,8 +61,12 @@ async function generate_image(message) {
|
||||
let tags = [
|
||||
["i", message, "text"]
|
||||
]
|
||||
let r = store.state.relays.join(",")
|
||||
tags.push(["relays", r])
|
||||
|
||||
let r = ["relays"]
|
||||
for (let relay of store.state.relays){
|
||||
r.push(relay)
|
||||
}
|
||||
tags.push(r)
|
||||
|
||||
hasmultipleinputs = false
|
||||
if (urlinput.value !== "" && urlinput.value.startsWith('http')){
|
||||
@@ -222,7 +226,7 @@ async function listen() {
|
||||
|
||||
|
||||
for (const el of store.state.nip89dvms) {
|
||||
if (JSON.parse(el.event).pubkey === event.author.toHex().toString()) {
|
||||
if (JSON.parse(el.event).pubkey === event.author.toHex().toString() && el.kind === "5100" ) {
|
||||
jsonentry.name = el.name
|
||||
jsonentry.about = el.about
|
||||
jsonentry.image = el.image
|
||||
@@ -439,54 +443,54 @@ const submitHandler = async () => {
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="dvm.result && store.state.pubkey.toHex() !== Keys.parse(store.state.nooglekey).publicKey.toHex() && !dvm.reactions.negativeUser && !dvm.reactions.positiveUser" style="margin-right: 5px">
|
||||
<div v-if="dvm.result && store.state.pubkey.toHex() !== Keys.parse(store.state.nooglekey).publicKey.toHex()" style="margin-right: 5px">
|
||||
<!-- && !dvm.reactions.negativeUser && !dvm.reactions.positiveUser-->
|
||||
|
||||
|
||||
|
||||
<button @click="react_to_dvm(dvm, '👍')" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-up" viewBox="0 0 16 16">
|
||||
<path d="M8.864.046C7.908-.193 7.02.53 6.956 1.466c-.072 1.051-.23 2.016-.428 2.59-.125.36-.479 1.013-1.04 1.639-.557.623-1.282 1.178-2.131 1.41C2.685 7.288 2 7.87 2 8.72v4.001c0 .845.682 1.464 1.448 1.545 1.07.114 1.564.415 2.068.723l.048.03c.272.165.578.348.97.484.397.136.861.217 1.466.217h3.5c.937 0 1.599-.477 1.934-1.064a1.86 1.86 0 0 0 .254-.912c0-.152-.023-.312-.077-.464.201-.263.38-.578.488-.901.11-.33.172-.762.004-1.149.069-.13.12-.269.159-.403.077-.27.113-.568.113-.857 0-.288-.036-.585-.113-.856a2 2 0 0 0-.138-.362 1.9 1.9 0 0 0 .234-1.734c-.206-.592-.682-1.1-1.2-1.272-.847-.282-1.803-.276-2.516-.211a10 10 0 0 0-.443.05 9.4 9.4 0 0 0-.062-4.509A1.38 1.38 0 0 0 9.125.111zM11.5 14.721H8c-.51 0-.863-.069-1.14-.164-.281-.097-.506-.228-.776-.393l-.04-.024c-.555-.339-1.198-.731-2.49-.868-.333-.036-.554-.29-.554-.55V8.72c0-.254.226-.543.62-.65 1.095-.3 1.977-.996 2.614-1.708.635-.71 1.064-1.475 1.238-1.978.243-.7.407-1.768.482-2.85.025-.362.36-.594.667-.518l.262.066c.16.04.258.143.288.255a8.34 8.34 0 0 1-.145 4.725.5.5 0 0 0 .595.644l.003-.001.014-.003.058-.014a9 9 0 0 1 1.036-.157c.663-.06 1.457-.054 2.11.164.175.058.45.3.57.65.107.308.087.67-.266 1.022l-.353.353.353.354c.043.043.105.141.154.315.048.167.075.37.075.581 0 .212-.027.414-.075.582-.05.174-.111.272-.154.315l-.353.353.353.354c.047.047.109.177.005.488a2.2 2.2 0 0 1-.505.805l-.353.353.353.354c.006.005.041.05.041.17a.9.9 0 0 1-.121.416c-.165.288-.503.56-1.066.56z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- <button @click="react_to_dvm(dvm, '👍')" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">-->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-up" viewBox="0 0 16 16">-->
|
||||
<!-- <path d="M8.864.046C7.908-.193 7.02.53 6.956 1.466c-.072 1.051-.23 2.016-.428 2.59-.125.36-.479 1.013-1.04 1.639-.557.623-1.282 1.178-2.131 1.41C2.685 7.288 2 7.87 2 8.72v4.001c0 .845.682 1.464 1.448 1.545 1.07.114 1.564.415 2.068.723l.048.03c.272.165.578.348.97.484.397.136.861.217 1.466.217h3.5c.937 0 1.599-.477 1.934-1.064a1.86 1.86 0 0 0 .254-.912c0-.152-.023-.312-.077-.464.201-.263.38-.578.488-.901.11-.33.172-.762.004-1.149.069-.13.12-.269.159-.403.077-.27.113-.568.113-.857 0-.288-.036-.585-.113-.856a2 2 0 0 0-.138-.362 1.9 1.9 0 0 0 .234-1.734c-.206-.592-.682-1.1-1.2-1.272-.847-.282-1.803-.276-2.516-.211a10 10 0 0 0-.443.05 9.4 9.4 0 0 0-.062-4.509A1.38 1.38 0 0 0 9.125.111zM11.5 14.721H8c-.51 0-.863-.069-1.14-.164-.281-.097-.506-.228-.776-.393l-.04-.024c-.555-.339-1.198-.731-2.49-.868-.333-.036-.554-.29-.554-.55V8.72c0-.254.226-.543.62-.65 1.095-.3 1.977-.996 2.614-1.708.635-.71 1.064-1.475 1.238-1.978.243-.7.407-1.768.482-2.85.025-.362.36-.594.667-.518l.262.066c.16.04.258.143.288.255a8.34 8.34 0 0 1-.145 4.725.5.5 0 0 0 .595.644l.003-.001.014-.003.058-.014a9 9 0 0 1 1.036-.157c.663-.06 1.457-.054 2.11.164.175.058.45.3.57.65.107.308.087.67-.266 1.022l-.353.353.353.354c.043.043.105.141.154.315.048.167.075.37.075.581 0 .212-.027.414-.075.582-.05.174-.111.272-.154.315l-.353.353.353.354c.047.047.109.177.005.488a2.2 2.2 0 0 1-.505.805l-.353.353.353.354c.006.005.041.05.041.17a.9.9 0 0 1-.121.416c-.165.288-.503.56-1.066.56z"/>-->
|
||||
<!-- </svg>-->
|
||||
<!-- </button>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
<div v-if="dvm.result && store.state.pubkey.toHex() !== Keys.parse(store.state.nooglekey).publicKey.toHex() && !dvm.reactions.negativeUser && !dvm.reactions.positiveUser" >
|
||||
<button @click="react_to_dvm(dvm, '👎')" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16">
|
||||
<path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856s-.036.586-.113.856c-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a10 10 0 0 1-.443-.05 9.36 9.36 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a9 9 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581s-.027-.414-.075-.581c-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.2 2.2 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.9.9 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- <div v-if="dvm.result && store.state.pubkey.toHex() !== Keys.parse(store.state.nooglekey).publicKey.toHex() && !dvm.reactions.negativeUser && !dvm.reactions.positiveUser" >-->
|
||||
<!-- <button @click="react_to_dvm(dvm, '👎')" class="w-8 h-8 rounded-full bg-nostr border-white border-1 text-white flex items-center justify-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black tooltip" data-top='Share' aria-label="make note" role="button">-->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16">-->
|
||||
<!-- <path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856s-.036.586-.113.856c-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a10 10 0 0 1-.443-.05 9.36 9.36 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a9 9 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581s-.027-.414-.075-.581c-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.2 2.2 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.9.9 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/>-->
|
||||
<!--</svg>-->
|
||||
<!-- </button>-->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="flex"> {{dvm.reactions.positive.length}}
|
||||
|
||||
<!-- <p class="flex"> {{dvm.reactions.positiveUser.length}}-->
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div className="dropdown">
|
||||
<div tabIndex={0} role="button" class="button" >
|
||||
<svg style="margin-left: 3px; margin-right: 10px; margin-top: 3px" xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-hand-thumbs-up" viewBox="0 0 16 16">
|
||||
<path d="M8.864.046C7.908-.193 7.02.53 6.956 1.466c-.072 1.051-.23 2.016-.428 2.59-.125.36-.479 1.013-1.04 1.639-.557.623-1.282 1.178-2.131 1.41C2.685 7.288 2 7.87 2 8.72v4.001c0 .845.682 1.464 1.448 1.545 1.07.114 1.564.415 2.068.723l.048.03c.272.165.578.348.97.484.397.136.861.217 1.466.217h3.5c.937 0 1.599-.477 1.934-1.064a1.86 1.86 0 0 0 .254-.912c0-.152-.023-.312-.077-.464.201-.263.38-.578.488-.901.11-.33.172-.762.004-1.149.069-.13.12-.269.159-.403.077-.27.113-.568.113-.857 0-.288-.036-.585-.113-.856a2 2 0 0 0-.138-.362 1.9 1.9 0 0 0 .234-1.734c-.206-.592-.682-1.1-1.2-1.272-.847-.282-1.803-.276-2.516-.211a10 10 0 0 0-.443.05 9.4 9.4 0 0 0-.062-4.509A1.38 1.38 0 0 0 9.125.111zM11.5 14.721H8c-.51 0-.863-.069-1.14-.164-.281-.097-.506-.228-.776-.393l-.04-.024c-.555-.339-1.198-.731-2.49-.868-.333-.036-.554-.29-.554-.55V8.72c0-.254.226-.543.62-.65 1.095-.3 1.977-.996 2.614-1.708.635-.71 1.064-1.475 1.238-1.978.243-.7.407-1.768.482-2.85.025-.362.36-.594.667-.518l.262.066c.16.04.258.143.288.255a8.34 8.34 0 0 1-.145 4.725.5.5 0 0 0 .595.644l.003-.001.014-.003.058-.014a9 9 0 0 1 1.036-.157c.663-.06 1.457-.054 2.11.164.175.058.45.3.57.65.107.308.087.67-.266 1.022l-.353.353.353.354c.043.043.105.141.154.315.048.167.075.37.075.581 0 .212-.027.414-.075.582-.05.174-.111.272-.154.315l-.353.353.353.354c.047.047.109.177.005.488a2.2 2.2 0 0 1-.505.805l-.353.353.353.354c.006.005.041.05.041.17a.9.9 0 0 1-.121.416c-.165.288-.503.56-1.066.56z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div tabIndex={0} className="dropdown-content -start-56 z-[1] horizontal card card-compact w-64 p-2 shadow bg-nostr text-primary-content">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title">Liked results by</h3>
|
||||
<div class="flex" >
|
||||
<div v-for="user in dvm.reactions.positive">
|
||||
<div className="wotplayeauthor-wrapper">
|
||||
<figure>
|
||||
<img className="wotavatar" v-if="user.profile && user.profile.picture" :src="user.profile.picture" onerror="this.src='https://noogle.lol/favicon.ico'" alt="DVM Picture" />
|
||||
<img class="wotavatar" v-else src="@/assets/nostr-purple.svg" />
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div className="dropdown">-->
|
||||
<!-- <div tabIndex={0} role="button" class="button" >-->
|
||||
<!-- <svg style="margin-left: 3px; margin-right: 10px; margin-top: 3px" xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-hand-thumbs-up" viewBox="0 0 16 16">-->
|
||||
<!-- <path d="M8.864.046C7.908-.193 7.02.53 6.956 1.466c-.072 1.051-.23 2.016-.428 2.59-.125.36-.479 1.013-1.04 1.639-.557.623-1.282 1.178-2.131 1.41C2.685 7.288 2 7.87 2 8.72v4.001c0 .845.682 1.464 1.448 1.545 1.07.114 1.564.415 2.068.723l.048.03c.272.165.578.348.97.484.397.136.861.217 1.466.217h3.5c.937 0 1.599-.477 1.934-1.064a1.86 1.86 0 0 0 .254-.912c0-.152-.023-.312-.077-.464.201-.263.38-.578.488-.901.11-.33.172-.762.004-1.149.069-.13.12-.269.159-.403.077-.27.113-.568.113-.857 0-.288-.036-.585-.113-.856a2 2 0 0 0-.138-.362 1.9 1.9 0 0 0 .234-1.734c-.206-.592-.682-1.1-1.2-1.272-.847-.282-1.803-.276-2.516-.211a10 10 0 0 0-.443.05 9.4 9.4 0 0 0-.062-4.509A1.38 1.38 0 0 0 9.125.111zM11.5 14.721H8c-.51 0-.863-.069-1.14-.164-.281-.097-.506-.228-.776-.393l-.04-.024c-.555-.339-1.198-.731-2.49-.868-.333-.036-.554-.29-.554-.55V8.72c0-.254.226-.543.62-.65 1.095-.3 1.977-.996 2.614-1.708.635-.71 1.064-1.475 1.238-1.978.243-.7.407-1.768.482-2.85.025-.362.36-.594.667-.518l.262.066c.16.04.258.143.288.255a8.34 8.34 0 0 1-.145 4.725.5.5 0 0 0 .595.644l.003-.001.014-.003.058-.014a9 9 0 0 1 1.036-.157c.663-.06 1.457-.054 2.11.164.175.058.45.3.57.65.107.308.087.67-.266 1.022l-.353.353.353.354c.043.043.105.141.154.315.048.167.075.37.075.581 0 .212-.027.414-.075.582-.05.174-.111.272-.154.315l-.353.353.353.354c.047.047.109.177.005.488a2.2 2.2 0 0 1-.505.805l-.353.353.353.354c.006.005.041.05.041.17a.9.9 0 0 1-.121.416c-.165.288-.503.56-1.066.56z"/>-->
|
||||
<!-- </svg>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div tabIndex={0} className="dropdown-content -start-56 z-[1] horizontal card card-compact w-64 p-2 shadow bg-nostr text-primary-content">-->
|
||||
<!-- <div className="card-body">-->
|
||||
<!-- <h3 className="card-title">Liked results by</h3>-->
|
||||
<!-- <div class="flex" >-->
|
||||
<!-- <div v-for="user in dvm.reactions.positive">-->
|
||||
<!-- <div className="wotplayeauthor-wrapper">-->
|
||||
<!-- <figure>-->
|
||||
<!-- <img className="wotavatar" v-if="user.profile && user.profile.picture" :src="user.profile.picture" onerror="this.src='https://noogle.lol/favicon.ico'" alt="DVM Picture" />-->
|
||||
<!-- <img class="wotavatar" v-else src="@/assets/nostr-purple.svg" />-->
|
||||
<!-- </figure>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
</div>
|
||||
|
||||
@@ -500,53 +504,53 @@ const submitHandler = async () => {
|
||||
|
||||
<div style="width: 10px"></div>
|
||||
|
||||
{{dvm.reactions.negative.length}}
|
||||
<div>
|
||||
<!-- {{dvm.reactions.negative.length}}-->
|
||||
<!-- <div>-->
|
||||
|
||||
<div className="dropdown">
|
||||
<div tabIndex={0} role="button" class="button" >
|
||||
<svg style="margin-left: 3px; margin-top: 3px" xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16">
|
||||
<path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856s-.036.586-.113.856c-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a10 10 0 0 1-.443-.05 9.36 9.36 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a9 9 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581s-.027-.414-.075-.581c-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.2 2.2 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.9.9 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div tabIndex={0} className="dropdown-content -start-56 z-[1] horizontal card card-compact w-64 p-2 shadow bg-nostr text-primary-content">
|
||||
<div className="card-body">
|
||||
<h3 className="card-title">Disliked results by</h3>
|
||||
<div class="flex" >
|
||||
<div v-for="user in dvm.reactions.negative">
|
||||
<div className="wotplayeauthor-wrapper">
|
||||
<!-- <div className="dropdown">-->
|
||||
<!-- <div tabIndex={0} role="button" class="button" >-->
|
||||
<!-- <svg style="margin-left: 3px; margin-top: 3px" xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-hand-thumbs-down" viewBox="0 0 16 16">-->
|
||||
<!-- <path d="M8.864 15.674c-.956.24-1.843-.484-1.908-1.42-.072-1.05-.23-2.015-.428-2.59-.125-.36-.479-1.012-1.04-1.638-.557-.624-1.282-1.179-2.131-1.41C2.685 8.432 2 7.85 2 7V3c0-.845.682-1.464 1.448-1.546 1.07-.113 1.564-.415 2.068-.723l.048-.029c.272-.166.578-.349.97-.484C6.931.08 7.395 0 8 0h3.5c.937 0 1.599.478 1.934 1.064.164.287.254.607.254.913 0 .152-.023.312-.077.464.201.262.38.577.488.9.11.33.172.762.004 1.15.069.13.12.268.159.403.077.27.113.567.113.856s-.036.586-.113.856c-.035.12-.08.244-.138.363.394.571.418 1.2.234 1.733-.206.592-.682 1.1-1.2 1.272-.847.283-1.803.276-2.516.211a10 10 0 0 1-.443-.05 9.36 9.36 0 0 1-.062 4.51c-.138.508-.55.848-1.012.964zM11.5 1H8c-.51 0-.863.068-1.14.163-.281.097-.506.229-.776.393l-.04.025c-.555.338-1.198.73-2.49.868-.333.035-.554.29-.554.55V7c0 .255.226.543.62.65 1.095.3 1.977.997 2.614 1.709.635.71 1.064 1.475 1.238 1.977.243.7.407 1.768.482 2.85.025.362.36.595.667.518l.262-.065c.16-.04.258-.144.288-.255a8.34 8.34 0 0 0-.145-4.726.5.5 0 0 1 .595-.643h.003l.014.004.058.013a9 9 0 0 0 1.036.157c.663.06 1.457.054 2.11-.163.175-.059.45-.301.57-.651.107-.308.087-.67-.266-1.021L12.793 7l.353-.354c.043-.042.105-.14.154-.315.048-.167.075-.37.075-.581s-.027-.414-.075-.581c-.05-.174-.111-.273-.154-.315l-.353-.354.353-.354c.047-.047.109-.176.005-.488a2.2 2.2 0 0 0-.505-.804l-.353-.354.353-.354c.006-.005.041-.05.041-.17a.9.9 0 0 0-.121-.415C12.4 1.272 12.063 1 11.5 1"/>-->
|
||||
<!--</svg>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div tabIndex={0} className="dropdown-content -start-56 z-[1] horizontal card card-compact w-64 p-2 shadow bg-nostr text-primary-content">-->
|
||||
<!-- <div className="card-body">-->
|
||||
<!-- <h3 className="card-title">Disliked results by</h3>-->
|
||||
<!-- <div class="flex" >-->
|
||||
<!-- <div v-for="user in dvm.reactions.negative">-->
|
||||
<!-- <div className="wotplayeauthor-wrapper">-->
|
||||
|
||||
<figure>
|
||||
<!-- <figure>-->
|
||||
|
||||
<img className="wotavatar" v-if="user.profile && user.profile.picture" :src="user.profile.picture" onerror="this.src='https://noogle.lol/favicon.ico'" alt="DVM Picture" />
|
||||
<img class="wotavatar" v-else src="@/assets/nostr-purple.svg" />
|
||||
</figure>
|
||||
<!-- <img className="wotavatar" v-if="user.profile && user.profile.picture" :src="user.profile.picture" onerror="this.src='https://noogle.lol/favicon.ico'" alt="DVM Picture" />-->
|
||||
<!-- <img class="wotavatar" v-else src="@/assets/nostr-purple.svg" />-->
|
||||
<!-- </figure>-->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
</div>
|
||||
<!--</div>-->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--<p>{{ this.current_user }}</p> -->
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!–<p>{{ this.current_user }}</p> –>-->
|
||||
<!-- </div>-->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -205,7 +205,7 @@ import {loadNWCObject} from "@/components/helper/Zap.vue"
|
||||
import {useDark, useEventListener, useToggle} from "@vueuse/core";
|
||||
import {ref} from "vue";
|
||||
import {webln} from "@getalby/sdk";
|
||||
import {nip04Decrypt} from "@rust-nostr/nostr-sdk/pkg/nostr_sdk_js_bg.wasm.js";
|
||||
import {contact_new, nip04Decrypt} from "@rust-nostr/nostr-sdk/pkg/nostr_sdk_js_bg.wasm.js";
|
||||
import app from "@/App.vue";
|
||||
const isDark = useDark();
|
||||
|
||||
@@ -752,6 +752,10 @@ export default {
|
||||
|
||||
for (const entry of evts){
|
||||
|
||||
try {
|
||||
|
||||
|
||||
|
||||
for (const tag in entry.tags){
|
||||
if (entry.tags[tag].asVec()[0] === "k")
|
||||
if(entry.tags[tag].asVec()[1] >= 5000 && entry.tags[tag].asVec()[1] <= 5999 && deadnip89s.filter(i => i.id === entry.id.toHex() ).length === 0) { // blocklist.indexOf(entry.id.toHex()) < 0){
|
||||
@@ -760,7 +764,8 @@ export default {
|
||||
|
||||
try {
|
||||
|
||||
let jsonentry = JSON.parse(entry.content)
|
||||
let jsonentry = JSON.parse(entry.content)
|
||||
|
||||
|
||||
let nip88 = {
|
||||
title: "",
|
||||
@@ -868,7 +873,17 @@ export default {
|
||||
//jsonentry.reactions = await dvmreactions(entry.author.toHex())
|
||||
// console.log("REACTIONS:" + jsonentry.reactions)
|
||||
jsonentry.id = entry.author.toHex()
|
||||
jsonentry.about = await parseandreplacenpubs(jsonentry.about)
|
||||
try{
|
||||
if (jsonentry.about != null){
|
||||
jsonentry.about = await parseandreplacenpubs(jsonentry.about)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch(Error){
|
||||
console.log(Error)
|
||||
}
|
||||
|
||||
jsonentry.event = entry.asJson()
|
||||
jsonentry.kind = entry.tags[tag].asVec()[1]
|
||||
|
||||
@@ -880,11 +895,13 @@ export default {
|
||||
}
|
||||
catch (error){
|
||||
console.log(error)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
store.commit('set_nip89dvms', nip89dvms)
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<h2 class="card-title">{{ dvm.name }}</h2>
|
||||
<h3 class="fa-cut text-gray" >Kind: {{ dvm.kind }}</h3>
|
||||
|
||||
<h3 class="fa-cut" v-html="StringUtil.parseHyperlinks(dvm.about)"></h3>
|
||||
<h3 v-if="dvm.about !== null" class="fa-cut" v-html="dvm.about"></h3>
|
||||
<div class="card-actions justify-end">
|
||||
<button className="btn" @click="copyDoiToClipboard(dvm.event);">Copy Event Json</button>
|
||||
</div>
|
||||
|
||||
@@ -93,8 +93,13 @@ async function generate_feed(id) {
|
||||
let tags = []
|
||||
tags.push(["param", "max_results", "200"])
|
||||
tags.push(["param", "user", store.state.pubkey.toHex()])
|
||||
let r = store.state.relays.join(",")
|
||||
tags.push(["relays", r])
|
||||
let r = ["relays"]
|
||||
|
||||
for (let relay of store.state.relays){
|
||||
r.push(relay)
|
||||
}
|
||||
|
||||
tags.push(r)
|
||||
|
||||
let res;
|
||||
let requestid;
|
||||
|
||||
@@ -153,8 +153,11 @@ async function send_search_request(msg) {
|
||||
["param", "until", ((dateto.value/1000).toFixed(0))],
|
||||
['param', 'users', JSON.stringify(users)]
|
||||
]
|
||||
let r = store.state.relays.join(",")
|
||||
tags.push(["relays", r])
|
||||
let r = ["relays"]
|
||||
for (let relay of store.state.relays){
|
||||
r.push(relay)
|
||||
}
|
||||
tags.push(r)
|
||||
|
||||
|
||||
let tags_as_str = JSON.stringify(tags)
|
||||
|
||||
@@ -63,8 +63,11 @@ let sortedIds = eventids.sort(function(a,b) {return (a.index > b.index) ? 1 : ((
|
||||
catch{}
|
||||
}
|
||||
|
||||
let r = store.state.relays.join(",")
|
||||
tags.push(["relays", r])
|
||||
let r = ["relays"]
|
||||
for (let relay of store.state.relays){
|
||||
r.push(relay)
|
||||
}
|
||||
tags.push(r)
|
||||
|
||||
|
||||
let res;
|
||||
|
||||
Reference in New Issue
Block a user