@yetter/client 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { YetterImageClient } from "./api.js";
2
2
  export * from "./types.js";
3
- export { yetter } from "./client.js";
3
+ export { yetter, YetterClient } from "./client.js";
4
4
  export type { UploadOptions, GetUploadUrlRequest, GetUploadUrlResponse, UploadCompleteRequest, UploadCompleteResponse, } from "./types.js";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { YetterImageClient } from "./api.js";
2
2
  export * from "./types.js";
3
- export { yetter } from "./client.js";
3
+ export { yetter, YetterClient } from "./client.js";
package/dist/types.d.ts CHANGED
@@ -58,6 +58,7 @@ export interface SubscribeOptions {
58
58
  input: Omit<GenerateRequest, 'model'>;
59
59
  logs?: boolean;
60
60
  onQueueUpdate?: (update: GetStatusResponse) => void;
61
+ pollIntervalMs?: number;
61
62
  }
62
63
  export interface SubmitQueueOptions {
63
64
  input: Omit<GenerateRequest, 'model'>;
@@ -96,6 +97,8 @@ export interface YetterStream extends AsyncIterable<StreamEvent> {
96
97
  export interface UploadOptions {
97
98
  /** Optional callback for upload progress (0-100) */
98
99
  onProgress?: (progress: number) => void;
100
+ /** Optional upload timeout in milliseconds (default: 5 minutes) */
101
+ timeout?: number;
99
102
  /** Optional custom filename (browser File uploads) */
100
103
  filename?: string;
101
104
  }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@yetter/client",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "tsc",
7
+ "test": "npm run build && node --test tests/*.test.mjs",
7
8
  "test:submit": "node --loader ts-node/esm examples/submit.ts",
8
9
  "test:subscribe": "node --loader ts-node/esm examples/subscribe.ts",
9
10
  "test:stream": "node --loader ts-node/esm examples/stream.ts",
@@ -11,6 +12,10 @@
11
12
  },
12
13
  "main": "dist/index.js",
13
14
  "types": "dist/index.d.ts",
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
14
19
  "exports": {
15
20
  ".": {
16
21
  "import": "./dist/index.js",
package/bowow2.jpeg DELETED
Binary file
@@ -1,54 +0,0 @@
1
- import { yetter } from "../src/client.js";
2
-
3
- async function main() {
4
- const model = "ytr-ai/flux/dev";
5
- console.log("\n--- Starting Stream Test ---");
6
- console.time("Stream Test");
7
- let streamRequestId = "";
8
-
9
- try {
10
- const streamInstance = await yetter.stream(model, {
11
- input: {
12
- prompt: "a bioluminescent forest at night, fantasy art",
13
- num_inference_steps: 28,
14
- },
15
- });
16
- streamRequestId = streamInstance.getRequestId();
17
- console.log(`[${new Date().toLocaleTimeString()}] Stream initiated for Request ID: ${streamRequestId}`);
18
-
19
- // Iterate over stream events
20
- for await (const event of streamInstance) {
21
- console.log(`[${new Date().toLocaleTimeString()}][STREAM EVENT - ${streamRequestId}] Status: ${event.status}, QPos: ${event.queue_position}`);
22
- if (event.logs && event.logs.length > 0) {
23
- console.log(` Logs for ${streamRequestId}:`);
24
- event.logs.forEach(log => console.log(` - ${log.message}`));
25
- }
26
- }
27
- console.log(`[${new Date().toLocaleTimeString()}] Stream for ${streamRequestId} finished iterating events.`);
28
-
29
- // Wait for the final result from the done() method
30
- console.log(`[${new Date().toLocaleTimeString()}] Waiting for done() on stream for ${streamRequestId}...`);
31
- const result = await streamInstance.done();
32
- console.log("\n--- Stream Test Final Result ---");
33
- console.log(`Request ID: ${streamRequestId}`);
34
- if (result.images && result.images.length > 0) {
35
- console.log("Generated Images:", result.images);
36
- } else {
37
- console.log("No images in final result.");
38
- }''
39
- console.log("Original Prompt:", result.prompt);
40
- console.timeEnd("Stream Test");
41
- } catch (err: any) {
42
- console.error(`\n--- Stream Test Failed (Request ID: ${streamRequestId || 'UNKNOWN'}) ---`);
43
- console.error("Error during stream test:", err.message || err);
44
- if (err.stack) {
45
- console.error(err.stack);
46
- }
47
- process.exit(1);
48
- }
49
- }
50
-
51
- main().catch(err => {
52
- console.error("Unhandled error in main:", err);
53
- process.exit(1);
54
- });
@@ -1,80 +0,0 @@
1
- import { yetter } from "../src/client.js";
2
-
3
- async function main() {
4
- const model = "ytr-ai/flux/dev";
5
- // Queue Submit test
6
- try {
7
- console.log("\n--- Starting Queue Submit Test ---");
8
- const { request_id, status, queue_position } = await yetter.queue.submit(model, {
9
- input: {
10
- prompt: "a fluffy white kitten playing with a yarn ball",
11
- num_inference_steps: 28,
12
- },
13
- });
14
-
15
- console.log("\n--- Queue Submit Test Result ---");
16
- console.log("Request ID:", request_id);
17
- console.log("Status:", status);
18
- console.log("Queue Position:", queue_position);
19
-
20
- if (request_id) {
21
- console.log(`\n--- Polling for status of Request ID: ${request_id} (3-minute timeout) ---`);
22
-
23
- const startTime = Date.now();
24
- const timeoutMilliseconds = 3 * 60 * 1000; // 3 minutes
25
- const pollIntervalMilliseconds = 10 * 1000; // Poll every 10 seconds
26
- let success = false;
27
-
28
- while (Date.now() - startTime < timeoutMilliseconds) {
29
- try {
30
- const statusResult = await yetter.queue.status(model, {
31
- requestId: request_id,
32
- });
33
- const currentStatus = statusResult.data.status;
34
- console.log(`[${new Date().toLocaleTimeString()}] Request ${request_id} status: ${currentStatus}, Queue Position: ${statusResult.data.queue_position}`);
35
-
36
- if (currentStatus === "COMPLETED") {
37
- console.log("Status is COMPLETED. Fetching final result...");
38
- const finalResult = await yetter.queue.result(model, {
39
- requestId: request_id,
40
- });
41
- console.log("\n--- Get Result Test Succeeded ---");
42
- console.log("Request ID:", finalResult.requestId);
43
- console.log("Image Data:", finalResult.data.images);
44
- console.log("Prompt:", finalResult.data.prompt);
45
- success = true;
46
- break; // Exit loop on success
47
- } else if (currentStatus === "ERROR") {
48
- console.error(`Request ${request_id} FAILED. Logs:`, statusResult.data.logs);
49
- break; // Exit loop on failure
50
- }
51
- // For other statuses (e.g., IN_QUEUE, IN_PROGRESS), continue polling
52
-
53
- } catch (pollError: any) {
54
- console.error(`Error during status polling for ${request_id} (will retry):`, pollError.message || pollError);
55
- }
56
-
57
- if (Date.now() - startTime + pollIntervalMilliseconds >= timeoutMilliseconds) {
58
- if (!success) console.error("Timeout approaching, last poll cycle completed or error occurred.");
59
- break; // Don't wait if the next interval exceeds timeout
60
- }
61
- await new Promise(resolve => setTimeout(resolve, pollIntervalMilliseconds));
62
- }
63
-
64
- if (!success) {
65
- console.error(`\n--- Polling Timed Out or Failed for Request ID: ${request_id} ---`);
66
- console.error(`Failed to get a COMPLETED status for ${request_id} within 3 minutes.`);
67
- }
68
- }
69
-
70
- } catch (err: any) {
71
- console.error("\n--- Queue Submit Test Failed ---");
72
- console.error("Error during queue submit:", err.message || err);
73
- if (err.stack) {
74
- console.error(err.stack);
75
- }
76
- process.exit(1);
77
- }
78
- }
79
-
80
- main();
@@ -1,41 +0,0 @@
1
- import { yetter } from "../dist/index.js";
2
-
3
- async function main() {
4
- const model = "ytr-ai/flux/dev";
5
- // Subscribe test
6
- try {
7
- console.log("\n--- Starting Subscribe Test ---");
8
- console.time("Subscribe Test");
9
- const result = await yetter.subscribe(model, {
10
- input: {
11
- prompt: "a vibrant coral reef, underwater photography",
12
- num_inference_steps: 28,
13
- },
14
- logs: true,
15
- onQueueUpdate: (update) => {
16
- console.log(`[Queue Update] Status: ${update.status}, Position: ${update.queue_position}`);
17
- if (update.status === "IN_PROGRESS" && update.logs) {
18
- console.log("Logs:");
19
- update.logs.map((log) => log.message).forEach(logMessage => console.log(` - ${logMessage}`));
20
- } else if (update.status === "COMPLETED") {
21
- console.log("Processing completed!");
22
- } else if (update.status === "ERROR") {
23
- console.error("Processing failed. Logs:", update.logs);
24
- }
25
- },
26
- });
27
-
28
- console.log("\n--- Subscribe Test Result ---");
29
- console.log("Results:", result);
30
- console.timeEnd("Subscribe Test");
31
- } catch (err: any) {
32
- console.error("\n--- Subscribe Test Failed ---");
33
- console.error("Error during subscribe:", err.message || err);
34
- if (err.stack) {
35
- console.error(err.stack);
36
- }
37
- process.exit(1);
38
- }
39
- }
40
-
41
- main();
@@ -1,39 +0,0 @@
1
- import { yetter } from "../src/client.js";
2
-
3
- async function main() {
4
- // Configure with API key
5
- yetter.configure({
6
- apiKey: process.env.YTR_API_KEY || "your_api_key_here"
7
- });
8
-
9
- console.log("Step 1: Uploading input image...");
10
-
11
- // Replace with your actual image path
12
- const imagePath = "./test-image.jpg";
13
-
14
- try {
15
- const uploadResult = await yetter.uploadFile(imagePath, {
16
- onProgress: (pct) => console.log(` Upload progress: ${pct}%`),
17
- });
18
- console.log(`✓ Uploaded: ${uploadResult.url}\n`);
19
-
20
- console.log("Step 2: Generating with uploaded image...");
21
- const genResult = await yetter.subscribe("ytr-ai/qwen/image-edit/i2i", {
22
- input: {
23
- prompt: "Transform to watercolor painting style",
24
- image_url: [uploadResult.url],
25
- num_inference_steps: 28,
26
- },
27
- onQueueUpdate: (status) => {
28
- console.log(` Status: ${status.status}, Queue: ${status.queue_position}`);
29
- },
30
- });
31
-
32
- console.log("\n✓ Generation complete!");
33
- console.log("Generated images:", genResult.images);
34
- } catch (error: any) {
35
- console.error("Error:", error.message);
36
- }
37
- }
38
-
39
- main().catch(console.error);
package/src/api.ts DELETED
@@ -1,159 +0,0 @@
1
- import fetch from "cross-fetch";
2
- import {
3
- ClientOptions,
4
- GenerateRequest,
5
- GenerateResponse,
6
- GetStatusRequest,
7
- GetStatusResponse,
8
- CancelRequest,
9
- CancelResponse,
10
- GetResponseRequest,
11
- GetResponseResponse,
12
- GetUploadUrlRequest,
13
- GetUploadUrlResponse,
14
- UploadCompleteRequest,
15
- UploadCompleteResponse,
16
- } from "./types";
17
-
18
- export class YetterImageClient {
19
- private apiKey: string;
20
- private endpoint: string;
21
-
22
- constructor(options: ClientOptions) {
23
- if (!options.apiKey) {
24
- throw new Error("`apiKey` is required");
25
- }
26
- this.apiKey = options.apiKey;
27
- this.endpoint = options.endpoint || "https://api.yetter.ai";
28
- }
29
-
30
- public getApiEndpoint(): string {
31
- return this.endpoint;
32
- }
33
-
34
- public async generate(
35
- body: GenerateRequest
36
- ): Promise<GenerateResponse> {
37
- const url = `${this.endpoint}/${body.model}`;
38
- const res = await fetch(url, {
39
- method: "POST",
40
- headers: {
41
- "Content-Type": "application/json",
42
- Authorization: this.apiKey,
43
- },
44
- body: JSON.stringify(body),
45
- });
46
-
47
- if (!res.ok) {
48
- const errorText = await res.text();
49
- throw new Error(`API error (${res.status}): ${errorText}`);
50
- }
51
-
52
- return (await res.json()) as GenerateResponse;
53
- }
54
-
55
- public async getStatus(body: GetStatusRequest): Promise<GetStatusResponse> {
56
- const url = new URL(body.url);
57
- if (body.logs) {
58
- url.searchParams.append('logs', '1');
59
- }
60
-
61
- const res = await fetch(url.toString(), {
62
- method: "GET",
63
- headers: {
64
- "Content-Type": "application/json",
65
- Authorization: this.apiKey,
66
- },
67
- });
68
-
69
- if (!res.ok) {
70
- const errorText = await res.text();
71
- throw new Error(`API error (${res.status}): ${errorText}`);
72
- }
73
-
74
- return (await res.json()) as GetStatusResponse;
75
- }
76
-
77
- public async cancel(body: CancelRequest): Promise<CancelResponse> {
78
- const res = await fetch(body.url, {
79
- method: "PUT",
80
- headers: {
81
- "Content-Type": "application/json",
82
- Authorization: this.apiKey,
83
- },
84
- });
85
-
86
- if (!res.ok) {
87
- const errorText = await res.text();
88
- throw new Error(`API error (${res.status}): ${errorText}`);
89
- }
90
-
91
- return (await res.json()) as CancelResponse;
92
- }
93
-
94
- public async getResponse(body: GetResponseRequest): Promise<GetResponseResponse> {
95
- const res = await fetch(body.url, {
96
- method: "GET",
97
- headers: {
98
- "Content-Type": "application/json",
99
- Authorization: this.apiKey,
100
- },
101
- });
102
-
103
- if (!res.ok) {
104
- const errorText = await res.text();
105
- throw new Error(`API error (${res.status}): ${errorText}`);
106
- }
107
- return (await res.json()) as GetResponseResponse;
108
- }
109
-
110
- /**
111
- * Request presigned URL(s) for file upload
112
- * @param body Upload request parameters
113
- * @returns Presigned URL response with mode (single/multipart)
114
- */
115
- public async getUploadUrl(
116
- body: GetUploadUrlRequest
117
- ): Promise<GetUploadUrlResponse> {
118
- const res = await fetch(`${this.endpoint}/uploads`, {
119
- method: "POST",
120
- headers: {
121
- "Content-Type": "application/json",
122
- Authorization: this.apiKey,
123
- },
124
- body: JSON.stringify(body),
125
- });
126
-
127
- if (!res.ok) {
128
- const errorText = await res.text();
129
- throw new Error(`Upload URL request failed (${res.status}): ${errorText}`);
130
- }
131
-
132
- return (await res.json()) as GetUploadUrlResponse;
133
- }
134
-
135
- /**
136
- * Notify server that upload is complete
137
- * @param body Completion request with S3 key
138
- * @returns Uploaded file metadata with public URL
139
- */
140
- public async uploadComplete(
141
- body: UploadCompleteRequest
142
- ): Promise<UploadCompleteResponse> {
143
- const res = await fetch(`${this.endpoint}/uploads/complete`, {
144
- method: "POST",
145
- headers: {
146
- "Content-Type": "application/json",
147
- Authorization: this.apiKey,
148
- },
149
- body: JSON.stringify(body),
150
- });
151
-
152
- if (!res.ok) {
153
- const errorText = await res.text();
154
- throw new Error(`Upload completion failed (${res.status}): ${errorText}`);
155
- }
156
-
157
- return (await res.json()) as UploadCompleteResponse;
158
- }
159
- }