upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/90.md
diff options
context:
space:
mode:
authorpablof7z <p@f7z.io>2023-07-25 17:20:24 +0300
committerpablof7z <p@f7z.io>2023-07-25 17:26:09 +0300
commit948ee24775fe89e779efe7680ca6a27dc5a6207f (patch)
treeae6e0d7d7e25d65c919c16229bf267730fc346b1 /90.md
parent723103506030749fc2bba9d5b4ddaf607dd24da3 (diff)
rename file
Diffstat (limited to '90.md')
-rw-r--r--90.md439
1 files changed, 439 insertions, 0 deletions
diff --git a/90.md b/90.md
new file mode 100644
index 0000000..99f313d
--- /dev/null
+++ b/90.md
@@ -0,0 +1,439 @@
1NIP-90
2======
3
4Data Vending Machine
5--------------------
6
7`draft` `optional` `author:pablof7z`
8
9This NIP defines the interaction between customers and Service Providers for performing on-demand computation.
10
11Money in, data out.
12
13## Kinds
14This NIP reserves the range `65000-66000` for data vending machine use.
15
16| Kind | Description |
17| ---- | ----------- |
18| 65000 | Job feedback |
19| 65001 | Job result |
20| 65002-66000 | Job request kinds |
21
22[Appendix 2](#appendix-2-job-types) defines the job request types.
23
24## Rationale
25Nostr can act as a marketplace for data processing, where users request jobs to be processed in certain ways (e.g., "speech-to-text", "summarization", etc.), but they don't necessarily care about "who" processes the data.
26
27This NIP is not to be confused with a 1:1 marketplace; instead, it describes a flow where a user announces a desired output, willingness to pay, and service providers compete to fulfill the job requirement in the best way possible.
28
29### Actors
30There are two actors in the workflow described in this NIP:
31* Customers (npubs who request a job)
32* Service providers (npubs who fulfill jobs)
33
34# Event Kinds
35
36* `kind:65000`: job feedback
37* `kind:65001`: job result
38* `kind:65002`-`kind:66000`: job requests
39
40## Job request
41A request to have data processed, published by a customer. This event signals that an npub is interested in receiving the result of some kind of compute.
42
43```json
44{
45 "kind": 65xxx, // kind in 65002-66000 range
46 "content": "",
47 "tags": [
48 [ "i", "<data>", "<input-type>", "<marker>", "<relay>" ],
49 [ "output", "<mime-type>" ],
50 [ "relays", "wss://..."],
51 [ "bid", "<msat-amount>" ],
52 [ "t", "bitcoin" ]
53 ]
54}
55```
56
57All tags are optional.
58
59* `i` tag: Input data for the job (zero or more inputs)
60 * `<data>`: The argument for the input
61 * `<input-type>`: The way this argument should be interpreted. MUST be one of:
62 * `url`: A URL to be fetched
63 * `event`: A Nostr event ID.
64 * `job`: The output of a previous job with the specified event ID
65 * `text`: `<data>` is the value of the input, no resolution is needed
66 * `<marker>`: An optional field indicating how this input should be used within the context of the job
67 * `<relay>`: If `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string
68* `output`: Expected output format. (e.g. MIME type)
69 * Service Providers MUST publish the result of the job in this format if it has been specified.
70 * Each job-type ([Appendix 2](#appendix-2-job-types)) might define the output format more narrowly.
71* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay
72* `relays`: List of relays where Service Providers SHOULD publish responses to
73* `p`: Service Providers the customer is interested in. Other SPs MIGHT still choose to process the job
74
75## Job result
76
77Service providers publish job results, providing the output of the job result. They should tag the original job request event id as well as the customer's pubkey.
78
79```json
80{
81 "pubkey": "<service-provider pubkey>",
82 "content": "<payload>",
83 "kind": 65001,
84 "tags": [
85 [ "request", "<job-request>" ],
86 [ "e", "<job-request-id>", "<relay-hint>" ],
87 [ "p", "<customer's-pubkey>" ],
88 [ "amount", "requested-payment-amount", "<optional-bolt11>" ]
89 ]
90}
91```
92
93* `request`: The job request event stringified-JSON.
94* `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11 invoice.
95
96## Job feedback
97Service providers can give feedback about a job back to the customer.
98
99```json
100{
101 "kind": 65000,
102 "content": "<empty-or-payload>",
103 "tags": [
104 [ "status", "<status>", "<extra-info>" ],
105 [ "amount", "requested-payment-amount", "<bolt11>" ],
106 [ "e", "<job-request-id>", "<relay-hint>" ],
107 [ "p", "<customer's-pubkey>" ],
108 ]
109}
110```
111
112* `content`: Either empty or a job-result (e.g. for partial-result samples)
113* `status` tag: Service Providers SHOULD indicate what this feedback status refers to. [Appendix 3](#appendix-3-job-feedback-status) defines status. Extra human-readable information can be added as an extra argument.
114* `amount` tag: as defined in the [Job Result](#job-result) section.
115
116# Protocol Flow
117* Customer publishes a job request (e.g. `kind:65002` speech-to-text).
118* Service Providers can submit `kind:65000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
119* Upon completion, the service provider publishes the result of the job with a `kind:65001` job-result event.
120* At any point, if there is an `amount` pending to be paid as instructed by the service provider, the user can pay the included `bolt11` or zap the job result event the service provider has sent to the user
121
122`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD use the `payment-required` feedback event to signal that a payment is required and no further actions will be performed until the payment is sent. Customers can always either pay the included `bolt11` invoice or zap the event requesting the payment and service providers should monitor for both if they choose to include a bolt11 invoice.
123
124## Notes about the protocol flow
125The flow is deliberately ambiguous, allowing vast flexibility for the interaction between customers and service providers so that service providers can model their behavior based on their own decisions/perceptions of risk.
126
127Some service providers might choose to submit a `payment-required` as the first reaction before sending a `processing` or before delivering `kind:65001` results, some might choose to serve partial results for the job (e.g. as a sample), send a `payment-required` to deliver the rest of the results, and some service providers might choose to assess likelihood of payment based on an npub's past behavior and thus serve the job results before requesting payment for the best possible UX.
128
129It's not up to this NIP to define how individual vending machines should choose to run their business.
130
131# Cancellation
132A job request might be cancelled by publishing a `kind:5` delete request event tagging the job request event.
133
134# Job chaining
135A Customer MAY request multiple jobs to be processed as a chain, where the output of a job can be the input of another job. (e.g. podcast transcription -> summarization of the transcription). This is done by specifying as input an event id of a different job with the `job` type.
136
137Service Providers MAY begin processing a subsequent job the moment they see the prior job's result, but they will likely wait for a zap to be published first. This introduces a risk that Service Provider of job #1 might delay publishing the zap event in order to have an advantage. This risk is up to Service Providers to mitigate or to decide whether the service provider of job #1 tends to have good-enough results so as to not wait for an explicit zap to assume the job was accepted.
138
139This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
140
141Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcast](#summarization-of-a-podcast)
142
143### E.g. Payment required (with sample content)
144```json
145{
146 "kind": 65000,
147 "content": "This is the transcription service that you",
148 "tags": [
149 [ "e", <job-request-id>, <relay-hint> ],
150 [ "p", <customer-pubkey> ],
151 [ "status", "payment-required" ],
152 [ "amount", "7000" ],
153 ]
154}
155```
156
157# Appendix 1: Examples
158
159## Transcript of a podcast from second `900` to `930`.
160
161### `kind:65002`: Speech-to-text job request
162```json
163{
164 "id": "12345",
165 "pubkey": "abcdef",
166 "content": "",
167 "kind": 65002,
168 "tags": [
169 [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
170 [ "params", "range", "900", "930" ],
171 [ "output", "text/vtt" ],
172 [ "bid", "50000" ],
173 [ "output", "text/plain" ]
174 ]
175}
176```
177
178### `kind:65000`: Job Feedback: request for (partial) payment
179* The SP is signaling here that it won't start processing until 100 sats are paid
180```json
181{
182 "kind": 65000,
183 "content": "",
184 "tags": [
185 ["e", "12345"],
186 ["p", "abcdef"],
187 ["status", "payment-required"],
188 ["amount", "100000"]
189 ]
190}
191```
192
193* User zaps 100 sats to the `kind:65000` job-feedback
194
195### `kind:65001`: Job result + request for remaining payment
196```json
197{
198 "content": "blah blah blah",
199 "tags": [
200 ["e", "12345"],
201 ["p", "abcdef"],
202 ["amount", "400000"]
203 ]
204}
205```
206
207## Summarization of a podcast
208User publishes two job requests at the same time. A job that transcribes an audio and a job that summarizes the transcription (output of job #1).
209
210User publishes event #1 and #2 together.
211
212### `kind:65002`: Job Request #1: speech-to-text
213```json
214{
215 "id": "12345",
216 "pubkey": "abcdef",
217 "kind": 65002,
218 "content": "",
219 "tags": [
220 [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
221 [ "output", "text/plain" ],
222 [ "params", "range", "900", "930" ],
223 [ "bid", "100000" ]
224 ]
225}
226```
227
228### `kind:65002`: Job Request #2: summarization of job #1's result
229```json
230{
231 "id": "12346",
232 "pubkey": "abcdef",
233 "kind": 65003,
234 "content": "",
235 "tags": [
236 [ "i", "12345", "job" ], // input is the output of job with id 12345
237 [ "output", "text/plain" ],
238 [ "params", "length", "3 paragraphs" ],
239 [ "bid", "10000" ]
240 ]
241}
242```
243
244## Translation of a note
245### `kind:65004`: Job Request #1: translation of an existing note
246```json
247{
248 "id": "12346",
249 "pubkey": "abcdef",
250 "content": "",
251 "kind": 65004,
252 "tags": [
253 [ "i", "<hexid>", "event", "wss://relay.nostr.com" ]
254 [ "output", "text/plain" ],
255 [ "params", "lang", "es_AR" ],
256 [ "bid", "5000" ]
257 ]
258}
259```
260
261### `kind:65001`: Job result
262```json
263{
264 "kind": 65001,
265 "content": "Che, que copado, boludo!",
266 "tags": [
267 ["e", "12346"],
268 ["p", "abcdef"],
269 ["amount", "4000"]
270 ]
271}
272```
273
274## AI-image of the summarization of 2 podcasts
275
276### `kind:65002`: Job request #1 (transcribe podcast #1)
277```json
278{
279 "id": "123",
280 "kind": 65002,
281 "tags": [
282 [ "i", "https://example.com/episode1.mp3", "url" ],
283 [ "bid", "100000" ]
284 ]
285}
286```
287
288### `kind:65002`: Job request #2 (transcribe podcast #2)
289```json
290{
291 "id": "124",
292 "kind": 65002,
293 "tags": [
294 [ "i", "https://example.com/episode2.mp3", "url" ],
295 [ "bid", "100000" ]
296 ]
297}
298```
299
300### `kind:65003`: Job request #3 (summarize the two job's outputs into one paragraph)
301```json
302{
303 "id": "125",
304 "kind": 65003,
305 "tags": [
306 [ "param", "length", "1 paragraph" ],
307 [ "i", "123", "job" ],
308 [ "i", "124", "job" ],
309 [ "bid", "100000" ]
310 ]
311}
312```
313
314### `kind:65005`: Job request #4 (generate image based on the summary)
315```json
316{
317 "id": "126",
318 "kind": 65004,
319 "tags": [
320 [ "i", "125", "job" ],
321 [ "param", "prompt", "photorealistic" ],
322 [ "param", "size", "4000x4000" ],
323 [ "bid", "500000" ]
324 ]
325}
326```
327
328## AI-image of embedded input
329
330### `kind:65005`: Job request
331```json
332{
333 "kind": 65004,
334 "tags": [
335 [ "i", "Millions of vending machines, interconnected with tubes with eah other", "text" ],
336 [ "param", "prompt", "photorealistic" ],
337 [ "bid", "500000" ]
338 ]
339}
340```
341
342# Appendix 2: Job types
343
344This is a list of all the supported job requests.
345
346## speech-to-text: `kind:65002`
347
348### params
349
350| param | req? | description |
351|------------|------|-----------------------------------------------------------|
352| `range` | opt | timestamp range (in seconds) of desired text to be transcribed |
353| `alignment`| opt | word, segment, raw: word-level, segment-level, or raw outputs |
354
355## summarization: `kind:65003`
356
357| param | req? | description |
358|-----------|------|---------------|
359| `length` | opt | desired length |
360
361## translation: `kind:65004`
362
363| param | req? | description |
364|-----------|------|--------------------------------------------|
365| `lang` | req | desired language in BCP 47 format. |
366
367## image generation: `kind:65005`
368
369| param | req? | description |
370|-----------|------|-------------------------------------------------------|
371| `prompt` | opt | extra prompt to be used for the image generation |
372| `size` | opt | desired size of the image |
373
374## event list generation: `kind:65006`
375
376Generates a list of event ids, (e.g. algorithmic feeds, spam-free notifications, trending topics)
377
378Output should be a stringified array of elements usually find in a nostr event' `tags`, e.g.:
379
380```json
381{ "content": "[
382 [\"e\", \"<id>\"],
383 [\"a\", \"30023:pubkey:id\"],
384 [\"t\", \"tag\"],
385 [\"p\", \"pubkey\"],
386]" }
387```
388
389| param | req? | description |
390|-----------|------|-------------------------------------------------------|
391| `filter` | opt | JSON-stringified `REQ`-like filter
392| `prompt` | opt | A human-readable description of the desired results. Which might be used with e.g. an LLM to tune the results.
393| `p` | opt | Array of pubkeys to generate a feed from someone else's point-of-view. This param allows for a client to choose to generate the feeds and incur the costs of its users.
394
395### example job-request
396
397Generate an algorithmic feed of the most interesting `kind:1`s related to the topic "bitcoin", tagging service providers specializing in safe-for-work content
398that would interest pubkey `pubkey1`.
399
400```json
401{
402 "kind": 65006,
403 "tags": [
404 [ "param", "filter", "{ \"kinds\": [1], \"#t\": [\"bitcoin\"] }" ],
405 [ "param", "p", "[\"pubkey1\"]"]
406 [ "bid", "5000" ],
407 [ "t", "sfw" ]
408 ]
409}
410```
411
412# Appendix 3: Job feedback status
413
414| status | description |
415|--------|-------------|
416| `payment-required` | Service Provider requires payment before continuing. |
417| `processing` | Service Provider is processing the job. |
418| `error` | Service Provider was unable to process the job. |
419| `success` | Service Provider successfully processed the job. |
420| `partial` | Service Provider partially processed the job. The `.content` might include a sample of the partial results. |
421
422Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result) section. This is useful for service providers to provide a sample of the results that have been processed so far.
423
424# Appendix 4: Service provider discoverability
425
426Service Providers can use NIP-89 announcements to advertise their support for job kinds:
427
428```json
429{
430 "kind": 31990,
431 "pubkey": "<pubkey>",
432 "tags": [
433 [ "k", 65002 ], // e.g. speech-to-text
434 [ "t", "bitcoin" ] // e.g. optionally advertises it specializes in bitcoin audio transcription that won't confuse "Drivechains" with "Ridechains"
435 ]
436}
437```
438
439Customers can use NIP-89 to see what service providers their follows use. \ No newline at end of file