Skip to content

Commit 0a28ef5

Browse files
committed
fix: fix vibe transfer custom host
1 parent cca2693 commit 0a28ef5

File tree

3 files changed

+101
-82
lines changed

3 files changed

+101
-82
lines changed

src/client.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class NovelAI {
8989
}
9090

9191
// Handle vibe transfer for V4 models
92-
await this.encodeVibe(processedMetadata);
92+
await this.encodeVibe(processedMetadata, host);
9393

9494
// Get host instance details
9595
const hostInstance =
@@ -142,9 +142,7 @@ export class NovelAI {
142142
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
143143

144144
const jsonPayload = JSON.stringify(payload);
145-
146-
console.log("✨ Sending request to NovelAI API... with:", jsonPayload);
147-
145+
148146
try {
149147
// Make the API request
150148
const response = await fetch(url, {
@@ -518,7 +516,10 @@ export class NovelAI {
518516
* @returns Promise resolving when encoding is complete
519517
* @private
520518
*/
521-
private async encodeVibe(metadata: Metadata): Promise<void> {
519+
private async encodeVibe(
520+
metadata: Metadata,
521+
host: Host | HostInstance = Host.WEB,
522+
): Promise<void> {
522523
// Skip if model is not V4 or V4 Curated
523524
const v4Models = [Model.V4, Model.V4_CUR];
524525
if (!metadata.model || !v4Models.includes(metadata.model)) {
@@ -562,8 +563,9 @@ export class NovelAI {
562563
model: metadata.model,
563564
};
564565

565-
// Use the web host for vibe encoding
566-
const hostInstance = HOST_INSTANCES[Host.WEB];
566+
// Get host instance details
567+
const hostInstance =
568+
typeof host === "string" ? HOST_INSTANCES[host as Host] : host;
567569

568570
try {
569571
// Make the API request using our central request method

src/utils/parse-utils.ts

Lines changed: 85 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,11 @@ async function extractStealthMetadata(
218218
// Dynamic import for Node.js only to prevent browser bundling issues
219219
const canvasModule = await import("canvas").catch(() => {
220220
console.error("Canvas module not installed in Node environment");
221-
throw new Error("Canvas module required for stealth metadata extraction in Node");
221+
throw new Error(
222+
"Canvas module required for stealth metadata extraction in Node",
223+
);
222224
});
223-
225+
224226
img = await canvasModule.loadImage(
225227
`data:image/png;base64,${imageData.base64}`,
226228
);
@@ -248,7 +250,8 @@ async function extractStealthMetadata(
248250
// Wait for image to load in browser
249251
await new Promise<void>((resolve, reject) => {
250252
img.onload = () => resolve();
251-
img.onerror = (e: Event | string) => reject(new Error(`Failed to load image: ${e}`));
253+
img.onerror = (e: Event | string) =>
254+
reject(new Error(`Failed to load image: ${e}`));
252255
// Add timeout to prevent hanging
253256
setTimeout(() => reject(new Error("Image loading timeout")), 30000);
254257
});
@@ -356,9 +359,11 @@ export async function extractImageMetadata(
356359
): Promise<ImageMetadata> {
357360
try {
358361
// First, parse the image to get a consistent format
359-
const parsedImage = await parseImage(input).catch(err => {
362+
const parsedImage = await parseImage(input).catch((err) => {
360363
console.error("Failed to parse image:", err);
361-
throw new Error(`Image parsing failed: ${err.message || "Unknown error"}`);
364+
throw new Error(
365+
`Image parsing failed: ${err.message || "Unknown error"}`,
366+
);
362367
});
363368

364369
let metadata: MetadataEntry[] = [];
@@ -371,7 +376,10 @@ export async function extractImageMetadata(
371376
if (fileType === "image/png") {
372377
// For PNG files, extract chunks
373378
const buffer = await input.arrayBuffer();
374-
metadata = await extractPngMetadata(buffer, { extractChunks, pngChunkText });
379+
metadata = await extractPngMetadata(buffer, {
380+
extractChunks,
381+
pngChunkText,
382+
});
375383
} else if (
376384
["image/webp", "image/jpeg", "image/avif"].includes(fileType)
377385
) {
@@ -393,7 +401,10 @@ export async function extractImageMetadata(
393401
const buffer = await fs.readFile(input);
394402

395403
if (input.toLowerCase().endsWith(".png")) {
396-
metadata = await extractPngMetadata(buffer.buffer, { extractChunks, pngChunkText });
404+
metadata = await extractPngMetadata(buffer.buffer, {
405+
extractChunks,
406+
pngChunkText,
407+
});
397408
} else if (
398409
[".jpg", ".jpeg", ".webp", ".avif"].some((ext) =>
399410
input.toLowerCase().endsWith(ext),
@@ -474,77 +485,77 @@ export async function getImageSummary(
474485
const parsedImage = await parseImage(input);
475486
const metadata = await extractImageMetadata(input);
476487

477-
const summary: ImageSummary = {
478-
dimensions: {
479-
width: parsedImage.width,
480-
height: parsedImage.height,
481-
},
482-
hasMetadata: metadata.entries.length > 0,
483-
metadataType: metadata.type,
484-
rawEntries: metadata.entries,
485-
};
488+
const summary: ImageSummary = {
489+
dimensions: {
490+
width: parsedImage.width,
491+
height: parsedImage.height,
492+
},
493+
hasMetadata: metadata.entries.length > 0,
494+
metadataType: metadata.type,
495+
rawEntries: metadata.entries,
496+
};
486497

487-
// Extract key information based on metadata type
488-
if (metadata.type === MetadataType.STABLE_DIFFUSION_WEBUI) {
489-
summary.generationTool = "Stable Diffusion WebUI";
490-
491-
// Find positive and negative prompts
492-
const positivePrompt = metadata.entries.find(
493-
(e) => e.keyword === "Positive prompt",
494-
);
495-
const negativePrompt = metadata.entries.find(
496-
(e) => e.keyword === "Negative prompt",
497-
);
498-
const genParams = metadata.entries.find(
499-
(e) => e.keyword === "Generation parameters",
500-
);
501-
502-
if (positivePrompt) summary.positivePrompt = positivePrompt.text;
503-
if (negativePrompt) summary.negativePrompt = negativePrompt.text;
504-
505-
// Parse parameters like Steps, Sampler, CFG, etc.
506-
if (genParams) {
507-
const params: Record<string, any> = {};
508-
const paramParts = genParams.text.split(",").map((p) => p.trim());
509-
510-
paramParts.forEach((part) => {
511-
const colonIndex = part.indexOf(":");
512-
if (colonIndex > 0) {
513-
const key = part.slice(0, colonIndex).trim();
514-
const value = part.slice(colonIndex + 1).trim();
515-
params[key] = value;
516-
}
517-
});
498+
// Extract key information based on metadata type
499+
if (metadata.type === MetadataType.STABLE_DIFFUSION_WEBUI) {
500+
summary.generationTool = "Stable Diffusion WebUI";
518501

519-
summary.parameters = params;
520-
}
521-
} else if (metadata.type === MetadataType.NOVELAI) {
522-
summary.generationTool = "NovelAI";
523-
524-
// Find common NovelAI entries
525-
const prompt = metadata.entries.find((e) => e.keyword === "prompt");
526-
const uc = metadata.entries.find((e) => e.keyword === "uc");
527-
528-
if (prompt) summary.positivePrompt = prompt.text;
529-
if (uc) summary.negativePrompt = uc.text;
530-
531-
// Convert all entries to parameters
532-
summary.parameters = metadata.entries.reduce(
533-
(acc, entry) => {
534-
if (entry.keyword !== "prompt" && entry.keyword !== "uc") {
535-
try {
536-
acc[entry.keyword] = JSON.parse(entry.text);
537-
} catch {
538-
acc[entry.keyword] = entry.text;
502+
// Find positive and negative prompts
503+
const positivePrompt = metadata.entries.find(
504+
(e) => e.keyword === "Positive prompt",
505+
);
506+
const negativePrompt = metadata.entries.find(
507+
(e) => e.keyword === "Negative prompt",
508+
);
509+
const genParams = metadata.entries.find(
510+
(e) => e.keyword === "Generation parameters",
511+
);
512+
513+
if (positivePrompt) summary.positivePrompt = positivePrompt.text;
514+
if (negativePrompt) summary.negativePrompt = negativePrompt.text;
515+
516+
// Parse parameters like Steps, Sampler, CFG, etc.
517+
if (genParams) {
518+
const params: Record<string, any> = {};
519+
const paramParts = genParams.text.split(",").map((p) => p.trim());
520+
521+
paramParts.forEach((part) => {
522+
const colonIndex = part.indexOf(":");
523+
if (colonIndex > 0) {
524+
const key = part.slice(0, colonIndex).trim();
525+
const value = part.slice(colonIndex + 1).trim();
526+
params[key] = value;
539527
}
540-
}
541-
return acc;
542-
},
543-
{} as Record<string, any>,
544-
);
545-
}
528+
});
529+
530+
summary.parameters = params;
531+
}
532+
} else if (metadata.type === MetadataType.NOVELAI) {
533+
summary.generationTool = "NovelAI";
534+
535+
// Find common NovelAI entries
536+
const prompt = metadata.entries.find((e) => e.keyword === "prompt");
537+
const uc = metadata.entries.find((e) => e.keyword === "uc");
538+
539+
if (prompt) summary.positivePrompt = prompt.text;
540+
if (uc) summary.negativePrompt = uc.text;
541+
542+
// Convert all entries to parameters
543+
summary.parameters = metadata.entries.reduce(
544+
(acc, entry) => {
545+
if (entry.keyword !== "prompt" && entry.keyword !== "uc") {
546+
try {
547+
acc[entry.keyword] = JSON.parse(entry.text);
548+
} catch {
549+
acc[entry.keyword] = entry.text;
550+
}
551+
}
552+
return acc;
553+
},
554+
{} as Record<string, any>,
555+
);
556+
}
546557

547-
return summary;
558+
return summary;
548559
} catch (error) {
549560
console.error("Failed to create image summary:", error);
550561
return {

tsup.config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ export default defineConfig({
77
splitting: false,
88
clean: true,
99
external: ["fs", "path", "canvas"], // Mark Node.js built-ins as external
10-
noExternal: ["jszip", "pako", "png-chunks-extract", "png-chunk-text", "exifreader"], // Bundle these dependencies
10+
noExternal: [
11+
"jszip",
12+
"pako",
13+
"png-chunks-extract",
14+
"png-chunk-text",
15+
"exifreader",
16+
], // Bundle these dependencies
1117
target: "es2020",
1218
define: {
1319
"process.env.NODE_ENV": '"production"',

0 commit comments

Comments
 (0)