thumbnailgpt 1.0.7 → 1.0.9
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/README.md +22 -27
- package/dist/client.d.ts +16 -8
- package/dist/client.js +51 -61
- package/dist/index.js +47 -14
- package/dist/types.d.ts +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,14 +15,14 @@ Generate, iterate, download, and manage viral, high-CTR YouTube thumbnails direc
|
|
|
15
15
|
|
|
16
16
|
## Highlights
|
|
17
17
|
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
18
|
+
- **Zero-Install Execution**: Run any command immediately via `npx thumbnailgpt`.
|
|
19
|
+
- **Multi-Resolution Rendering**: Generate in standard **1K**, HD **2K**, or Ultra-HD **4K**.
|
|
20
|
+
- **Dual Aspect Ratios**: Native support for **16:9** (YouTube standard) and **9:16** (YouTube Shorts / TikTok / Reels).
|
|
21
|
+
- **Creator Persona Consistency**: Feature your trained creator persona across any generation using `--persona <id>`.
|
|
22
|
+
- **Conversational Iteration**: Thread your edits using `--chat <chatId>` to refine text, lighting, facial expression, or background details.
|
|
23
|
+
- **Interactive Terminal REPL**: Full interactive terminal chat session with live preview links (`thumbnailgpt chat`).
|
|
24
|
+
- **Scripting & Automation Ready**: Output raw image URLs with `--url-only` or machine-readable JSON with `--json` for shell pipes, webhooks, and GitHub Actions.
|
|
25
|
+
- **Account Deletion Guardrails**: Enforces production security; destructive deletions are restricted to the web dashboard to prevent accidental loss from automated scripts or autonomous AI agents.
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -62,20 +62,16 @@ npx thumbnailgpt login
|
|
|
62
62
|
npx thumbnailgpt login --key tgpt_live_YOUR_API_KEY
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
### 2. Verify Your Account
|
|
65
|
+
### 2. Verify Your Account Status
|
|
66
66
|
```bash
|
|
67
67
|
npx thumbnailgpt whoami
|
|
68
68
|
```
|
|
69
69
|
*Output:*
|
|
70
70
|
```text
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
Pricing Tiers:
|
|
76
|
-
1K (Standard): 10 credits
|
|
77
|
-
2K (HD): 20 credits
|
|
78
|
-
4K (Ultra HD): 30 credits
|
|
71
|
+
ThumbnailGPT Account
|
|
72
|
+
Account: user@example.com
|
|
73
|
+
Plan Status: ACTIVE
|
|
74
|
+
Credits: 583 available
|
|
79
75
|
```
|
|
80
76
|
|
|
81
77
|
### 3. Generate a Thumbnail
|
|
@@ -84,7 +80,7 @@ npx thumbnailgpt generate "Extreme 100 Days Hardcore Survival in Minecraft" --re
|
|
|
84
80
|
```
|
|
85
81
|
*Output:*
|
|
86
82
|
```text
|
|
87
|
-
|
|
83
|
+
Generation complete (14s)
|
|
88
84
|
|
|
89
85
|
Thumbnail URL: https://assets.thumbnailgpt.com/generations/.../thumbnail.png
|
|
90
86
|
Chat Thread: https://thumbnailgpt.com/studio/3c9d1e5f-...
|
|
@@ -109,7 +105,7 @@ npx thumbnailgpt generate [options] <prompt>
|
|
|
109
105
|
| Flag | Short | Default | Description |
|
|
110
106
|
| :--- | :---: | :---: | :--- |
|
|
111
107
|
| `--ratio <ratio>` | `-r` | `16:9` | Aspect ratio: `16:9` (YouTube standard) or `9:16` (Shorts / Reels) |
|
|
112
|
-
| `--res <resolution>` | `-q` | `1K` | Resolution quality: `1K
|
|
108
|
+
| `--res <resolution>` | `-q` | `1K` | Resolution quality: `1K`, `2K`, or `4K` |
|
|
113
109
|
| `--ref <urls...>` | | | Up to 5 public image URLs or base64 data URIs as visual references |
|
|
114
110
|
| `--yt <url>` | | | YouTube video URL to extract title, context, and current thumbnail |
|
|
115
111
|
| `--persona <personaId>` | `-p` | | Creator Persona UUID to feature in the generated thumbnail |
|
|
@@ -172,10 +168,9 @@ npx thumbnailgpt chat 3c9d1e5f-c648-4b3c-a6f0-811d073c22c2
|
|
|
172
168
|
```
|
|
173
169
|
|
|
174
170
|
Commands available inside interactive chat mode:
|
|
175
|
-
- Type your prompt
|
|
171
|
+
- Type your prompt to iterate.
|
|
176
172
|
- `/url` — Display the latest generated thumbnail URL.
|
|
177
173
|
- `/open` — Open the current thumbnail in your default web browser.
|
|
178
|
-
- `/cost` — View credit cost tiers.
|
|
179
174
|
- `/help` — Display interactive mode shortcuts.
|
|
180
175
|
- `/exit` or `exit` — Exit interactive session.
|
|
181
176
|
|
|
@@ -183,7 +178,7 @@ Commands available inside interactive chat mode:
|
|
|
183
178
|
|
|
184
179
|
### `thumbnailgpt whoami`
|
|
185
180
|
|
|
186
|
-
Display your authenticated email, subscription
|
|
181
|
+
Display your authenticated email, subscription status, and available balance.
|
|
187
182
|
|
|
188
183
|
```bash
|
|
189
184
|
npx thumbnailgpt whoami
|
|
@@ -304,17 +299,17 @@ Now you can instruct Claude or Cursor:
|
|
|
304
299
|
|
|
305
300
|
To prevent accidental data loss or unauthorized bulk deletions by third-party scripts and autonomous AI agents:
|
|
306
301
|
- Destructive deletions (`DELETE` operations) are disabled over Personal API Keys, the CLI, and the MCP server.
|
|
307
|
-
- Resource creation, iteration,
|
|
302
|
+
- Resource creation, iteration, account balance checks, persona styling, and asset retrievals are fully enabled.
|
|
308
303
|
- Deletions can be performed safely by the account owner inside the **[ThumbnailGPT Web Studio](https://thumbnailgpt.com/studio)**.
|
|
309
304
|
|
|
310
305
|
---
|
|
311
306
|
|
|
312
307
|
## Support & Resources
|
|
313
308
|
|
|
314
|
-
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
309
|
+
- Web Studio: [https://thumbnailgpt.com](https://thumbnailgpt.com)
|
|
310
|
+
- API & CLI Docs: [https://thumbnailgpt.com/docs](https://thumbnailgpt.com/docs)
|
|
311
|
+
- API Key Management: [https://thumbnailgpt.com/studio?settings=api-key](https://thumbnailgpt.com/studio?settings=api-key)
|
|
312
|
+
- Support Email: [support@thumbnailgpt.com](mailto:support@thumbnailgpt.com)
|
|
318
313
|
|
|
319
314
|
---
|
|
320
315
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { CreditBalanceResponse, StudioGenerateOptions, StudioDispatchResult, StudioConversationResponse, GenerationSettledResult, PersonaItem, ThumbnailItem } from "./types.js";
|
|
1
|
+
import type { CreditBalanceResponse, StudioGenerateOptions, StudioDispatchResult, StudioConversationResponse, GenerationSettledResult, PersonaItem, ThumbnailItem, ListChatsResponse, ListPersonasResponse } from "./types.js";
|
|
2
2
|
export declare class ThumbnailGPTClient {
|
|
3
3
|
private apiKey;
|
|
4
4
|
private apiUrl;
|
|
5
5
|
constructor(apiKey?: string, apiUrl?: string);
|
|
6
6
|
private request;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Fetch current credit balance and subscription status
|
|
9
9
|
*/
|
|
10
10
|
getCredits(): Promise<CreditBalanceResponse>;
|
|
11
11
|
/**
|
|
12
|
-
* Dispatch
|
|
12
|
+
* Dispatch studio thumbnail generation task
|
|
13
13
|
*/
|
|
14
14
|
dispatchStudio(options: StudioGenerateOptions): Promise<StudioDispatchResult>;
|
|
15
15
|
/**
|
|
@@ -17,13 +17,21 @@ export declare class ThumbnailGPTClient {
|
|
|
17
17
|
*/
|
|
18
18
|
getChat(chatId: string): Promise<StudioConversationResponse>;
|
|
19
19
|
/**
|
|
20
|
-
* List recent studio conversations
|
|
20
|
+
* List recent studio conversations with pagination
|
|
21
21
|
*/
|
|
22
|
-
listChats(
|
|
22
|
+
listChats(options?: {
|
|
23
|
+
page?: number;
|
|
24
|
+
limit?: number;
|
|
25
|
+
}): Promise<ListChatsResponse>;
|
|
23
26
|
/**
|
|
24
|
-
* Retrieve active, ready-to-use personas for the user
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
* Retrieve active, ready-to-use personas for the user with pagination
|
|
28
|
+
*/
|
|
29
|
+
listPersonas(options?: {
|
|
30
|
+
page?: number;
|
|
31
|
+
limit?: number;
|
|
32
|
+
}): Promise<ListPersonasResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Retrieve active, ready-to-use personas (returns array for backward compatibility)
|
|
27
35
|
*/
|
|
28
36
|
getPersonas(): Promise<PersonaItem[]>;
|
|
29
37
|
/**
|
package/dist/client.js
CHANGED
|
@@ -14,74 +14,51 @@ export class ThumbnailGPTClient {
|
|
|
14
14
|
async request(endpoint, options = {}) {
|
|
15
15
|
const url = `${this.apiUrl}${endpoint.startsWith("/") ? "" : "/"}${endpoint}`;
|
|
16
16
|
const headers = {
|
|
17
|
-
"Content-Type": "application/json",
|
|
18
17
|
Authorization: `Bearer ${this.apiKey}`,
|
|
19
|
-
|
|
20
|
-
"User-Agent": "thumbnailgpt-cli/1.0.7",
|
|
18
|
+
"Content-Type": "application/json",
|
|
21
19
|
...options.headers,
|
|
22
20
|
};
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
let res;
|
|
22
|
+
try {
|
|
23
|
+
res = await fetch(url, { ...options, headers });
|
|
24
|
+
}
|
|
25
|
+
catch (netErr) {
|
|
26
|
+
throw new Error(`Failed to reach ThumbnailGPT backend at ${this.apiUrl}: ${netErr.message}`);
|
|
27
|
+
}
|
|
25
28
|
if (!res.ok) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
let errMsg = `Request failed (${res.status} ${res.statusText})`;
|
|
30
|
+
try {
|
|
31
|
+
const errorJson = await res.json();
|
|
32
|
+
errMsg = errorJson.error || errorJson.message || errMsg;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Fallback to text status
|
|
36
|
+
}
|
|
37
|
+
throw new Error(errMsg);
|
|
33
38
|
}
|
|
34
|
-
return
|
|
39
|
+
return res.json();
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
|
-
*
|
|
42
|
+
* Fetch current credit balance and subscription status
|
|
38
43
|
*/
|
|
39
44
|
async getCredits() {
|
|
40
45
|
return this.request("/api/credits/balance");
|
|
41
46
|
}
|
|
42
47
|
/**
|
|
43
|
-
* Dispatch
|
|
48
|
+
* Dispatch studio thumbnail generation task
|
|
44
49
|
*/
|
|
45
50
|
async dispatchStudio(options) {
|
|
46
|
-
if (options.referenceImages && options.referenceImages.length > 5) {
|
|
47
|
-
throw new Error("A maximum of 5 reference images is allowed.");
|
|
48
|
-
}
|
|
49
|
-
const rawRefImages = (options.referenceImages || []).slice(0, 5);
|
|
50
|
-
const processedRefImages = [];
|
|
51
|
-
for (const img of rawRefImages) {
|
|
52
|
-
if (typeof img === "string") {
|
|
53
|
-
if (img.startsWith("http://") || img.startsWith("https://") || img.startsWith("data:")) {
|
|
54
|
-
processedRefImages.push(img);
|
|
55
|
-
}
|
|
56
|
-
else if (fs.existsSync(img)) {
|
|
57
|
-
const ext = path.extname(img).toLowerCase().replace(".", "");
|
|
58
|
-
const mimeType = ext === "jpg" || ext === "jpeg"
|
|
59
|
-
? "image/jpeg"
|
|
60
|
-
: ext === "png"
|
|
61
|
-
? "image/png"
|
|
62
|
-
: ext === "webp"
|
|
63
|
-
? "image/webp"
|
|
64
|
-
: "image/jpeg";
|
|
65
|
-
const buffer = fs.readFileSync(img);
|
|
66
|
-
const base64 = buffer.toString("base64");
|
|
67
|
-
processedRefImages.push(`data:${mimeType};base64,${base64}`);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
processedRefImages.push(img);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
51
|
return this.request("/api/studio", {
|
|
75
52
|
method: "POST",
|
|
76
53
|
body: JSON.stringify({
|
|
77
|
-
chatId: options.chatId,
|
|
78
54
|
feature: "recreate_thumbnail",
|
|
79
55
|
prompt: options.prompt,
|
|
56
|
+
chatId: options.chatId,
|
|
80
57
|
aspectRatio: options.aspectRatio || "16:9",
|
|
81
58
|
resolution: options.resolution || "1K",
|
|
82
|
-
referenceImages:
|
|
83
|
-
youtubeUrl: options.youtubeUrl
|
|
84
|
-
personaId: options.personaId
|
|
59
|
+
referenceImages: options.referenceImages || [],
|
|
60
|
+
youtubeUrl: options.youtubeUrl,
|
|
61
|
+
personaId: options.personaId,
|
|
85
62
|
baseImage: options.baseImage,
|
|
86
63
|
}),
|
|
87
64
|
});
|
|
@@ -93,23 +70,36 @@ export class ThumbnailGPTClient {
|
|
|
93
70
|
return this.request(`/api/studio/${chatId}`);
|
|
94
71
|
}
|
|
95
72
|
/**
|
|
96
|
-
* List recent studio conversations
|
|
73
|
+
* List recent studio conversations with pagination
|
|
97
74
|
*/
|
|
98
|
-
async listChats() {
|
|
99
|
-
|
|
75
|
+
async listChats(options) {
|
|
76
|
+
const page = Math.max(1, options?.page ?? 1);
|
|
77
|
+
const limit = Math.min(100, Math.max(1, options?.limit ?? 20));
|
|
78
|
+
return this.request(`/api/studio?page=${page}&limit=${limit}`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Retrieve active, ready-to-use personas for the user with pagination
|
|
82
|
+
*/
|
|
83
|
+
async listPersonas(options) {
|
|
84
|
+
const page = Math.max(1, options?.page ?? 1);
|
|
85
|
+
const limit = Math.min(50, Math.max(1, options?.limit ?? 20));
|
|
86
|
+
const res = await this.request(`/api/personas?page=${page}&limit=${limit}`);
|
|
87
|
+
return {
|
|
88
|
+
success: res.success ?? true,
|
|
89
|
+
personas: (res.personas || []).map((p) => ({
|
|
90
|
+
id: p.id,
|
|
91
|
+
name: p.name,
|
|
92
|
+
created_at: p.created_at,
|
|
93
|
+
})),
|
|
94
|
+
pagination: res.pagination,
|
|
95
|
+
};
|
|
100
96
|
}
|
|
101
97
|
/**
|
|
102
|
-
* Retrieve active, ready-to-use personas for
|
|
103
|
-
* Only 'ready' personas are returned. Raw image URLs, character sheets,
|
|
104
|
-
* error traces, and database internals are strictly redacted.
|
|
98
|
+
* Retrieve active, ready-to-use personas (returns array for backward compatibility)
|
|
105
99
|
*/
|
|
106
100
|
async getPersonas() {
|
|
107
|
-
const res = await this.
|
|
108
|
-
return
|
|
109
|
-
id: p.id,
|
|
110
|
-
name: p.name,
|
|
111
|
-
created_at: p.created_at,
|
|
112
|
-
}));
|
|
101
|
+
const res = await this.listPersonas({ page: 1, limit: 50 });
|
|
102
|
+
return res.personas;
|
|
113
103
|
}
|
|
114
104
|
/**
|
|
115
105
|
* Asynchronously dispatch and poll until completion
|
|
@@ -117,8 +107,8 @@ export class ThumbnailGPTClient {
|
|
|
117
107
|
async generateAndWait(options, onProgress, timeoutSec = 120) {
|
|
118
108
|
// 1. Credit Pre-check
|
|
119
109
|
const credits = await this.getCredits();
|
|
120
|
-
const resolutionCosts = { "1K":
|
|
121
|
-
const required = resolutionCosts[options.resolution || "1K"] ||
|
|
110
|
+
const resolutionCosts = { "1K": 20, "2K": 30, "4K": 40 };
|
|
111
|
+
const required = resolutionCosts[options.resolution || "1K"] || 20;
|
|
122
112
|
if (credits.credits < required) {
|
|
123
113
|
throw new Error(`Insufficient credits. Required: ${required}, Available: ${credits.credits}. Top up at https://thumbnailgpt.com/pricing`);
|
|
124
114
|
}
|
package/dist/index.js
CHANGED
|
@@ -55,7 +55,7 @@ const program = new Command();
|
|
|
55
55
|
program
|
|
56
56
|
.name("thumbnailgpt")
|
|
57
57
|
.description("Official CLI for ThumbnailGPT — Generate, iterate, and manage thumbnails from your terminal")
|
|
58
|
-
.version("1.0.
|
|
58
|
+
.version("1.0.9");
|
|
59
59
|
// 1. Auth Login
|
|
60
60
|
program
|
|
61
61
|
.command("login")
|
|
@@ -108,9 +108,11 @@ program
|
|
|
108
108
|
const credits = await client.getCredits();
|
|
109
109
|
spinner.stop();
|
|
110
110
|
console.log(pc.bold("\nThumbnailGPT Account"));
|
|
111
|
+
if (credits.email) {
|
|
112
|
+
console.log(`${pc.gray("Account:")} ${pc.white(pc.bold(credits.email))}`);
|
|
113
|
+
}
|
|
111
114
|
console.log(`${pc.gray("Plan Status:")} ${pc.cyan(credits.subscription_status.toUpperCase())}`);
|
|
112
|
-
console.log(`${pc.gray("Credits:")} ${pc.green(pc.bold(String(credits.credits)))} available`);
|
|
113
|
-
console.log(`${pc.gray("Cost Tiers:")} 1K = 10 cr | 2K = 20 cr | 4K = 30 cr\n`);
|
|
115
|
+
console.log(`${pc.gray("Credits:")} ${pc.green(pc.bold(String(credits.credits)))} available\n`);
|
|
114
116
|
}
|
|
115
117
|
catch (err) {
|
|
116
118
|
handleError(err, spinner);
|
|
@@ -143,7 +145,7 @@ program
|
|
|
143
145
|
}
|
|
144
146
|
const res = (options.res || "1K").toUpperCase().trim();
|
|
145
147
|
if (res !== "1K" && res !== "2K" && res !== "4K") {
|
|
146
|
-
console.error(pc.red(`\nError: Invalid resolution "${res}". Supported resolutions: 1K
|
|
148
|
+
console.error(pc.red(`\nError: Invalid resolution "${res}". Supported resolutions: 1K, 2K, 4K`));
|
|
147
149
|
process.exit(1);
|
|
148
150
|
}
|
|
149
151
|
const client = new ThumbnailGPTClient();
|
|
@@ -284,14 +286,25 @@ program
|
|
|
284
286
|
const chats = program.command("chats").description("Manage chat conversations");
|
|
285
287
|
chats
|
|
286
288
|
.command("list")
|
|
287
|
-
.description("List recent chat conversations")
|
|
288
|
-
.
|
|
289
|
+
.description("List recent chat conversations with pagination")
|
|
290
|
+
.option("-p, --page <number>", "Page number", "1")
|
|
291
|
+
.option("-l, --limit <number>", "Items per page (max 100)", "20")
|
|
292
|
+
.option("--json", "Output response as raw JSON", false)
|
|
293
|
+
.action(async (opts) => {
|
|
289
294
|
let spinner = null;
|
|
290
295
|
try {
|
|
296
|
+
const page = Math.max(1, parseInt(opts.page, 10) || 1);
|
|
297
|
+
const limit = Math.min(100, Math.max(1, parseInt(opts.limit, 10) || 20));
|
|
298
|
+
if (!opts.json) {
|
|
299
|
+
spinner = ora("Fetching conversations...").start();
|
|
300
|
+
}
|
|
291
301
|
const client = new ThumbnailGPTClient();
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
302
|
+
const res = await client.listChats({ page, limit });
|
|
303
|
+
if (opts.json) {
|
|
304
|
+
console.log(JSON.stringify(res, null, 2));
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
spinner?.stop();
|
|
295
308
|
const chatList = res.chats || [];
|
|
296
309
|
if (chatList.length === 0) {
|
|
297
310
|
console.log(pc.gray("No conversations found."));
|
|
@@ -302,6 +315,10 @@ chats
|
|
|
302
315
|
console.log(`• ${pc.bold(c.title || "Untitled")} ${pc.gray(`(${c.id})`)}`);
|
|
303
316
|
console.log(` ${pc.gray("Updated:")} ${new Date(c.updated_at).toLocaleString()}`);
|
|
304
317
|
});
|
|
318
|
+
if (res.pagination) {
|
|
319
|
+
const { page: currPage, totalPages, total, hasMore } = res.pagination;
|
|
320
|
+
console.log(pc.dim(`\nPage ${currPage} of ${totalPages} (${total} total conversations)${hasMore ? ` • Run with --page ${currPage + 1} to view more` : ""}`));
|
|
321
|
+
}
|
|
305
322
|
console.log();
|
|
306
323
|
}
|
|
307
324
|
catch (err) {
|
|
@@ -410,14 +427,26 @@ const personasCmd = program
|
|
|
410
427
|
.description("Inspect active creator personas for thumbnail generation");
|
|
411
428
|
personasCmd
|
|
412
429
|
.command("list")
|
|
413
|
-
.description("List your active creator personas (only ready personas are shown)")
|
|
414
|
-
.
|
|
430
|
+
.description("List your active creator personas with pagination (only ready personas are shown)")
|
|
431
|
+
.option("-p, --page <number>", "Page number", "1")
|
|
432
|
+
.option("-l, --limit <number>", "Items per page (max 50)", "20")
|
|
433
|
+
.option("--json", "Output response as raw JSON", false)
|
|
434
|
+
.action(async (opts) => {
|
|
415
435
|
let spinner = null;
|
|
416
436
|
try {
|
|
437
|
+
const page = Math.max(1, parseInt(opts.page, 10) || 1);
|
|
438
|
+
const limit = Math.min(50, Math.max(1, parseInt(opts.limit, 10) || 20));
|
|
439
|
+
if (!opts.json) {
|
|
440
|
+
spinner = ora("Fetching active personas...").start();
|
|
441
|
+
}
|
|
417
442
|
const client = new ThumbnailGPTClient();
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
443
|
+
const res = await client.listPersonas({ page, limit });
|
|
444
|
+
if (opts.json) {
|
|
445
|
+
console.log(JSON.stringify(res, null, 2));
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
spinner?.stop();
|
|
449
|
+
const personas = res.personas || [];
|
|
421
450
|
if (personas.length === 0) {
|
|
422
451
|
console.log(pc.yellow("\nNo active personas found."));
|
|
423
452
|
console.log(`Create your first persona in ThumbnailGPT at: ${pc.cyan("https://thumbnailgpt.com/studio")}\n`);
|
|
@@ -430,6 +459,10 @@ personasCmd
|
|
|
430
459
|
console.log(`${pc.cyan(p.id)} ${pc.bold(p.name)} ${dateStr}`);
|
|
431
460
|
});
|
|
432
461
|
console.log(pc.dim("--------------------------------------------------------------------------------"));
|
|
462
|
+
if (res.pagination) {
|
|
463
|
+
const { page: currPage, totalPages, total, hasMore } = res.pagination;
|
|
464
|
+
console.log(pc.dim(`Page ${currPage} of ${totalPages} (${total} total personas)${hasMore ? ` • Run with --page ${currPage + 1} to view more` : ""}\n`));
|
|
465
|
+
}
|
|
433
466
|
console.log(`Use in generation: ${pc.green('npx thumbnailgpt generate "..." --persona <id>')}\n`);
|
|
434
467
|
}
|
|
435
468
|
catch (err) {
|
package/dist/types.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface StudioDispatchResult {
|
|
|
22
22
|
availableCredits?: number;
|
|
23
23
|
}
|
|
24
24
|
export interface CreditBalanceResponse {
|
|
25
|
+
email?: string;
|
|
25
26
|
credits: number;
|
|
26
27
|
subscription_status: string;
|
|
27
28
|
error?: string;
|
|
@@ -72,3 +73,28 @@ export interface PersonaItem {
|
|
|
72
73
|
name: string;
|
|
73
74
|
created_at?: string;
|
|
74
75
|
}
|
|
76
|
+
export interface PaginationMetadata {
|
|
77
|
+
page: number;
|
|
78
|
+
limit: number;
|
|
79
|
+
total: number;
|
|
80
|
+
totalPages: number;
|
|
81
|
+
hasMore: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface ListChatsResponse {
|
|
84
|
+
success: boolean;
|
|
85
|
+
chats: Array<{
|
|
86
|
+
id: string;
|
|
87
|
+
title: string;
|
|
88
|
+
created_at: string;
|
|
89
|
+
updated_at: string;
|
|
90
|
+
thumbnails?: ThumbnailItem[];
|
|
91
|
+
}>;
|
|
92
|
+
pagination?: PaginationMetadata;
|
|
93
|
+
error?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface ListPersonasResponse {
|
|
96
|
+
success: boolean;
|
|
97
|
+
personas: PersonaItem[];
|
|
98
|
+
pagination?: PaginationMetadata;
|
|
99
|
+
error?: string;
|
|
100
|
+
}
|
package/package.json
CHANGED