image gen / edit - google
This commit is contained in:
parent
0817127d3e
commit
bfdef44b9f
BIN
packages/kbot/cat.png
Normal file
BIN
packages/kbot/cat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
2
packages/kbot/dist-in/commands/images.d.ts
vendored
Normal file
2
packages/kbot/dist-in/commands/images.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare const ImageOptionsSchema: () => any;
|
||||
export declare const imageCommand: (argv: any) => Promise<void>;
|
||||
69
packages/kbot/dist-in/commands/images.js
Normal file
69
packages/kbot/dist-in/commands/images.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { z } from 'zod';
|
||||
import { sync as write } from '@polymech/fs/write';
|
||||
import { sync as exists } from '@polymech/fs/exists';
|
||||
import { isArray } from '@polymech/core/primitives';
|
||||
import { OptionsSchema } from '../zod_schema.js';
|
||||
import { createImage, editImage } from '../lib/images-google.js';
|
||||
import { getLogger } from '../index.js';
|
||||
export const ImageOptionsSchema = () => {
|
||||
const baseSchema = OptionsSchema().pick({
|
||||
prompt: true,
|
||||
include: true,
|
||||
dst: true,
|
||||
model: true,
|
||||
logLevel: true,
|
||||
config: true,
|
||||
api_key: true,
|
||||
});
|
||||
return baseSchema.extend({
|
||||
model: z.string().default('gemini-2.5-flash-image-preview').describe('AI model to use for image generation/editing.'),
|
||||
dst: z.string().describe('Destination path for the output image. Required.'),
|
||||
prompt: z.string().optional().describe('The prompt for image creation or editing.'),
|
||||
});
|
||||
};
|
||||
export const imageCommand = async (argv) => {
|
||||
const logger = getLogger(argv);
|
||||
try {
|
||||
const parsedOptions = ImageOptionsSchema().parse(argv);
|
||||
const { prompt, include, dst, ...rest } = parsedOptions;
|
||||
if (!prompt && !include) {
|
||||
logger.error('Either --prompt (for image creation) or --include (for image editing) must be provided.');
|
||||
return;
|
||||
}
|
||||
if (!dst) {
|
||||
logger.error('--dst is required to specify the output file path.');
|
||||
return;
|
||||
}
|
||||
let imageBuffer = null;
|
||||
if (include && isArray(include) && include.length > 0) {
|
||||
// Image editing
|
||||
const imagePath = include[0];
|
||||
if (!exists(imagePath)) {
|
||||
logger.error(`Input image not found at: ${imagePath}`);
|
||||
return;
|
||||
}
|
||||
if (!prompt) {
|
||||
logger.error('--prompt is required for image editing.');
|
||||
return;
|
||||
}
|
||||
logger.info(`Editing image "${imagePath}" with prompt: "${prompt}"`);
|
||||
imageBuffer = await editImage(prompt, imagePath, parsedOptions);
|
||||
}
|
||||
else if (prompt) {
|
||||
// Image creation
|
||||
logger.info(`Creating image with prompt: "${prompt}"`);
|
||||
imageBuffer = await createImage(prompt, parsedOptions);
|
||||
}
|
||||
if (imageBuffer) {
|
||||
write(dst, imageBuffer);
|
||||
logger.info(`Image saved to: ${dst}`);
|
||||
}
|
||||
else {
|
||||
logger.error('Failed to generate image.');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
logger.error('Failed to parse options or generate image:', error.message, error.issues, error.stack);
|
||||
}
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2VzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL2ltYWdlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXhCLE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVyRCxPQUFPLEVBQUUsT0FBTyxFQUFZLE1BQU0sMkJBQTJCLENBQUM7QUFFOUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUV4QyxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxHQUFHLEVBQUU7SUFDbkMsTUFBTSxVQUFVLEdBQUcsYUFBYSxFQUFFLENBQUMsSUFBSSxDQUFDO1FBQ3BDLE1BQU0sRUFBRSxJQUFJO1FBQ1osT0FBTyxFQUFFLElBQUk7UUFDYixHQUFHLEVBQUUsSUFBSTtRQUNULEtBQUssRUFBRSxJQUFJO1FBQ1gsUUFBUSxFQUFFLElBQUk7UUFDZCxNQUFNLEVBQUUsSUFBSTtRQUNaLE9BQU8sRUFBRSxJQUFJO0tBQ2hCLENBQUMsQ0FBQztJQUVILE9BQU8sVUFBVSxDQUFDLE1BQU0sQ0FBQztRQUNyQixLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLFFBQVEsQ0FBQywrQ0FBK0MsQ0FBQztRQUNySCxHQUFHLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxrREFBa0QsQ0FBQztRQUM1RSxNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0s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
|
||||
3
packages/kbot/dist-in/lib/images-google.d.ts
vendored
Normal file
3
packages/kbot/dist-in/lib/images-google.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import { IKBotOptions } from "../zod_types.js";
|
||||
export declare const createImage: (prompt: string, options: IKBotOptions) => Promise<Buffer | null>;
|
||||
export declare const editImage: (prompt: string, imagePath: string, options: IKBotOptions) => Promise<Buffer | null>;
|
||||
70
packages/kbot/dist-in/lib/images-google.js
Normal file
70
packages/kbot/dist-in/lib/images-google.js
Normal file
@ -0,0 +1,70 @@
|
||||
import { GoogleGenerativeAI } from "@google/generative-ai";
|
||||
import * as fs from "node:fs";
|
||||
import { loadConfig } from "../config.js";
|
||||
import { logger } from "../index.js";
|
||||
import { lookup } from 'mime-types';
|
||||
const createGoogleGenAIClient = (options) => {
|
||||
const config = loadConfig(options);
|
||||
if (!config) {
|
||||
logger.error("Config not found in $HOME/.osr/config.json. " +
|
||||
"Optionally, export OSR_CONFIG with the path to the configuration file.");
|
||||
return undefined;
|
||||
}
|
||||
let apiKey = options.api_key || config?.google?.key;
|
||||
logger.debug(`Google API Key: ${apiKey}`);
|
||||
if (!apiKey) {
|
||||
logger.error(`No gemini key found. Please provide an "api_key", set it in the config, or pass it via JSON config.`);
|
||||
return undefined;
|
||||
}
|
||||
return new GoogleGenerativeAI(apiKey);
|
||||
};
|
||||
export const createImage = async (prompt, options) => {
|
||||
const ai = createGoogleGenAIClient(options);
|
||||
if (!ai) {
|
||||
return null;
|
||||
}
|
||||
const model = ai.getGenerativeModel({ model: options.model || 'gemini-1.5-flash-image-preview' });
|
||||
const result = await model.generateContent(prompt);
|
||||
const response = result.response;
|
||||
const parts = response.candidates[0].content.parts;
|
||||
for (const part of parts) {
|
||||
if ('inlineData' in part) {
|
||||
const inlineData = part.inlineData;
|
||||
if (inlineData) {
|
||||
return Buffer.from(inlineData.data, "base64");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
export const editImage = async (prompt, imagePath, options) => {
|
||||
const ai = createGoogleGenAIClient(options);
|
||||
if (!ai) {
|
||||
return null;
|
||||
}
|
||||
const model = ai.getGenerativeModel({ model: options.model || 'gemini-2.5-flash-image-preview' });
|
||||
const imageData = fs.readFileSync(imagePath);
|
||||
const base64Image = imageData.toString("base64");
|
||||
const mimeType = lookup(imagePath) || 'image/png';
|
||||
const textPart = { text: prompt };
|
||||
const imagePart = {
|
||||
inlineData: {
|
||||
mimeType,
|
||||
data: base64Image,
|
||||
},
|
||||
};
|
||||
const promptParts = [textPart, imagePart];
|
||||
const result = await model.generateContent(promptParts);
|
||||
const response = result.response;
|
||||
const parts = response.candidates[0].content.parts;
|
||||
for (const part of parts) {
|
||||
if ('inlineData' in part) {
|
||||
const inlineData = part.inlineData;
|
||||
if (inlineData) {
|
||||
return Buffer.from(inlineData.data, "base64");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2VzLWdvb2dsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvaW1hZ2VzLWdvb2dsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsa0JBQWtCLEVBQVEsTUFBTSx1QkFBdUIsQ0FBQztBQUNqRSxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUU5QixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUVuQyxNQUFNLHVCQUF1QixHQUFHLENBQUMsT0FBcUIsRUFBRSxFQUFFO0lBQ3RELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNuQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDVixNQUFNLENBQUMsS0FBSyxDQUNSLDhDQUE4QztZQUM5Qyx3RUFBd0UsQ0FDM0UsQ0FBQztRQUNGLE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7SUFFRCxJQUFJLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxDQUFDO0lBQ3BELE1BQU0sQ0FBQyxLQUFLLENBQUMsbUJBQW1CLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFFMUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ1YsTUFBTSxDQUFDLEtBQUssQ0FBQyxxR0FBcUcsQ0FBQyxDQUFDO1FBQ3BILE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7SUFFRCxPQUFPLElBQUksa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDMUMsQ0FBQyxDQUFBO0FBRUQsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLEtBQUssRUFBRSxNQUFjLEVBQUUsT0FBcUIsRUFBMEIsRUFBRTtJQUMvRixNQUFNLEVB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
|
||||
@ -11,6 +11,7 @@ import { build } from './commands/build.js';
|
||||
import { fetch } from './commands/fetch.js';
|
||||
import { run } from './commands/run.js';
|
||||
import { transcribeCommand, TranscribeOptionsSchema } from './commands/transcribe.js';
|
||||
import { imageCommand, ImageOptionsSchema } from './commands/images.js';
|
||||
export const logger = createLogger('llm-tools');
|
||||
const modify = async (argv) => await run(argv);
|
||||
const yargOptions = {
|
||||
@ -30,6 +31,7 @@ const yargOptions = {
|
||||
yargs(hideBin(process.argv))
|
||||
.command('init', 'Initialize KBot configuration', (yargs) => toYargs(yargs, OptionsSchema(), yargOptions), init)
|
||||
.command('modify [prompt]', 'Modify an existing project', (yargs) => toYargs(yargs, OptionsSchema(), yargOptions), modify)
|
||||
.command('image [prompt]', 'Create or edit an image', (yargs) => toYargs(yargs, ImageOptionsSchema(), yargOptions), imageCommand)
|
||||
.command('transcribe', 'Transcribe audio files', (yargs) => toYargs(yargs, TranscribeOptionsSchema(), yargOptions), transcribeCommand)
|
||||
.command('types', 'Generate types', (yargs) => { }, (argv) => types())
|
||||
.command('schemas', 'Generate schemas', (yargs) => { }, (argv) => schemas())
|
||||
@ -41,4 +43,4 @@ yargs(hideBin(process.argv))
|
||||
.help()
|
||||
//.wrap(yargs.terminalWidth() - 20)
|
||||
.parse();
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEtBQUssTUFBTSxPQUFPLENBQUE7QUFDekIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUN2QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUU1QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUcvRCxPQUFPLFdBQVcsTUFBTSxvQkFBb0IsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDakQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDM0MsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBRXZDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDBCQUEwQixDQUFBO0FBRXJGLE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBUSxZQUFZLENBQUMsV0FBVyxDQUFDLENBQUE7QUFFcEQsTUFBTSxNQUFNLEdBQUcsS0FBSyxFQUFFLElBQWUsRUFBRSxFQUFFLENBQUUsTUFBTSxHQUFHLENBQUMsSUFBaUIsQ0FBQyxDQUFBO0FBRXZFLE1BQU0sV0FBVyxHQUFRO0lBQ3ZCLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsRUFBRTtRQUMvQixRQUFRLEdBQUcsRUFBRSxDQUFDO1lBQ1osS0FBSyxRQUFRO2dCQUNYLENBQUM7b0JBQ0Ms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
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEtBQUssTUFBTSxPQUFPLENBQUE7QUFDekIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUN2QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUU1QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUcvRCxPQUFPLFdBQVcsTUFBTSxvQkFBb0IsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDakQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDM0MsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBRXZDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDBCQUEwQixDQUFBO0FBQ3JGLE9BQU8sRUFBRSxZQUFZLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUV2RSxNQUFNLENBQUMsTUFBTSxNQUFNLEdBQVEsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFBO0FBRXBELE1BQU0sTUFBTSxHQUFHLEtBQUssRUFBRSxJQUFlLEVBQUUsRUFBRSxDQUFFLE1BQU0sR0FBRyxDQUFDLElBQWlCLENBQUMsQ0FBQTtBQUV2RSxNQUFNLFdBQVcsR0FBUTtJQUN2QixLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLEVBQUU7UUFD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
|
||||
38
packages/kbot/docs/images.md
Normal file
38
packages/kbot/docs/images.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Image Command
|
||||
|
||||
The `image` command allows you to create and edit images using Google's Gemini models.
|
||||
|
||||
## Description
|
||||
|
||||
This tool can be used in two modes:
|
||||
|
||||
1. **Image Creation (Text-to-Image)**: Generate an image from a text description.
|
||||
2. **Image Editing (Image-and-Text-to-Image)**: Modify an existing image based on a text description.
|
||||
|
||||
## Usage
|
||||
|
||||
### Image Creation
|
||||
|
||||
To create an image, provide a text prompt using the `prompt` argument or option. You must also specify an output path with `--dst`.
|
||||
|
||||
```bash
|
||||
kbot image "A futuristic cityscape at sunset" --dst ./cityscape.png
|
||||
```
|
||||
|
||||
### Image Editing
|
||||
|
||||
To edit an image, you need to provide the path to the input image using the `--include` (or `-i`) option and a text prompt describing the desired changes.
|
||||
|
||||
```bash
|
||||
kbot image "Make the sky purple" --include ./cityscape.png --dst ./cityscape_purple.png
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
- `[prompt]`: (Optional) The text prompt for creating or editing an image. Can be provided as a positional argument.
|
||||
- `--dst <path>`: (Required) The path to save the output image.
|
||||
- `--include <path>`, `-i <path>`: (Optional) The path to the input image for editing.
|
||||
- `--model <model_name>`: (Optional) The model to use for image generation. Defaults to `gemini-1.5-flash-image-preview`.
|
||||
- `--api_key <key>`: (Optional) Your Google GenAI API key. It can also be configured in the kbot config file.
|
||||
- `--logLevel <level>`: (Optional) Set the logging level.
|
||||
- `--config <path>`: (Optional) Path to a custom configuration file.
|
||||
249
packages/kbot/package-lock.json
generated
249
packages/kbot/package-lock.json
generated
@ -10,6 +10,8 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dmitryrechkin/json-schema-to-zod": "1.0.1",
|
||||
"@google/genai": "1.19.0",
|
||||
"@google/generative-ai": "0.24.1",
|
||||
"@polymech/ai-tools": "file:../ai-tools",
|
||||
"@polymech/cache": "file:../cache",
|
||||
"@polymech/commons": "file:../commons",
|
||||
@ -74,7 +76,6 @@
|
||||
"dependencies": {
|
||||
"@datalust/winston-seq": "^2.0.0",
|
||||
"@inquirer/prompts": "^7.3.2",
|
||||
"@keyv/sqlite": "^4.0.5",
|
||||
"@polymech/commons": "file:../commons",
|
||||
"@polymech/core": "file:../core",
|
||||
"@polymech/fs": "file:../fs",
|
||||
@ -912,6 +913,36 @@
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.19.0.tgz",
|
||||
"integrity": "sha512-mIMV3M/KfzzFA//0fziK472wKBJ1TdJLhozIUJKTPLyTDN1NotU+hyoHW/N0cfrcEWUK20YA0GxCeHC4z0SbMA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"google-auth-library": "^9.14.2",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.11.4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@modelcontextprotocol/sdk": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@google/generative-ai": {
|
||||
"version": "0.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz",
|
||||
"integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||
@ -2653,6 +2684,15 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
@ -3017,7 +3057,6 @@
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -3034,6 +3073,15 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
|
||||
"integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
@ -3156,6 +3204,12 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/buffer-fill": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
|
||||
@ -4592,6 +4646,15 @@
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.102",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz",
|
||||
@ -5418,6 +5481,48 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
|
||||
"integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"extend": "^3.0.2",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"is-stream": "^2.0.0",
|
||||
"node-fetch": "^2.6.9",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios/node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gcp-metadata": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz",
|
||||
"integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"gaxios": "^6.1.1",
|
||||
"google-logging-utils": "^0.0.2",
|
||||
"json-bigint": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
@ -5620,6 +5725,32 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/google-auth-library": {
|
||||
"version": "9.15.1",
|
||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz",
|
||||
"integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"ecdsa-sig-formatter": "^1.0.11",
|
||||
"gaxios": "^6.1.1",
|
||||
"gcp-metadata": "^6.1.0",
|
||||
"gtoken": "^7.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/google-logging-utils": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz",
|
||||
"integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
@ -5710,6 +5841,19 @@
|
||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gtoken": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
||||
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"gaxios": "^6.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@ -5833,6 +5977,19 @@
|
||||
"node": ">=10.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@ -6339,6 +6496,15 @@
|
||||
"node": ">= 10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-bigint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
@ -6407,6 +6573,27 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
||||
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "^1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
|
||||
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@ -7786,6 +7973,26 @@
|
||||
"integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||
@ -9048,7 +9255,6 @@
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -10063,6 +10269,12 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/trim-repeated": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
|
||||
@ -11054,6 +11266,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
@ -11262,6 +11487,12 @@
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.97.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
|
||||
@ -11477,6 +11708,16 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@ -11598,8 +11839,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
"test": "vitest run",
|
||||
"test:basic": "vitest run tests/unit/basic.test.ts",
|
||||
"test:transcribe": "vitest run tests/unit/transcribe/transcribe.test.ts",
|
||||
"test:images": "vitest run tests/unit/images/images.test.ts",
|
||||
"test:math": "vitest run tests/unit/math.test.ts",
|
||||
"test:format": "vitest run tests/unit/format.test.ts",
|
||||
"test:options-glob": "vitest run tests/unit/options-glob.test.ts",
|
||||
@ -56,6 +57,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@dmitryrechkin/json-schema-to-zod": "1.0.1",
|
||||
"@google/genai": "1.19.0",
|
||||
"@google/generative-ai": "0.24.1",
|
||||
"@polymech/ai-tools": "file:../ai-tools",
|
||||
"@polymech/cache": "file:../cache",
|
||||
"@polymech/commons": "file:../commons",
|
||||
|
||||
78
packages/kbot/src/commands/images.ts
Normal file
78
packages/kbot/src/commands/images.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { z } from 'zod';
|
||||
import * as path from 'node:path';
|
||||
import { sync as write } from '@polymech/fs/write';
|
||||
import { sync as exists } from '@polymech/fs/exists';
|
||||
import { ILogObj, Logger } from 'tslog';
|
||||
import { isArray, isString } from '@polymech/core/primitives';
|
||||
|
||||
import { OptionsSchema } from '../zod_schema.js';
|
||||
import { createImage, editImage } from '../lib/images-google.js';
|
||||
import { getLogger } from '../index.js';
|
||||
|
||||
export const ImageOptionsSchema = () => {
|
||||
const baseSchema = OptionsSchema().pick({
|
||||
prompt: true,
|
||||
include: true,
|
||||
dst: true,
|
||||
model: true,
|
||||
logLevel: true,
|
||||
config: true,
|
||||
api_key: true,
|
||||
});
|
||||
|
||||
return baseSchema.extend({
|
||||
model: z.string().default('gemini-2.5-flash-image-preview').describe('AI model to use for image generation/editing.'),
|
||||
dst: z.string().describe('Destination path for the output image. Required.'),
|
||||
prompt: z.string().optional().describe('The prompt for image creation or editing.'),
|
||||
});
|
||||
}
|
||||
|
||||
export const imageCommand = async (argv: any) => {
|
||||
const logger = getLogger(argv);
|
||||
|
||||
try {
|
||||
const parsedOptions = ImageOptionsSchema().parse(argv);
|
||||
const { prompt, include, dst, ...rest } = parsedOptions;
|
||||
|
||||
if (!prompt && !include) {
|
||||
logger.error('Either --prompt (for image creation) or --include (for image editing) must be provided.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dst) {
|
||||
logger.error('--dst is required to specify the output file path.');
|
||||
return;
|
||||
}
|
||||
|
||||
let imageBuffer: Buffer | null = null;
|
||||
|
||||
if (include && isArray(include) && include.length > 0) {
|
||||
// Image editing
|
||||
const imagePath = include[0];
|
||||
if (!exists(imagePath)) {
|
||||
logger.error(`Input image not found at: ${imagePath}`);
|
||||
return;
|
||||
}
|
||||
if (!prompt) {
|
||||
logger.error('--prompt is required for image editing.');
|
||||
return;
|
||||
}
|
||||
logger.info(`Editing image "${imagePath}" with prompt: "${prompt}"`);
|
||||
imageBuffer = await editImage(prompt, imagePath, parsedOptions);
|
||||
} else if (prompt) {
|
||||
// Image creation
|
||||
logger.info(`Creating image with prompt: "${prompt}"`);
|
||||
imageBuffer = await createImage(prompt, parsedOptions);
|
||||
}
|
||||
|
||||
if (imageBuffer) {
|
||||
write(dst, imageBuffer);
|
||||
logger.info(`Image saved to: ${dst}`);
|
||||
} else {
|
||||
logger.error('Failed to generate image.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Failed to parse options or generate image:', error.message, error.issues, error.stack);
|
||||
}
|
||||
};
|
||||
89
packages/kbot/src/lib/images-google.ts
Normal file
89
packages/kbot/src/lib/images-google.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { GoogleGenerativeAI, Part } from "@google/generative-ai";
|
||||
import * as fs from "node:fs";
|
||||
import { IKBotOptions } from "../zod_types.js";
|
||||
import { loadConfig } from "../config.js";
|
||||
import { logger } from "../index.js";
|
||||
import { lookup } from 'mime-types'
|
||||
|
||||
const createGoogleGenAIClient = (options: IKBotOptions) => {
|
||||
const config = loadConfig(options);
|
||||
if (!config) {
|
||||
logger.error(
|
||||
"Config not found in $HOME/.osr/config.json. " +
|
||||
"Optionally, export OSR_CONFIG with the path to the configuration file."
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let apiKey = options.api_key || config?.google?.key;
|
||||
logger.debug(`Google API Key: ${apiKey}`);
|
||||
|
||||
if (!apiKey) {
|
||||
logger.error(`No gemini key found. Please provide an "api_key", set it in the config, or pass it via JSON config.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new GoogleGenerativeAI(apiKey);
|
||||
}
|
||||
|
||||
export const createImage = async (prompt: string, options: IKBotOptions): Promise<Buffer | null> => {
|
||||
const ai = createGoogleGenAIClient(options);
|
||||
if (!ai) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const model = ai.getGenerativeModel({ model: options.model || 'gemini-1.5-flash-image-preview' });
|
||||
|
||||
const result = await model.generateContent(prompt);
|
||||
|
||||
const response = result.response;
|
||||
const parts = response.candidates[0].content.parts;
|
||||
for (const part of parts) {
|
||||
if ('inlineData' in part) {
|
||||
const inlineData = part.inlineData;
|
||||
if (inlineData) {
|
||||
return Buffer.from(inlineData.data, "base64");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const editImage = async (prompt: string, imagePath: string, options: IKBotOptions): Promise<Buffer | null> => {
|
||||
const ai = createGoogleGenAIClient(options);
|
||||
if (!ai) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const model = ai.getGenerativeModel({ model: options.model || 'gemini-2.5-flash-image-preview' });
|
||||
|
||||
const imageData = fs.readFileSync(imagePath);
|
||||
const base64Image = imageData.toString("base64");
|
||||
const mimeType = lookup(imagePath) || 'image/png';
|
||||
|
||||
const textPart: Part = { text: prompt };
|
||||
const imagePart: Part = {
|
||||
inlineData: {
|
||||
mimeType,
|
||||
data: base64Image,
|
||||
},
|
||||
};
|
||||
|
||||
const promptParts = [textPart, imagePart];
|
||||
|
||||
const result = await model.generateContent(promptParts);
|
||||
|
||||
const response = result.response;
|
||||
const parts = response.candidates[0].content.parts;
|
||||
for (const part of parts) {
|
||||
if ('inlineData' in part) {
|
||||
const inlineData = part.inlineData;
|
||||
if (inlineData) {
|
||||
return Buffer.from(inlineData.data, "base64");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -15,6 +15,7 @@ import { fetch } from './commands/fetch.js'
|
||||
import { run } from './commands/run.js'
|
||||
|
||||
import { transcribeCommand, TranscribeOptionsSchema } from './commands/transcribe.js'
|
||||
import { imageCommand, ImageOptionsSchema } from './commands/images.js'
|
||||
|
||||
export const logger: any = createLogger('llm-tools')
|
||||
|
||||
@ -48,6 +49,12 @@ yargs(hideBin(process.argv))
|
||||
(yargs) => toYargs(yargs, OptionsSchema(), yargOptions),
|
||||
modify
|
||||
)
|
||||
.command(
|
||||
'image [prompt]',
|
||||
'Create or edit an image',
|
||||
(yargs) => toYargs(yargs, ImageOptionsSchema(), yargOptions),
|
||||
imageCommand
|
||||
)
|
||||
.command(
|
||||
'transcribe',
|
||||
'Transcribe audio files',
|
||||
|
||||
BIN
packages/kbot/tests/unit/images/cat-bird.png
Normal file
BIN
packages/kbot/tests/unit/images/cat-bird.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
packages/kbot/tests/unit/images/cat-fish.png
Normal file
BIN
packages/kbot/tests/unit/images/cat-fish.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
BIN
packages/kbot/tests/unit/images/cat.png
Normal file
BIN
packages/kbot/tests/unit/images/cat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
73
packages/kbot/tests/unit/images/images.test.ts
Normal file
73
packages/kbot/tests/unit/images/images.test.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { describe, it, expect, afterAll, beforeAll } from 'vitest'
|
||||
import * as path from 'node:path'
|
||||
import * as fs from 'node:fs'
|
||||
import { sync as exists } from "@polymech/fs/exists"
|
||||
|
||||
import { imageCommand } from '../../../src/commands/images.js'
|
||||
import { IKBotTask } from '@polymech/ai-tools'
|
||||
|
||||
const TEST_DATA_DIR = './tests/unit/images'
|
||||
const TEST_TIMEOUT = 60000 // Increased timeout for API call
|
||||
|
||||
describe('Image Command', () => {
|
||||
|
||||
const createOutputFile = path.resolve(path.join(TEST_DATA_DIR, 'cat.png'))
|
||||
const editInputFile = path.resolve(path.join(TEST_DATA_DIR, 'cat-bird.png'))
|
||||
const editOutputFile = path.resolve(path.join(TEST_DATA_DIR, 'cat-fish.png'))
|
||||
|
||||
const cleanupFiles = () => {
|
||||
if (fs.existsSync(createOutputFile)) {
|
||||
// fs.unlinkSync(createOutputFile)
|
||||
}
|
||||
if (fs.existsSync(editOutputFile)) {
|
||||
fs.unlinkSync(editOutputFile)
|
||||
}
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
if (!fs.existsSync(TEST_DATA_DIR)) {
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
}
|
||||
cleanupFiles()
|
||||
})
|
||||
// afterAll(cleanupFiles)
|
||||
|
||||
it('should create an image from a prompt and save it to a file', async () => {
|
||||
const options: IKBotTask = {
|
||||
prompt: 'create an image of a little fat orange cat eating little birds',
|
||||
dst: createOutputFile,
|
||||
logLevel: 2,
|
||||
}
|
||||
|
||||
await imageCommand(options)
|
||||
|
||||
expect(exists(createOutputFile)).toBe('file')
|
||||
|
||||
}, TEST_TIMEOUT)
|
||||
|
||||
it('should edit an image from a prompt and an input file', async () => {
|
||||
// First, ensure the input file exists for the edit operation
|
||||
if (!exists(editInputFile)) {
|
||||
// As a fallback, copy the created file to the expected input path
|
||||
if (exists(createOutputFile)) {
|
||||
fs.copyFileSync(createOutputFile, editInputFile)
|
||||
} else {
|
||||
// If neither exists, we must skip this test
|
||||
console.warn(`Skipping edit test: Input file not found at ${editInputFile}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const options: IKBotTask = {
|
||||
prompt: 'replace bird with fish',
|
||||
include: [editInputFile],
|
||||
dst: editOutputFile,
|
||||
logLevel: 2,
|
||||
}
|
||||
|
||||
await imageCommand(options)
|
||||
|
||||
expect(exists(editOutputFile)).toBe('file')
|
||||
|
||||
}, TEST_TIMEOUT)
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user