upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vending-machine.md206
1 files changed, 138 insertions, 68 deletions
diff --git a/vending-machine.md b/vending-machine.md
index a94cd33..eb26688 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -1,8 +1,15 @@
1# NIP-XX: Data Vending Machine 1NIP-XX
2Money in, data out. 2======
3
4Data Vending Machine
5--------------------
6
7`draft` `optional` `author:pablof7z`
8
9This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
3 10
4## Rationale 11## Rationale
5Nostr can act as a marketplace for data processing, where users request jobs to be processed in certain ways (e.g. "speech-to-text", "summarization"), but where they don't necessarily care about "who" processes the data. 12Nostr 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 where they don't necessarily care about "who" processes the data.
6 13
7This NIP is not to be confused with a 1:1 marketplace; but rather, a flow where user announces a desired output, willigness to pay, and service providers compete to fulfill the job requirement in the best way possible. 14This NIP is not to be confused with a 1:1 marketplace; but rather, a flow where user announces a desired output, willigness to pay, and service providers compete to fulfill the job requirement in the best way possible.
8 15
@@ -11,26 +18,9 @@ There are two actors to the workflow described in this NIP:
11* Customers (npubs who request a job) 18* Customers (npubs who request a job)
12* Service providers (npubs who fulfill jobs) 19* Service providers (npubs who fulfill jobs)
13 20
14## User flow 21# Event Kinds
15* User publishes a job request 22## Job request
16`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }` 23A request to have data processed -- published by a customer
17
18* Service providers listen for the type of jobs they can perform
19`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
20
21* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it
22* Upon completion, the service provider publishes the result of the job with a `job-result` event.
23* Upon acceptance, the user zaps the service provider, tagging the job request
24
25## Kinds
26
27This NIP introduces two new kinds:
28
29* `kind:68001`: Job request -- a request to have a job be processed
30* `kind:68002`: Job result -- a proposal of the resulting job
31
32### Job request
33A request to have data processed -- published by a user
34 24
35```json 25```json
36{ 26{
@@ -38,40 +28,35 @@ A request to have data processed -- published by a user
38 "content": "", 28 "content": "",
39 "tags": [ 29 "tags": [
40 // The type data processing the user wants to be performed 30 // The type data processing the user wants to be performed
41 // on the 31 [ "j", "<job-type>", "<optional-model>" ],
42 [ "j", "<job-type>", "<model>" ],
43 [ "input", "<data>", "<input-type>", "<marker>" ],
44 [ "relays", "wss://..."],
45 32
46 // stringified sat amount that the user is offering to pay 33 // input(s) for the job request
47 // for this request 34 [ "i", "<data>", "<input-type>", "<marker>" ],
48 // should this include an optional max price or is it too
49 // ambiguous?
50 [ "bid", "<sat-amount>", ["<optional-max-price>"] ],
51 35
52 // max timestamp at which the job is no longer to be processed 36 // relays where the job result should be published
53 [ "expiration", "<timestamp>" ] 37 [ "relays", "wss://..."],
54 38
55 // p tags 39 // millisats amount that the user is offering to pay
40 [ "bid", "<msat-amount>", "<optional-max-price>" ],
41 [ "exp", "<timestamp>" ],
56 [ "p", "service-provider-1" ], 42 [ "p", "service-provider-1" ],
57 [ "p", "service-provider-2" ], 43 [ "p", "service-provider-2" ],
58
59 // NIP-33 d-tag
60 [ "d", "<unique-job-name>"]
61 ] 44 ]
62} 45}
63``` 46```
64 47
65#### `content` field 48### `content` field
66An optional, human-readable description of what this job is for. 49An optional, human-readable description of what this job is for.
67 50
68#### `j` tag 51### `j` tag
69Specifies the job to be executed. A job request MUST have exactly one `j` tag. 52Specifies the job to be executed. A job request MUST have exactly one `j` tag.
70 53
71A `j` tag MIGHT name a specific model to be used for the computed with. 54A `j` tag MIGHT name a specific model to be used for the computed with as the second value.
72 55
73#### `input` tag 56### `i` (input) tag
74Specified the input that the job should be executed with. 57Specifies the input that the job should be executed with. The input is relay-indexable so that clients interested in the exact same job can find it it's result if it's already fulfilled.
58
59A job request CAN have zero or more inputs.
75 60
76* `<data>`: The argument for the input 61* `<data>`: The argument for the input
77* `<input-type>`: The way this argument should be interpreted 62* `<input-type>`: The way this argument should be interpreted
@@ -81,17 +66,20 @@ Specified the input that the job should be executed with.
81 * `job`: the output of a previous job with the specified event ID 66 * `job`: the output of a previous job with the specified event ID
82* `<marker>`: 67* `<marker>`:
83 68
84#### `relays` tag 69### `bid` tag
70The user MIGHT specify an amount of millisats they are willing to pay for the job to be processed. The user MIGHT also specify a maximum amount of millisats they are willing to pay.
71
72### `relays` tag
85A list of relays the service provider should publish its job result to. 73A list of relays the service provider should publish its job result to.
86 74
87#### `p` tags (optional) 75### `p` tags
88A user might want to explicitly request this job to be processed by specific service provider(s). Other service providers might still choose to compete for this job. 76A user MIGHT want to explicitly request this job to be processed by specific service provider(s). Other service providers might still choose to compete for this job.
89 77
90#### `expiration` (optional) 78### `exp`
91A user might specify that they will not be interested in results past a certain time (e.g. a time-sensitive job whos value is no longer relevant after some time, like a live transcription service) 79A user might specify that they will not be interested in results past a certain time (e.g. a time-sensitive job whos value is no longer relevant after some time, like a live transcription service)
92 80
93### Job result 81## Job result
94The output of processing the data -- published by the 82The output of processing the data -- published by the service provider.
95```json 83```json
96{ 84{
97 "pubkey": "service-provider", 85 "pubkey": "service-provider",
@@ -100,19 +88,22 @@ The output of processing the data -- published by the
100 "content": "<payload>", 88 "content": "<payload>",
101 "tags" [ 89 "tags" [
102 // stringified JSON request event 90 // stringified JSON request event
103 [ "request", "<2xxx1-event>" ], 91 [ "request", "<68001-event>" ],
104 [ "e", <id-of-2xxx1-event>], 92 [ "e", <id-of-68001-event>],
105 [ "p", "<job-requester's pubkey>" ], 93 [ "p", "<job-requester's pubkey>" ],
106 [ "status", "success", "<more-info>"], 94 [ "status", "success", "<more-info>"],
107 [ "payment", "requested-payment-amount" ] 95 [ "amount", "requested-payment-amount" ]
108 ] 96 ]
109} 97}
110``` 98```
111 99
112### `status` tag 100The result of the job should be in the `content`. If the output is not text, the `content` field should be empty and an `output` tag should be used instead as described below.
101
102#### `status` tag
113The service provider might want to return an error to the user in case the job could not be processed correctly 103The service provider might want to return an error to the user in case the job could not be processed correctly
114 104
115### `payment` 105#### `amount`
106The amount of millisats the service provider is requesting to be paid. This amount MIGHT be different than the amount specified by the user in the `bid` tag. The amount SHOULD be less than the maximum amount specified by the user in the `bid` tag.
116 107
117## Job types 108## Job types
118 109
@@ -133,21 +124,52 @@ This NIP defines some job types, clients SHOULD specify these types for maximum
133#### params 124#### params
134| param | req? | description 125| param | req? | description
135|--------------------------------|------|-------- 126|--------------------------------|------|--------
136| `language` | req | desired language in BCP 47 format. 127| `language` | req | requested language in BCP 47 format.
128
129# Protocol Flow
130* User publishes a job request
131`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
132
133* Service providers listen for the type of jobs they can perform
134`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
135
136* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it, or they can react to it with feedback for the user (e.g. _payment required_, _unprocessable entity_, etc.)
137* Upon completion, the service provider publishes the result of the job with a `job-result` event.
138* Upon acceptance, the user zaps the service provider, tagging the job result event.
137 139
138## Job chaining 140# Payment
141Customers SHOULD pay service providers whose job results they accept. Users should zap the service provider, tagging the `kind:68002` job result.
142
143
144# Job chaining
139A customer CAN request multiple jobs to be chained, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker. 145A customer CAN request multiple jobs to be chained, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
140 146
141Service providers might opt to start processing a subsequent job the moment they see the prior job's result, or they might choose to wait for a zap to have been published. This introduces the 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 a explicit zap to assume the job was accepted. 147Service providers might opt to start processing a subsequent job the moment they see the prior job's result, or they might choose to wait for a zap to have been published. This introduces the 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 a explicit zap to assume the job was accepted.
142 148
143## Job feedback 149# Reactions
144> **Warning** 150> **Warning**
145> Is this hijacking/modifying the meaning of NIP-25 reactions too much? 151> Is this hijacking/modifying the meaning of NIP-25 reactions too much?
146 152
147A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions. 153## Job request reactions
148The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result, either 154Service Providers might opt to give feedback about a job.
149in the form of 155
156### E.g. Payment required
157```json
158{
159 "kind": 7,
160 "content": "Please pay 7 sats for job xxxx",
161 "tags": [
162 [ "e", <job-request-id> ],
163 [ "status", "payment-required" ],
164 [ "amount", "7000" ],
165 ]
166}
167```
150 168
169## Job feedback
170
171A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
172The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result.
151 173
152## Explicitly not addressed in this NIP 174## Explicitly not addressed in this NIP
153 175
@@ -163,7 +185,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
163 185
164# Appendix 1: Examples 186# Appendix 1: Examples
165 187
166## Customer wants to get a transcript of a podcast from second 900 to 930. 188## Transcript of a podcast from second `900` to `930`.
167 189
168### `kind:68001`: Job Request 190### `kind:68001`: Job Request
169```json 191```json
@@ -174,7 +196,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
174 "tags": [ 196 "tags": [
175 [ "j", "speech-to-text" ], 197 [ "j", "speech-to-text" ],
176 [ "params", "range", "900", "930" ], 198 [ "params", "range", "900", "930" ],
177 [ "input", "https://bitcoin.review/episode1.mp3", "url" ], 199 [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
178 [ "bid", "5000", "9000" ] 200 [ "bid", "5000", "9000" ]
179 ] 201 ]
180} 202}
@@ -192,7 +214,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
192} 214}
193``` 215```
194 216
195## Customer wants to get a summarization of a podcast 217## Summarization of a podcast
196 218
197User publishes two job requests at the same time in the order they should be executed. 219User publishes two job requests at the same time in the order they should be executed.
198 220
@@ -205,7 +227,7 @@ User publishes two job requests at the same time in the order they should be exe
205 "tags": [ 227 "tags": [
206 [ "j", "speech-to-text" ], 228 [ "j", "speech-to-text" ],
207 [ "params", "range", "900", "930" ], 229 [ "params", "range", "900", "930" ],
208 [ "input", "https://bitcoin.review/episode1.mp3", "url" ], 230 [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
209 [ "bid", "5000", "9000" ] 231 [ "bid", "5000", "9000" ]
210 ] 232 ]
211} 233}
@@ -220,13 +242,13 @@ User publishes two job requests at the same time in the order they should be exe
220 "tags": [ 242 "tags": [
221 [ "j", "summarization" ], 243 [ "j", "summarization" ],
222 [ "params", "length", "3 paragraphs" ], 244 [ "params", "length", "3 paragraphs" ],
223 [ "input", "12346", "job" ], 245 [ "i", "12346", "job" ],
224 [ "bid", "300", "900" ] 246 [ "bid", "300", "900" ]
225 ] 247 ]
226} 248}
227``` 249```
228 250
229## Customer wants a translation of a note 251## Translation of a note
230### `kind:68001`: Job Request #1 252### `kind:68001`: Job Request #1
231```json 253```json
232{ 254{
@@ -235,9 +257,57 @@ User publishes two job requests at the same time in the order they should be exe
235 "content": "", 257 "content": "",
236 "tags": [ 258 "tags": [
237 [ "j", "translation" ], 259 [ "j", "translation" ],
238 [ "input", "<hexid>", "event" ] 260 [ "i", "<hexid>", "event" ]
239 [ "params", "language", "es_AR" ], 261 [ "params", "language", "es_AR" ],
240 [ "bid", "100", "500" ] 262 [ "bid", "100", "500" ]
241 ] 263 ]
242} 264}
243``` \ No newline at end of file 265```
266
267## AI-image of the summarization of 2 podcasts
268
269### `kind:68001`: Job request #1 (transcribe podcast #1)
270```json
271{
272 "id": "123",
273 "tags": [
274 [ "j", "speech-to-text" ],
275 [ "i", "https://example.com/episode1.mp3", "url" ],
276 [ "bid", "100", "500" ]
277 ]
278}
279```
280
281### `kind:68001`: Job request #2 (transcribe podcast #2)
282```json
283{
284 "id": "124",
285 "tags": [
286 [ "j", "speech-to-text" ],
287 [ "i", "https://example.com/episode2.mp3", "url" ],
288 [ "bid", "100", "500" ]
289 ]
290}
291```
292
293### `kind:68001`: Job request #3 (summarize both podcasts into one podcast)
294```json
295{
296 "id": "125",
297 "tags": [
298 [ "j", "summarize" ],
299 [ "param", "length", "1 paragraph" ],
300 [ "i", "123", "job" ],
301 [ "i", "124", "job" ],
302 [ "bid", "100", "500" ]
303 ]
304}
305```
306
307# Notes
308
309* Should there be a possibility of getting the job result delivered encrypted? I don't like it but maybe it should be supported.
310
311* Ambiguity on job acceptance, particularly for job-chaining circumstances is deliberately ambiguous: service providers could wait until explicit job result acceptance / payment to start working on the next item on the chain, or they could start working as soon as they see a result of the previous job computed.
312
313That's up to each service provider to choose how to behave depending on the circumstances. This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).