├── .npmrc ├── src ├── routes │ ├── jobs │ │ ├── +layout.svelte │ │ ├── new │ │ │ └── +page.svelte │ │ ├── [ids] │ │ │ └── +page.svelte │ │ ├── my │ │ │ └── +page.svelte │ │ └── +page.svelte │ ├── +layout.ts │ ├── dvms │ │ ├── [id] │ │ │ └── +page.svelte │ │ └── +page.svelte │ ├── +layout.svelte │ ├── magic │ │ └── +page.svelte │ └── +page.svelte ├── lib │ ├── utils │ │ ├── nip90.ts │ │ ├── nip89.ts │ │ ├── index.ts │ │ └── login.ts │ ├── stores │ │ ├── current-user.ts │ │ ├── settings.ts │ │ ├── nip89.ts │ │ ├── jobRequests.ts │ │ ├── notifications.ts │ │ └── ndk.ts │ ├── modals │ │ ├── Nip89RecommendModal.svelte │ │ ├── JobRequestEditorModal.svelte │ │ └── Nip89AddParamModal.svelte │ ├── icons │ │ ├── Close.svelte │ │ ├── arrow-path.svg │ │ ├── Key.svelte │ │ ├── Lightning.svelte │ │ ├── Nostr.svelte │ │ ├── Gear.svelte │ │ └── Logo.svelte │ └── components │ │ ├── buttons │ │ ├── SubtleButton.svelte │ │ └── AttentionButton.svelte │ │ ├── jobs │ │ ├── JobRequestEditor │ │ │ ├── JobRequestEditorPayment.svelte │ │ │ ├── SelectDvms.svelte │ │ │ ├── TypeCard.svelte │ │ │ ├── JobRequestEditorParameters65002.svelte │ │ │ ├── AddInputButton.svelte │ │ │ ├── JobRequestEditorParameters65005.svelte │ │ │ ├── ParamInput.svelte │ │ │ ├── DvmTile.svelte │ │ │ ├── ParamSection.svelte │ │ │ ├── JobRequestEditorInput.svelte │ │ │ └── JobRequestEditor.svelte │ │ ├── JobStatusLabel.svelte │ │ ├── JobTypeIcon.svelte │ │ ├── JobCard.svelte │ │ ├── JobSummarization.svelte │ │ ├── AddJobButton.svelte │ │ ├── JobTextExtraction.svelte │ │ ├── PaymentRequiredButton.svelte │ │ ├── JobFeedbackRow.svelte │ │ ├── EventCard.svelte │ │ ├── JobResultRow.svelte │ │ ├── JobRequestCard.svelte │ │ └── JobDvmEventsCard.svelte │ │ ├── Notification.svelte │ │ ├── CurrentUser.svelte │ │ ├── Avatar.svelte │ │ ├── LoginGuestButton.svelte │ │ ├── CollapsableDropdown.svelte │ │ ├── ElementConnector.svelte │ │ ├── LoginNip07Button.svelte │ │ ├── NotificationButton.svelte │ │ ├── ModalWrapper.svelte │ │ ├── LoginDropdown.svelte │ │ ├── dvms │ │ ├── DvmCard.svelte │ │ ├── DvmListItem.svelte │ │ └── Nip89Tool │ │ │ ├── Nip89Tool.svelte │ │ │ └── Nip89Form.svelte │ │ ├── Navbar.svelte │ │ ├── UserDropdown.svelte │ │ └── feed │ │ └── FeedItem.svelte ├── app.d.ts ├── app.html ├── app.postcss └── svg.d.ts ├── static ├── favicon.png └── fonts │ └── Inter-VariableFont_slnt,wght.woff2 ├── renovate.json ├── justfile ├── vite.config.ts ├── .eslintignore ├── .prettierignore ├── tests └── test.ts ├── .gitignore ├── .prettierrc ├── playwright.config.ts ├── postcss.config.cjs ├── tsconfig.json ├── .vscode └── extensions.json ├── .eslintrc.cjs ├── svelte.config.js ├── package.json ├── tailwind.config.cjs └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | resolution-mode=highest 3 | -------------------------------------------------------------------------------- /src/routes/jobs/+layout.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/believethehype/vendata.io/master/static/favicon.png -------------------------------------------------------------------------------- /src/lib/utils/nip90.ts: -------------------------------------------------------------------------------- 1 | export type Nip90Param = { 2 | required?: boolean; 3 | values?: string[]; 4 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /static/fonts/Inter-VariableFont_slnt,wght.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/believethehype/vendata.io/master/static/fonts/Inter-VariableFont_slnt,wght.woff2 -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | update: 2 | pnpm add @nostr-dev-kit/ndk@latest @nostr-dev-kit/ndk-svelte-components@latest @nostr-dev-kit/ndk-svelte@latest @nostr-dev-kit/ndk-cache-dexie@latest 3 | 4 | 5 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | sveltekit(), 7 | ] 8 | }); 9 | -------------------------------------------------------------------------------- /src/lib/stores/current-user.ts: -------------------------------------------------------------------------------- 1 | import type { NDKUser } from "@nostr-dev-kit/ndk"; 2 | import { writable } from "svelte/store"; 3 | 4 | export const currentUser = writable(undefined); -------------------------------------------------------------------------------- /src/lib/modals/Nip89RecommendModal.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | Mark this 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /src/routes/+layout.ts: -------------------------------------------------------------------------------- 1 | import { dev } from '$app/environment'; 2 | import { inject } from '@vercel/analytics'; 3 | 4 | inject({ mode: dev ? 'development' : 'production' }); 5 | 6 | export const prerender = false; 7 | export const ssr = false; -------------------------------------------------------------------------------- /tests/test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from '@playwright/test'; 2 | 3 | test('index page has expected h1', async ({ page }) => { 4 | await page.goto('/'); 5 | expect(await page.textContent('h1')).toBe('Welcome to SvelteKit'); 6 | }); 7 | -------------------------------------------------------------------------------- /src/lib/icons/Close.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | 12 | # Ignore files for PNPM, NPM and YARN 13 | pnpm-lock.yaml 14 | package-lock.json 15 | yarn.lock 16 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /src/lib/stores/settings.ts: -------------------------------------------------------------------------------- 1 | import { persist, createLocalStorage } from "@macfja/svelte-persistent-store"; 2 | import { writable, get as getStore } from "svelte/store"; 3 | 4 | export const addJobButtonsSeen = persist( 5 | writable(0), 6 | createLocalStorage(), 7 | "add-job-buttons-seen", 8 | ); -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 'npm run build && npm run preview', 6 | port: 4173 7 | }, 8 | testDir: 'tests', 9 | testMatch: /(.+\.)?(test|spec)\.[jt]s/ 10 | }; 11 | 12 | export default config; 13 | -------------------------------------------------------------------------------- /src/lib/icons/arrow-path.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const tailwindcss = require('tailwindcss'); 2 | const autoprefixer = require('autoprefixer'); 3 | 4 | const config = { 5 | plugins: [ 6 | //Some plugins, like tailwindcss/nesting, need to run before Tailwind, 7 | tailwindcss(), 8 | //But others, like autoprefixer, need to run after, 9 | autoprefixer 10 | ] 11 | }; 12 | 13 | module.exports = config; 14 | -------------------------------------------------------------------------------- /src/lib/components/buttons/SubtleButton.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /src/lib/components/buttons/AttentionButton.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/lib/stores/nip89.ts: -------------------------------------------------------------------------------- 1 | import { NDKAppHandlerEvent, NDKDVMRequest } from "@nostr-dev-kit/ndk"; 2 | import { get as getStore } from "svelte/store"; 3 | import ndk from './ndk'; 4 | import { jobRequestKinds } from "$utils"; 5 | 6 | const $ndk = getStore(ndk); 7 | 8 | export const appHandlers = $ndk.storeSubscribe({ 9 | kinds: [31990 as number], 10 | "#k": jobRequestKinds.map(j => j.toString()) 11 | }, { closeOnEose: false, subId: 'app-handlers' }, 12 | NDKAppHandlerEvent 13 | ); -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | %sveltekit.head% 15 | 16 | 17 |
%sveltekit.body%
18 | 19 | 20 | -------------------------------------------------------------------------------- /src/lib/utils/nip89.ts: -------------------------------------------------------------------------------- 1 | import { get as getStore } from "svelte/store"; 2 | import { appHandlers } from "$stores/nip89"; 3 | 4 | export function findNip89Event(dvmPubkey: string, handledKind: number) { 5 | const $appHandlers = getStore(appHandlers); 6 | const kindAsString = handledKind.toString(); 7 | 8 | console.log(`trying to find nip89 event with ${appHandlers?.length} handlers`); 9 | 10 | return $appHandlers.find((event) => ( 11 | event.pubkey === dvmPubkey && 12 | event.getMatchingTags("k").find(kTag => kTag[1] === kindAsString) 13 | )); 14 | } -------------------------------------------------------------------------------- /src/lib/icons/Key.svelte: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/JobRequestEditorPayment.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 11 |
12 | 13 | sats 14 |
15 |
-------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "inlang.vs-code-extension", 8 | "ms-playwright.playwright", 9 | "csstools.postcss", 10 | "svelte.svelte-vscode", 11 | "bradlc.vscode-tailwindcss" 12 | ], 13 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 14 | "unwantedRecommendations": [] 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:svelte/recommended', 7 | 'prettier' 8 | ], 9 | parser: '@typescript-eslint/parser', 10 | plugins: ['@typescript-eslint'], 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020, 14 | extraFileExtensions: ['.svelte'] 15 | }, 16 | env: { 17 | browser: true, 18 | es2017: true, 19 | node: true 20 | }, 21 | overrides: [ 22 | { 23 | files: ['*.svelte'], 24 | parser: 'svelte-eslint-parser', 25 | parserOptions: { 26 | parser: '@typescript-eslint/parser' 27 | } 28 | } 29 | ] 30 | }; 31 | -------------------------------------------------------------------------------- /src/lib/icons/Lightning.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/lib/components/Notification.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |
8 | {#if notifications} 9 |
10 | 11 | {notifications} 12 | 13 |
14 | {/if} 15 |
16 | 17 | {title} 18 | 19 |
-------------------------------------------------------------------------------- /src/lib/components/jobs/JobStatusLabel.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | {#if status === 'success'} 12 | Success 13 | {:else if status === 'processing'} 14 | Processing 15 | {:else if status === 'payment-required' && event} 16 | 17 | {:else} 18 | {status} 19 | {/if} -------------------------------------------------------------------------------- /src/lib/components/CurrentUser.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | {#if $currentUser} 8 | 9 | {:else} 10 | 11 | {/if} 12 | 13 | 26 | -------------------------------------------------------------------------------- /src/lib/modals/JobRequestEditorModal.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/SelectDvms.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 |

Choose one or more DVMs

17 | 18 |
19 | {#each $dvms as dvm (dvm.id)} 20 | 21 | {/each} 22 |
-------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import preprocess from 'svelte-preprocess'; 2 | import adapter from '@sveltejs/adapter-auto'; 3 | import { vitePreprocess } from '@sveltejs/kit/vite'; 4 | 5 | /** @type {import('@sveltejs/kit').Config} */ 6 | const config = { 7 | // Consult https://github.com/sveltejs/svelte-preprocess 8 | // for more information about preprocessors 9 | preprocess: [ 10 | vitePreprocess(), 11 | preprocess({ 12 | postcss: true 13 | }) 14 | ], 15 | 16 | kit: { 17 | adapter: adapter(), 18 | alias: { 19 | $actions: 'src/lib/actions', 20 | $components: 'src/lib/components', 21 | $icons: 'src/lib/icons', 22 | $modals: 'src/lib/modals', 23 | $stores: 'src/lib/stores', 24 | $utils: 'src/lib/utils' 25 | } 26 | }, 27 | 28 | vitePlugin: { 29 | inspector: { 30 | holdMode: true, 31 | toggleKeyCombo: 'control-shift' 32 | } 33 | } 34 | }; 35 | 36 | export default config; 37 | -------------------------------------------------------------------------------- /src/app.postcss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | @font-face { 7 | font-family: 'Inter'; 8 | font-style: normal; 9 | font-weight: 100 900; 10 | font-display: swap; 11 | ascent-override: 80%; 12 | descent-override: 20%; 13 | line-gap-override: 0%; 14 | src: url(/fonts/Inter-VariableFont_slnt,wght.woff2) format('woff2'); 15 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, 16 | U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 17 | } 18 | 19 | html, 20 | body, 21 | body > div { 22 | height: 100%; 23 | } 24 | 25 | .list-container { 26 | @apply flex flex-col divide-y divide-base-300; 27 | @apply md:divide-y-0 md:gap-4; 28 | 29 | } 30 | 31 | .event-card--dropdown-menu { 32 | @apply absolute top-0 right-0 z-10; 33 | @apply !opacity-75; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg?component' { 2 | import type { ComponentType, SvelteComponentTyped } from 'svelte'; 3 | import type { SVGAttributes } from 'svelte/elements'; 4 | 5 | const content: ComponentType>>; 6 | 7 | export default content; 8 | } 9 | 10 | declare module '*.svg?src' { 11 | const content: string; 12 | export default content; 13 | } 14 | 15 | declare module '*.svg?url' { 16 | const content: string; 17 | export default content; 18 | } 19 | 20 | declare module '*.svg?dataurl' { 21 | const content: string; 22 | export default content; 23 | } 24 | 25 | declare module '*.svg?dataurl=base64' { 26 | const content: string; 27 | export default content; 28 | } 29 | 30 | declare module '*.svg?dataurl=enc' { 31 | const content: string; 32 | export default content; 33 | } 34 | 35 | declare module '*.svg?dataurl=unenc' { 36 | const content: string; 37 | export default content; 38 | } 39 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobTypeIcon.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 |
10 | {#if kind === 65002} 11 | 12 | {:else if kind === 65004} 13 | 14 | {:else if kind === 65007} 15 | 16 | {:else if kind === 65005} 17 | 18 | {:else} 19 | {/if} 20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /src/lib/icons/Nostr.svelte: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/lib/components/Avatar.svelte: -------------------------------------------------------------------------------- 1 | 30 | 31 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/TypeCard.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/JobRequestEditorParameters65002.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 |

23 | Range (for audio/video) 24 | Optional 25 |

26 |
27 | 28 | 29 |
30 | -------------------------------------------------------------------------------- /src/lib/components/LoginGuestButton.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 |
24 | 25 | Continue as Guest 26 |
27 |
28 | -------------------------------------------------------------------------------- /src/routes/dvms/[id]/+page.svelte: -------------------------------------------------------------------------------- 1 | 23 | 24 |
25 | 26 | 27 | {#if $nip89events} 28 | {#each $nip89events as nip89event (nip89event.id)} 29 | 30 | {/each} 31 | {/if} 32 |
33 | 34 | -------------------------------------------------------------------------------- /src/lib/utils/index.ts: -------------------------------------------------------------------------------- 1 | import type { NDKEvent } from "@nostr-dev-kit/ndk"; 2 | 3 | const kinds: Record = { 4 | 65002: "Text extraction", 5 | 65003: "Summarization", 6 | 65004: "Translation", 7 | 65005: "Image Generation", 8 | 65006: "Nostr Discovery", 9 | 65007: "Nostr Filtering", 10 | }; 11 | 12 | export function kindToText(kind: number): string { 13 | if (kind in kinds) { 14 | return kinds[kind]; 15 | } 16 | 17 | return `Unknown kind ${kind}`; 18 | } 19 | 20 | export function kindToDescription(kind: number): string | undefined { 21 | switch (kind) { 22 | case 65002: return "Extracts text from an image, audio, video or anything else"; 23 | case 65003: return "Summarizes a text"; 24 | case 65004: return "Translates a text"; 25 | case 65005: return "Generates an image"; 26 | case 65006: return "Discover people or content in nostr"; 27 | case 65007: return "Filter in or out people or content in nostr"; 28 | } 29 | } 30 | 31 | export const jobRequestKinds = Object.keys(kinds).map((k) => parseInt(k)); 32 | 33 | export function eventUserReference(event: NDKEvent | string): string { 34 | const id = typeof event === "string" ? event : event.id; 35 | 36 | return "#" + id.slice(0, 4); 37 | } -------------------------------------------------------------------------------- /src/lib/components/CollapsableDropdown.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | 36 | -------------------------------------------------------------------------------- /src/lib/stores/jobRequests.ts: -------------------------------------------------------------------------------- 1 | import { NDKDVMRequest, NDKEvent } from "@nostr-dev-kit/ndk"; 2 | import type { NDKEventStore } from "@nostr-dev-kit/ndk-svelte"; 3 | import { get as getStore } from "svelte/store"; 4 | import ndk from './ndk'; 5 | import { currentUser } from "./current-user"; 6 | import { jobRequestKinds } from "$utils"; 7 | 8 | const $ndk = getStore(ndk); 9 | 10 | export let userJobRequests: NDKEventStore | undefined = undefined; 11 | export let userTaggedEvents: NDKEventStore | undefined = undefined; 12 | 13 | export function initJobRequests() { 14 | const $currentUser = getStore(currentUser); 15 | 16 | console.log('initJobRequests'); 17 | 18 | if (!$currentUser) { 19 | throw new Error("Current user not initialized"); 20 | } 21 | 22 | userJobRequests = $ndk.storeSubscribe( 23 | { kinds: jobRequestKinds, authors: [$currentUser.hexpubkey()], limit: 100 }, 24 | { closeOnEose: false, subId: 'user-job-requests' }, 25 | NDKDVMRequest 26 | ); 27 | 28 | userTaggedEvents = $ndk.storeSubscribe({ 29 | kinds: [ 65000, 65001 ], 30 | "#p": [ $currentUser.hexpubkey() ], 31 | since: Math.floor(Date.now() / 1000) - 60 * 60 * 24 * 7, 32 | limit: 100 33 | }, { closeOnEose: false, subId: 'user-tagged-events' }); 34 | } 35 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/AddInputButton.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /src/routes/jobs/new/+page.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 |
21 | {#if showNewJobRequest} 22 |
23 | 28 |
29 | {:else} 30 | 36 | {/if} 37 |
38 |
39 | 40 | 45 | -------------------------------------------------------------------------------- /src/lib/components/ElementConnector.svelte: -------------------------------------------------------------------------------- 1 | 38 | 39 |
43 |
50 | 51 | 52 |
-------------------------------------------------------------------------------- /src/lib/components/jobs/JobCard.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | {#if Component} 34 |
35 |
36 | 37 | {#if !job.id} 38 | 41 | {/if} 42 | 43 | 44 |
45 |
46 | {/if} 47 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/JobRequestEditorParameters65005.svelte: -------------------------------------------------------------------------------- 1 | 25 | 26 |
27 |

Negative prompt (optional)

28 | 102 | 103 | 104 |
105 | 106 |
107 |

108 | Advanced 109 |

110 |
111 |
112 | 113 |
114 |
115 |
116 |
117 |

118 | Params 119 |

120 | 121 | If your DVM supports some extra parameters or some 122 | specific parameter options (e.g. models being 123 | chatgpt3.5 and chatgpt4) you 124 | can specify them here so users can choose from them. 125 | 126 |
127 | 128 | 131 |
132 | 133 | 150 | 151 |
152 |
153 |
154 | 155 |
156 | 157 |
158 | 159 | 160 | You'll be able to sign with your DVMs key. No event will be published now. 161 | 162 |
163 | 164 |
165 | 166 | -------------------------------------------------------------------------------- /src/lib/components/jobs/JobDvmEventsCard.svelte: -------------------------------------------------------------------------------- 1 | 96 | 97 | 98 | {#if paymentPending && paymentPendingEvent} 99 | {#if nip89event} 100 | 104 |
105 | {#if paymentPendingEvent.content.length > 0} 106 |
107 |
108 | 111 |
112 |
113 | {/if} 114 | 118 |
119 |
120 | {:else} 121 | 122 |
123 | {#if paymentPendingEvent.content.length > 0} 124 |
125 |
126 | 129 |
130 |
131 | {/if} 132 | 133 | 137 |
138 |
139 | {/if} 140 | {:else if !fetchingProfile} 141 | 142 |
143 | 144 |
145 |
146 | 147 |
148 | 149 | 150 | 151 |
152 |
153 | 154 | {#if showTime} 155 |
163 |
164 | 165 |
166 | {#if !hasJobResult} 167 | 168 | {/if} 169 |
170 | 171 | 172 | 173 | {#if hasJobResult} 174 | {#each jobResults as jobResult (jobResult.id)} 175 | 176 | {/each} 177 | {:else} 178 | {mostRecentEvent.content} 179 | {/if} 180 |
181 | {:else} 182 | {JSON.stringify(mostRecentEvent.rawEvent())} 183 | {/if} 184 |
185 | 186 | 187 | -------------------------------------------------------------------------------- /src/lib/components/feed/FeedItem.svelte: -------------------------------------------------------------------------------- 1 | 111 | 112 |
113 |
114 |
115 | 116 | ID: #{item.id.slice(0, 3)} 117 | 118 | 119 | 120 | 126 |
127 |
128 | 129 | 130 | 131 |
132 | 133 |
134 | {#if item.kind === 65001} 135 | 136 | Result 137 | 138 | {:else if item.kind === 65000} 139 | {#if !['payment-required'].includes(item.tagValue('status'))} 140 | 141 | {item.content} 142 | {item.tagValue('status')} 143 | {#if jobRequestId} 144 | 145 | #{jobRequestId.slice(0, 3)} 146 | 147 | {/if} 148 | 149 | {/if} 150 | {:else} 151 | {kindToText(item.kind)} 152 | {/if} 153 | 154 | {#if item.tagValue('status') === 'payment-required'} 155 | 158 | {/if} 159 |
160 |
161 | 162 |
163 | {#if item.tagValue('image')} 164 | 165 | {/if} 166 | 167 |
168 | {#each inputs as input} 169 |

170 | input: 171 | {#if input[2] === 'job'} 172 | output of 173 | 174 | #{input[1]?.slice(0, 8)} 175 | 176 | (job chaining) 177 | {:else if input[2] === 'event'} 178 | #{input[1]?.slice(0, 8)} 179 | {:else} 180 | {input[1]} 181 | {/if} 182 |

183 | {/each} 184 | 185 | {#if item.tagValue('output')} 186 |

187 | output: 188 | {item.tagValue('output')} 189 |

190 | {/if} 191 |
192 |
193 | 194 |
195 | {#each Object.entries(dvms) as [dvmPubkey, events]} 196 |
197 | 198 | 199 |
200 | 201 |
202 | {#each events as event} 203 |
{event.content}
204 | {#if event.kind === 65001} 205 | 206 | Result 207 | 208 | {/if} 209 | {#if !['payment-required'].includes(event.tagValue('status'))} 210 | 211 | {event.content} 212 | {event.tagValue('status')} 213 | {#if jobRequestId} 214 | 215 | #{jobRequestId.slice(0, 3)} 216 | 217 | {/if} 218 | 219 | {/if} 220 | 221 | {#if event.tagValue('status') === 'payment-required'} 222 | 225 | {/if} 226 | {/each} 227 |
228 | {/each} 229 |
230 |
231 |
232 | 233 | {#if dependentJobs?.length > 0} 234 |
235 | {#each dependentJobs as dependentJob} 236 | 237 | {/each} 238 |
239 | {/if} -------------------------------------------------------------------------------- /src/lib/components/jobs/JobRequestEditor/JobRequestEditor.svelte: -------------------------------------------------------------------------------- 1 | 113 | 114 |
115 | {#if !type} 116 |

Choose the job type you would like to run

117 | 118 |
119 | 120 | {#each jobRequestKinds as kind} 121 | { type = kind.toString(); if (type === '65006' || type === '65007') { addInput(); } }} /> 122 | {/each} 123 |
124 | {:else if requireSelectingDvms && $nip89Events} 125 | 126 | 127 |
128 | 132 | 133 | 136 |
137 | {:else} 138 |
139 |

{kindToText(parseInt(type))}

140 | 141 |
142 |
143 | 144 |
145 | 146 |
147 |

148 | Input 149 |

150 | 151 | Enter the data you want to be processed 152 | 153 | 154 |
155 |
156 | 157 |
158 | {#each inputTags as inputTag, index (index)} 159 |
160 | 163 | 164 |
165 | {/each} 166 |
167 |
168 | 169 |
170 | 171 | 172 | {#if $nip89Events && $nip89Events.length > 0} 173 |
174 | 175 |
176 |

177 | DVMs 178 | {#if selectedDvms.length > 0} 179 | ({selectedDvms.length} selected) 180 | {:else} 181 | ({$nip89Events.length}) 182 | {/if} 183 |

184 | 185 | Specify additional parameters 186 | 187 |
188 |
189 | 190 |
191 | {#each $nip89Events as nip89Event (nip89Event.id)} 192 | { 196 | if (selected) { 197 | selectedDvms.push(nip89Event); 198 | } else { 199 | selectedDvms.splice(selectedDvms.indexOf(nip89Event), 1); 200 | } 201 | selectedDvms = selectedDvms; 202 | }} 203 | /> 204 | {/each} 205 |
206 |
207 | {/if} 208 | 209 |
210 | 211 |
212 |

213 | Advanced 214 |

215 |
216 |
217 | 218 |
219 |
220 |
221 |
222 |

223 | Payment 224 |

225 | 226 | Max you are willing to pay 227 | 228 |
229 | 230 |
231 | 232 |
233 |
234 |
235 | 236 |
237 |
238 |
239 |

240 | Tags 241 |

242 | 243 | Some DVMs use tags to identify the jobs 244 | they can best serve. 245 |
246 | E.g. if this is a bitcoin podcast, 247 | tag it bitcoin 248 | for better discoverability. 249 |
250 |
251 | 252 | 253 |
254 |
255 | 256 | {#if shouldShowOutput} 257 |
258 |
259 |
260 |

261 | Output 262 |

263 | 264 | Specify the desired output format 265 | 266 |
267 | 268 | 269 |
270 |
271 | {/if} 272 |
273 |
274 |
275 | 276 |
277 | 281 | 282 | 285 |
286 | {/if} 287 |
288 | 289 | --------------------------------------------------------------------------------