agentstr 0.1.11__py3-none-any.whl → 0.1.12__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- agentstr/__init__.py +20 -13
- agentstr/buyer.py +291 -0
- agentstr/buyer.pyi +31 -0
- agentstr/{marketplace.py → merchant.py} +126 -323
- agentstr/merchant.pyi +37 -0
- agentstr/models.py +381 -0
- agentstr/models.pyi +103 -0
- agentstr/nostr.py +389 -53
- agentstr/nostr.pyi +82 -0
- agentstr/py.typed +0 -0
- {agentstr-0.1.11.dist-info → agentstr-0.1.12.dist-info}/METADATA +36 -53
- agentstr-0.1.12.dist-info/RECORD +15 -0
- agentstr-0.1.11.dist-info/RECORD +0 -8
- {agentstr-0.1.11.dist-info → agentstr-0.1.12.dist-info}/LICENSE +0 -0
- {agentstr-0.1.11.dist-info → agentstr-0.1.12.dist-info}/WHEEL +0 -0
- {agentstr-0.1.11.dist-info → agentstr-0.1.12.dist-info}/top_level.txt +0 -0
@@ -1,288 +1,22 @@
|
|
1
|
-
import ast
|
2
1
|
import json
|
3
2
|
import logging
|
4
|
-
import
|
5
|
-
from typing import Any,
|
6
|
-
|
7
|
-
from agentstr.
|
8
|
-
|
9
|
-
Keys,
|
10
|
-
NostrClient,
|
11
|
-
ProductData,
|
12
|
-
ShippingCost,
|
13
|
-
ShippingMethod,
|
14
|
-
StallData,
|
15
|
-
)
|
3
|
+
import time
|
4
|
+
from typing import Any, List, Optional, Tuple, Union
|
5
|
+
|
6
|
+
from agentstr.models import AgentProfile, MerchantProduct, MerchantStall
|
7
|
+
from agentstr.nostr import EventId, NostrClient
|
16
8
|
|
17
9
|
try:
|
18
|
-
from
|
10
|
+
from agno.tools import Toolkit
|
19
11
|
except ImportError:
|
20
|
-
raise ImportError(
|
21
|
-
"`phidata` not installed. Please install using `pip install phidata`"
|
22
|
-
)
|
23
|
-
|
24
|
-
from pydantic import BaseModel, ConfigDict, Field, validate_call
|
25
|
-
|
26
|
-
|
27
|
-
class Profile:
|
28
|
-
|
29
|
-
logger = logging.getLogger("Profile")
|
30
|
-
WEB_URL: str = "https://primal.net/p/"
|
31
|
-
|
32
|
-
def __init__(self, name: str, about: str, picture: str, nsec: Optional[str] = None):
|
33
|
-
"""Initialize the profile.
|
34
|
-
|
35
|
-
Args:
|
36
|
-
name: Name for the merchant
|
37
|
-
about: brief description about the merchant
|
38
|
-
picture: url to a png file with a picture for the merchant
|
39
|
-
nsec: optional private key to be used by this Merchant
|
40
|
-
"""
|
41
|
-
|
42
|
-
# Set log handling for MerchantProfile
|
43
|
-
if not Profile.logger.hasHandlers():
|
44
|
-
console_handler = logging.StreamHandler()
|
45
|
-
console_handler.setLevel(logging.INFO)
|
46
|
-
formatter = logging.Formatter(
|
47
|
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
48
|
-
)
|
49
|
-
console_handler.setFormatter(formatter)
|
50
|
-
Profile.logger.addHandler(console_handler)
|
51
|
-
|
52
|
-
self.name = name
|
53
|
-
self.about = about
|
54
|
-
self.picture = picture
|
55
|
-
|
56
|
-
if nsec:
|
57
|
-
self.private_key = nsec
|
58
|
-
keys = Keys.parse(self.private_key)
|
59
|
-
self.public_key = keys.public_key().to_bech32()
|
60
|
-
Profile.logger.info(
|
61
|
-
f"Pre-defined private key reused for {self.name}: {self.private_key}"
|
62
|
-
)
|
63
|
-
Profile.logger.info(
|
64
|
-
f"Pre-defined public key reused for {self.name}: {self.public_key}"
|
65
|
-
)
|
66
|
-
else:
|
67
|
-
keys = Keys.generate()
|
68
|
-
self.private_key = keys.secret_key().to_bech32()
|
69
|
-
self.public_key = keys.public_key().to_bech32()
|
70
|
-
Profile.logger.info(
|
71
|
-
f"New private key created for {self.name}: {self.private_key}"
|
72
|
-
)
|
73
|
-
Profile.logger.info(
|
74
|
-
f"New public key created for {self.name}: {self.public_key}"
|
75
|
-
)
|
76
|
-
|
77
|
-
self.url = str(self.WEB_URL) + str(self.public_key)
|
78
|
-
|
79
|
-
def __str__(self) -> str:
|
80
|
-
return (
|
81
|
-
"Merchant Profile:\n"
|
82
|
-
"Name = {}\n"
|
83
|
-
"Description = {}\n"
|
84
|
-
"Picture = {}\n"
|
85
|
-
"URL = {}\n"
|
86
|
-
"Private key = {}\n"
|
87
|
-
"Public key = {}".format(
|
88
|
-
self.name,
|
89
|
-
self.about,
|
90
|
-
self.picture,
|
91
|
-
self.url,
|
92
|
-
self.private_key,
|
93
|
-
self.public_key,
|
94
|
-
)
|
95
|
-
)
|
96
|
-
|
97
|
-
def to_dict(self) -> dict:
|
98
|
-
return {
|
99
|
-
"name": self.name,
|
100
|
-
"description": self.about,
|
101
|
-
"picture": self.picture,
|
102
|
-
"public key": self.public_key,
|
103
|
-
"private key": self.private_key,
|
104
|
-
}
|
105
|
-
|
106
|
-
def get_about(self) -> str:
|
107
|
-
"""
|
108
|
-
Returns a description of the Merchant
|
109
|
-
|
110
|
-
Returns:
|
111
|
-
str: description of the Merchant
|
112
|
-
"""
|
113
|
-
return self.about
|
114
|
-
|
115
|
-
def get_name(self) -> str:
|
116
|
-
"""
|
117
|
-
Returns the Merchant's name
|
12
|
+
raise ImportError("`agno` not installed. Please install using `pip install agno`")
|
118
13
|
|
119
|
-
|
120
|
-
str: Merchant's name
|
121
|
-
"""
|
122
|
-
return self.name
|
123
|
-
|
124
|
-
def get_picture(self) -> str:
|
125
|
-
"""
|
126
|
-
Returns the picture associated with the Merchant.
|
127
|
-
|
128
|
-
Returns:
|
129
|
-
str: URL to the picture associated with the Merchant
|
130
|
-
"""
|
131
|
-
return self.picture
|
132
|
-
|
133
|
-
def get_private_key(self) -> str:
|
134
|
-
"""
|
135
|
-
Returns the private key.
|
136
|
-
|
137
|
-
Returns:
|
138
|
-
str: private key in bech32 format
|
139
|
-
"""
|
140
|
-
return str(self.private_key)
|
141
|
-
|
142
|
-
def get_public_key(self) -> str:
|
143
|
-
"""
|
144
|
-
Returns the public key.
|
14
|
+
from pydantic import BaseModel, ConfigDict
|
145
15
|
|
146
|
-
Returns:
|
147
|
-
str: public key in bech32 format
|
148
|
-
"""
|
149
|
-
return str(self.public_key)
|
150
|
-
|
151
|
-
def get_url(self) -> str:
|
152
|
-
return str(self.url)
|
153
|
-
|
154
|
-
|
155
|
-
class MerchantProduct(BaseModel):
|
156
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
157
|
-
|
158
|
-
id: str
|
159
|
-
stall_id: str
|
160
|
-
name: str
|
161
|
-
description: str
|
162
|
-
images: List[str]
|
163
|
-
currency: str
|
164
|
-
price: float
|
165
|
-
quantity: int
|
166
|
-
shipping: List[ShippingCost]
|
167
|
-
categories: Optional[List[str]] = []
|
168
|
-
specs: Optional[List[List[str]]] = []
|
169
|
-
|
170
|
-
@classmethod
|
171
|
-
def from_product_data(cls, product: ProductData) -> "MerchantProduct":
|
172
|
-
return cls(
|
173
|
-
id=product.id,
|
174
|
-
stall_id=product.stall_id,
|
175
|
-
name=product.name,
|
176
|
-
description=product.description,
|
177
|
-
images=product.images,
|
178
|
-
currency=product.currency,
|
179
|
-
price=product.price,
|
180
|
-
quantity=product.quantity,
|
181
|
-
shipping=product.shipping,
|
182
|
-
categories=product.categories if product.categories is not None else [],
|
183
|
-
specs=product.specs if product.specs is not None else [],
|
184
|
-
)
|
185
|
-
|
186
|
-
def to_product_data(self) -> ProductData:
|
187
|
-
return ProductData(
|
188
|
-
id=self.id,
|
189
|
-
stall_id=self.stall_id,
|
190
|
-
name=self.name,
|
191
|
-
description=self.description,
|
192
|
-
images=self.images,
|
193
|
-
currency=self.currency,
|
194
|
-
price=self.price,
|
195
|
-
quantity=self.quantity,
|
196
|
-
shipping=self.shipping,
|
197
|
-
categories=self.categories,
|
198
|
-
specs=self.specs,
|
199
|
-
)
|
200
|
-
|
201
|
-
def to_dict(self) -> dict:
|
202
|
-
"""
|
203
|
-
Returns a dictionary representation of the MerchantProduct.
|
204
|
-
ShippingCost class is not serializable, so we need to convert it to a dictionary.
|
205
|
-
|
206
|
-
Returns:
|
207
|
-
dict: dictionary representation of the MerchantProduct
|
208
|
-
"""
|
209
|
-
shipping_dicts = []
|
210
|
-
for shipping in self.shipping:
|
211
|
-
shipping_dicts.append({"id": shipping.id, "cost": shipping.cost})
|
212
|
-
|
213
|
-
return {
|
214
|
-
"id": self.id,
|
215
|
-
"stall_id": self.stall_id,
|
216
|
-
"name": self.name,
|
217
|
-
"description": self.description,
|
218
|
-
"images": self.images,
|
219
|
-
"currency": self.currency,
|
220
|
-
"price": self.price,
|
221
|
-
"quantity": self.quantity,
|
222
|
-
"shipping": shipping_dicts,
|
223
|
-
"categories": self.categories,
|
224
|
-
"specs": self.specs,
|
225
|
-
}
|
226
|
-
|
227
|
-
|
228
|
-
class MerchantStall(BaseModel):
|
229
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
230
|
-
|
231
|
-
id: str
|
232
|
-
name: str
|
233
|
-
description: str
|
234
|
-
currency: str
|
235
|
-
shipping: List[ShippingMethod]
|
236
|
-
|
237
|
-
@classmethod
|
238
|
-
def from_stall_data(cls, stall: StallData) -> "MerchantStall":
|
239
|
-
return cls(
|
240
|
-
id=stall.id(),
|
241
|
-
name=stall.name(),
|
242
|
-
description=stall.description(),
|
243
|
-
currency=stall.currency(),
|
244
|
-
shipping=stall.shipping(),
|
245
|
-
)
|
246
|
-
|
247
|
-
def to_stall_data(self) -> StallData:
|
248
|
-
return StallData(
|
249
|
-
self.id,
|
250
|
-
self.name,
|
251
|
-
self.description,
|
252
|
-
self.currency,
|
253
|
-
self.shipping, # No conversion needed
|
254
|
-
)
|
255
16
|
|
256
|
-
|
257
|
-
"""
|
258
|
-
Returns a dictionary representation of the MerchantStall.
|
259
|
-
ShippingMethod class is not serializable, so we need to convert it to a dictionary.
|
260
|
-
We can only access cost and id from the ShippingMethod class. We can't access name or regions.
|
261
|
-
|
262
|
-
Returns:
|
263
|
-
dict: dictionary representation of the MerchantStall
|
264
|
-
"""
|
265
|
-
shipping_dicts = []
|
266
|
-
for shipping in self.shipping:
|
267
|
-
shipping_dicts.append(
|
268
|
-
{
|
269
|
-
"cost": shipping.get_shipping_cost().cost,
|
270
|
-
"id": shipping.get_shipping_cost().id,
|
271
|
-
}
|
272
|
-
)
|
273
|
-
|
274
|
-
return {
|
275
|
-
"id": self.id,
|
276
|
-
"name": self.name,
|
277
|
-
"description": self.description,
|
278
|
-
"currency": self.currency,
|
279
|
-
"shipping zones": [shipping_dicts],
|
280
|
-
}
|
281
|
-
|
282
|
-
|
283
|
-
class Merchant(Toolkit):
|
17
|
+
class MerchantTools(Toolkit):
|
284
18
|
"""
|
285
|
-
|
19
|
+
MerchantTools is a toolkit that allows a merchant to publish products and stalls to Nostr.
|
286
20
|
|
287
21
|
TBD:
|
288
22
|
- Better differentiation between products and stalls in the database and products and stalls published.
|
@@ -301,7 +35,7 @@ class Merchant(Toolkit):
|
|
301
35
|
|
302
36
|
def __init__(
|
303
37
|
self,
|
304
|
-
merchant_profile:
|
38
|
+
merchant_profile: AgentProfile,
|
305
39
|
relay: str,
|
306
40
|
stalls: List[MerchantStall],
|
307
41
|
products: List[MerchantProduct],
|
@@ -317,9 +51,7 @@ class Merchant(Toolkit):
|
|
317
51
|
super().__init__(name="merchant")
|
318
52
|
self.relay = relay
|
319
53
|
self.merchant_profile = merchant_profile
|
320
|
-
self._nostr_client = NostrClient(
|
321
|
-
self.relay, self.merchant_profile.get_private_key()
|
322
|
-
)
|
54
|
+
self._nostr_client = NostrClient(relay, merchant_profile.get_private_key())
|
323
55
|
|
324
56
|
# initialize the Product DB with no event id
|
325
57
|
self.product_db = [(product, None) for product in products]
|
@@ -327,7 +59,7 @@ class Merchant(Toolkit):
|
|
327
59
|
# initialize the Stall DB with no event id
|
328
60
|
self.stall_db = [(stall, None) for stall in stalls]
|
329
61
|
|
330
|
-
# Register
|
62
|
+
# Register methods
|
331
63
|
self.register(self.get_profile)
|
332
64
|
self.register(self.get_relay)
|
333
65
|
self.register(self.get_products)
|
@@ -347,19 +79,25 @@ class Merchant(Toolkit):
|
|
347
79
|
|
348
80
|
def get_profile(self) -> str:
|
349
81
|
"""
|
350
|
-
|
82
|
+
Get the merchant profile in JSON format
|
351
83
|
|
352
84
|
Returns:
|
353
85
|
str: merchant profile in JSON format
|
354
86
|
"""
|
355
|
-
return json.dumps(self.merchant_profile.
|
87
|
+
return json.dumps(self.merchant_profile.to_json())
|
356
88
|
|
357
89
|
def get_relay(self) -> str:
|
90
|
+
"""
|
91
|
+
Get the Nostr relay the merchant is using
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
str: Nostr relay
|
95
|
+
"""
|
358
96
|
return self.relay
|
359
97
|
|
360
98
|
def get_products(self) -> str:
|
361
99
|
"""
|
362
|
-
|
100
|
+
Get all the merchant products
|
363
101
|
|
364
102
|
Returns:
|
365
103
|
str: JSON string containing all products
|
@@ -368,7 +106,7 @@ class Merchant(Toolkit):
|
|
368
106
|
|
369
107
|
def get_stalls(self) -> str:
|
370
108
|
"""
|
371
|
-
|
109
|
+
Get all the merchant stalls in JSON format
|
372
110
|
|
373
111
|
Returns:
|
374
112
|
str: JSON string containing all stalls
|
@@ -379,10 +117,13 @@ class Merchant(Toolkit):
|
|
379
117
|
self,
|
380
118
|
) -> str:
|
381
119
|
"""
|
382
|
-
Publishes or updates
|
120
|
+
Publishes or updates to Nostrall products in the Merchant's Product DB
|
383
121
|
|
384
122
|
Returns:
|
385
123
|
str: JSON array with status of all product publishing operations
|
124
|
+
|
125
|
+
Raises:
|
126
|
+
ValueError: if NostrClient is not initialized
|
386
127
|
"""
|
387
128
|
|
388
129
|
if self._nostr_client is None:
|
@@ -393,9 +134,9 @@ class Merchant(Toolkit):
|
|
393
134
|
for i, (product, _) in enumerate(self.product_db):
|
394
135
|
try:
|
395
136
|
# Convert MerchantProduct to ProductData for nostr_client
|
396
|
-
product_data = product.to_product_data()
|
137
|
+
# product_data = product.to_product_data()
|
397
138
|
# Publish using the SDK's synchronous method
|
398
|
-
event_id = self._nostr_client.publish_product(
|
139
|
+
event_id = self._nostr_client.publish_product(product)
|
399
140
|
self.product_db[i] = (product, event_id)
|
400
141
|
results.append(
|
401
142
|
{
|
@@ -404,8 +145,10 @@ class Merchant(Toolkit):
|
|
404
145
|
"product_name": product.name,
|
405
146
|
}
|
406
147
|
)
|
148
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
149
|
+
time.sleep(0.5)
|
407
150
|
except Exception as e:
|
408
|
-
|
151
|
+
logging.error(f"Unable to publish product {product}. Error {e}")
|
409
152
|
results.append(
|
410
153
|
{"status": "error", "message": str(e), "product_name": product.name}
|
411
154
|
)
|
@@ -416,10 +159,13 @@ class Merchant(Toolkit):
|
|
416
159
|
self,
|
417
160
|
) -> str:
|
418
161
|
"""
|
419
|
-
Publishes or updates all stalls managed by the merchant and adds the corresponding EventId to the Stall DB
|
162
|
+
Publishes or updates to Nostr all stalls managed by the merchant and adds the corresponding EventId to the Stall DB
|
420
163
|
|
421
164
|
Returns:
|
422
165
|
str: JSON array with status of all stall publishing operations
|
166
|
+
|
167
|
+
Raises:
|
168
|
+
ValueError: if NostrClient is not initialized
|
423
169
|
"""
|
424
170
|
if self._nostr_client is None:
|
425
171
|
raise ValueError("NostrClient not initialized")
|
@@ -427,9 +173,9 @@ class Merchant(Toolkit):
|
|
427
173
|
|
428
174
|
for i, (stall, _) in enumerate(self.stall_db):
|
429
175
|
try:
|
430
|
-
#
|
431
|
-
stall_data = stall.to_stall_data()
|
432
|
-
event_id = self._nostr_client.publish_stall(
|
176
|
+
# We don't need to convert MerchantStall to StallData for nostr_client
|
177
|
+
# stall_data = stall.to_stall_data()
|
178
|
+
event_id = self._nostr_client.publish_stall(stall)
|
433
179
|
self.stall_db[i] = (stall, event_id)
|
434
180
|
results.append(
|
435
181
|
{
|
@@ -438,8 +184,10 @@ class Merchant(Toolkit):
|
|
438
184
|
"stall_name": stall.name,
|
439
185
|
}
|
440
186
|
)
|
187
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
188
|
+
time.sleep(0.5)
|
441
189
|
except Exception as e:
|
442
|
-
|
190
|
+
logging.error(f"Unable to publish stall {stall}. Error {e}")
|
443
191
|
results.append(
|
444
192
|
{"status": "error", "message": str(e), "stall_name": stall.name}
|
445
193
|
)
|
@@ -448,13 +196,16 @@ class Merchant(Toolkit):
|
|
448
196
|
|
449
197
|
def publish_new_product(self, product: MerchantProduct) -> str:
|
450
198
|
"""
|
451
|
-
Publishes
|
199
|
+
Publishes to Nostra new product that is not currently in the Merchant's Product DB and adds it to the Product DB
|
452
200
|
|
453
201
|
Args:
|
454
202
|
product: MerchantProduct to be published
|
455
203
|
|
456
204
|
Returns:
|
457
205
|
str: JSON string with status of the operation
|
206
|
+
|
207
|
+
Raises:
|
208
|
+
ValueError: if NostrClient is not initialized
|
458
209
|
"""
|
459
210
|
if self._nostr_client is None:
|
460
211
|
raise ValueError("NostrClient not initialized")
|
@@ -480,12 +231,15 @@ class Merchant(Toolkit):
|
|
480
231
|
|
481
232
|
def publish_product_by_name(self, arguments: str) -> str:
|
482
233
|
"""
|
483
|
-
Publishes or updates
|
234
|
+
Publishes or updates to Nostra given product from the Merchant's Product DB
|
484
235
|
Args:
|
485
236
|
arguments: JSON string that may contain {"name": "product_name"} or just "product_name"
|
486
237
|
|
487
238
|
Returns:
|
488
239
|
str: JSON string with status of the operation
|
240
|
+
|
241
|
+
Raises:
|
242
|
+
ValueError: if NostrClient is not initialized
|
489
243
|
"""
|
490
244
|
if self._nostr_client is None:
|
491
245
|
raise ValueError("NostrClient not initialized")
|
@@ -508,9 +262,9 @@ class Merchant(Toolkit):
|
|
508
262
|
if product.name == name:
|
509
263
|
try:
|
510
264
|
# Convert MerchantProduct to ProductData for nostr_client
|
511
|
-
product_data = product.to_product_data()
|
265
|
+
# product_data = product.to_product_data()
|
512
266
|
# Publish using the SDK's synchronous method
|
513
|
-
event_id = self._nostr_client.publish_product(
|
267
|
+
event_id = self._nostr_client.publish_product(product)
|
514
268
|
# Update the product_db with the new event_id
|
515
269
|
self.product_db[i] = (product, event_id)
|
516
270
|
return json.dumps(
|
@@ -520,6 +274,8 @@ class Merchant(Toolkit):
|
|
520
274
|
"product_name": product.name,
|
521
275
|
}
|
522
276
|
)
|
277
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
278
|
+
time.sleep(0.5)
|
523
279
|
except Exception as e:
|
524
280
|
return json.dumps(
|
525
281
|
{
|
@@ -540,7 +296,7 @@ class Merchant(Toolkit):
|
|
540
296
|
|
541
297
|
def publish_products_by_stall_name(self, arguments: Union[str, dict]) -> str:
|
542
298
|
"""
|
543
|
-
Publishes or updates all products sold by the merchant in a given stall
|
299
|
+
Publishes or updates to Nostr all products sold by the merchant in a given stall
|
544
300
|
|
545
301
|
Args:
|
546
302
|
arguments: str or dict with the stall name. Can be in formats:
|
@@ -550,6 +306,9 @@ class Merchant(Toolkit):
|
|
550
306
|
|
551
307
|
Returns:
|
552
308
|
str: JSON array with status of all product publishing operations
|
309
|
+
|
310
|
+
Raises:
|
311
|
+
ValueError: if NostrClient is not initialized
|
553
312
|
"""
|
554
313
|
if self._nostr_client is None:
|
555
314
|
raise ValueError("NostrClient not initialized")
|
@@ -604,8 +363,8 @@ class Merchant(Toolkit):
|
|
604
363
|
for i, (product, _) in enumerate(self.product_db):
|
605
364
|
if product.stall_id == stall_id:
|
606
365
|
try:
|
607
|
-
product_data = product.to_product_data()
|
608
|
-
event_id = self._nostr_client.publish_product(
|
366
|
+
# product_data = product.to_product_data()
|
367
|
+
event_id = self._nostr_client.publish_product(product)
|
609
368
|
self.product_db[i] = (product, event_id)
|
610
369
|
results.append(
|
611
370
|
{
|
@@ -615,6 +374,8 @@ class Merchant(Toolkit):
|
|
615
374
|
"stall_name": stall_name,
|
616
375
|
}
|
617
376
|
)
|
377
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
378
|
+
time.sleep(0.5)
|
618
379
|
except Exception as e:
|
619
380
|
results.append(
|
620
381
|
{
|
@@ -645,7 +406,7 @@ class Merchant(Toolkit):
|
|
645
406
|
|
646
407
|
def publish_profile(self) -> str:
|
647
408
|
"""
|
648
|
-
Publishes the profile
|
409
|
+
Publishes the profile to Nostr
|
649
410
|
|
650
411
|
Returns:
|
651
412
|
str: JSON of the event that published the profile
|
@@ -668,22 +429,25 @@ class Merchant(Toolkit):
|
|
668
429
|
|
669
430
|
def publish_new_stall(self, stall: MerchantStall) -> str:
|
670
431
|
"""
|
671
|
-
Publishes a new stall that is not currently in the Merchant's Stall DB and adds it to the Stall DB
|
432
|
+
Publishes to Nostr a new stall that is not currently in the Merchant's Stall DB and adds it to the Stall DB
|
672
433
|
|
673
434
|
Args:
|
674
435
|
stall: MerchantStall to be published
|
675
436
|
|
676
437
|
Returns:
|
677
438
|
str: JSON string with status of the operation
|
439
|
+
|
440
|
+
Raises:
|
441
|
+
ValueError: if NostrClient is not initialized
|
678
442
|
"""
|
679
443
|
if self._nostr_client is None:
|
680
444
|
raise ValueError("NostrClient not initialized")
|
681
445
|
|
682
446
|
try:
|
683
|
-
#
|
684
|
-
stall_data = stall.to_stall_data()
|
685
|
-
# Publish using the
|
686
|
-
event_id = self._nostr_client.publish_stall(
|
447
|
+
# We don't ned to convert to StallData. nostr_client.publish_stall() accepts a MerchantStall
|
448
|
+
# stall_data = stall.to_stall_data()
|
449
|
+
# Publish using the synchronous method
|
450
|
+
event_id = self._nostr_client.publish_stall(stall)
|
687
451
|
# we need to add the stall event id to the stall db
|
688
452
|
self.stall_db.append((stall, event_id))
|
689
453
|
return json.dumps(
|
@@ -699,6 +463,21 @@ class Merchant(Toolkit):
|
|
699
463
|
)
|
700
464
|
|
701
465
|
def publish_stall_by_name(self, arguments: Union[str, dict]) -> str:
|
466
|
+
"""
|
467
|
+
Publishes or updates to Nostr a given stall by name
|
468
|
+
|
469
|
+
Args:
|
470
|
+
arguments: str or dict with the stall name. Can be in formats:
|
471
|
+
- {"name": "stall_name"}
|
472
|
+
- {"arguments": "{\"name\": \"stall_name\"}"}
|
473
|
+
- "stall_name"
|
474
|
+
|
475
|
+
Returns:
|
476
|
+
str: JSON array with status of the operation
|
477
|
+
|
478
|
+
Raises:
|
479
|
+
ValueError: if NostrClient is not initialized
|
480
|
+
"""
|
702
481
|
if self._nostr_client is None:
|
703
482
|
raise ValueError("NostrClient not initialized")
|
704
483
|
|
@@ -735,8 +514,9 @@ class Merchant(Toolkit):
|
|
735
514
|
for i, (stall, _) in enumerate(self.stall_db):
|
736
515
|
if stall.name == stall_name:
|
737
516
|
try:
|
738
|
-
|
739
|
-
|
517
|
+
# We are not passing StallData to nostr_client.publish_stall() anymore
|
518
|
+
# stall_data = stall.to_stall_data()
|
519
|
+
event_id = self._nostr_client.publish_stall(stall)
|
740
520
|
self.stall_db[i] = (stall, event_id)
|
741
521
|
return json.dumps(
|
742
522
|
{
|
@@ -745,6 +525,8 @@ class Merchant(Toolkit):
|
|
745
525
|
"stall_name": stall.name,
|
746
526
|
}
|
747
527
|
)
|
528
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
529
|
+
time.sleep(0.5)
|
748
530
|
except Exception as e:
|
749
531
|
return json.dumps(
|
750
532
|
[
|
@@ -774,10 +556,13 @@ class Merchant(Toolkit):
|
|
774
556
|
|
775
557
|
def remove_all_products(self) -> str:
|
776
558
|
"""
|
777
|
-
Removes all published
|
559
|
+
Removes from Nostr all products published by the merchant
|
778
560
|
|
779
561
|
Returns:
|
780
562
|
str: JSON array with status of all product removal operations
|
563
|
+
|
564
|
+
Raises:
|
565
|
+
ValueError: if NostrClient is not initialized
|
781
566
|
"""
|
782
567
|
if self._nostr_client is None:
|
783
568
|
raise ValueError("NostrClient not initialized")
|
@@ -810,6 +595,8 @@ class Merchant(Toolkit):
|
|
810
595
|
"event_id": str(event_id),
|
811
596
|
}
|
812
597
|
)
|
598
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
599
|
+
time.sleep(0.5)
|
813
600
|
except Exception as e:
|
814
601
|
results.append(
|
815
602
|
{"status": "error", "message": str(e), "product_name": product.name}
|
@@ -819,10 +606,13 @@ class Merchant(Toolkit):
|
|
819
606
|
|
820
607
|
def remove_all_stalls(self) -> str:
|
821
608
|
"""
|
822
|
-
Removes all stalls and their products
|
609
|
+
Removes from Nostr all stalls from the merchant and their corresponding products
|
823
610
|
|
824
611
|
Returns:
|
825
612
|
str: JSON array with status of all removal operations
|
613
|
+
|
614
|
+
Raises:
|
615
|
+
ValueError: if NostrClient is not initialized
|
826
616
|
"""
|
827
617
|
if self._nostr_client is None:
|
828
618
|
raise ValueError("NostrClient not initialized")
|
@@ -897,6 +687,8 @@ class Merchant(Toolkit):
|
|
897
687
|
"event_id": str(stall_event_id),
|
898
688
|
}
|
899
689
|
)
|
690
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
691
|
+
time.sleep(0.5)
|
900
692
|
except Exception as e:
|
901
693
|
results.append(
|
902
694
|
{"status": "error", "message": str(e), "stall_name": stall_name}
|
@@ -906,13 +698,16 @@ class Merchant(Toolkit):
|
|
906
698
|
|
907
699
|
def remove_product_by_name(self, arguments: str) -> str:
|
908
700
|
"""
|
909
|
-
|
701
|
+
Removes from Nostr a product with the given name
|
910
702
|
|
911
703
|
Args:
|
912
704
|
arguments: JSON string that may contain {"name": "product_name"} or just "product_name"
|
913
705
|
|
914
706
|
Returns:
|
915
707
|
str: JSON string with status of the operation
|
708
|
+
|
709
|
+
Raises:
|
710
|
+
ValueError: if NostrClient is not initialized
|
916
711
|
"""
|
917
712
|
if self._nostr_client is None:
|
918
713
|
raise ValueError("NostrClient not initialized")
|
@@ -949,6 +744,8 @@ class Merchant(Toolkit):
|
|
949
744
|
)
|
950
745
|
# Remove the event_id, keeping the product in the database
|
951
746
|
self.product_db[i] = (product, None)
|
747
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
748
|
+
time.sleep(0.5)
|
952
749
|
return json.dumps(
|
953
750
|
{
|
954
751
|
"status": "success",
|
@@ -972,7 +769,8 @@ class Merchant(Toolkit):
|
|
972
769
|
)
|
973
770
|
|
974
771
|
def remove_stall_by_name(self, arguments: Union[str, dict]) -> str:
|
975
|
-
"""
|
772
|
+
"""
|
773
|
+
Remove from Nostr a stall and its products by name
|
976
774
|
|
977
775
|
Args:
|
978
776
|
arguments: str or dict with the stall name. Can be in formats:
|
@@ -982,6 +780,9 @@ class Merchant(Toolkit):
|
|
982
780
|
|
983
781
|
Returns:
|
984
782
|
str: JSON array with status of the operation
|
783
|
+
|
784
|
+
Raises:
|
785
|
+
ValueError: if NostrClient is not initialized
|
985
786
|
"""
|
986
787
|
if self._nostr_client is None:
|
987
788
|
raise ValueError("NostrClient not initialized")
|
@@ -1063,6 +864,8 @@ class Merchant(Toolkit):
|
|
1063
864
|
"event_id": str(event_id),
|
1064
865
|
}
|
1065
866
|
)
|
867
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
868
|
+
time.sleep(0.5)
|
1066
869
|
except Exception as e:
|
1067
870
|
results.append(
|
1068
871
|
{
|
@@ -1117,15 +920,15 @@ class Merchant(Toolkit):
|
|
1117
920
|
[{"status": "error", "message": str(e), "stall_name": "unknown"}]
|
1118
921
|
)
|
1119
922
|
|
1120
|
-
def get_event_id(self, response: Any) -> str:
|
1121
|
-
|
923
|
+
# def get_event_id(self, response: Any) -> str:
|
924
|
+
# """Convert any response to a string event ID.
|
1122
925
|
|
1123
|
-
|
1124
|
-
|
926
|
+
# Args:
|
927
|
+
# response: Response that might contain an event ID
|
1125
928
|
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
929
|
+
# Returns:
|
930
|
+
# str: String representation of event ID or empty string if None
|
931
|
+
# """
|
932
|
+
# if response is None:
|
933
|
+
# return ""
|
934
|
+
# return str(response)
|