mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 16:35:52 -05:00
wip, part 2
This commit is contained in:
parent
71803c21a6
commit
ce552554a0
|
@ -1,8 +1,15 @@
|
||||||
# NIP-XX: Data Vending Machine
|
NIP-XX
|
||||||
Money in, data out.
|
======
|
||||||
|
|
||||||
|
Data Vending Machine
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
`draft` `optional` `author:pablof7z`
|
||||||
|
|
||||||
|
This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
|
||||||
|
|
||||||
## Rationale
|
## 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.
|
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)
|
* Customers (npubs who request a job)
|
||||||
* Service providers (npubs who fulfill jobs)
|
* Service providers (npubs who fulfill jobs)
|
||||||
|
|
||||||
## User flow
|
# Event Kinds
|
||||||
* User publishes a job request
|
## Job request
|
||||||
`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
|
A request to have data processed -- published by a customer
|
||||||
|
|
||||||
* 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
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -38,40 +28,35 @@ A request to have data processed -- published by a user
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
// The type data processing the user wants to be performed
|
// The type data processing the user wants to be performed
|
||||||
// on the
|
[ "j", "<job-type>", "<optional-model>" ],
|
||||||
[ "j", "<job-type>", "<model>" ],
|
|
||||||
[ "input", "<data>", "<input-type>", "<marker>" ],
|
// input(s) for the job request
|
||||||
|
[ "i", "<data>", "<input-type>", "<marker>" ],
|
||||||
|
|
||||||
|
// relays where the job result should be published
|
||||||
[ "relays", "wss://..."],
|
[ "relays", "wss://..."],
|
||||||
|
|
||||||
// stringified sat amount that the user is offering to pay
|
// millisats amount that the user is offering to pay
|
||||||
// for this request
|
[ "bid", "<msat-amount>", "<optional-max-price>" ],
|
||||||
// should this include an optional max price or is it too
|
[ "exp", "<timestamp>" ],
|
||||||
// ambiguous?
|
|
||||||
[ "bid", "<sat-amount>", ["<optional-max-price>"] ],
|
|
||||||
|
|
||||||
// max timestamp at which the job is no longer to be processed
|
|
||||||
[ "expiration", "<timestamp>" ]
|
|
||||||
|
|
||||||
// p tags
|
|
||||||
[ "p", "service-provider-1" ],
|
[ "p", "service-provider-1" ],
|
||||||
[ "p", "service-provider-2" ],
|
[ "p", "service-provider-2" ],
|
||||||
|
|
||||||
// NIP-33 d-tag
|
|
||||||
[ "d", "<unique-job-name>"]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `content` field
|
### `content` field
|
||||||
An optional, human-readable description of what this job is for.
|
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.
|
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
|
### `i` (input) tag
|
||||||
Specified the input that the job should be executed with.
|
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.
|
||||||
|
|
||||||
* `<data>`: The argument for the input
|
* `<data>`: The argument for the input
|
||||||
* `<input-type>`: The way this argument should be interpreted
|
* `<input-type>`: 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
|
* `job`: the output of a previous job with the specified event ID
|
||||||
* `<marker>`:
|
* `<marker>`:
|
||||||
|
|
||||||
#### `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.
|
A list of relays the service provider should publish its job result to.
|
||||||
|
|
||||||
#### `p` tags (optional)
|
### `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.
|
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)
|
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
|
## Job result
|
||||||
The output of processing the data -- published by the
|
The output of processing the data -- published by the service provider.
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"pubkey": "service-provider",
|
"pubkey": "service-provider",
|
||||||
|
@ -100,19 +88,22 @@ The output of processing the data -- published by the
|
||||||
"content": "<payload>",
|
"content": "<payload>",
|
||||||
"tags" [
|
"tags" [
|
||||||
// stringified JSON request event
|
// stringified JSON request event
|
||||||
[ "request", "<2xxx1-event>" ],
|
[ "request", "<68001-event>" ],
|
||||||
[ "e", <id-of-2xxx1-event>],
|
[ "e", <id-of-68001-event>],
|
||||||
[ "p", "<job-requester's pubkey>" ],
|
[ "p", "<job-requester's pubkey>" ],
|
||||||
[ "status", "success", "<more-info>"],
|
[ "status", "success", "<more-info>"],
|
||||||
[ "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
|
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
|
## Job types
|
||||||
|
|
||||||
|
@ -133,21 +124,52 @@ This NIP defines some job types, clients SHOULD specify these types for maximum
|
||||||
#### params
|
#### params
|
||||||
| param | req? | description
|
| 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.
|
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.
|
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**
|
> **Warning**
|
||||||
> Is this hijacking/modifying the meaning of NIP-25 reactions too much?
|
> 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.
|
## Job request reactions
|
||||||
The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result, either
|
Service Providers might opt to give feedback about a job.
|
||||||
in the form of
|
|
||||||
|
|
||||||
|
### E.g. Payment required
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"kind": 7,
|
||||||
|
"content": "Please pay 7 sats for job xxxx",
|
||||||
|
"tags": [
|
||||||
|
[ "e", <job-request-id> ],
|
||||||
|
[ "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
|
## 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
|
# 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
|
### `kind:68001`: Job Request
|
||||||
```json
|
```json
|
||||||
|
@ -174,7 +196,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
|
||||||
"tags": [
|
"tags": [
|
||||||
[ "j", "speech-to-text" ],
|
[ "j", "speech-to-text" ],
|
||||||
[ "params", "range", "900", "930" ],
|
[ "params", "range", "900", "930" ],
|
||||||
[ "input", "https://bitcoin.review/episode1.mp3", "url" ],
|
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
|
||||||
[ "bid", "5000", "9000" ]
|
[ "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.
|
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": [
|
"tags": [
|
||||||
[ "j", "speech-to-text" ],
|
[ "j", "speech-to-text" ],
|
||||||
[ "params", "range", "900", "930" ],
|
[ "params", "range", "900", "930" ],
|
||||||
[ "input", "https://bitcoin.review/episode1.mp3", "url" ],
|
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
|
||||||
[ "bid", "5000", "9000" ]
|
[ "bid", "5000", "9000" ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -220,13 +242,13 @@ User publishes two job requests at the same time in the order they should be exe
|
||||||
"tags": [
|
"tags": [
|
||||||
[ "j", "summarization" ],
|
[ "j", "summarization" ],
|
||||||
[ "params", "length", "3 paragraphs" ],
|
[ "params", "length", "3 paragraphs" ],
|
||||||
[ "input", "12346", "job" ],
|
[ "i", "12346", "job" ],
|
||||||
[ "bid", "300", "900" ]
|
[ "bid", "300", "900" ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customer wants a translation of a note
|
## Translation of a note
|
||||||
### `kind:68001`: Job Request #1
|
### `kind:68001`: Job Request #1
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -235,9 +257,57 @@ User publishes two job requests at the same time in the order they should be exe
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
[ "j", "translation" ],
|
[ "j", "translation" ],
|
||||||
[ "input", "<hexid>", "event" ]
|
[ "i", "<hexid>", "event" ]
|
||||||
[ "params", "language", "es_AR" ],
|
[ "params", "language", "es_AR" ],
|
||||||
[ "bid", "100", "500" ]
|
[ "bid", "100", "500" ]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 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).
|
||||||
|
|
Loading…
Reference in New Issue
Block a user