mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 08:25:53 -05:00
wip, part 2
This commit is contained in:
parent
71803c21a6
commit
ce552554a0
|
@ -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", "<job-type>", "<model>" ],
|
||||
[ "input", "<data>", "<input-type>", "<marker>" ],
|
||||
[ "j", "<job-type>", "<optional-model>" ],
|
||||
|
||||
// input(s) for the job request
|
||||
[ "i", "<data>", "<input-type>", "<marker>" ],
|
||||
|
||||
// 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", "<sat-amount>", ["<optional-max-price>"] ],
|
||||
|
||||
// max timestamp at which the job is no longer to be processed
|
||||
[ "expiration", "<timestamp>" ]
|
||||
|
||||
// p tags
|
||||
// millisats amount that the user is offering to pay
|
||||
[ "bid", "<msat-amount>", "<optional-max-price>" ],
|
||||
[ "exp", "<timestamp>" ],
|
||||
[ "p", "service-provider-1" ],
|
||||
[ "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.
|
||||
|
||||
#### `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.
|
||||
|
||||
* `<data>`: The argument for the input
|
||||
* `<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
|
||||
* `<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.
|
||||
|
||||
#### `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": "<payload>",
|
||||
"tags" [
|
||||
// stringified JSON request event
|
||||
[ "request", "<2xxx1-event>" ],
|
||||
[ "e", <id-of-2xxx1-event>],
|
||||
[ "request", "<68001-event>" ],
|
||||
[ "e", <id-of-68001-event>],
|
||||
[ "p", "<job-requester's pubkey>" ],
|
||||
[ "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
|
||||
|
||||
### `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", <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
|
||||
|
||||
|
@ -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", "<hexid>", "event" ]
|
||||
[ "i", "<hexid>", "event" ]
|
||||
[ "params", "language", "es_AR" ],
|
||||
[ "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