From ce552554a08bb5b9878621abfdde3207d54cae62 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Wed, 5 Jul 2023 11:14:50 +0200
Subject: [PATCH] wip, part 2
---
vending-machine.md | 208 ++++++++++++++++++++++++++++++---------------
1 file changed, 139 insertions(+), 69 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index a94cd332..eb26688d 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -1,8 +1,15 @@
-# NIP-XX: Data Vending Machine
-Money in, data out.
+NIP-XX
+======
+
+Data Vending Machine
+--------------------
+
+`draft` `optional` `author:pablof7z`
+
+This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
## Rationale
-Nostr 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.
+Nostr 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.
This 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.
@@ -11,26 +18,9 @@ There are two actors to the workflow described in this NIP:
* Customers (npubs who request a job)
* Service providers (npubs who fulfill jobs)
-## User flow
-* User publishes a job request
-`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
-
-* Service providers listen for the type of jobs they can perform
-`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
-
-* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it
-* Upon completion, the service provider publishes the result of the job with a `job-result` event.
-* Upon acceptance, the user zaps the service provider, tagging the job request
-
-## Kinds
-
-This NIP introduces two new kinds:
-
-* `kind:68001`: Job request -- a request to have a job be processed
-* `kind:68002`: Job result -- a proposal of the resulting job
-
-### Job request
-A request to have data processed -- published by a user
+# Event Kinds
+## Job request
+A request to have data processed -- published by a customer
```json
{
@@ -38,40 +28,35 @@ A request to have data processed -- published by a user
"content": "",
"tags": [
// The type data processing the user wants to be performed
- // on the
- [ "j", "", "" ],
- [ "input", "", "", "" ],
+ [ "j", "", "" ],
+
+ // input(s) for the job request
+ [ "i", "", "", "" ],
+
+ // relays where the job result should be published
[ "relays", "wss://..."],
- // stringified sat amount that the user is offering to pay
- // for this request
- // should this include an optional max price or is it too
- // ambiguous?
- [ "bid", "", [""] ],
-
- // max timestamp at which the job is no longer to be processed
- [ "expiration", "" ]
-
- // p tags
+ // millisats amount that the user is offering to pay
+ [ "bid", "", "" ],
+ [ "exp", "" ],
[ "p", "service-provider-1" ],
[ "p", "service-provider-2" ],
-
- // NIP-33 d-tag
- [ "d", ""]
]
}
```
-#### `content` field
+### `content` field
An optional, human-readable description of what this job is for.
-#### `j` tag
+### `j` tag
Specifies the job to be executed. A job request MUST have exactly one `j` tag.
-A `j` tag MIGHT name a specific model to be used for the computed with.
+A `j` tag MIGHT name a specific model to be used for the computed with as the second value.
-#### `input` tag
-Specified the input that the job should be executed with.
+### `i` (input) tag
+Specifies 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.
+
+A job request CAN have zero or more inputs.
* ``: The argument for the input
* ``: The way this argument should be interpreted
@@ -81,17 +66,20 @@ Specified the input that the job should be executed with.
* `job`: the output of a previous job with the specified event ID
* ``:
-#### `relays` tag
+### `bid` tag
+The 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.
+
+### `relays` tag
A list of relays the service provider should publish its job result to.
-#### `p` tags (optional)
-A 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.
+### `p` tags
+A 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.
-#### `expiration` (optional)
+### `exp`
A 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)
-### Job result
-The output of processing the data -- published by the
+## Job result
+The output of processing the data -- published by the service provider.
```json
{
"pubkey": "service-provider",
@@ -100,19 +88,22 @@ The output of processing the data -- published by the
"content": "",
"tags" [
// stringified JSON request event
- [ "request", "<2xxx1-event>" ],
- [ "e", ],
+ [ "request", "<68001-event>" ],
+ [ "e", ],
[ "p", "" ],
[ "status", "success", ""],
- [ "payment", "requested-payment-amount" ]
+ [ "amount", "requested-payment-amount" ]
]
}
```
-### `status` tag
+The 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.
+
+#### `status` tag
The service provider might want to return an error to the user in case the job could not be processed correctly
-### `payment`
+#### `amount`
+The 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.
## Job types
@@ -133,21 +124,52 @@ This NIP defines some job types, clients SHOULD specify these types for maximum
#### params
| param | req? | description
|--------------------------------|------|--------
-| `language` | req | desired language in BCP 47 format.
+| `language` | req | requested language in BCP 47 format.
-## Job chaining
+# Protocol Flow
+* User publishes a job request
+`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
+
+* Service providers listen for the type of jobs they can perform
+`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
+
+* 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.)
+* Upon completion, the service provider publishes the result of the job with a `job-result` event.
+* Upon acceptance, the user zaps the service provider, tagging the job result event.
+
+# Payment
+Customers SHOULD pay service providers whose job results they accept. Users should zap the service provider, tagging the `kind:68002` job result.
+
+
+# Job chaining
A 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.
Service 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.
-## Job feedback
+# Reactions
> **Warning**
> Is this hijacking/modifying the meaning of NIP-25 reactions too much?
-A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
-The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result, either
-in the form of
+## Job request reactions
+Service Providers might opt to give feedback about a job.
+### E.g. Payment required
+```json
+{
+ "kind": 7,
+ "content": "Please pay 7 sats for job xxxx",
+ "tags": [
+ [ "e", ],
+ [ "status", "payment-required" ],
+ [ "amount", "7000" ],
+ ]
+}
+```
+
+## Job feedback
+
+A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
+The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result.
## Explicitly not addressed in this NIP
@@ -163,7 +185,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
# Appendix 1: Examples
-## Customer wants to get a transcript of a podcast from second 900 to 930.
+## Transcript of a podcast from second `900` to `930`.
### `kind:68001`: Job Request
```json
@@ -174,7 +196,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
"tags": [
[ "j", "speech-to-text" ],
[ "params", "range", "900", "930" ],
- [ "input", "https://bitcoin.review/episode1.mp3", "url" ],
+ [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "bid", "5000", "9000" ]
]
}
@@ -192,7 +214,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
}
```
-## Customer wants to get a summarization of a podcast
+## Summarization of a podcast
User publishes two job requests at the same time in the order they should be executed.
@@ -205,7 +227,7 @@ User publishes two job requests at the same time in the order they should be exe
"tags": [
[ "j", "speech-to-text" ],
[ "params", "range", "900", "930" ],
- [ "input", "https://bitcoin.review/episode1.mp3", "url" ],
+ [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "bid", "5000", "9000" ]
]
}
@@ -220,13 +242,13 @@ User publishes two job requests at the same time in the order they should be exe
"tags": [
[ "j", "summarization" ],
[ "params", "length", "3 paragraphs" ],
- [ "input", "12346", "job" ],
+ [ "i", "12346", "job" ],
[ "bid", "300", "900" ]
]
}
```
-## Customer wants a translation of a note
+## Translation of a note
### `kind:68001`: Job Request #1
```json
{
@@ -235,9 +257,57 @@ User publishes two job requests at the same time in the order they should be exe
"content": "",
"tags": [
[ "j", "translation" ],
- [ "input", "", "event" ]
+ [ "i", "", "event" ]
[ "params", "language", "es_AR" ],
[ "bid", "100", "500" ]
]
}
-```
\ No newline at end of file
+```
+
+## AI-image of the summarization of 2 podcasts
+
+### `kind:68001`: Job request #1 (transcribe podcast #1)
+```json
+{
+ "id": "123",
+ "tags": [
+ [ "j", "speech-to-text" ],
+ [ "i", "https://example.com/episode1.mp3", "url" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
+
+### `kind:68001`: Job request #2 (transcribe podcast #2)
+```json
+{
+ "id": "124",
+ "tags": [
+ [ "j", "speech-to-text" ],
+ [ "i", "https://example.com/episode2.mp3", "url" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
+
+### `kind:68001`: Job request #3 (summarize both podcasts into one podcast)
+```json
+{
+ "id": "125",
+ "tags": [
+ [ "j", "summarize" ],
+ [ "param", "length", "1 paragraph" ],
+ [ "i", "123", "job" ],
+ [ "i", "124", "job" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
+
+# Notes
+
+* Should there be a possibility of getting the job result delivered encrypted? I don't like it but maybe it should be supported.
+
+* 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.
+
+That'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).