pm-media:background/watermark

This commit is contained in:
babayaga 2025-08-10 12:13:29 +02:00
parent 8909093b91
commit b5a9c2dbea
414 changed files with 6439 additions and 411 deletions

View File

@ -0,0 +1,3 @@
import { IKBotTask } from '../../types.js';
export declare const decode_base64: (base64: string) => string;
export declare const tools: (target: string, options: IKBotTask) => Array<any>;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
import Keyv from 'keyv';
export declare const store: (storePath: string, ns?: string, opts?: any) => Keyv<any>;
export declare const get: (key: string, storePath: string, ns?: string, opts?: any) => Promise<any>;
export declare const set: (key: string, value: any, storePath: string, ns?: string, opts?: any) => Promise<boolean>;
export declare const list: (key: string, value: any, storePath: string, ns?: string, opts?: any) => Promise<boolean>;

View File

@ -0,0 +1,21 @@
import * as path from 'path';
import Keyv from 'keyv';
import KeyvSqlite from '@keyv/sqlite';
import { resolve } from '@polymech/commons';
export const store = (storePath, ns = 'ns-unknown', opts = {}) => {
const keyvSqlite = new KeyvSqlite(path.resolve(resolve(storePath)));
return new Keyv({ store: keyvSqlite, ttl: 5000, namespace: ns, ...opts });
};
export const get = async (key, storePath, ns = 'ns-unknown', opts = {}) => {
const keyv = store(storePath, ns, opts);
return await keyv.get(key);
};
export const set = async (key, value, storePath, ns = 'ns-unknown', opts = {}) => {
const keyv = store(storePath, ns, opts);
return await keyv.set(key, value);
};
export const list = async (key, value, storePath, ns = 'ns-unknown', opts = {}) => {
const keyv = store(storePath, ns, opts);
return await keyv.set(key, value);
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5di5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvdG9vbHMva2V5di50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUM1QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFDdkIsT0FBTyxVQUFVLE1BQU0sY0FBYyxDQUFBO0FBRXJDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUUzQyxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDbEYsTUFBTSxVQUFVLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ25FLE9BQU8sSUFBSSxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBRSxDQUFDLENBQUE7QUFDN0UsQ0FBQyxDQUFBO0FBQ0QsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHLEtBQUssRUFBRSxHQUFXLEVBQUUsU0FBaUIsRUFBRSxLQUFhLFlBQVksRUFBRSxPQUFZLEVBQUUsRUFBRSxFQUFFO0lBQ25HLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxTQUFTLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFBO0lBQ3ZDLE9BQU8sTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0FBQzlCLENBQUMsQ0FBQTtBQUNELE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBVyxFQUFFLEtBQVUsRUFBRSxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDL0csTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDdkMsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO0FBQ3JDLENBQUMsQ0FBQTtBQUNELE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBVyxFQUFFLEtBQVUsRUFBRSxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDaEgsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDdkMsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO0FBQ3JDLENBQUMsQ0FBQSJ9

View File

@ -0,0 +1,2 @@
import { IKBotTask } from '../../types.js';
export declare const tools: (target: string, options: IKBotTask) => Array<any>;

File diff suppressed because one or more lines are too long

View File

@ -7,4 +7,5 @@ export declare const tools: {
user: (target: string, options: import("../../types.js").IKBotTask) => any[]; user: (target: string, options: import("../../types.js").IKBotTask) => any[];
search: (target: string, options: import("../../types.js").IKBotTask) => any[]; search: (target: string, options: import("../../types.js").IKBotTask) => any[];
web: (target: string, options: import("../../types.js").IKBotTask) => any[]; web: (target: string, options: import("../../types.js").IKBotTask) => any[];
memory: (target: string, options: import("../../types.js").IKBotTask) => any[];
}; };

View File

@ -6,6 +6,7 @@ import { tools as interactTools } from './interact.js';
import { tools as userTools } from './user.js'; import { tools as userTools } from './user.js';
import { tools as search } from './search.js'; import { tools as search } from './search.js';
import { tools as webTools } from './web.js'; import { tools as webTools } from './web.js';
import { tools as memoryTools } from './memory.js';
//import { tools as emailTools } from './email' //import { tools as emailTools } from './email'
export const tools = { export const tools = {
fs: fsTools, fs: fsTools,
@ -16,6 +17,7 @@ export const tools = {
user: userTools, user: userTools,
search: search, search: search,
web: webTools, web: webTools,
memory: memoryTools,
// email: emailTools // email: emailTools
}; };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3Rvb2xzL3Rvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLElBQUksT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzFDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzlDLE9BQU8sRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLCtDQUErQztBQUUvQyxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDakIsRUFBRSxFQUFFLE9BQU87SUFDWCxHQUFHLEVBQUUsUUFBUTtJQUNiLEdBQUcsRUFBRSxRQUFRO0lBQ2IsUUFBUSxFQUFFLGFBQWE7SUFDdkIsUUFBUSxFQUFFLGFBQWE7SUFDdkIsSUFBSSxFQUFFLFNBQVM7SUFDZixNQUFNLEVBQUUsTUFBTTtJQUNkLEdBQUcsRUFBRSxRQUFRO0lBQ2Isb0JBQW9CO0NBQ3ZCLENBQUEifQ== //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3Rvb2xzL3Rvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLElBQUksT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzFDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzlDLE9BQU8sRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ2xELCtDQUErQztBQUUvQyxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDakIsRUFBRSxFQUFFLE9BQU87SUFDWCxHQUFHLEVBQUUsUUFBUTtJQUNiLEdBQUcsRUFBRSxRQUFRO0lBQ2IsUUFBUSxFQUFFLGFBQWE7SUFDdkIsUUFBUSxFQUFFLGFBQWE7SUFDdkIsSUFBSSxFQUFFLFNBQVM7SUFDZixNQUFNLEVBQUUsTUFBTTtJQUNkLEdBQUcsRUFBRSxRQUFRO0lBQ2IsTUFBTSxFQUFFLFdBQVc7SUFDbkIsb0JBQW9CO0NBQ3ZCLENBQUEifQ==

View File

@ -8,7 +8,7 @@ export interface IKBotOptions {
/** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */ /** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */
dst?: string | undefined; dst?: string | undefined;
/** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */ /** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */
append?: ("concat" | "merge") | undefined; append?: ("concat" | "merge" | "replace") | undefined;
/** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */ /** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */
wrap?: "meta" | "none"; wrap?: "meta" | "none";
/** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */ /** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */
@ -31,8 +31,6 @@ export interface IKBotOptions {
 
 OpenRouter models:  OpenRouter models:
 
01-ai/yi-large | paid
aetherwiing/mn-starcannon-12b | paid
agentica-org/deepcoder-14b-preview | paid agentica-org/deepcoder-14b-preview | paid
agentica-org/deepcoder-14b-preview:free | free agentica-org/deepcoder-14b-preview:free | free
ai21/jamba-1.6-large | paid ai21/jamba-1.6-large | paid
@ -48,11 +46,8 @@ export interface IKBotOptions {
anthropic/claude-3-haiku:beta | paid anthropic/claude-3-haiku:beta | paid
anthropic/claude-3-opus | paid anthropic/claude-3-opus | paid
anthropic/claude-3-opus:beta | paid anthropic/claude-3-opus:beta | paid
anthropic/claude-3-sonnet | paid
anthropic/claude-3-sonnet:beta | paid
anthropic/claude-3.5-haiku | paid anthropic/claude-3.5-haiku | paid
anthropic/claude-3.5-haiku-20241022 | paid anthropic/claude-3.5-haiku-20241022 | paid
anthropic/claude-3.5-haiku-20241022:beta | paid
anthropic/claude-3.5-haiku:beta | paid anthropic/claude-3.5-haiku:beta | paid
anthropic/claude-3.5-sonnet | paid anthropic/claude-3.5-sonnet | paid
anthropic/claude-3.5-sonnet-20240620 | paid anthropic/claude-3.5-sonnet-20240620 | paid
@ -62,23 +57,17 @@ export interface IKBotOptions {
anthropic/claude-3.7-sonnet:beta | paid anthropic/claude-3.7-sonnet:beta | paid
anthropic/claude-3.7-sonnet:thinking | paid anthropic/claude-3.7-sonnet:thinking | paid
anthropic/claude-opus-4 | paid anthropic/claude-opus-4 | paid
anthropic/claude-opus-4.1 | paid
anthropic/claude-sonnet-4 | paid anthropic/claude-sonnet-4 | paid
anthropic/claude-2 | paid
anthropic/claude-2:beta | paid
anthropic/claude-2.0 | paid
anthropic/claude-2.0:beta | paid
anthropic/claude-2.1 | paid
anthropic/claude-2.1:beta | paid
arcee-ai/arcee-blitz | paid
arcee-ai/caller-large | paid
arcee-ai/coder-large | paid arcee-ai/coder-large | paid
arcee-ai/maestro-reasoning | paid arcee-ai/maestro-reasoning | paid
arcee-ai/spotlight | paid arcee-ai/spotlight | paid
arcee-ai/virtuoso-large | paid arcee-ai/virtuoso-large | paid
arcee-ai/virtuoso-medium-v2 | paid arliai/qwq-32b-arliai-rpr-v1 | paid
arliai/qwq-32b-arliai-rpr-v1:free | free arliai/qwq-32b-arliai-rpr-v1:free | free
openrouter/auto | paid openrouter/auto | paid
baidu/ernie-4.5-300b-a47b | paid baidu/ernie-4.5-300b-a47b | paid
bytedance/ui-tars-1.5-7b | paid
cohere/command | paid cohere/command | paid
cohere/command-a | paid cohere/command-a | paid
cohere/command-r | paid cohere/command-r | paid
@ -92,10 +81,9 @@ export interface IKBotOptions {
deepseek/deepseek-r1-0528-qwen3-8b | paid deepseek/deepseek-r1-0528-qwen3-8b | paid
deepseek/deepseek-r1-0528-qwen3-8b:free | free deepseek/deepseek-r1-0528-qwen3-8b:free | free
deepseek/deepseek-chat | paid deepseek/deepseek-chat | paid
deepseek/deepseek-chat:free | free
deepseek/deepseek-chat-v3-0324 | paid deepseek/deepseek-chat-v3-0324 | paid
deepseek/deepseek-chat-v3-0324:free | free deepseek/deepseek-chat-v3-0324:free | free
deepseek/deepseek-v3-base:free | free deepseek/deepseek-v3-base | paid
deepseek/deepseek-r1 | paid deepseek/deepseek-r1 | paid
deepseek/deepseek-r1:free | free deepseek/deepseek-r1:free | free
deepseek/deepseek-r1-0528 | paid deepseek/deepseek-r1-0528 | paid
@ -109,12 +97,11 @@ export interface IKBotOptions {
deepseek/deepseek-r1-distill-qwen-32b | paid deepseek/deepseek-r1-distill-qwen-32b | paid
deepseek/deepseek-r1-distill-qwen-7b | paid deepseek/deepseek-r1-distill-qwen-7b | paid
cognitivecomputations/dolphin-mixtral-8x22b | paid cognitivecomputations/dolphin-mixtral-8x22b | paid
cognitivecomputations/dolphin3.0-mistral-24b | paid
cognitivecomputations/dolphin3.0-mistral-24b:free | free cognitivecomputations/dolphin3.0-mistral-24b:free | free
cognitivecomputations/dolphin3.0-r1-mistral-24b | paid cognitivecomputations/dolphin3.0-r1-mistral-24b | paid
cognitivecomputations/dolphin3.0-r1-mistral-24b:free | free cognitivecomputations/dolphin3.0-r1-mistral-24b:free | free
eleutherai/llemma_7b | paid eleutherai/llemma_7b | paid
eva-unit-01/eva-llama-3.33-70b | paid
eva-unit-01/eva-qwen-2.5-72b | paid
sao10k/fimbulvetr-11b-v2 | paid sao10k/fimbulvetr-11b-v2 | paid
alpindale/goliath-120b | paid alpindale/goliath-120b | paid
google/gemini-flash-1.5 | paid google/gemini-flash-1.5 | paid
@ -124,6 +111,7 @@ export interface IKBotOptions {
google/gemini-2.0-flash-exp:free | free google/gemini-2.0-flash-exp:free | free
google/gemini-2.0-flash-lite-001 | paid google/gemini-2.0-flash-lite-001 | paid
google/gemini-2.5-flash | paid google/gemini-2.5-flash | paid
google/gemini-2.5-flash-lite | paid
google/gemini-2.5-flash-lite-preview-06-17 | paid google/gemini-2.5-flash-lite-preview-06-17 | paid
google/gemini-2.5-pro | paid google/gemini-2.5-pro | paid
google/gemini-2.5-pro-exp-03-25 | paid google/gemini-2.5-pro-exp-03-25 | paid
@ -141,6 +129,7 @@ export interface IKBotOptions {
google/gemma-3n-e2b-it:free | free google/gemma-3n-e2b-it:free | free
google/gemma-3n-e4b-it | paid google/gemma-3n-e4b-it | paid
google/gemma-3n-e4b-it:free | free google/gemma-3n-e4b-it:free | free
openrouter/horizon-beta | paid
inception/mercury | paid inception/mercury | paid
inception/mercury-coder | paid inception/mercury-coder | paid
infermatic/mn-inferor-12b | paid infermatic/mn-inferor-12b | paid
@ -151,7 +140,6 @@ export interface IKBotOptions {
liquid/lfm-40b | paid liquid/lfm-40b | paid
liquid/lfm-7b | paid liquid/lfm-7b | paid
meta-llama/llama-guard-3-8b | paid meta-llama/llama-guard-3-8b | paid
alpindale/magnum-72b | paid
anthracite-org/magnum-v2-72b | paid anthracite-org/magnum-v2-72b | paid
anthracite-org/magnum-v4-72b | paid anthracite-org/magnum-v4-72b | paid
mancer/weaver | paid mancer/weaver | paid
@ -174,6 +162,7 @@ export interface IKBotOptions {
meta-llama/llama-4-scout | paid meta-llama/llama-4-scout | paid
meta-llama/llama-guard-4-12b | paid meta-llama/llama-guard-4-12b | paid
meta-llama/llama-guard-2-8b | paid meta-llama/llama-guard-2-8b | paid
microsoft/mai-ds-r1 | paid
microsoft/mai-ds-r1:free | free microsoft/mai-ds-r1:free | free
microsoft/phi-4 | paid microsoft/phi-4 | paid
microsoft/phi-4-multimodal-instruct | paid microsoft/phi-4-multimodal-instruct | paid
@ -187,10 +176,10 @@ export interface IKBotOptions {
mistralai/mistral-large | paid mistralai/mistral-large | paid
mistralai/mistral-large-2407 | paid mistralai/mistral-large-2407 | paid
mistralai/mistral-large-2411 | paid mistralai/mistral-large-2411 | paid
nothingiisreal/mn-celeste-12b | paid
mistralai/mistral-small | paid mistralai/mistral-small | paid
mistralai/mistral-tiny | paid mistralai/mistral-tiny | paid
mistralai/codestral-2501 | paid mistralai/codestral-2501 | paid
mistralai/codestral-2508 | paid
mistralai/devstral-medium | paid mistralai/devstral-medium | paid
mistralai/devstral-small | paid mistralai/devstral-small | paid
mistralai/devstral-small-2505 | paid mistralai/devstral-small-2505 | paid
@ -219,10 +208,10 @@ export interface IKBotOptions {
mistralai/pixtral-12b | paid mistralai/pixtral-12b | paid
mistralai/pixtral-large-2411 | paid mistralai/pixtral-large-2411 | paid
mistralai/mistral-saba | paid mistralai/mistral-saba | paid
moonshotai/kimi-vl-a3b-thinking | paid
moonshotai/kimi-vl-a3b-thinking:free | free moonshotai/kimi-vl-a3b-thinking:free | free
moonshotai/kimi-k2 | paid moonshotai/kimi-k2 | paid
moonshotai/kimi-k2:free | free moonshotai/kimi-k2:free | free
morph/morph-v2 | paid
morph/morph-v3-fast | paid morph/morph-v3-fast | paid
morph/morph-v3-large | paid morph/morph-v3-large | paid
gryphe/mythomax-l2-13b | paid gryphe/mythomax-l2-13b | paid
@ -230,6 +219,7 @@ export interface IKBotOptions {
neversleep/llama-3.1-lumimaid-8b | paid neversleep/llama-3.1-lumimaid-8b | paid
neversleep/noromaid-20b | paid neversleep/noromaid-20b | paid
nousresearch/deephermes-3-llama-3-8b-preview:free | free nousresearch/deephermes-3-llama-3-8b-preview:free | free
nousresearch/deephermes-3-mistral-24b-preview | paid
nousresearch/nous-hermes-2-mixtral-8x7b-dpo | paid nousresearch/nous-hermes-2-mixtral-8x7b-dpo | paid
nousresearch/hermes-3-llama-3.1-405b | paid nousresearch/hermes-3-llama-3.1-405b | paid
nousresearch/hermes-3-llama-3.1-70b | paid nousresearch/hermes-3-llama-3.1-70b | paid
@ -240,6 +230,8 @@ export interface IKBotOptions {
nvidia/llama-3.3-nemotron-super-49b-v1 | paid nvidia/llama-3.3-nemotron-super-49b-v1 | paid
openai/chatgpt-4o-latest | paid openai/chatgpt-4o-latest | paid
openai/codex-mini | paid openai/codex-mini | paid
openai/gpt-oss-120b | paid
openai/gpt-oss-20b | paid
openai/gpt-3.5-turbo | paid openai/gpt-3.5-turbo | paid
openai/gpt-3.5-turbo-0613 | paid openai/gpt-3.5-turbo-0613 | paid
openai/gpt-3.5-turbo-16k | paid openai/gpt-3.5-turbo-16k | paid
@ -264,8 +256,6 @@ export interface IKBotOptions {
openai/o1 | paid openai/o1 | paid
openai/o1-mini | paid openai/o1-mini | paid
openai/o1-mini-2024-09-12 | paid openai/o1-mini-2024-09-12 | paid
openai/o1-preview | paid
openai/o1-preview-2024-09-12 | paid
openai/o1-pro | paid openai/o1-pro | paid
openai/o3 | paid openai/o3 | paid
openai/o3-mini | paid openai/o3-mini | paid
@ -281,6 +271,7 @@ export interface IKBotOptions {
perplexity/sonar-reasoning | paid perplexity/sonar-reasoning | paid
perplexity/sonar-reasoning-pro | paid perplexity/sonar-reasoning-pro | paid
pygmalionai/mythalion-13b | paid pygmalionai/mythalion-13b | paid
featherless/qwerky-72b:free | free
qwen/qwen-2-72b-instruct | paid qwen/qwen-2-72b-instruct | paid
qwen/qwen-vl-max | paid qwen/qwen-vl-max | paid
qwen/qwen-vl-plus | paid qwen/qwen-vl-plus | paid
@ -296,13 +287,16 @@ export interface IKBotOptions {
qwen/qwen3-14b:free | free qwen/qwen3-14b:free | free
qwen/qwen3-235b-a22b | paid qwen/qwen3-235b-a22b | paid
qwen/qwen3-235b-a22b:free | free qwen/qwen3-235b-a22b:free | free
qwen/qwen3-235b-a22b-2507 | paid
qwen/qwen3-235b-a22b-thinking-2507 | paid
qwen/qwen3-30b-a3b | paid qwen/qwen3-30b-a3b | paid
qwen/qwen3-30b-a3b:free | free qwen/qwen3-30b-a3b:free | free
qwen/qwen3-30b-a3b-instruct-2507 | paid
qwen/qwen3-32b | paid qwen/qwen3-32b | paid
qwen/qwen3-32b:free | free
qwen/qwen3-4b:free | free qwen/qwen3-4b:free | free
qwen/qwen3-8b | paid qwen/qwen3-8b | paid
qwen/qwen3-8b:free | free qwen/qwen3-8b:free | free
qwen/qwen3-coder | paid
qwen/qwq-32b | paid qwen/qwq-32b | paid
qwen/qwq-32b:free | free qwen/qwq-32b:free | free
qwen/qwq-32b-preview | paid qwen/qwq-32b-preview | paid
@ -311,16 +305,14 @@ export interface IKBotOptions {
qwen/qwen-2.5-7b-instruct | paid qwen/qwen-2.5-7b-instruct | paid
qwen/qwen-2.5-coder-32b-instruct | paid qwen/qwen-2.5-coder-32b-instruct | paid
qwen/qwen-2.5-coder-32b-instruct:free | free qwen/qwen-2.5-coder-32b-instruct:free | free
featherless/qwerky-72b:free | free
rekaai/reka-flash-3 | paid
rekaai/reka-flash-3:free | free rekaai/reka-flash-3:free | free
undi95/remm-slerp-l2-13b | paid undi95/remm-slerp-l2-13b | paid
sao10k/l3-lunaris-8b | paid sao10k/l3-lunaris-8b | paid
sao10k/l3-euryale-70b | paid sao10k/l3-euryale-70b | paid
sao10k/l3.1-euryale-70b | paid sao10k/l3.1-euryale-70b | paid
sao10k/l3.3-euryale-70b | paid sao10k/l3.3-euryale-70b | paid
sarvamai/sarvam-m | paid
sarvamai/sarvam-m:free | free sarvamai/sarvam-m:free | free
shisa-ai/shisa-v2-llama3.3-70b | paid
shisa-ai/shisa-v2-llama3.3-70b:free | free shisa-ai/shisa-v2-llama3.3-70b:free | free
raifle/sorcererlm-8x22b | paid raifle/sorcererlm-8x22b | paid
switchpoint/router | paid switchpoint/router | paid
@ -333,9 +325,9 @@ export interface IKBotOptions {
thedrummer/unslopnemo-12b | paid thedrummer/unslopnemo-12b | paid
thedrummer/valkyrie-49b-v1 | paid thedrummer/valkyrie-49b-v1 | paid
thudm/glm-4-32b | paid thudm/glm-4-32b | paid
thudm/glm-4-32b:free | free
thudm/glm-4.1v-9b-thinking | paid thudm/glm-4.1v-9b-thinking | paid
thudm/glm-z1-32b:free | free thudm/glm-z1-32b:free | free
tngtech/deepseek-r1t-chimera | paid
tngtech/deepseek-r1t-chimera:free | free tngtech/deepseek-r1t-chimera:free | free
tngtech/deepseek-r1t2-chimera:free | free tngtech/deepseek-r1t2-chimera:free | free
undi95/toppy-m-7b | paid undi95/toppy-m-7b | paid
@ -350,6 +342,10 @@ export interface IKBotOptions {
x-ai/grok-3-mini-beta | paid x-ai/grok-3-mini-beta | paid
x-ai/grok-4 | paid x-ai/grok-4 | paid
x-ai/grok-vision-beta | paid x-ai/grok-vision-beta | paid
z-ai/glm-4-32b | paid
z-ai/glm-4.5 | paid
z-ai/glm-4.5-air | paid
z-ai/glm-4.5-air:free | free
 
 OpenAI models:  OpenAI models:
 
@ -408,8 +404,6 @@ export interface IKBotOptions {
o1-2024-12-17 o1-2024-12-17
o1-mini o1-mini
o1-mini-2024-09-12 o1-mini-2024-09-12
o1-preview
o1-preview-2024-09-12
o1-pro o1-pro
o1-pro-2025-03-19 o1-pro-2025-03-19
o3-mini o3-mini

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@
"dependencies": { "dependencies": {
"@datalust/winston-seq": "^2.0.0", "@datalust/winston-seq": "^2.0.0",
"@inquirer/prompts": "^7.3.2", "@inquirer/prompts": "^7.3.2",
"@keyv/sqlite": "^4.0.5",
"@polymech/commons": "file:../commons", "@polymech/commons": "file:../commons",
"@polymech/core": "file:../core", "@polymech/core": "file:../core",
"@polymech/fs": "file:../fs", "@polymech/fs": "file:../fs",
@ -40,6 +41,8 @@
"glob": "^11.0.1", "glob": "^11.0.1",
"inquirer": "^12.2.0", "inquirer": "^12.2.0",
"jsdom": "^25.0.1", "jsdom": "^25.0.1",
"keyv": "^5.5.0",
"keyv-file": "^5.1.3",
"marked": "^15.0.4", "marked": "^15.0.4",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"nodemailer": "^6.9.16", "nodemailer": "^6.9.16",

View File

@ -98,7 +98,7 @@ const decodeContentSmart = (content: string, logger: any, identifier: string): s
export const tools = (target: string, options: IKBotTask): Array<any> => { export const tools = (target: string, options: IKBotTask): Array<any> => {
const logger = toolLogger('fs', options) const logger = toolLogger('fs', options)
const category = 'fs'
return [ return [
{ {
type: 'function', type: 'function',

View File

@ -0,0 +1,22 @@
import * as path from 'path'
import Keyv from 'keyv'
import KeyvSqlite from '@keyv/sqlite'
import { resolve } from '@polymech/commons'
export const store = (storePath: string, ns: string = 'ns-unknown', opts: any = {}) => {
const keyvSqlite = new KeyvSqlite(path.resolve(resolve(storePath)))
return new Keyv({ store: keyvSqlite, ttl: 5000, namespace: ns, ...opts })
}
export const get = async (key: string, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => {
const keyv = store(storePath, ns, opts)
return await keyv.get(key)
}
export const set = async (key: string, value: any, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => {
const keyv = store(storePath, ns, opts)
return await keyv.set(key, value)
}
export const list = async (key: string, value: any, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => {
const keyv = store(storePath, ns, opts)
return await keyv.set(key, value)
}

View File

@ -0,0 +1,379 @@
import * as path from 'path'
import { RunnableToolFunction } from 'openai/lib/RunnableFunction'
import { isString } from '@polymech/core/primitives'
import { toolLogger } from '../../index.js'
import { IKBotTask } from '../../types.js'
import { store, get, set } from './keyv.js'
// Helper function to get storage path
const getStoragePath = (options: IKBotTask): string => {
// For now, use default path. Later this can be configured via options
return path.join(process.cwd(), 'memory.sqlite');
};
// Default collection name when none provided
const DEFAULT_COLLECTION = 'no-collection';
// Supported data formats
type DataFormat = 'text' | 'json' | 'binary';
// Memory entry structure
interface MemoryEntry {
value: string;
meta: {
type: DataFormat;
created: string;
updated: string;
};
}
// Helper function to process value based on format
const processValueForStorage = (value: string, format: DataFormat): string => {
switch (format) {
case 'json':
try {
// Validate JSON by parsing and re-stringifying
JSON.parse(value);
return value;
} catch (error) {
throw new Error('Invalid JSON format provided');
}
case 'binary':
// For binary, we expect base64 encoded data
try {
// Validate base64
Buffer.from(value, 'base64');
return value;
} catch (error) {
throw new Error('Invalid base64 format for binary data');
}
case 'text':
default:
return value;
}
};
// Helper function to create memory entry
const createMemoryEntry = (value: string, format: DataFormat): MemoryEntry => {
const now = new Date().toISOString();
return {
value: processValueForStorage(value, format),
meta: {
type: format,
created: now,
updated: now
}
};
};
export const tools = (target: string, options: IKBotTask): Array<any> => {
const logger = toolLogger('memory', options)
const storagePath = getStoragePath(options);
return [
{
type: 'function',
function: {
name: 'memorize',
description: `Store information in memory as a key-value collection with format support. Supports text, JSON, and binary (base64) formats.
Returns: {
success: boolean,
message: string,
meta: {
type: "text" | "json" | "binary",
created: string (ISO timestamp),
updated: string (ISO timestamp)
}
}`,
parameters: {
type: 'object',
properties: {
collection: {
type: 'string',
description: 'Collection name to organize related data (defaults to "no-collection" if not provided). Acts like a namespace.',
optional: true
},
key: {
type: 'string',
description: 'Unique identifier for the data within the collection. Must be a string.'
},
value: {
type: 'string',
description: 'The data to store. For format="text": any string. For format="json": valid JSON string. For format="binary": base64 encoded data.'
},
format: {
type: 'string',
description: 'Data format type. "text" for plain text (default), "json" for JSON data (validates structure), "binary" for base64 encoded binary data.',
enum: ['text', 'json', 'binary'],
optional: true
}
},
required: ['key', 'value']
},
function: async (params: any) => {
try {
const { collection = DEFAULT_COLLECTION, key, value, format = 'text' } = params;
logger.debug(`Tool::Memorize Storing ${key} in collection ${collection} as ${format}`);
const memoryEntry = createMemoryEntry(value, format as DataFormat);
await set(`${collection}:${key}`, memoryEntry, storagePath, collection);
return {
success: true,
message: `Stored ${key} in collection ${collection} as ${format}`,
meta: memoryEntry.meta
};
} catch (error) {
logger.error('Error storing memory', error);
return {
success: false,
message: error instanceof Error ? error.message : 'Unknown error occurred'
};
}
},
parse: JSON.parse
}
} as RunnableToolFunction<any>,
{
type: 'function',
function: {
name: 'recall',
description: `Retrieve stored information from memory by collection and key, including format metadata.
Returns: {
success: boolean,
value?: string (the stored data),
meta?: {
type: "text" | "json" | "binary",
created: string (ISO timestamp),
updated: string (ISO timestamp)
},
key: string,
collection: string,
message?: string (error message if success=false)
}`,
parameters: {
type: 'object',
properties: {
collection: {
type: 'string',
description: 'Collection name to retrieve from (defaults to "no-collection" if not provided). Must match the collection used when storing.',
optional: true
},
key: {
type: 'string',
description: 'The unique identifier of the data to retrieve. Must match the key used when storing.'
}
},
required: ['key']
},
function: async (params: any) => {
try {
const { collection = DEFAULT_COLLECTION, key } = params;
logger.debug(`Tool::Recall Retrieving ${key} from collection ${collection}`);
const storedData = await get(`${collection}:${key}`, storagePath, collection);
if (storedData === undefined) {
return { success: false, message: `Key ${key} not found in collection ${collection}` };
}
// Handle both old format (plain string) and new format (MemoryEntry)
let memoryEntry: MemoryEntry;
if (typeof storedData === 'string') {
// Legacy format - convert to new format
memoryEntry = {
value: storedData,
meta: {
type: 'text',
created: new Date().toISOString(),
updated: new Date().toISOString()
}
};
} else {
memoryEntry = storedData as MemoryEntry;
}
return {
success: true,
value: memoryEntry.value,
meta: memoryEntry.meta,
key,
collection
};
} catch (error) {
logger.error('Error retrieving memory', error);
return {
success: false,
message: error instanceof Error ? error.message : 'Unknown error occurred'
};
}
},
parse: JSON.parse
}
} as RunnableToolFunction<any>,
{
type: 'function',
function: {
name: 'forget',
description: `Remove a specific key from memory collection.
Returns: {
success: boolean,
message: string (confirmation or error message)
}`,
parameters: {
type: 'object',
properties: {
collection: {
type: 'string',
description: 'Collection name to remove from (defaults to "no-collection" if not provided). Must match the collection where the key was stored.',
optional: true
},
key: {
type: 'string',
description: 'The unique identifier of the data to remove. Must match exactly the key used when storing.'
}
},
required: ['key']
},
function: async (params: any) => {
try {
const { collection = DEFAULT_COLLECTION, key } = params;
logger.debug(`Tool::Forget Removing ${key} from collection ${collection}`);
const keyv = store(storagePath, collection);
const deleted = await keyv.delete(`${collection}:${key}`);
return { success: deleted, message: deleted ? `Removed ${key} from ${collection}` : `Key ${key} not found in ${collection}` };
} catch (error) {
logger.error('Error removing from memory', error);
return {
success: false,
message: error instanceof Error ? error.message : 'Unknown error occurred'
};
}
},
parse: JSON.parse
}
} as RunnableToolFunction<any>,
{
type: 'function',
function: {
name: 'list_memories',
description: `List all keys in a specific collection using Keyv's iterator method.
Returns: {
success: boolean,
collection: string (the collection name),
keys: string[] (array of key names in the collection),
entries: Array<{
key: string,
meta?: {
type: "text" | "json" | "binary",
created: string (ISO timestamp),
updated: string (ISO timestamp)
}
}>,
count: number (total number of keys),
message?: string (info or error message)
}`,
parameters: {
type: 'object',
properties: {
collection: {
type: 'string',
description: 'Collection name to list keys from (defaults to "no-collection" if not provided). Will return all keys stored in this collection namespace.',
optional: true
}
},
required: []
},
function: async (params: any) => {
try {
const { collection = DEFAULT_COLLECTION } = params;
logger.debug(`Tool::ListMemories Listing keys in collection ${collection}`);
// Create a Keyv instance for the specific collection to use iterator
const keyv = store(storagePath, collection);
const keys: string[] = [];
const entries: { key: string; meta?: any }[] = [];
try {
// Check if iterator method exists and use it
if (typeof keyv.iterator === 'function') {
try {
// Try calling iterator without arguments first
const iterator = (keyv as any).iterator();
for await (const [key, value] of iterator) {
// Remove the collection prefix from the key to get the clean key name
const cleanKey = key.replace(`${collection}:`, '');
keys.push(cleanKey);
// Try to extract metadata if it's a MemoryEntry
let meta = undefined;
if (value && typeof value === 'object' && value.meta) {
meta = value.meta;
}
entries.push({ key: cleanKey, meta });
}
} catch (iteratorCallError) {
logger.warn(`Tool::ListMemories Iterator call failed:`, iteratorCallError);
// Fall through to the not available case
return {
success: true,
collection,
keys: [],
entries: [],
count: 0,
message: 'Iterator call failed. Unable to list keys.'
};
}
} else {
// Iterator not available, provide helpful message
logger.warn(`Tool::ListMemories Iterator method not available for Keyv instance`);
return {
success: true,
collection,
keys: [],
entries: [],
count: 0,
message: 'Iterator method not available in this Keyv version. Use individual key operations instead.'
};
}
return {
success: true,
collection,
keys,
entries,
count: keys.length
};
} catch (iteratorError) {
// If iterator fails, fall back to returning basic info
logger.warn(`Tool::ListMemories Iterator failed for collection ${collection}:`, iteratorError);
return {
success: true,
collection,
keys: [],
entries: [],
count: 0,
message: 'Iterator failed or collection is empty'
};
}
} catch (error) {
logger.error('Error listing memories', error);
return {
success: false,
message: error instanceof Error ? error.message : 'Unknown error occurred'
};
}
},
parse: JSON.parse
}
} as RunnableToolFunction<any>
]
};

View File

@ -6,6 +6,7 @@ import { tools as interactTools } from './interact.js'
import { tools as userTools } from './user.js' import { tools as userTools } from './user.js'
import { tools as search } from './search.js' import { tools as search } from './search.js'
import { tools as webTools } from './web.js' import { tools as webTools } from './web.js'
import { tools as memoryTools } from './memory.js'
//import { tools as emailTools } from './email' //import { tools as emailTools } from './email'
export const tools = { export const tools = {
@ -17,5 +18,6 @@ export const tools = {
user: userTools, user: userTools,
search: search, search: search,
web: webTools, web: webTools,
memory: memoryTools,
// email: emailTools // email: emailTools
} }

View File

@ -8,7 +8,7 @@ export interface IKBotOptions {
/** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */ /** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */
dst?: string | undefined; dst?: string | undefined;
/** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */ /** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */
append?: ("concat" | "merge") | undefined; append?: ("concat" | "merge" | "replace") | undefined;
/** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */ /** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */
wrap?: "meta" | "none"; wrap?: "meta" | "none";
/** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */ /** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */
@ -31,8 +31,6 @@ export interface IKBotOptions {
 
 OpenRouter models:  OpenRouter models:
 
01-ai/yi-large | paid
aetherwiing/mn-starcannon-12b | paid
agentica-org/deepcoder-14b-preview | paid agentica-org/deepcoder-14b-preview | paid
agentica-org/deepcoder-14b-preview:free | free agentica-org/deepcoder-14b-preview:free | free
ai21/jamba-1.6-large | paid ai21/jamba-1.6-large | paid
@ -48,11 +46,8 @@ export interface IKBotOptions {
anthropic/claude-3-haiku:beta | paid anthropic/claude-3-haiku:beta | paid
anthropic/claude-3-opus | paid anthropic/claude-3-opus | paid
anthropic/claude-3-opus:beta | paid anthropic/claude-3-opus:beta | paid
anthropic/claude-3-sonnet | paid
anthropic/claude-3-sonnet:beta | paid
anthropic/claude-3.5-haiku | paid anthropic/claude-3.5-haiku | paid
anthropic/claude-3.5-haiku-20241022 | paid anthropic/claude-3.5-haiku-20241022 | paid
anthropic/claude-3.5-haiku-20241022:beta | paid
anthropic/claude-3.5-haiku:beta | paid anthropic/claude-3.5-haiku:beta | paid
anthropic/claude-3.5-sonnet | paid anthropic/claude-3.5-sonnet | paid
anthropic/claude-3.5-sonnet-20240620 | paid anthropic/claude-3.5-sonnet-20240620 | paid
@ -62,23 +57,17 @@ export interface IKBotOptions {
anthropic/claude-3.7-sonnet:beta | paid anthropic/claude-3.7-sonnet:beta | paid
anthropic/claude-3.7-sonnet:thinking | paid anthropic/claude-3.7-sonnet:thinking | paid
anthropic/claude-opus-4 | paid anthropic/claude-opus-4 | paid
anthropic/claude-opus-4.1 | paid
anthropic/claude-sonnet-4 | paid anthropic/claude-sonnet-4 | paid
anthropic/claude-2 | paid
anthropic/claude-2:beta | paid
anthropic/claude-2.0 | paid
anthropic/claude-2.0:beta | paid
anthropic/claude-2.1 | paid
anthropic/claude-2.1:beta | paid
arcee-ai/arcee-blitz | paid
arcee-ai/caller-large | paid
arcee-ai/coder-large | paid arcee-ai/coder-large | paid
arcee-ai/maestro-reasoning | paid arcee-ai/maestro-reasoning | paid
arcee-ai/spotlight | paid arcee-ai/spotlight | paid
arcee-ai/virtuoso-large | paid arcee-ai/virtuoso-large | paid
arcee-ai/virtuoso-medium-v2 | paid arliai/qwq-32b-arliai-rpr-v1 | paid
arliai/qwq-32b-arliai-rpr-v1:free | free arliai/qwq-32b-arliai-rpr-v1:free | free
openrouter/auto | paid openrouter/auto | paid
baidu/ernie-4.5-300b-a47b | paid baidu/ernie-4.5-300b-a47b | paid
bytedance/ui-tars-1.5-7b | paid
cohere/command | paid cohere/command | paid
cohere/command-a | paid cohere/command-a | paid
cohere/command-r | paid cohere/command-r | paid
@ -92,10 +81,9 @@ export interface IKBotOptions {
deepseek/deepseek-r1-0528-qwen3-8b | paid deepseek/deepseek-r1-0528-qwen3-8b | paid
deepseek/deepseek-r1-0528-qwen3-8b:free | free deepseek/deepseek-r1-0528-qwen3-8b:free | free
deepseek/deepseek-chat | paid deepseek/deepseek-chat | paid
deepseek/deepseek-chat:free | free
deepseek/deepseek-chat-v3-0324 | paid deepseek/deepseek-chat-v3-0324 | paid
deepseek/deepseek-chat-v3-0324:free | free deepseek/deepseek-chat-v3-0324:free | free
deepseek/deepseek-v3-base:free | free deepseek/deepseek-v3-base | paid
deepseek/deepseek-r1 | paid deepseek/deepseek-r1 | paid
deepseek/deepseek-r1:free | free deepseek/deepseek-r1:free | free
deepseek/deepseek-r1-0528 | paid deepseek/deepseek-r1-0528 | paid
@ -109,12 +97,11 @@ export interface IKBotOptions {
deepseek/deepseek-r1-distill-qwen-32b | paid deepseek/deepseek-r1-distill-qwen-32b | paid
deepseek/deepseek-r1-distill-qwen-7b | paid deepseek/deepseek-r1-distill-qwen-7b | paid
cognitivecomputations/dolphin-mixtral-8x22b | paid cognitivecomputations/dolphin-mixtral-8x22b | paid
cognitivecomputations/dolphin3.0-mistral-24b | paid
cognitivecomputations/dolphin3.0-mistral-24b:free | free cognitivecomputations/dolphin3.0-mistral-24b:free | free
cognitivecomputations/dolphin3.0-r1-mistral-24b | paid cognitivecomputations/dolphin3.0-r1-mistral-24b | paid
cognitivecomputations/dolphin3.0-r1-mistral-24b:free | free cognitivecomputations/dolphin3.0-r1-mistral-24b:free | free
eleutherai/llemma_7b | paid eleutherai/llemma_7b | paid
eva-unit-01/eva-llama-3.33-70b | paid
eva-unit-01/eva-qwen-2.5-72b | paid
sao10k/fimbulvetr-11b-v2 | paid sao10k/fimbulvetr-11b-v2 | paid
alpindale/goliath-120b | paid alpindale/goliath-120b | paid
google/gemini-flash-1.5 | paid google/gemini-flash-1.5 | paid
@ -124,6 +111,7 @@ export interface IKBotOptions {
google/gemini-2.0-flash-exp:free | free google/gemini-2.0-flash-exp:free | free
google/gemini-2.0-flash-lite-001 | paid google/gemini-2.0-flash-lite-001 | paid
google/gemini-2.5-flash | paid google/gemini-2.5-flash | paid
google/gemini-2.5-flash-lite | paid
google/gemini-2.5-flash-lite-preview-06-17 | paid google/gemini-2.5-flash-lite-preview-06-17 | paid
google/gemini-2.5-pro | paid google/gemini-2.5-pro | paid
google/gemini-2.5-pro-exp-03-25 | paid google/gemini-2.5-pro-exp-03-25 | paid
@ -141,6 +129,7 @@ export interface IKBotOptions {
google/gemma-3n-e2b-it:free | free google/gemma-3n-e2b-it:free | free
google/gemma-3n-e4b-it | paid google/gemma-3n-e4b-it | paid
google/gemma-3n-e4b-it:free | free google/gemma-3n-e4b-it:free | free
openrouter/horizon-beta | paid
inception/mercury | paid inception/mercury | paid
inception/mercury-coder | paid inception/mercury-coder | paid
infermatic/mn-inferor-12b | paid infermatic/mn-inferor-12b | paid
@ -151,7 +140,6 @@ export interface IKBotOptions {
liquid/lfm-40b | paid liquid/lfm-40b | paid
liquid/lfm-7b | paid liquid/lfm-7b | paid
meta-llama/llama-guard-3-8b | paid meta-llama/llama-guard-3-8b | paid
alpindale/magnum-72b | paid
anthracite-org/magnum-v2-72b | paid anthracite-org/magnum-v2-72b | paid
anthracite-org/magnum-v4-72b | paid anthracite-org/magnum-v4-72b | paid
mancer/weaver | paid mancer/weaver | paid
@ -174,6 +162,7 @@ export interface IKBotOptions {
meta-llama/llama-4-scout | paid meta-llama/llama-4-scout | paid
meta-llama/llama-guard-4-12b | paid meta-llama/llama-guard-4-12b | paid
meta-llama/llama-guard-2-8b | paid meta-llama/llama-guard-2-8b | paid
microsoft/mai-ds-r1 | paid
microsoft/mai-ds-r1:free | free microsoft/mai-ds-r1:free | free
microsoft/phi-4 | paid microsoft/phi-4 | paid
microsoft/phi-4-multimodal-instruct | paid microsoft/phi-4-multimodal-instruct | paid
@ -187,10 +176,10 @@ export interface IKBotOptions {
mistralai/mistral-large | paid mistralai/mistral-large | paid
mistralai/mistral-large-2407 | paid mistralai/mistral-large-2407 | paid
mistralai/mistral-large-2411 | paid mistralai/mistral-large-2411 | paid
nothingiisreal/mn-celeste-12b | paid
mistralai/mistral-small | paid mistralai/mistral-small | paid
mistralai/mistral-tiny | paid mistralai/mistral-tiny | paid
mistralai/codestral-2501 | paid mistralai/codestral-2501 | paid
mistralai/codestral-2508 | paid
mistralai/devstral-medium | paid mistralai/devstral-medium | paid
mistralai/devstral-small | paid mistralai/devstral-small | paid
mistralai/devstral-small-2505 | paid mistralai/devstral-small-2505 | paid
@ -219,10 +208,10 @@ export interface IKBotOptions {
mistralai/pixtral-12b | paid mistralai/pixtral-12b | paid
mistralai/pixtral-large-2411 | paid mistralai/pixtral-large-2411 | paid
mistralai/mistral-saba | paid mistralai/mistral-saba | paid
moonshotai/kimi-vl-a3b-thinking | paid
moonshotai/kimi-vl-a3b-thinking:free | free moonshotai/kimi-vl-a3b-thinking:free | free
moonshotai/kimi-k2 | paid moonshotai/kimi-k2 | paid
moonshotai/kimi-k2:free | free moonshotai/kimi-k2:free | free
morph/morph-v2 | paid
morph/morph-v3-fast | paid morph/morph-v3-fast | paid
morph/morph-v3-large | paid morph/morph-v3-large | paid
gryphe/mythomax-l2-13b | paid gryphe/mythomax-l2-13b | paid
@ -230,6 +219,7 @@ export interface IKBotOptions {
neversleep/llama-3.1-lumimaid-8b | paid neversleep/llama-3.1-lumimaid-8b | paid
neversleep/noromaid-20b | paid neversleep/noromaid-20b | paid
nousresearch/deephermes-3-llama-3-8b-preview:free | free nousresearch/deephermes-3-llama-3-8b-preview:free | free
nousresearch/deephermes-3-mistral-24b-preview | paid
nousresearch/nous-hermes-2-mixtral-8x7b-dpo | paid nousresearch/nous-hermes-2-mixtral-8x7b-dpo | paid
nousresearch/hermes-3-llama-3.1-405b | paid nousresearch/hermes-3-llama-3.1-405b | paid
nousresearch/hermes-3-llama-3.1-70b | paid nousresearch/hermes-3-llama-3.1-70b | paid
@ -240,6 +230,8 @@ export interface IKBotOptions {
nvidia/llama-3.3-nemotron-super-49b-v1 | paid nvidia/llama-3.3-nemotron-super-49b-v1 | paid
openai/chatgpt-4o-latest | paid openai/chatgpt-4o-latest | paid
openai/codex-mini | paid openai/codex-mini | paid
openai/gpt-oss-120b | paid
openai/gpt-oss-20b | paid
openai/gpt-3.5-turbo | paid openai/gpt-3.5-turbo | paid
openai/gpt-3.5-turbo-0613 | paid openai/gpt-3.5-turbo-0613 | paid
openai/gpt-3.5-turbo-16k | paid openai/gpt-3.5-turbo-16k | paid
@ -264,8 +256,6 @@ export interface IKBotOptions {
openai/o1 | paid openai/o1 | paid
openai/o1-mini | paid openai/o1-mini | paid
openai/o1-mini-2024-09-12 | paid openai/o1-mini-2024-09-12 | paid
openai/o1-preview | paid
openai/o1-preview-2024-09-12 | paid
openai/o1-pro | paid openai/o1-pro | paid
openai/o3 | paid openai/o3 | paid
openai/o3-mini | paid openai/o3-mini | paid
@ -281,6 +271,7 @@ export interface IKBotOptions {
perplexity/sonar-reasoning | paid perplexity/sonar-reasoning | paid
perplexity/sonar-reasoning-pro | paid perplexity/sonar-reasoning-pro | paid
pygmalionai/mythalion-13b | paid pygmalionai/mythalion-13b | paid
featherless/qwerky-72b:free | free
qwen/qwen-2-72b-instruct | paid qwen/qwen-2-72b-instruct | paid
qwen/qwen-vl-max | paid qwen/qwen-vl-max | paid
qwen/qwen-vl-plus | paid qwen/qwen-vl-plus | paid
@ -296,13 +287,16 @@ export interface IKBotOptions {
qwen/qwen3-14b:free | free qwen/qwen3-14b:free | free
qwen/qwen3-235b-a22b | paid qwen/qwen3-235b-a22b | paid
qwen/qwen3-235b-a22b:free | free qwen/qwen3-235b-a22b:free | free
qwen/qwen3-235b-a22b-2507 | paid
qwen/qwen3-235b-a22b-thinking-2507 | paid
qwen/qwen3-30b-a3b | paid qwen/qwen3-30b-a3b | paid
qwen/qwen3-30b-a3b:free | free qwen/qwen3-30b-a3b:free | free
qwen/qwen3-30b-a3b-instruct-2507 | paid
qwen/qwen3-32b | paid qwen/qwen3-32b | paid
qwen/qwen3-32b:free | free
qwen/qwen3-4b:free | free qwen/qwen3-4b:free | free
qwen/qwen3-8b | paid qwen/qwen3-8b | paid
qwen/qwen3-8b:free | free qwen/qwen3-8b:free | free
qwen/qwen3-coder | paid
qwen/qwq-32b | paid qwen/qwq-32b | paid
qwen/qwq-32b:free | free qwen/qwq-32b:free | free
qwen/qwq-32b-preview | paid qwen/qwq-32b-preview | paid
@ -311,16 +305,14 @@ export interface IKBotOptions {
qwen/qwen-2.5-7b-instruct | paid qwen/qwen-2.5-7b-instruct | paid
qwen/qwen-2.5-coder-32b-instruct | paid qwen/qwen-2.5-coder-32b-instruct | paid
qwen/qwen-2.5-coder-32b-instruct:free | free qwen/qwen-2.5-coder-32b-instruct:free | free
featherless/qwerky-72b:free | free
rekaai/reka-flash-3 | paid
rekaai/reka-flash-3:free | free rekaai/reka-flash-3:free | free
undi95/remm-slerp-l2-13b | paid undi95/remm-slerp-l2-13b | paid
sao10k/l3-lunaris-8b | paid sao10k/l3-lunaris-8b | paid
sao10k/l3-euryale-70b | paid sao10k/l3-euryale-70b | paid
sao10k/l3.1-euryale-70b | paid sao10k/l3.1-euryale-70b | paid
sao10k/l3.3-euryale-70b | paid sao10k/l3.3-euryale-70b | paid
sarvamai/sarvam-m | paid
sarvamai/sarvam-m:free | free sarvamai/sarvam-m:free | free
shisa-ai/shisa-v2-llama3.3-70b | paid
shisa-ai/shisa-v2-llama3.3-70b:free | free shisa-ai/shisa-v2-llama3.3-70b:free | free
raifle/sorcererlm-8x22b | paid raifle/sorcererlm-8x22b | paid
switchpoint/router | paid switchpoint/router | paid
@ -333,9 +325,9 @@ export interface IKBotOptions {
thedrummer/unslopnemo-12b | paid thedrummer/unslopnemo-12b | paid
thedrummer/valkyrie-49b-v1 | paid thedrummer/valkyrie-49b-v1 | paid
thudm/glm-4-32b | paid thudm/glm-4-32b | paid
thudm/glm-4-32b:free | free
thudm/glm-4.1v-9b-thinking | paid thudm/glm-4.1v-9b-thinking | paid
thudm/glm-z1-32b:free | free thudm/glm-z1-32b:free | free
tngtech/deepseek-r1t-chimera | paid
tngtech/deepseek-r1t-chimera:free | free tngtech/deepseek-r1t-chimera:free | free
tngtech/deepseek-r1t2-chimera:free | free tngtech/deepseek-r1t2-chimera:free | free
undi95/toppy-m-7b | paid undi95/toppy-m-7b | paid
@ -350,6 +342,10 @@ export interface IKBotOptions {
x-ai/grok-3-mini-beta | paid x-ai/grok-3-mini-beta | paid
x-ai/grok-4 | paid x-ai/grok-4 | paid
x-ai/grok-vision-beta | paid x-ai/grok-vision-beta | paid
z-ai/glm-4-32b | paid
z-ai/glm-4.5 | paid
z-ai/glm-4.5-air | paid
z-ai/glm-4.5-air:free | free
 
 OpenAI models:  OpenAI models:
 
@ -408,8 +404,6 @@ export interface IKBotOptions {
o1-2024-12-17 o1-2024-12-17
o1-mini o1-mini
o1-mini-2024-09-12 o1-mini-2024-09-12
o1-preview
o1-preview-2024-09-12
o1-pro o1-pro
o1-pro-2025-03-19 o1-pro-2025-03-19
o3-mini o3-mini

View File

@ -0,0 +1,2 @@
ollama pull gpt-oss:20b
ollama run gpt-oss:20b

View File

@ -0,0 +1,11 @@
kbot-d.cmd --router=ollama \
--model=gpt-oss:20b \
--mode=completion \
--baseURL=http://localhost:11434/v1 \
--prompt=./tools.md \
--preferences=none \
--filters=code \
--dst=./tools-test-ouput.md

View File

@ -0,0 +1 @@
meaning of love, per continent - as markdown

View File

@ -0,0 +1,6 @@
import * as CLI from 'yargs';
export declare const defaultOptions: (yargs: CLI.Argv) => any;
export declare const command = "background:remove";
export declare const desc = "Remove background from images using AI";
export declare const builder: (yargs: CLI.Argv) => any;
export declare function handler(argv: CLI.Arguments): Promise<void>;

View File

@ -0,0 +1,86 @@
import { CONFIG_DEFAULT } from '@polymech/commons';
import { logger } from '../index.js';
import { cli } from '../cli.js';
import { sanitize, defaults } from '../_cli.js';
import { backgroundRemove } from '../lib/media/images/background-remove.js';
export const defaultOptions = (yargs) => {
return yargs.option('src', {
describe: 'FILE|FOLDER|GLOB',
demandOption: true
}).option('dst', {
describe: 'FILE|FOLDER|GLOB'
}).option('debug', {
default: false,
describe: 'Enable internal debug messages',
type: 'boolean'
}).option('alt', {
default: false,
describe: 'Use alternate tokenizer, & instead of $',
type: 'boolean'
}).option('dry', {
default: false,
describe: 'Run without conversion',
type: 'boolean'
}).option('verbose', {
default: false,
describe: 'Show internal messages',
type: 'boolean'
}).option('logLevel', {
describe: 'Log level : warn, info, debug, error',
type: 'string',
default: 'info'
}).option('apiKey', {
describe: 'Replicate API key (or set REPLICATE_API_TOKEN env var)',
type: 'string'
}).option('model', {
describe: 'Background removal model to use',
choices: ['u2net', 'u2netp', 'u2net_human_seg', 'u2net_cloth_seg', 'silueta'],
default: 'u2net'
}).option('alphaMattting', {
describe: 'Enable alpha matting for better edge refinement',
type: 'boolean',
default: false
}).option('alphaMattingForegroundThreshold', {
describe: 'Alpha matting foreground threshold',
type: 'number',
default: 270
}).option('alphaMattingBackgroundThreshold', {
describe: 'Alpha matting background threshold',
type: 'number',
default: 10
}).option('alphaMattingErodeSize', {
describe: 'Alpha matting erode size',
type: 'number',
default: 10
});
};
export const command = 'background:remove';
export const desc = 'Remove background from images using AI';
export const builder = defaultOptions;
export async function handler(argv) {
defaults();
const options = sanitize(argv);
logger.settings.minLevel = options.logLevel;
const config = CONFIG_DEFAULT();
// Get API key from argument or environment variable
options.apiKey = options.apiKey || process.env.REPLICATE_API_TOKEN || config?.replicate?.key;
if (!options.apiKey) {
logger.error('Replicate API key is required. Provide it via --apiKey argument or set REPLICATE_API_TOKEN environment variable');
logger.info('Get your API key at: https://replicate.com/account/api-tokens');
process.exit(1);
}
// Map CLI arguments to library options
options.model = argv.model;
options.alpha_matting = argv.alphaMattting;
options.alpha_matting_foreground_threshold = argv.alphaMattingForegroundThreshold;
options.alpha_matting_background_threshold = argv.alphaMattingBackgroundThreshold;
options.alpha_matting_erode_size = argv.alphaMattingErodeSize;
logger.info("Removing background with options:", {
model: options.model,
alpha_matting: options.alpha_matting,
files: options.srcInfo?.FILES?.length || 0
});
await backgroundRemove(options);
}
cli.command(command, desc, builder, handler);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2dyb3VuZC1yZW1vdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZHMvYmFja2dyb3VuZC1yZW1vdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDcEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUMvQixPQUFPLEVBQ0gsUUFBUSxFQUNSLFFBQVEsRUFDWCxNQUFNLFlBQVksQ0FBQTtBQUVuQixPQUFPLEVBQ0gsZ0JBQWdCLEVBRW5CLE1BQU0sMENBQTBDLENBQUE7QUFFakQsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBZSxFQUFFLEVBQUU7SUFDOUMsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUN2QixRQUFRLEVBQUUsa0JBQWtCO1FBQzVCLFlBQVksRUFBRSxJQUFJO0tBQ3JCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2IsUUFBUSxFQUFFLGtCQUFrQjtLQUMvQixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNmLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLGdDQUFnQztRQUMxQyxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHlDQUF5QztRQUNuRCxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHdCQUF3QjtRQUNsQyxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUU7UUFDbEIsUUFBUSxFQUFFLHNDQUFzQztRQUNoRCxJQUFJLEVBQUUsUUFBUTtRQUNkLE9BQU8sRUFBRSxNQUFNO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2hCLFFBQVEsRUFBRSx3REFBd0Q7UUFDbEUsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixRQUFRLEVBQUUsaUNBQWlDO1FBQzNDLE9BQU8sRUFBRSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxDQUFDO1FBQzdFLE9BQU8sRUFBRSxPQUFPO0tBQ25CLENBQUMsQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFO1FBQ3ZCLFFBQVEsRUFBRSxpREFBaUQ7UUFDM0QsSUFBSSxFQUFFLFNBQVM7UUFDZixPQUFPLEVBQUUsS0FBSztLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLGlDQUFpQyxFQUFFO1FBQ3pDLFFBQVEsRUFBRSxvQ0FBb0M7UUFDOUMsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsR0FBRztLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsaUNBQWlDLEVBQUU7UUFDekMsUUFBUSxFQUFFLG9DQUFvQztRQUM5QyxJQUFJLEVBQUUsUUFBUTtRQUNkLE9BQU8sRUFBRSxFQUFFO0tBQ2QsQ0FBQyxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsRUFBRTtRQUMvQixRQUFRLEVBQUUsMEJBQTBCO1FBQ3BDLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLEVBQUU7S0FDZCxDQUFDLENBQUE7QUFDTixDQUFDLENBQUE7QUFFRCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsbUJBQW1CLENBQUM7QUFDM0MsTUFBTSxDQUFDLE1BQU0sSUFBSSxHQUFHLHdDQUF3QyxDQUFDO0FBQzdELE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxjQUFjLENBQUM7QUFFdEMsTUFBTSxDQUFDLEtBQUssVUFBVSxPQUFPLENBQUMsSUFBbUI7SUFDN0MsUUFBUSxFQUFFLENBQUE7SUFDVixNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUE0QixDQUFBO0lBQ3pELE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUFlLENBQUE7SUFDbEQsTUFBTSxNQUFNLEdBQVEsY0FBYyxFQUFFLENBQUE7SUFFcEMsb0RBQW9EO0lBQ3BELE9BQU8sQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixJQUFJLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxDQUFDO0lBRTdGLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxpSEFBaUgsQ0FBQyxDQUFDO1FBQ2hJLE1BQU0sQ0FBQyxJQUFJLENBQUMsK0RBQStELENBQUMsQ0FBQztRQUM3RSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BCLENBQUM7SUFFRCx1Q0FBdUM7SUFDdkMsT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBZSxDQUFDO0lBQ3JDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLGFBQXdCLENBQUM7SUFDdEQsT0FBTyxDQUFDLGtDQUFrQyxHQUFHLElBQUksQ0FBQywrQkFBeUMsQ0FBQztJQUM1RixPQUFPLENBQUMsa0NBQWtDLEdBQUcsSUFBSSxDQUFDLCtCQUF5QyxDQUFDO0lBQzVGLE9BQU8sQ0FBQyx3QkFBd0IsR0FBRyxJQUFJLENBQUMscUJBQStCLENBQUM7SUFFeEUsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsRUFBRTtRQUM3QyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7UUFDcEIsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1FBQ3BDLEtBQUssRUFBRSxPQUFPLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQztLQUM3QyxDQUFDLENBQUM7SUFFSCxNQUFNLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3BDLENBQUM7QUFFRCxHQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFBIn0=

View File

@ -1,3 +1,6 @@
import * as CLI from 'yargs'; import * as CLI from 'yargs';
export declare const defaultOptions: (yargs: CLI.Argv) => any; export declare const defaultOptions: (yargs: CLI.Argv) => any;
export declare const register: (cli: CLI.Argv) => any; export declare const command = "resize";
export declare const desc = "Resizes files";
export declare const builder: (yargs: CLI.Argv) => any;
export declare function handler(argv: CLI.Arguments): Promise<void>;

View File

@ -1,5 +1,6 @@
import { logger } from '../index.js'; import { logger } from '../index.js';
import { resize } from '../lib/media/images/resize.js'; import { resize } from '../lib/media/images/resize.js';
import { cli } from '../cli.js';
import { sanitize, defaults } from '../_cli.js'; import { sanitize, defaults } from '../_cli.js';
export const defaultOptions = (yargs) => { export const defaultOptions = (yargs) => {
return yargs.option('src', { return yargs.option('src', {
@ -51,14 +52,15 @@ export const defaultOptions = (yargs) => {
default: 'info' default: 'info'
}); });
}; };
let options = (yargs) => defaultOptions(yargs); export const command = 'resize';
export const register = (cli) => { export const desc = 'Resizes files';
return cli.command('resize', 'Resizes files', options, async (argv) => { export const builder = defaultOptions;
defaults(); export async function handler(argv) {
const options = sanitize(argv); defaults();
logger.settings.minLevel = options.logLevel; const options = sanitize(argv);
logger.info("options " + argv.dst, options); logger.settings.minLevel = options.logLevel;
await resize(options); logger.info("options " + argv.dst, options);
}); await resize(options);
}; }
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzaXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3Jlc2l6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sRUFDSCxNQUFNLEVBQ1QsTUFBTSwrQkFBK0IsQ0FBQTtBQUV0QyxPQUFPLEVBQ0gsUUFBUSxFQUNSLFFBQVEsRUFDWCxNQUFNLFlBQVksQ0FBQTtBQU1uQixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxLQUFlLEVBQUUsRUFBRTtJQUM5QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ3ZCLFFBQVEsRUFBRSxrQkFBa0I7UUFDNUIsWUFBWSxFQUFFLElBQUk7S0FDckIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixRQUFRLEVBQUUsa0JBQWtCO0tBQy9CLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFO1FBQ2YsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsZ0NBQWdDO1FBQzFDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2IsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUseUNBQXlDO1FBQ25ELElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2IsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHdCQUF3QjtRQUNsQyxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSwyQkFBMkI7UUFDckMsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixRQUFRLEVBQUUsbUJBQW1CO1FBQzdCLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2hCLFFBQVEsRUFBRSxxQkFBcUI7UUFDL0IsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUU7UUFDbkIsUUFBUSxFQUFFLDZCQUE2QjtRQUN2QyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNsQixRQUFRLEVBQUUsNEJBQTRCO1FBQ3RDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLFFBQVEsRUFBRSwyQkFBMkI7UUFDckMsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsUUFBUSxFQUFFLGlDQUFpQztRQUMzQyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNsQixRQUFRLEVBQUUsc0NBQXNDO1FBQ2hELElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLE1BQU07S0FDbEIsQ0FBQyxDQUFBO0FBQ04sQ0FBQyxDQUFBO0FBRUQsSUFBSSxPQUFPLEdBQUcsQ0FBQyxLQUFlLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUV4RCxNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFhLEVBQUUsRUFBRTtJQUN0QyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQW1CLEVBQUUsRUFBRTtRQUNqRixRQUFRLEVBQUUsQ0FBQTtRQUNWLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQWEsQ0FBQTtRQUMxQyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBZSxDQUFBO1FBQ2xELE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDM0MsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDekIsQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUEifQ== cli.command(command, desc, builder, handler);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzaXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3Jlc2l6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sRUFDSCxNQUFNLEVBQ1QsTUFBTSwrQkFBK0IsQ0FBQTtBQUN0QyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQy9CLE9BQU8sRUFDSCxRQUFRLEVBQ1IsUUFBUSxFQUNYLE1BQU0sWUFBWSxDQUFBO0FBTW5CLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLEtBQWUsRUFBRSxFQUFFO0lBQzlDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDdkIsUUFBUSxFQUFFLGtCQUFrQjtRQUM1QixZQUFZLEVBQUUsSUFBSTtLQUNyQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLFFBQVEsRUFBRSxrQkFBa0I7S0FDL0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSxnQ0FBZ0M7UUFDMUMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNmLFFBQVEsRUFBRSxtQkFBbUI7UUFDN0IsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUU7UUFDaEIsUUFBUSxFQUFFLHFCQUFxQjtRQUMvQixJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRTtRQUNuQixRQUFRLEVBQUUsNkJBQTZCO1FBQ3ZDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1FBQ2xCLFFBQVEsRUFBRSw0QkFBNEI7UUFDdEMsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixRQUFRLEVBQUUsaUNBQWlDO1FBQzNDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1FBQ2xCLFFBQVEsRUFBRSxzQ0FBc0M7UUFDaEQsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsTUFBTTtLQUNsQixDQUFDLENBQUE7QUFDTixDQUFDLENBQUE7QUFFRCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDO0FBQ2hDLE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxlQUFlLENBQUM7QUFDcEMsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQztBQUV0QyxNQUFNLENBQUMsS0FBSyxVQUFVLE9BQU8sQ0FBQyxJQUFtQjtJQUM3QyxRQUFRLEVBQUUsQ0FBQTtJQUNWLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQWEsQ0FBQTtJQUMxQyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBZSxDQUFBO0lBQ2xELE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFDM0MsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDekIsQ0FBQztBQUVELEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUEifQ==

View File

@ -1,3 +1,6 @@
import * as CLI from 'yargs'; import * as CLI from 'yargs';
export declare const defaultOptions: (yargs: CLI.Argv) => any; export declare const defaultOptions: (yargs: CLI.Argv) => any;
export declare const register: (cli: CLI.Argv) => any; export declare const command = "watermark";
export declare const desc = "Adds watermarks to images";
export declare const builder: (yargs: CLI.Argv) => any;
export declare function handler(argv: CLI.Arguments): Promise<void>;

View File

@ -1,7 +1,7 @@
import { CONFIG_DEFAULT } from '@polymech/commons';
import { logger } from '../index.js'; import { logger } from '../index.js';
import { watermark } from '../lib/media/images/watermark.js'; import { cli } from '../cli.js';
import { sanitize, defaults } from '../_cli.js'; import { sanitize, defaults } from '../_cli.js';
import { watermark } from '../lib/media/images/watermark.js';
export const defaultOptions = (yargs) => { export const defaultOptions = (yargs) => {
return yargs.option('src', { return yargs.option('src', {
describe: 'FILE|FOLDER|GLOB', describe: 'FILE|FOLDER|GLOB',
@ -24,47 +24,98 @@ export const defaultOptions = (yargs) => {
default: false, default: false,
describe: 'Show internal messages', describe: 'Show internal messages',
type: 'boolean' type: 'boolean'
}).option('percent', { }).option('logLevel', {
default: false, describe: 'Log level : warn, info, debug, error',
describe: 'Resize image with percent', type: 'string',
type: 'number' default: 'info'
}).option('width', { }).option('watermarkType', {
default: false, describe: 'Type of watermark: text or image',
describe: 'Resize image with', choices: ['text', 'image'],
type: 'number' demandOption: true
}).option('height', { }).option('text', {
default: false, describe: 'Text to use for text watermark',
describe: 'Resize image height',
type: 'number'
}).option('minHeight', {
describe: 'Resize image minimum height',
type: 'number'
}).option('minWidth', {
describe: 'Resize image minimum width',
type: 'number'
}).option('minSize', {
describe: 'Resize image size (bytes)',
type: 'number'
}).option('percent', {
describe: 'Resize image in percent (width)',
type: 'number'
}).option('key', {
describe: 'API Key',
type: 'string' type: 'string'
}).option('logoPath', {
describe: 'Path to logo image for image watermark',
type: 'string'
}).option('position', {
describe: 'Position of watermark',
choices: ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'],
default: 'bottom-right'
}).option('margin', {
describe: 'Margin from edges in pixels',
type: 'number',
default: 24
}).option('opacity', {
describe: 'Opacity of watermark (0-1)',
type: 'number',
default: 0.85
}).option('sizePct', {
describe: 'Size of image watermark as percentage of base image width (0-1)',
type: 'number',
default: 0.2
}).option('fontSize', {
describe: 'Font size for text watermark in pixels',
type: 'number',
default: 48
}).option('color', {
describe: 'Text color (hex format, e.g., #ffffff)',
type: 'string',
default: '#ffffff'
}).option('fontFamily', {
describe: 'Font family for text watermark',
type: 'string',
default: 'Arial'
}).option('strokeColor', {
describe: 'Text stroke color (hex format, e.g., #000000)',
type: 'string',
default: '#000000'
}).option('strokeWidth', {
describe: 'Text stroke width in pixels',
type: 'number',
default: 2
}); });
}; };
const options = (yargs) => defaultOptions(yargs); export const command = 'watermark';
export const register = (cli) => { export const desc = 'Adds watermarks to images';
return cli.command('watermark', 'Remove watermark : FILE|GLOB', options, async (argv) => { export const builder = defaultOptions;
defaults(); export async function handler(argv) {
const options = sanitize(argv); defaults();
const config = CONFIG_DEFAULT(); const options = sanitize(argv);
if (!config.novita) { logger.settings.minLevel = options.logLevel;
logger.error("Novita key not found"); // Validate required options based on watermark type
return; if (options.watermarkType === 'text' && !options.text) {
} logger.error('Text is required when using text watermark type');
options.debug && logger.info("Watermark Options " + argv.dst, options); process.exit(1);
return watermark({ ...options, key: config.novita.key }); }
}); if (options.watermarkType === 'image' && !options.logoPath) {
}; logger.error('Logo path is required when using image watermark type');
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0ZXJtYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3dhdGVybWFyay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFbEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUNwQyxPQUFPLEVBQ0wsU0FBUyxFQUNWLE1BQU0sa0NBQWtDLENBQUE7QUFFekMsT0FBTyxFQUNMLFFBQVEsRUFDUixRQUFRLEVBQ1QsTUFBTSxZQUFZLENBQUE7QUFNbkIsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBZSxFQUFFLEVBQUU7SUFDaEQsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUN6QixRQUFRLEVBQUUsa0JBQWtCO1FBQzVCLFlBQVksRUFBRSxJQUFJO0tBQ25CLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2YsUUFBUSxFQUFFLGtCQUFrQjtLQUM3QixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNqQixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSxnQ0FBZ0M7UUFDMUMsSUFBSSxFQUFFLFNBQVM7S0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsSUFBSSxFQUFFLFNBQVM7S0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDbkIsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2hCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ25CLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFO1FBQ2pCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLG1CQUFtQjtRQUM3QixJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2xCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHFCQUFxQjtRQUMvQixJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFO1FBQ3JCLFFBQVEsRUFBRSw2QkFBNkI7UUFDdkMsSUFBSSxFQUFFLFFBQVE7S0FDZixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNwQixRQUFRLEVBQUUsNEJBQTRCO1FBQ3RDLElBQUksRUFBRSxRQUFRO0tBQ2YsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDbkIsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ25CLFFBQVEsRUFBRSxpQ0FBaUM7UUFDM0MsSUFBSSxFQUFFLFFBQVE7S0FDZixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNmLFFBQVEsRUFBRSxTQUFTO1FBQ25CLElBQUksRUFBRSxRQUFRO0tBQ2YsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBRUQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxLQUFlLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUUxRCxNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFhLEVBQUUsRUFBRTtJQUN4QyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLDhCQUE4QixFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBbUIsRUFBRSxFQUFFO1FBQ3JHLFFBQVEsRUFBRSxDQUFBO1FBQ1YsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBYSxDQUFBO1FBQzFDLE1BQU0sTUFBTSxHQUFRLGNBQWMsRUFBRSxDQUFBO1FBQ3BDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1lBQ3JDLE9BQU07UUFDUixDQUFDO1FBQ0QsT0FBTyxDQUFDLEtBQUssSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDdEUsT0FBTyxTQUFTLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFBO0lBQzFELENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBIn0= process.exit(1);
}
// Set up watermark options based on type
if (options.watermarkType === 'text') {
options.textOptions = {
position: argv.position,
margin: argv.margin,
fontSize: argv.fontSize,
opacity: argv.opacity,
color: argv.color,
fontFamily: argv.fontFamily,
strokeColor: argv.strokeColor,
strokeWidth: argv.strokeWidth,
};
}
else if (options.watermarkType === 'image') {
options.imageOptions = {
position: argv.position,
margin: argv.margin,
sizePct: argv.sizePct,
opacity: argv.opacity,
blend: 'over'
};
}
logger.info("Adding watermark with options:", options);
await watermark(options);
}
cli.command(command, desc, builder, handler);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0ZXJtYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3dhdGVybWFyay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDL0IsT0FBTyxFQUNILFFBQVEsRUFDUixRQUFRLEVBQ1gsTUFBTSxZQUFZLENBQUE7QUFNbkIsT0FBTyxFQUNILFNBQVMsRUFFWixNQUFNLGtDQUFrQyxDQUFBO0FBRXpDLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLEtBQWUsRUFBRSxFQUFFO0lBQzlDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDdkIsUUFBUSxFQUFFLGtCQUFrQjtRQUM1QixZQUFZLEVBQUUsSUFBSTtLQUNyQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLFFBQVEsRUFBRSxrQkFBa0I7S0FDL0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSxnQ0FBZ0M7UUFDMUMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1FBQ2xCLFFBQVEsRUFBRSxzQ0FBc0M7UUFDaEQsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsTUFBTTtLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLGVBQWUsRUFBRTtRQUN2QixRQUFRLEVBQUUsa0NBQWtDO1FBQzVDLE9BQU8sRUFBRSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUM7UUFDMUIsWUFBWSxFQUFFLElBQUk7S0FDckIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUU7UUFDZCxRQUFRLEVBQUUsZ0NBQWdDO1FBQzFDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1FBQ2xCLFFBQVEsRUFBRSx3Q0FBd0M7UUFDbEQsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUU7UUFDbEIsUUFBUSxFQUFFLHVCQUF1QjtRQUNqQyxPQUFPLEVBQUUsQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsUUFBUSxDQUFDO1FBQzNFLE9BQU8sRUFBRSxjQUFjO0tBQzFCLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2hCLFFBQVEsRUFBRSw2QkFBNkI7UUFDdkMsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsRUFBRTtLQUNkLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLFFBQVEsRUFBRSw0QkFBNEI7UUFDdEMsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsSUFBSTtLQUNoQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixRQUFRLEVBQUUsaUVBQWlFO1FBQzNFLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLEdBQUc7S0FDZixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNsQixRQUFRLEVBQUUsd0NBQXdDO1FBQ2xELElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLEVBQUU7S0FDZCxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNmLFFBQVEsRUFBRSx3Q0FBd0M7UUFDbEQsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsU0FBUztLQUNyQixDQUFDLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRTtRQUNwQixRQUFRLEVBQUUsZ0NBQWdDO1FBQzFDLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLE9BQU87S0FDbkIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUU7UUFDckIsUUFBUSxFQUFFLCtDQUErQztRQUN6RCxJQUFJLEVBQUUsUUFBUTtRQUNkLE9BQU8sRUFBRSxTQUFTO0tBQ3JCLENBQUMsQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFO1FBQ3JCLFFBQVEsRUFBRSw2QkFBNkI7UUFDdkMsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsQ0FBQztLQUNiLENBQUMsQ0FBQTtBQUNOLENBQUMsQ0FBQTtBQUlELE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxXQUFXLENBQUM7QUFDbkMsTUFBTSxDQUFDLE1BQU0sSUFBSSxHQUFHLDJCQUEyQixDQUFDO0FBQ2hELE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxjQUFjLENBQUM7QUFFdEMsTUFBTSxDQUFDLEtBQUssVUFBVSxPQUFPLENBQUMsSUFBbUI7SUFDN0MsUUFBUSxFQUFFLENBQUE7SUFDVixNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFxQixDQUFBO0lBQ2xELE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUFlLENBQUE7SUFFbEQsb0RBQW9EO0lBQ3BELElBQUksT0FBTyxDQUFDLGFBQWEsS0FBSyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDcEQsTUFBTSxDQUFDLEtBQUssQ0FBQyxpREFBaUQsQ0FBQyxDQUFBO1FBQy9ELE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDbkIsQ0FBQztJQUVELElBQUksT0FBTyxDQUFDLGFBQWEsS0FBSyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDekQsTUFBTSxDQUFDLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFBO1FBQ3JFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDbkIsQ0FBQztJQUVELHlDQUF5QztJQUN6QyxJQUFJLE9BQU8sQ0FBQyxhQUFhLEtBQUssTUFBTSxFQUFFLENBQUM7UUFDbkMsT0FBTyxDQUFDLFdBQVcsR0FBRztZQUNsQixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQWU7WUFDOUIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFnQjtZQUM3QixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQWtCO1lBQ2pDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBaUI7WUFDL0IsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFlO1lBQzNCLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBb0I7WUFDckMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFxQjtZQUN2QyxXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQXFCO1NBQzFDLENBQUE7SUFDTCxDQUFDO1NBQU0sSUFBSSxPQUFPLENBQUMsYUFBYSxLQUFLLE9BQU8sRUFBRSxDQUFDO1FBQzNDLE9BQU8sQ0FBQyxZQUFZLEdBQUc7WUFDbkIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFlO1lBQzlCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBZ0I7WUFDN0IsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFpQjtZQUMvQixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQWlCO1lBQy9CLEtBQUssRUFBRSxNQUFNO1NBQ2hCLENBQUE7SUFDTCxDQUFDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxnQ0FBZ0MsRUFBRSxPQUFPLENBQUMsQ0FBQTtJQUN0RCxNQUFNLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQTtBQUM1QixDQUFDO0FBRUQsR0FBRyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQSJ9

View File

@ -0,0 +1,11 @@
import { IOptions } from '../../../types.js';
export interface BackgroundRemoveOptions extends IOptions {
apiKey?: string;
model?: string;
alpha_matting?: boolean;
alpha_matting_foreground_threshold?: number;
alpha_matting_background_threshold?: number;
alpha_matting_erode_size?: number;
}
export declare function removeBackgroundFile(inputPath: string, outputPath: string, options: BackgroundRemoveOptions): Promise<void>;
export declare const backgroundRemove: (options: BackgroundRemoveOptions) => Promise<void[][]>;

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,31 @@
import { OverlayOptions } from "sharp";
import { IOptions } from '../../../types.js'; import { IOptions } from '../../../types.js';
export declare const watermark: (options: IOptions) => Promise<any>; type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center";
export interface LogoWatermarkOptions {
position?: Corner;
margin?: number;
sizePct?: number;
opacity?: number;
blend?: OverlayOptions["blend"];
}
export interface TextWatermarkOptions {
position?: Corner;
margin?: number;
fontSize?: number;
opacity?: number;
color?: string;
fontFamily?: string;
strokeColor?: string;
strokeWidth?: number;
}
export interface WatermarkOptions extends IOptions {
watermarkType: 'text' | 'image';
text?: string;
textOptions?: TextWatermarkOptions;
logoPath?: string;
imageOptions?: LogoWatermarkOptions;
}
export declare function addLogoWatermark(inputPath: string, logoPath: string, outputPath: string, opts?: LogoWatermarkOptions): Promise<void>;
export declare function addTextWatermark(inputPath: string, text: string, outputPath: string, opts?: TextWatermarkOptions): Promise<void>;
export declare const watermark: (options: WatermarkOptions) => Promise<void[][]>;
export {};

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,5 @@
#!/usr/bin/env node #!/usr/bin/env node
import './commands/resize.js'; import './commands/resize.js';
import './commands/pdf2jpg.js'; import './commands/pdf2jpg.js';
import './commands/watermark.js';
import './commands/background-remove.js';

View File

@ -4,6 +4,8 @@ defaults();
import { cli } from './cli.js'; import { cli } from './cli.js';
import './commands/resize.js'; import './commands/resize.js';
import './commands/pdf2jpg.js'; import './commands/pdf2jpg.js';
import './commands/watermark.js';
import './commands/background-remove.js';
const argv = cli.argv; const argv = cli.argv;
if (argv.h || argv.help) { if (argv.h || argv.help) {
cli.showHelp(); cli.showHelp();
@ -12,4 +14,4 @@ if (argv.h || argv.help) {
else if (argv.v || argv.version) { else if (argv.v || argv.version) {
process.exit(); process.exit();
} }
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQUMsUUFBUSxFQUFFLENBQUE7QUFFaEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUM5QixPQUFPLHNCQUFzQixDQUFBO0FBQzdCLE9BQU8sdUJBQXVCLENBQUE7QUFFOUIsTUFBTSxJQUFJLEdBQVEsR0FBRyxDQUFDLElBQUksQ0FBQztBQUUzQixJQUFJLElBQUksQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3RCLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUNmLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUNuQixDQUFDO0tBQU0sSUFBSSxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNoQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDbkIsQ0FBQyJ9 //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQUMsUUFBUSxFQUFFLENBQUE7QUFFaEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUU5QixPQUFPLHNCQUFzQixDQUFBO0FBQzdCLE9BQU8sdUJBQXVCLENBQUE7QUFDOUIsT0FBTyx5QkFBeUIsQ0FBQTtBQUNoQyxPQUFPLGlDQUFpQyxDQUFBO0FBRXhDLE1BQU0sSUFBSSxHQUFRLEdBQUcsQ0FBQyxJQUFJLENBQUM7QUFFM0IsSUFBSSxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN0QixHQUFHLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDZixPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDbkIsQ0FBQztLQUFNLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDaEMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0FBQ25CLENBQUMifQ==

View File

@ -50,3 +50,5 @@ export type IConvertVideoOptions = IOptions & {
verb: string; verb: string;
audio: string; audio: string;
}; };
export type { WatermarkOptions, LogoWatermarkOptions, TextWatermarkOptions } from './lib/media/images/watermark.js';
export type { BackgroundRemoveOptions } from './lib/media/images/background-remove.js';

View File

@ -0,0 +1,638 @@
# Background Remove CLI Documentation
The `pm-media background:remove` command uses AI-powered background removal to automatically isolate subjects from their backgrounds. This tool leverages the [Replicate API](https://replicate.com/cjwbw/rembg) for high-quality results and supports batch processing with multiple AI models.
## Table of Contents
- [Installation](#installation)
- [Setup](#setup)
- [Basic Usage](#basic-usage)
- [AI Models](#ai-models)
- [Command Line Options](#command-line-options)
- [API Usage](#api-usage)
- [Examples](#examples)
- [Alpha Matting](#alpha-matting)
- [Performance Tips](#performance-tips)
- [Troubleshooting](#troubleshooting)
## Installation
```bash
npm install @polymech/media
```
## Setup
### 1. Get Replicate API Key
1. Visit [Replicate API Tokens](https://replicate.com/account/api-tokens)
2. Sign up or log in to your account
3. Create a new API token
4. Copy your API token
### 2. Set API Key
You can provide your API key in two ways:
**Option A: Environment Variable (Recommended)**
```bash
export REPLICATE_API_TOKEN="your_api_token_here"
```
**Option B: Command Line Argument**
```bash
pm-media background:remove --src input.jpg --apiKey "your_api_token_here"
```
## Basic Usage
```bash
pm-media background:remove --src <input> --dst <output> [options]
```
### Required Parameters
- `--src`: Source files (FILE|FOLDER|GLOB pattern)
### Optional Parameters
- `--dst`: Destination path (defaults to source location with modified name)
- `--apiKey`: Replicate API key (if not set via environment variable)
## AI Models
The tool supports multiple specialized AI models for different use cases:
### Available Models
| Model | Best For | Description |
|-------|----------|-------------|
| `u2net` (default) | General use | Universal background removal |
| `u2netp` | Performance | Lighter version of U2Net |
| `u2net_human_seg` | People | Optimized for human subjects |
| `u2net_cloth_seg` | Clothing | Specialized for clothing items |
| `silueta` | Portraits | High-quality person silhouettes |
### Model Selection
```bash
# General purpose (default)
pm-media background:remove --src photo.jpg --model u2net
# Optimized for people
pm-media background:remove --src portrait.jpg --model u2net_human_seg
# Clothing/fashion
pm-media background:remove --src product.jpg --model u2net_cloth_seg
```
## Command Line Options
### Core Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--src` | string | required | Source files (FILE\|FOLDER\|GLOB) |
| `--dst` | string | - | Destination path |
| `--apiKey` | string | - | Replicate API key |
| `--model` | choice | "u2net" | AI model to use |
### Alpha Matting Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--alphaMattting` | boolean | false | Enable alpha matting for better edges |
| `--alphaMattingForegroundThreshold` | number | 270 | Foreground detection threshold |
| `--alphaMattingBackgroundThreshold` | number | 10 | Background detection threshold |
| `--alphaMattingErodeSize` | number | 10 | Edge erosion size |
### Utility Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--dry` | boolean | false | Preview mode (no API calls) |
| `--verbose` | boolean | false | Show detailed processing info |
| `--debug` | boolean | false | Enable debug messages |
| `--logLevel` | string | "info" | Log level (warn\|info\|debug\|error) |
## API Usage
### Import the Library
```typescript
import {
backgroundRemove,
removeBackgroundFile,
BackgroundRemoveOptions
} from '@polymech/media';
```
### Single File Background Removal
```typescript
import { removeBackgroundFile } from '@polymech/media';
await removeBackgroundFile(
'input.jpg',
'output.png',
{
apiKey: 'your_api_token',
model: 'u2net',
alpha_matting: false
}
);
```
### Batch Processing API
```typescript
import { backgroundRemove } from '@polymech/media';
const options: BackgroundRemoveOptions = {
src: 'photos/*.jpg',
dst: 'no-bg/',
apiKey: process.env.REPLICATE_API_TOKEN,
model: 'u2net_human_seg',
alpha_matting: true,
// ... other IOptions
};
await backgroundRemove(options);
```
### Advanced Configuration
```typescript
const advancedOptions: BackgroundRemoveOptions = {
src: 'portraits/*.jpg',
dst: 'processed/',
apiKey: 'your_token',
model: 'u2net_human_seg',
alpha_matting: true,
alpha_matting_foreground_threshold: 280,
alpha_matting_background_threshold: 15,
alpha_matting_erode_size: 8,
verbose: true
};
await backgroundRemove(advancedOptions);
```
## Examples
### Example 1: Basic Background Removal
```bash
# Remove background from a single image
pm-media background:remove \
--src "photo.jpg" \
--dst "no-background.png"
```
### Example 2: Batch Processing
```bash
# Process multiple images
pm-media background:remove \
--src "photos/*.jpg" \
--dst "processed/" \
--model u2net
```
### Example 3: Portrait Optimization
```bash
# Optimized for people/portraits
pm-media background:remove \
--src "portraits/*.jpg" \
--dst "headshots/" \
--model u2net_human_seg \
--alphaMattting
```
### Example 4: Product Photography
```bash
# E-commerce product images
pm-media background:remove \
--src "products/*.jpg" \
--dst "catalog/" \
--model u2net_cloth_seg \
--alphaMattting \
--alphaMattingForegroundThreshold 280
```
### Example 5: High-Quality Processing
```bash
# Maximum quality with alpha matting
pm-media background:remove \
--src "studio-photos/*.jpg" \
--dst "final/" \
--model silueta \
--alphaMattting \
--alphaMattingForegroundThreshold 300 \
--alphaMattingBackgroundThreshold 5 \
--verbose
```
### Example 6: Fast Batch Processing
```bash
# Quick processing for previews
pm-media background:remove \
--src "batch/*.jpg" \
--dst "previews/" \
--model u2netp
```
### Example 7: Dry Run Preview
```bash
# Preview what would be processed
pm-media background:remove \
--src "archive/**/*.jpg" \
--dst "processed/" \
--dry \
--verbose
```
### Example 8: Organized Output
```bash
# Maintain folder structure
pm-media background:remove \
--src "organized/session-1/*.jpg" \
--dst "no-bg/session-1/" \
--model u2net_human_seg
```
## Alpha Matting
Alpha matting provides superior edge quality for complex subjects with fine details like hair, fur, or transparent materials.
### When to Use Alpha Matting
✅ **Use alpha matting for:**
- Portraits with detailed hair
- Furry animals
- Objects with fine edges
- Semi-transparent materials
- Professional/commercial work
❌ **Skip alpha matting for:**
- Simple shapes
- Hard edges
- Quick previews
- Batch processing (slower)
### Alpha Matting Parameters
```bash
# Standard alpha matting
pm-media background:remove \
--src input.jpg \
--dst output.png \
--alphaMattting
# Fine-tuned alpha matting
pm-media background:remove \
--src portrait.jpg \
--dst result.png \
--alphaMattting \
--alphaMattingForegroundThreshold 280 \
--alphaMattingBackgroundThreshold 12 \
--alphaMattingErodeSize 6
```
### Parameter Guidelines
| Parameter | Low Value | High Value | Effect |
|-----------|-----------|------------|--------|
| Foreground Threshold | 200 | 350 | More/less foreground detection |
| Background Threshold | 5 | 20 | More/less background detection |
| Erode Size | 3 | 15 | Smaller/larger edge refinement |
## File Format Support
### Supported Input Formats
- JPEG (.jpg, .jpeg)
- PNG (.png)
- WebP (.webp)
- TIFF (.tiff, .tif)
### Output Format
- **PNG with transparency** (recommended)
- Automatically adds transparency channel
- Preserves original quality
### Format Recommendations
```bash
# For web use
pm-media background:remove --src input.jpg --dst output.png
# For print/professional
pm-media background:remove --src input.tiff --dst output.png --alphaMattting
```
## Performance Tips
### 1. Choose Appropriate Models
```bash
# Fast processing
--model u2netp
# Balanced quality/speed
--model u2net
# High quality (slower)
--model silueta
```
### 2. Use Alpha Matting Selectively
```bash
# For most images (faster)
pm-media background:remove --src batch/*.jpg --dst output/
# For detailed work only (slower)
pm-media background:remove --src detailed/*.jpg --dst output/ --alphaMattting
```
### 3. Batch Processing Strategies
```bash
# Process in chunks for large batches
pm-media background:remove --src "batch1/*.jpg" --dst "output1/"
pm-media background:remove --src "batch2/*.jpg" --dst "output2/"
```
### 4. API Rate Limiting
The Replicate API has rate limits. For large batches:
- Process during off-peak hours
- Consider parallel processing limits
- Monitor API usage in your Replicate dashboard
## Cost Considerations
### Replicate Pricing
Background removal costs per prediction. Check current pricing at [Replicate Pricing](https://replicate.com/pricing).
### Cost Optimization
```bash
# Test with dry run first
pm-media background:remove --src "*.jpg" --dst "output/" --dry
# Use efficient models
--model u2netp # Fastest/cheapest
--model u2net # Balanced
--model silueta # Highest quality/most expensive
```
## Troubleshooting
### Common Issues
#### "API key is required"
```bash
# Set environment variable
export REPLICATE_API_TOKEN="your_token"
# Or use command line
pm-media background:remove --src input.jpg --apiKey "your_token"
```
#### "Replicate package not found"
```bash
# Install missing dependency
npm install replicate
```
#### Poor edge quality
```bash
# Enable alpha matting
pm-media background:remove \
--src input.jpg \
--dst output.png \
--alphaMattting \
--alphaMattingForegroundThreshold 280
```
#### API rate limit errors
- Reduce batch size
- Add delays between requests
- Check your Replicate dashboard for limits
#### Large file processing fails
- Resize images before processing
- Use appropriate model for image type
- Check API payload limits
### Debug Mode
Enable detailed logging:
```bash
pm-media background:remove \
--src "input/*" \
--dst "output/" \
--debug \
--verbose
```
### Quality Issues
```bash
# For people/portraits
--model u2net_human_seg
# For products/objects
--model u2net_cloth_seg
# For complex edges
--alphaMattting --alphaMattingForegroundThreshold 300
```
## Integration Examples
### E-commerce Workflow
```bash
#!/bin/bash
# Product photography pipeline
INPUT_DIR="$1"
OUTPUT_DIR="$2"
# Remove backgrounds
pm-media background:remove \
--src "$INPUT_DIR/*.jpg" \
--dst "$OUTPUT_DIR/no-bg/" \
--model u2net_cloth_seg \
--alphaMattting
# Create thumbnails
pm-media resize \
--src "$OUTPUT_DIR/no-bg/*.png" \
--dst "$OUTPUT_DIR/thumbs/" \
--width 300 \
--height 300 \
--fit contain \
--background white
```
### Portrait Studio Workflow
```bash
#!/bin/bash
# Professional portrait processing
pm-media background:remove \
--src "portraits/*.jpg" \
--dst "processed/" \
--model u2net_human_seg \
--alphaMattting \
--alphaMattingForegroundThreshold 290 \
--verbose
echo "Background removal complete"
```
### Batch Organization Script
```bash
#!/bin/bash
# Organize processed images
for dir in */; do
if [ -d "$dir" ]; then
echo "Processing directory: $dir"
pm-media background:remove \
--src "$dir*.jpg" \
--dst "no-bg/$dir" \
--model u2net \
--verbose
fi
done
```
## Advanced Usage
### Environment Configuration
```bash
# .env file
REPLICATE_API_TOKEN=your_token_here
DEFAULT_BG_MODEL=u2net_human_seg
ALPHA_MATTING=true
# Use in scripts
pm-media background:remove \
--src "*.jpg" \
--dst "output/" \
--model "$DEFAULT_BG_MODEL"
```
### Quality Control
```bash
#!/bin/bash
# Process with multiple quality levels
INPUT="$1"
BASE_NAME=$(basename "$INPUT" .jpg)
# Quick preview
pm-media background:remove \
--src "$INPUT" \
--dst "preview/${BASE_NAME}_preview.png" \
--model u2netp
# High quality
pm-media background:remove \
--src "$INPUT" \
--dst "final/${BASE_NAME}_final.png" \
--model silueta \
--alphaMattting
```
### Conditional Processing
```bash
#!/bin/bash
# Different models based on file type
for image in *.jpg; do
if [[ $image == *"portrait"* ]]; then
MODEL="u2net_human_seg"
elif [[ $image == *"product"* ]]; then
MODEL="u2net_cloth_seg"
else
MODEL="u2net"
fi
pm-media background:remove \
--src "$image" \
--dst "processed/" \
--model "$MODEL"
done
```
## TypeScript Definitions
```typescript
interface BackgroundRemoveOptions extends IOptions {
apiKey?: string;
model?: 'u2net' | 'u2netp' | 'u2net_human_seg' | 'u2net_cloth_seg' | 'silueta';
alpha_matting?: boolean;
alpha_matting_foreground_threshold?: number;
alpha_matting_background_threshold?: number;
alpha_matting_erode_size?: number;
}
declare function removeBackgroundFile(
inputPath: string,
outputPath: string,
options: BackgroundRemoveOptions
): Promise<void>;
declare function backgroundRemove(
options: BackgroundRemoveOptions
): Promise<any>;
```
## Security Notes
### API Key Security
- Never commit API keys to version control
- Use environment variables in production
- Rotate keys regularly
- Monitor usage in Replicate dashboard
### File Handling
- Validate input file types
- Check file sizes before processing
- Sanitize file paths
- Handle temporary files securely
## Contributing
For bug reports, feature requests, or contributions, please visit the project repository.
## References
- [Replicate API Documentation](https://replicate.com/docs)
- [rembg Model on Replicate](https://replicate.com/cjwbw/rembg)
- [Replicate Pricing](https://replicate.com/pricing)
- [API Rate Limits](https://replicate.com/docs/reference/http#rate-limits)
## License
This tool is part of the @polymech/media package. Please refer to the package license for usage terms.

View File

@ -0,0 +1,532 @@
# PDF2JPG CLI Documentation
The `pm-media pdf2jpg` command converts PDF documents to high-quality images (JPG or PNG). This tool supports batch processing, custom DPI settings, page range selection, and advanced rendering options using MuPDF.
## Table of Contents
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Output Formats](#output-formats)
- [Command Line Options](#command-line-options)
- [API Usage](#api-usage)
- [Examples](#examples)
- [Template Variables](#template-variables)
- [Performance Optimization](#performance-optimization)
- [Troubleshooting](#troubleshooting)
## Installation
```bash
npm install @polymech/media
```
## Basic Usage
```bash
pm-media pdf2jpg --input <pdf-file> [options]
```
### Required Parameters
- `--input` (or `-i`): Path to the input PDF file
### Optional Parameters
- `--output` (or `-o`): Output path template
- `--dpi`: Resolution for output images (default: 300)
- `--format`: Output format - 'jpg' or 'png' (default: 'jpg')
- `--scale`: Scaling factor (default: 2)
- `--startPage`: First page to convert (1-based)
- `--endPage`: Last page to convert (1-based)
## Output Formats
### JPEG Format
- **Extension**: `.jpg`
- **Use case**: Photographs, complex images
- **Pros**: Smaller file sizes, good compression
- **Cons**: Lossy compression, no transparency
### PNG Format
- **Extension**: `.png`
- **Use case**: Text, diagrams, images with transparency
- **Pros**: Lossless compression, transparency support
- **Cons**: Larger file sizes
## Command Line Options
### Core Options
| Option | Alias | Type | Default | Description |
|--------|-------|------|---------|-------------|
| `--input` | `-i` | string | required | Path to the input PDF file |
| `--output` | `-o` | string | auto | Output path template |
| `--dpi` | - | number | 300 | Resolution for output images |
| `--format` | - | choice | 'jpg' | Output format: 'jpg' or 'png' |
| `--scale` | - | number | 2 | Scaling factor for rendering |
### Page Range Options
| Option | Type | Description |
|--------|------|-------------|
| `--startPage` | number | First page to convert (1-based index) |
| `--endPage` | number | Last page to convert (1-based index) |
### Quality & Performance
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--dpi` | number | 300 | Higher = better quality, larger files |
| `--scale` | number | 2 | Rendering scale factor |
## API Usage
### Import the Library
```typescript
import {
runConversion,
convertPdfToImages,
ConvertCommandConfig,
ImageFormat
} from '@polymech/media';
```
### Single PDF Conversion
```typescript
import { runConversion } from '@polymech/media';
import { logger } from 'tslog';
const config: ConvertCommandConfig = {
input: 'document.pdf',
output: 'output/page_{PAGE}.jpg',
dpi: 300,
format: 'jpg',
scale: 2
};
const outputFiles = await runConversion(config, logger);
console.log(`Generated ${outputFiles.length} images`);
```
### Advanced PDF Conversion
```typescript
import { convertPdfToImages } from '@polymech/media';
import { readFile } from 'fs/promises';
const pdfBuffer = await readFile('document.pdf');
const options = {
baseVariables: {
SRC_NAME: 'document',
SRC_DIR: '/output'
},
outputPathTemplate: '${SRC_DIR}/${SRC_NAME}_${PAGE}.${FORMAT}',
dpi: 600,
scale: 1.5,
format: 'png' as ImageFormat,
startPage: 1,
endPage: 10
};
const outputFiles = await convertPdfToImages(pdfBuffer, options);
```
### Custom Page Range
```typescript
const config: ConvertCommandConfig = {
input: 'large-document.pdf',
output: 'pages/chapter_{PAGE}.png',
format: 'png',
startPage: 10,
endPage: 25,
dpi: 150 // Lower DPI for faster processing
};
await runConversion(config, logger);
```
## Examples
### Example 1: Basic PDF to JPG
```bash
# Convert entire PDF to JPG images
pm-media pdf2jpg \
--input "document.pdf" \
--output "images/page_{PAGE}.jpg"
```
### Example 2: High-Quality PNG Conversion
```bash
# High-quality PNG conversion
pm-media pdf2jpg \
--input "technical-manual.pdf" \
--output "manual/page_{PAGE}.png" \
--format png \
--dpi 600 \
--scale 1
```
### Example 3: Specific Page Range
```bash
# Convert only pages 5-15
pm-media pdf2jpg \
--input "book.pdf" \
--output "chapter/page_{PAGE}.jpg" \
--startPage 5 \
--endPage 15 \
--dpi 300
```
### Example 4: Fast Preview Generation
```bash
# Low-quality previews for quick processing
pm-media pdf2jpg \
--input "presentation.pdf" \
--output "previews/slide_{PAGE}.jpg" \
--dpi 150 \
--scale 1
```
### Example 5: Print-Quality Images
```bash
# Print-quality conversion
pm-media pdf2jpg \
--input "brochure.pdf" \
--output "print-ready/page_{PAGE}.png" \
--format png \
--dpi 600 \
--scale 2
```
### Example 6: Organized Output Structure
```bash
# Organized folder structure
pm-media pdf2jpg \
--input "reports/quarterly-report.pdf" \
--output "output/quarterly/{PAGE:03d}_page.jpg" \
--dpi 300
```
### Example 7: Single Page Extraction
```bash
# Extract just the first page
pm-media pdf2jpg \
--input "document.pdf" \
--output "cover.jpg" \
--startPage 1 \
--endPage 1 \
--dpi 300
```
### Example 8: Batch Processing Script
```bash
#!/bin/bash
# Process multiple PDFs
for pdf in *.pdf; do
name=$(basename "$pdf" .pdf)
pm-media pdf2jpg \
--input "$pdf" \
--output "converted/${name}/{PAGE}.jpg" \
--dpi 300 \
--format jpg
done
```
## Template Variables
The output path supports template variables for dynamic naming:
### Available Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `{PAGE}` | Page number | `1`, `2`, `3` |
| `{PAGE:03d}` | Zero-padded page | `001`, `002`, `003` |
| `{SRC_NAME}` | PDF filename (no extension) | `document` |
| `{SRC_DIR}` | Source directory | `/path/to/source` |
| `{FORMAT}` | Output format | `jpg`, `png` |
### Template Examples
```bash
# Basic template
--output "pages/page_{PAGE}.jpg"
# Result: pages/page_1.jpg, pages/page_2.jpg
# Zero-padded pages
--output "output/{PAGE:03d}_page.{FORMAT}"
# Result: output/001_page.jpg, output/002_page.jpg
# Include source name
--output "{SRC_NAME}/page_{PAGE}.{FORMAT}"
# Result: document/page_1.jpg, document/page_2.jpg
# Complex structure
--output "converted/{SRC_NAME}/{PAGE:04d}_{SRC_NAME}.{FORMAT}"
# Result: converted/manual/0001_manual.jpg
```
## DPI and Quality Guidelines
### DPI Recommendations
| Use Case | DPI | File Size | Quality |
|----------|-----|-----------|---------|
| Web preview | 72-96 | Small | Basic |
| Screen viewing | 150 | Medium | Good |
| Standard print | 300 | Large | High |
| Professional print | 600+ | Very large | Excellent |
### Quality vs Performance
```bash
# Fast processing (previews)
pm-media pdf2jpg --input doc.pdf --dpi 150 --scale 1
# Balanced (general use)
pm-media pdf2jpg --input doc.pdf --dpi 300 --scale 2
# High quality (print/archive)
pm-media pdf2jpg --input doc.pdf --dpi 600 --scale 1 --format png
```
## Performance Optimization
### 1. Adjust DPI for Use Case
```bash
# Thumbnails/previews
pm-media pdf2jpg --input large.pdf --dpi 96 --output "thumbs/{PAGE}.jpg"
# Print quality
pm-media pdf2jpg --input doc.pdf --dpi 300 --output "print/{PAGE}.png"
```
### 2. Use Appropriate Format
```bash
# Photos/complex images → JPG
pm-media pdf2jpg --input photo-catalog.pdf --format jpg --dpi 300
# Text/diagrams → PNG
pm-media pdf2jpg --input technical-docs.pdf --format png --dpi 300
```
### 3. Process Page Ranges
```bash
# Process in chunks for large PDFs
pm-media pdf2jpg --input huge.pdf --startPage 1 --endPage 50 --output "batch1/{PAGE}.jpg"
pm-media pdf2jpg --input huge.pdf --startPage 51 --endPage 100 --output "batch2/{PAGE}.jpg"
```
### 4. Scale Factor Optimization
```bash
# Scale = 1 for faster processing
pm-media pdf2jpg --input doc.pdf --scale 1 --dpi 300
# Scale = 2 for better quality (default)
pm-media pdf2jpg --input doc.pdf --scale 2 --dpi 300
```
## File Organization
### Automatic Directory Creation
The tool automatically creates output directories:
```bash
# Creates nested directories as needed
pm-media pdf2jpg \
--input "doc.pdf" \
--output "output/projects/client-a/pages/{PAGE}.jpg"
```
### Organized Output Patterns
```bash
# By document name
--output "{SRC_NAME}/page_{PAGE:03d}.jpg"
# By date and document
--output "$(date +%Y-%m-%d)/{SRC_NAME}/{PAGE}.jpg"
# By quality level
--output "high-res/{SRC_NAME}/page_{PAGE}.png"
```
## Troubleshooting
### Common Issues
#### "Input file does not exist"
```bash
# Check file path and permissions
ls -la path/to/file.pdf
pm-media pdf2jpg --input "./document.pdf" --output "output/{PAGE}.jpg"
```
#### "Unable to open PDF"
- Ensure PDF is not corrupted
- Check if PDF is password-protected
- Verify file permissions
#### Poor image quality
```bash
# Increase DPI and use PNG for text
pm-media pdf2jpg \
--input doc.pdf \
--format png \
--dpi 600 \
--scale 1
```
#### Large file sizes
```bash
# Reduce DPI or use JPG format
pm-media pdf2jpg \
--input doc.pdf \
--format jpg \
--dpi 300 \
--scale 1
```
#### Memory issues with large PDFs
```bash
# Process in smaller page ranges
pm-media pdf2jpg --input large.pdf --startPage 1 --endPage 10
pm-media pdf2jpg --input large.pdf --startPage 11 --endPage 20
```
### Debug Mode
No specific debug mode, but check output for errors:
```bash
pm-media pdf2jpg --input doc.pdf --output "{PAGE}.jpg" 2>&1 | tee conversion.log
```
### Page Range Validation
```bash
# Check PDF page count first
pm-media pdf2jpg --input doc.pdf --startPage 1 --endPage 1 # Test first page
```
## Advanced Usage
### Integration with Other Tools
```bash
#!/bin/bash
# Convert PDF and create thumbnails
PDF_FILE="$1"
BASE_NAME=$(basename "$PDF_FILE" .pdf)
# Convert to high-res images
pm-media pdf2jpg \
--input "$PDF_FILE" \
--output "images/${BASE_NAME}/{PAGE:03d}.png" \
--format png \
--dpi 300
# Create thumbnails
pm-media resize \
--src "images/${BASE_NAME}/*.png" \
--dst "thumbnails/${BASE_NAME}/" \
--width 200 \
--height 200 \
--fit cover
```
### Automation Scripts
```bash
#!/bin/bash
# Automated PDF processing pipeline
INPUT_DIR="$1"
OUTPUT_DIR="$2"
find "$INPUT_DIR" -name "*.pdf" | while read pdf; do
name=$(basename "$pdf" .pdf)
echo "Processing: $pdf"
pm-media pdf2jpg \
--input "$pdf" \
--output "$OUTPUT_DIR/$name/{PAGE:03d}.jpg" \
--dpi 300 \
--format jpg
echo "Completed: $name"
done
```
### Quality Control
```bash
#!/bin/bash
# Generate multiple quality versions
PDF="$1"
NAME=$(basename "$PDF" .pdf)
# Preview quality
pm-media pdf2jpg --input "$PDF" --output "preview/$NAME/{PAGE}.jpg" --dpi 150
# Standard quality
pm-media pdf2jpg --input "$PDF" --output "standard/$NAME/{PAGE}.jpg" --dpi 300
# Print quality
pm-media pdf2jpg --input "$PDF" --output "print/$NAME/{PAGE}.png" --dpi 600 --format png
```
## TypeScript Definitions
```typescript
interface ConvertCommandConfig {
input: string;
output?: string;
dpi: number;
scale?: number;
format: 'png' | 'jpg';
startPage?: number;
endPage?: number;
}
interface PdfToImageOptions {
baseVariables: Record<string, any>;
outputPathTemplate: string;
dpi: number;
scale?: number;
format: ImageFormat;
startPage?: number;
endPage?: number;
logger?: Logger<any>;
}
type ImageFormat = 'png' | 'jpg';
```
## Contributing
For bug reports, feature requests, or contributions, please visit the project repository.
## License
This tool is part of the @polymech/media package. Please refer to the package license for usage terms.

View File

@ -0,0 +1,545 @@
# Resize CLI Documentation
The `pm-media resize` command allows you to resize images with precise control over dimensions, quality, and performance. This tool supports batch processing and offers extensive options for scaling, cropping, and format conversion.
## Table of Contents
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Resize Methods](#resize-methods)
- [Command Line Options](#command-line-options)
- [API Usage](#api-usage)
- [Examples](#examples)
- [Performance Options](#performance-options)
- [Troubleshooting](#troubleshooting)
## Installation
```bash
npm install @polymech/media
```
## Basic Usage
```bash
pm-media resize --src <input> --dst <output> [resize-options]
```
### Required Parameters
- `--src`: Source files (FILE|FOLDER|GLOB pattern)
### Optional Parameters
- `--dst`: Destination path (defaults to source location)
## Resize Methods
### 1. Percentage-based Resizing
Resize images by a percentage of their original size:
```bash
pm-media resize \
--src "photos/*.jpg" \
--dst "thumbnails/" \
--percent 50
```
### 2. Fixed Width/Height
Resize to specific dimensions:
```bash
pm-media resize \
--src "photos/*.jpg" \
--dst "resized/" \
--width 800 \
--height 600
```
### 3. Width-only or Height-only
Maintain aspect ratio with one dimension:
```bash
# Resize to 1920px width, auto height
pm-media resize \
--src "photos/*.jpg" \
--dst "web/" \
--width 1920
# Resize to 1080px height, auto width
pm-media resize \
--src "photos/*.jpg" \
--dst "web/" \
--height 1080
```
## Command Line Options
### Resize Dimensions
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--width` | number | - | Target width in pixels |
| `--height` | number | - | Target height in pixels |
| `--percent` | number | - | Resize by percentage (1-100) |
### Minimum Size Constraints
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--minWidth` | number | - | Don't resize if width below this value |
| `--minHeight` | number | - | Don't resize if height below this value |
| `--minSize` | number | - | Don't resize if file size below this (bytes) |
### Sharp-specific Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--fit` | string | 'cover' | How to fit: cover, contain, fill, inside, outside |
| `--position` | string | 'centre' | Position when using fit: top, bottom, left, right, etc |
| `--background` | string | 'white' | Background color for contain/letterbox |
| `--withoutEnlargement` | boolean | false | Don't enlarge smaller images |
| `--withoutReduction` | boolean | false | Don't reduce larger images |
| `--fastShrinkOnLoad` | boolean | true | Use JPEG/WebP shrink-on-load |
### Common Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--src` | string | required | Source files (FILE\|FOLDER\|GLOB) |
| `--dst` | string | - | Destination path |
| `--dry` | boolean | false | Preview mode (no files written) |
| `--verbose` | boolean | false | Show detailed processing info |
| `--debug` | boolean | false | Enable debug messages |
| `--logLevel` | string | "info" | Log level (warn\|info\|debug\|error) |
## API Usage
### Import the Library
```typescript
import {
resize,
resizeFile,
IResizeOptions
} from '@polymech/media';
```
### Single File Resize
```typescript
import { resizeFile } from '@polymech/media';
// Resize by percentage
await resizeFile(
'input.jpg',
'output.jpg',
() => {}, // onNode callback
{
percent: 50,
logLevel: 'info'
}
);
// Resize to specific dimensions
await resizeFile(
'input.jpg',
'thumbnail.jpg',
() => {},
{
width: 300,
height: 300,
fit: 'cover',
withoutEnlargement: true
}
);
```
### Batch Resize API
```typescript
import { resize } from '@polymech/media';
const options: IResizeOptions = {
src: 'photos/*.jpg',
dst: 'resized/',
width: 1920,
height: 1080,
fit: 'inside',
withoutEnlargement: true,
// ... other IOptions
};
const results = await resize(options);
```
### Advanced Resize Options
```typescript
const advancedOptions: IResizeOptions = {
src: 'raw/*.tiff',
dst: 'processed/',
width: 2048,
height: 1536,
fit: 'cover',
position: 'center',
background: { r: 255, g: 255, b: 255, alpha: 1 },
withoutEnlargement: true,
fastShrinkOnLoad: true,
kernel: 'lanczos3'
};
```
## Examples
### Example 1: Create Thumbnails
```bash
# Generate 150px square thumbnails
pm-media resize \
--src "gallery/*.jpg" \
--dst "thumbs/" \
--width 150 \
--height 150 \
--fit cover \
--withoutEnlargement
```
### Example 2: Web Optimization
```bash
# Optimize for web (max 1920px width)
pm-media resize \
--src "photos/*.jpg" \
--dst "web-optimized/" \
--width 1920 \
--minWidth 800 \
--fit inside \
--withoutEnlargement
```
### Example 3: Percentage-based Batch Resize
```bash
# Reduce all images to 75% of original size
pm-media resize \
--src "archive/**/*.{jpg,png}" \
--dst "compressed/" \
--percent 75
```
### Example 4: Social Media Formats
```bash
# Instagram square format (1080x1080)
pm-media resize \
--src "photos/*.jpg" \
--dst "instagram/" \
--width 1080 \
--height 1080 \
--fit cover \
--position center
# Twitter header (1500x500)
pm-media resize \
--src "headers/*.jpg" \
--dst "twitter/" \
--width 1500 \
--height 500 \
--fit cover
```
### Example 5: Preserve Small Images
```bash
# Don't resize images smaller than 500px width
pm-media resize \
--src "mixed/*.jpg" \
--dst "standardized/" \
--width 1200 \
--minWidth 500 \
--withoutEnlargement
```
### Example 6: File Size Based Resize
```bash
# Only resize files larger than 2MB
pm-media resize \
--src "large/*.jpg" \
--dst "optimized/" \
--percent 60 \
--minSize 2097152
```
### Example 7: Format Conversion with Resize
```bash
# Resize and convert to WebP
pm-media resize \
--src "photos/*.jpg" \
--dst "webp/{SRC_NAME}.webp" \
--width 1920 \
--fit inside
```
## Fit Options Explained
### `cover` (default)
- Crop to fill exact dimensions
- Maintains aspect ratio
- May crop parts of the image
```bash
pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit cover
```
### `contain`
- Letterbox to fit within dimensions
- Maintains aspect ratio
- No cropping, adds background
```bash
pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit contain --background white
```
### `fill`
- Stretch to exact dimensions
- Does not maintain aspect ratio
- No cropping
```bash
pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit fill
```
### `inside`
- Resize to fit within dimensions
- Maintains aspect ratio
- May result in smaller dimensions
```bash
pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit inside
```
### `outside`
- Resize to cover dimensions
- Maintains aspect ratio
- May result in larger dimensions
```bash
pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit outside
```
## Position Options
When using `fit: cover` or `fit: contain`, control crop/letterbox position:
- `center` (default)
- `top`, `bottom`, `left`, `right`
- `top left`, `top right`, `bottom left`, `bottom right`
- `north`, `south`, `east`, `west`
- `northeast`, `northwest`, `southeast`, `southwest`
```bash
pm-media resize \
--src portrait.jpg \
--dst cropped.jpg \
--width 800 \
--height 600 \
--fit cover \
--position "top center"
```
## File Format Support
### Supported Input Formats
- JPEG (.jpg, .jpeg)
- PNG (.png)
- WebP (.webp)
- TIFF (.tiff, .tif)
- AVIF (.avif)
- SVG (.svg) - rasterized
- GIF (.gif) - first frame
### Supported Output Formats
Output format determined by destination file extension:
- `.jpg`, `.jpeg` → JPEG
- `.png` → PNG
- `.webp` → WebP
- `.tiff`, `.tif` → TIFF
- `.avif` → AVIF
## Performance Tips
### 1. Fast Shrink-on-Load
```bash
# Use JPEG/WebP built-in scaling (faster for large reductions)
pm-media resize \
--src "huge/*.jpg" \
--dst "thumbnails/" \
--width 300 \
--fastShrinkOnLoad
```
### 2. Batch Processing
```bash
# Process multiple files efficiently
pm-media resize --src "batch/*.jpg" --dst "output/" --percent 50
```
### 3. Prevent Unnecessary Enlargement
```bash
# Don't enlarge small images (saves processing time)
pm-media resize \
--src "mixed/*.jpg" \
--dst "standardized/" \
--width 1920 \
--withoutEnlargement
```
### 4. Size-based Processing
```bash
# Only process large files
pm-media resize \
--src "photos/*.jpg" \
--dst "compressed/" \
--percent 70 \
--minSize 1048576 # 1MB minimum
```
## Troubleshooting
### Common Issues
#### Images appear distorted
```bash
# Maintain aspect ratio with 'inside' or 'cover'
pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit inside
```
#### Small images getting enlarged
```bash
# Prevent enlargement
pm-media resize --src input.jpg --dst output.jpg --width 1920 --withoutEnlargement
```
#### Poor quality on large reductions
```bash
# Use better kernel for quality
pm-media resize --src input.jpg --dst output.jpg --percent 25 --kernel lanczos3
```
#### Memory issues with large files
```bash
# Use fast shrink for initial reduction
pm-media resize --src huge.jpg --dst smaller.jpg --percent 50 --fastShrinkOnLoad
```
### Debug Mode
Enable detailed logging:
```bash
pm-media resize \
--src "input/*" \
--dst "output/" \
--width 800 \
--debug \
--verbose
```
### File Permissions
Ensure you have:
- Read access to source files
- Write access to destination directory
- Sufficient disk space for output files
## Advanced Usage
### Template Variables
Use template variables in destination paths:
```bash
# Use source filename in destination
pm-media resize \
--src "photos/*.jpg" \
--dst "resized/{SRC_NAME}_resized.jpg" \
--width 1200
```
Available variables:
- `{SRC_NAME}`: Source filename without extension
- `{SRC_EXT}`: Source file extension
- `{SRC_DIR}`: Source directory
### Integration Scripts
```bash
#!/bin/bash
# Multi-size generation script
SIZES=(300 600 1200 1920)
INPUT_DIR="$1"
OUTPUT_BASE="$2"
for size in "${SIZES[@]}"; do
pm-media resize \
--src "$INPUT_DIR/*.jpg" \
--dst "$OUTPUT_BASE/${size}px/" \
--width $size \
--withoutEnlargement \
--fit inside
done
```
### Conditional Processing
```bash
#!/bin/bash
# Only resize if source is larger than target
if [ -f "$1" ]; then
pm-media resize \
--src "$1" \
--dst "$2" \
--width 1920 \
--minWidth 1920 \
--withoutEnlargement
fi
```
## TypeScript Definitions
```typescript
interface IResizeOptionsSharp {
width?: number;
height?: number;
fit?: keyof sharp.FitEnum;
position?: number | string;
background?: sharp.Color;
kernel?: keyof sharp.KernelEnum;
withoutEnlargement?: boolean;
withoutReduction?: boolean;
fastShrinkOnLoad?: boolean;
}
interface IResizeOptions extends IOptions, IResizeOptionsSharp {
percent?: number;
minWidth?: number;
minHeight?: number;
minSize?: number;
}
```
## Contributing
For bug reports, feature requests, or contributions, please visit the project repository.
## License
This tool is part of the @polymech/media package. Please refer to the package license for usage terms.

View File

@ -0,0 +1,446 @@
# Watermark CLI Documentation
The `pm-media watermark` command allows you to add watermarks to images using either text or image overlays. This tool supports batch processing and offers extensive customization options for positioning, styling, and opacity.
## Table of Contents
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Text Watermarks](#text-watermarks)
- [Image Watermarks](#image-watermarks)
- [Command Line Options](#command-line-options)
- [API Usage](#api-usage)
- [Examples](#examples)
- [Troubleshooting](#troubleshooting)
## Installation
```bash
npm install @polymech/media
```
## Basic Usage
```bash
pm-media watermark --src <input> --dst <output> --watermarkType <type> [options]
```
### Required Parameters
- `--src`: Source files (FILE|FOLDER|GLOB pattern)
- `--watermarkType`: Type of watermark (`text` or `image`)
### Conditional Requirements
- For text watermarks: `--text` is required
- For image watermarks: `--logoPath` is required
## Text Watermarks
Add text overlays to your images with full typography control.
### Basic Text Watermark
```bash
pm-media watermark \
--src "photos/*.jpg" \
--dst "output/" \
--watermarkType text \
--text "© 2024 MyBrand"
```
### Advanced Text Styling
```bash
pm-media watermark \
--src "photos/*.jpg" \
--dst "output/" \
--watermarkType text \
--text "© 2024 MyBrand" \
--position bottom-right \
--fontSize 42 \
--color "#ffffff" \
--fontFamily "Arial" \
--strokeColor "#000000" \
--strokeWidth 3 \
--opacity 0.9 \
--margin 30
```
### Text Watermark Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--text` | string | required | Text to display as watermark |
| `--fontSize` | number | 48 | Font size in pixels |
| `--color` | string | "#ffffff" | Text color (hex format) |
| `--fontFamily` | string | "Arial" | Font family name |
| `--strokeColor` | string | "#000000" | Text outline color (hex format) |
| `--strokeWidth` | number | 2 | Text outline width in pixels |
## Image Watermarks
Add logo or image overlays with automatic scaling and positioning.
### Basic Image Watermark
```bash
pm-media watermark \
--src "photos/*.jpg" \
--dst "output/" \
--watermarkType image \
--logoPath "logo.png"
```
### Advanced Image Positioning
```bash
pm-media watermark \
--src "photos/*.jpg" \
--dst "output/" \
--watermarkType image \
--logoPath "watermark.png" \
--position top-left \
--sizePct 0.15 \
--opacity 0.7 \
--margin 20
```
### Image Watermark Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--logoPath` | string | required | Path to logo/watermark image file |
| `--sizePct` | number | 0.2 | Size as percentage of base image width (0-1) |
## Command Line Options
### Common Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--src` | string | required | Source files (FILE\|FOLDER\|GLOB) |
| `--dst` | string | - | Destination path |
| `--watermarkType` | choice | required | "text" or "image" |
| `--position` | choice | "bottom-right" | Watermark position |
| `--margin` | number | 24 | Margin from edges in pixels |
| `--opacity` | number | 0.85 | Opacity level (0-1) |
### Position Options
- `top-left`: Upper left corner
- `top-right`: Upper right corner
- `bottom-left`: Lower left corner
- `bottom-right`: Lower right corner (default)
- `center`: Center of image
### Utility Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `--dry` | boolean | false | Preview mode (no files written) |
| `--verbose` | boolean | false | Show detailed processing info |
| `--debug` | boolean | false | Enable debug messages |
| `--logLevel` | string | "info" | Log level (warn\|info\|debug\|error) |
## API Usage
### Import the Library
```typescript
import {
watermark,
addTextWatermark,
addLogoWatermark,
WatermarkOptions,
TextWatermarkOptions,
LogoWatermarkOptions
} from '@polymech/media';
```
### Text Watermark API
```typescript
import { addTextWatermark } from '@polymech/media';
await addTextWatermark(
'input.jpg',
'© 2024 MyBrand',
'output.jpg',
{
position: 'bottom-right',
fontSize: 48,
color: '#ffffff',
opacity: 0.9,
margin: 24,
fontFamily: 'Arial',
strokeColor: '#000000',
strokeWidth: 2
}
);
```
### Image Watermark API
```typescript
import { addLogoWatermark } from '@polymech/media';
await addLogoWatermark(
'input.jpg',
'logo.png',
'output.jpg',
{
position: 'bottom-right',
sizePct: 0.2,
opacity: 0.85,
margin: 24,
blend: 'over'
}
);
```
### Batch Processing API
```typescript
import { watermark } from '@polymech/media';
const options: WatermarkOptions = {
src: 'photos/*.jpg',
dst: 'output/',
watermarkType: 'text',
text: '© 2024 MyBrand',
textOptions: {
position: 'bottom-right',
fontSize: 48,
color: '#ffffff',
opacity: 0.9
},
// ... other IOptions
};
await watermark(options);
```
## Examples
### Example 1: Brand Photos with Logo
```bash
# Add company logo to product photos
pm-media watermark \
--src "products/*.jpg" \
--dst "branded/" \
--watermarkType image \
--logoPath "brand-logo.png" \
--position bottom-right \
--sizePct 0.12 \
--opacity 0.8 \
--margin 30
```
### Example 2: Copyright Text on Multiple Formats
```bash
# Add copyright to various image formats
pm-media watermark \
--src "gallery/*.{jpg,png,webp}" \
--dst "copyrighted/" \
--watermarkType text \
--text "© 2024 Photography Studio" \
--position bottom-left \
--fontSize 28 \
--color "#ffffff" \
--strokeColor "#000000" \
--strokeWidth 1 \
--opacity 0.85
```
### Example 3: Centered Watermark
```bash
# Large central watermark for draft images
pm-media watermark \
--src "drafts/*.jpg" \
--dst "review/" \
--watermarkType text \
--text "DRAFT - NOT FOR PUBLICATION" \
--position center \
--fontSize 72 \
--color "#ff0000" \
--opacity 0.3
```
### Example 4: Batch Processing with Dry Run
```bash
# Preview changes before applying
pm-media watermark \
--src "archive/**/*.jpg" \
--dst "processed/" \
--watermarkType image \
--logoPath "watermark.png" \
--dry \
--verbose
```
### Example 5: Custom Logo Positioning
```bash
# Small logo in top-right corner
pm-media watermark \
--src "social-media/*.png" \
--dst "branded/" \
--watermarkType image \
--logoPath "social-logo.png" \
--position top-right \
--sizePct 0.08 \
--margin 15 \
--opacity 0.9
```
## File Format Support
### Supported Input Formats
- JPEG (.jpg, .jpeg)
- PNG (.png)
- WebP (.webp)
- TIFF (.tiff, .tif)
### Supported Output Formats
Output format is automatically determined by the destination file extension or input format.
## Performance Tips
1. **Batch Processing**: Process multiple files in one command for better performance
2. **Concurrency**: The tool processes files with controlled concurrency (default: 1)
3. **Logo Optimization**: Use PNG logos with transparency for best results
4. **Size Optimization**: Keep logo files reasonably sized to improve processing speed
## Troubleshooting
### Common Issues
#### "Logo file not found"
```bash
# Ensure the logo path is correct and file exists
ls -la path/to/logo.png
```
#### "Unable to open for write"
```bash
# Ensure output directory exists
mkdir -p output/directory
```
#### Text appears blurry
- Increase `--fontSize` for better clarity
- Adjust `--strokeWidth` for better contrast
- Use appropriate `--color` contrast against background
#### Logo appears too large/small
- Adjust `--sizePct` (0.1 = 10% of image width)
- Consider image dimensions when setting size
### Debug Mode
Enable detailed logging to troubleshoot issues:
```bash
pm-media watermark \
--src "input/*" \
--dst "output/" \
--watermarkType text \
--text "Debug Test" \
--debug \
--verbose
```
### File Permissions
Ensure you have:
- Read access to source files
- Write access to destination directory
- Execute permissions on the tool
## Advanced Usage
### Using Environment Variables
```bash
export WATERMARK_TEXT="© 2024 MyCompany"
export WATERMARK_LOGO="./assets/logo.png"
pm-media watermark \
--src "batch/*.jpg" \
--dst "output/" \
--watermarkType text \
--text "$WATERMARK_TEXT"
```
### Integration with Scripts
```bash
#!/bin/bash
# Automated watermarking script
INPUT_DIR="$1"
OUTPUT_DIR="$2"
WATERMARK_TYPE="$3"
if [ "$WATERMARK_TYPE" = "logo" ]; then
pm-media watermark \
--src "$INPUT_DIR/*.jpg" \
--dst "$OUTPUT_DIR/" \
--watermarkType image \
--logoPath "./branding/logo.png" \
--position bottom-right
else
pm-media watermark \
--src "$INPUT_DIR/*.jpg" \
--dst "$OUTPUT_DIR/" \
--watermarkType text \
--text "© $(date +%Y) MyBrand" \
--position bottom-right
fi
```
## TypeScript Definitions
```typescript
type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center";
interface LogoWatermarkOptions {
position?: Corner;
margin?: number;
sizePct?: number;
opacity?: number;
blend?: OverlayOptions["blend"];
}
interface TextWatermarkOptions {
position?: Corner;
margin?: number;
fontSize?: number;
opacity?: number;
color?: string;
fontFamily?: string;
strokeColor?: string;
strokeWidth?: number;
}
interface WatermarkOptions extends IOptions {
watermarkType: 'text' | 'image';
text?: string;
textOptions?: TextWatermarkOptions;
logoPath?: string;
imageOptions?: LogoWatermarkOptions;
}
```
## Contributing
For bug reports, feature requests, or contributions, please visit the project repository.
## License
This tool is part of the @polymech/media package. Please refer to the package license for usage terms.

View File

@ -1 +0,0 @@
mock-jpg-data

View File

@ -1 +0,0 @@
mock-jpg-data

View File

@ -1 +0,0 @@
mock-jpg-data

View File

@ -1 +0,0 @@
mock-png-data

View File

@ -1 +0,0 @@
mock-png-data

View File

@ -1 +0,0 @@
mock-png-data

View File

@ -1 +0,0 @@
mock-png-data

View File

@ -1 +0,0 @@
mock-png-data

View File

@ -20,11 +20,11 @@
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fluent-ffmpeg": "^2.1.3", "fluent-ffmpeg": "^2.1.3",
"glob": "^11.0.0", "glob": "^11.0.0",
"glob-base": "^0.3.0",
"js-beautify": "^1.14.6", "js-beautify": "^1.14.6",
"mupdf": "^1.3.3", "mupdf": "^1.3.3",
"novita-sdk": "^1.0.37", "novita-sdk": "^1.0.37",
"p-map": "^7.0.3", "p-map": "^7.0.3",
"replicate": "^1.0.1",
"sharp": "^0.34.2", "sharp": "^0.34.2",
"tslog": "^4.9.3", "tslog": "^4.9.3",
"typescript": "^5.8.3", "typescript": "^5.8.3",
@ -32,7 +32,7 @@
"zod": "^3.25.74" "zod": "^3.25.74"
}, },
"bin": { "bin": {
"pm-media": "main.js" "pm-media": "dist-in/main.js"
}, },
"devDependencies": { "devDependencies": {
"@types/glob": "^8.1.0", "@types/glob": "^8.1.0",
@ -1691,6 +1691,19 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
}, },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"license": "MIT",
"optional": true,
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
@ -1751,6 +1764,27 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"optional": true
},
"node_modules/bluebird": { "node_modules/bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -1768,6 +1802,31 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"optional": true,
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/cac": { "node_modules/cac": {
"version": "6.7.14", "version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
@ -2051,6 +2110,26 @@
"@types/estree": "^1.0.0" "@types/estree": "^1.0.0"
} }
}, },
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=6"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/expect-type": { "node_modules/expect-type": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
@ -2237,49 +2316,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/glob-base": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
"integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==",
"license": "MIT",
"dependencies": {
"glob-parent": "^2.0.0",
"is-glob": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/glob-base/node_modules/glob-parent": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
"integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==",
"license": "ISC",
"dependencies": {
"is-glob": "^2.0.0"
}
},
"node_modules/glob-base/node_modules/is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/glob-base/node_modules/is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==",
"license": "MIT",
"dependencies": {
"is-extglob": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/glob-parent": { "node_modules/glob-parent": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@ -2292,6 +2328,27 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause",
"optional": true
},
"node_modules/inflight": { "node_modules/inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -2722,6 +2779,16 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/proto-list": { "node_modules/proto-list": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -2757,6 +2824,38 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/readable-stream": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
"license": "MIT",
"optional": true,
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/replicate": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/replicate/-/replicate-1.0.1.tgz",
"integrity": "sha512-EY+rK1YR5bKHcM9pd6WyaIbv6m2aRIvHfHDh51j/LahlHTLKemTYXF6ptif2sLa+YospupAsIoxw8Ndt5nI3vg==",
"license": "Apache-2.0",
"engines": {
"git": ">=2.11.0",
"node": ">=18.0.0",
"npm": ">=7.19.0",
"yarn": ">=1.7.0"
},
"optionalDependencies": {
"readable-stream": ">=4.0.0"
}
},
"node_modules/reusify": { "node_modules/reusify": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@ -2830,6 +2929,27 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"optional": true
},
"node_modules/semver": { "node_modules/semver": {
"version": "5.7.2", "version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
@ -2969,6 +3089,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"optional": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
@ -4323,6 +4453,15 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
}, },
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"optional": true,
"requires": {
"event-target-shim": "^5.0.0"
}
},
"ansi-regex": { "ansi-regex": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
@ -4364,6 +4503,12 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"optional": true
},
"bluebird": { "bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -4377,6 +4522,16 @@
"fill-range": "^7.1.1" "fill-range": "^7.1.1"
} }
}, },
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"optional": true,
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"cac": { "cac": {
"version": "6.7.14", "version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
@ -4586,6 +4741,18 @@
"@types/estree": "^1.0.0" "@types/estree": "^1.0.0"
} }
}, },
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"optional": true
},
"events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"optional": true
},
"expect-type": { "expect-type": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
@ -4695,38 +4862,6 @@
"path-scurry": "^2.0.0" "path-scurry": "^2.0.0"
} }
}, },
"glob-base": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
"integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==",
"requires": {
"glob-parent": "^2.0.0",
"is-glob": "^2.0.0"
},
"dependencies": {
"glob-parent": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
"integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==",
"requires": {
"is-glob": "^2.0.0"
}
},
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww=="
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==",
"requires": {
"is-extglob": "^1.0.0"
}
}
}
},
"glob-parent": { "glob-parent": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@ -4735,6 +4870,12 @@
"is-glob": "^4.0.1" "is-glob": "^4.0.1"
} }
}, },
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"optional": true
},
"inflight": { "inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -5020,6 +5161,12 @@
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
} }
}, },
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"optional": true
},
"proto-list": { "proto-list": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -5040,6 +5187,27 @@
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
}, },
"readable-stream": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
"optional": true,
"requires": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
}
},
"replicate": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/replicate/-/replicate-1.0.1.tgz",
"integrity": "sha512-EY+rK1YR5bKHcM9pd6WyaIbv6m2aRIvHfHDh51j/LahlHTLKemTYXF6ptif2sLa+YospupAsIoxw8Ndt5nI3vg==",
"requires": {
"readable-stream": ">=4.0.0"
}
},
"reusify": { "reusify": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@ -5083,6 +5251,12 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"optional": true
},
"semver": { "semver": {
"version": "5.7.2", "version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
@ -5181,6 +5355,15 @@
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
"dev": true "dev": true
}, },
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"optional": true,
"requires": {
"safe-buffer": "~5.2.0"
}
},
"string-width": { "string-width": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",

View File

@ -6,7 +6,7 @@
"access": "public" "access": "public"
}, },
"bin": { "bin": {
"pm-media": "main.js" "pm-media": "dist-in/main.js"
}, },
"type": "module", "type": "module",
"exports": { "exports": {
@ -28,6 +28,7 @@
"mupdf": "^1.3.3", "mupdf": "^1.3.3",
"novita-sdk": "^1.0.37", "novita-sdk": "^1.0.37",
"p-map": "^7.0.3", "p-map": "^7.0.3",
"replicate": "^1.0.1",
"sharp": "^0.34.2", "sharp": "^0.34.2",
"tslog": "^4.9.3", "tslog": "^4.9.3",
"typescript": "^5.8.3", "typescript": "^5.8.3",

View File

@ -0,0 +1,102 @@
import * as CLI from 'yargs'
import { CONFIG_DEFAULT } from '@polymech/commons'
import { logger } from '../index.js'
import { cli } from '../cli.js'
import {
sanitize,
defaults
} from '../_cli.js'
import {
backgroundRemove,
BackgroundRemoveOptions
} from '../lib/media/images/background-remove.js'
export const defaultOptions = (yargs: CLI.Argv) => {
return yargs.option('src', {
describe: 'FILE|FOLDER|GLOB',
demandOption: true
}).option('dst', {
describe: 'FILE|FOLDER|GLOB'
}).option('debug', {
default: false,
describe: 'Enable internal debug messages',
type: 'boolean'
}).option('alt', {
default: false,
describe: 'Use alternate tokenizer, & instead of $',
type: 'boolean'
}).option('dry', {
default: false,
describe: 'Run without conversion',
type: 'boolean'
}).option('verbose', {
default: false,
describe: 'Show internal messages',
type: 'boolean'
}).option('logLevel', {
describe: 'Log level : warn, info, debug, error',
type: 'string',
default: 'info'
}).option('apiKey', {
describe: 'Replicate API key (or set REPLICATE_API_TOKEN env var)',
type: 'string'
}).option('model', {
describe: 'Background removal model to use',
choices: ['u2net', 'u2netp', 'u2net_human_seg', 'u2net_cloth_seg', 'silueta'],
default: 'u2net'
}).option('alphaMattting', {
describe: 'Enable alpha matting for better edge refinement',
type: 'boolean',
default: false
}).option('alphaMattingForegroundThreshold', {
describe: 'Alpha matting foreground threshold',
type: 'number',
default: 270
}).option('alphaMattingBackgroundThreshold', {
describe: 'Alpha matting background threshold',
type: 'number',
default: 10
}).option('alphaMattingErodeSize', {
describe: 'Alpha matting erode size',
type: 'number',
default: 10
})
}
export const command = 'background:remove';
export const desc = 'Remove background from images using AI';
export const builder = defaultOptions;
export async function handler(argv: CLI.Arguments) {
defaults()
const options = sanitize(argv) as BackgroundRemoveOptions
logger.settings.minLevel = options.logLevel as any
const config: any = CONFIG_DEFAULT()
// Get API key from argument or environment variable
options.apiKey = options.apiKey || process.env.REPLICATE_API_TOKEN || config?.replicate?.key;
if (!options.apiKey) {
logger.error('Replicate API key is required. Provide it via --apiKey argument or set REPLICATE_API_TOKEN environment variable');
logger.info('Get your API key at: https://replicate.com/account/api-tokens');
process.exit(1);
}
// Map CLI arguments to library options
options.model = argv.model as string;
options.alpha_matting = argv.alphaMattting as boolean;
options.alpha_matting_foreground_threshold = argv.alphaMattingForegroundThreshold as number;
options.alpha_matting_background_threshold = argv.alphaMattingBackgroundThreshold as number;
options.alpha_matting_erode_size = argv.alphaMattingErodeSize as number;
logger.info("Removing background with options:", {
model: options.model,
alpha_matting: options.alpha_matting,
files: options.srcInfo?.FILES?.length || 0
});
await backgroundRemove(options);
}
cli.command(command, desc, builder, handler)

View File

@ -64,14 +64,16 @@ export const defaultOptions = (yargs: CLI.Argv) => {
}) })
} }
let options = (yargs: CLI.Argv) => defaultOptions(yargs) export const command = 'resize';
export const desc = 'Resizes files';
export const builder = defaultOptions;
export const register = (cli: CLI.Argv) => { export async function handler(argv: CLI.Arguments) {
return cli.command('resize', 'Resizes files', options, async (argv: CLI.Arguments) => { defaults()
defaults() const options = sanitize(argv) as IOptions
const options = sanitize(argv) as IOptions logger.settings.minLevel = options.logLevel as any
logger.settings.minLevel = options.logLevel as any logger.info("options " + argv.dst, options)
logger.info("options " + argv.dst, options) await resize(options)
await resize(options)
})
} }
cli.command(command, desc, builder, handler)

View File

@ -0,0 +1,83 @@
import { CONFIG_DEFAULT } from '@polymech/commons'
import * as CLI from 'yargs'
import { logger } from '../index.js'
import {
watermark
} from '../lib/media/images/watermark.js'
import {
sanitize,
defaults
} from '../_cli.js'
import {
IOptions
} from '../types.js'
export const defaultOptions = (yargs: CLI.Argv) => {
return yargs.option('src', {
describe: 'FILE|FOLDER|GLOB',
demandOption: true
}).option('dst', {
describe: 'FILE|FOLDER|GLOB'
}).option('debug', {
default: false,
describe: 'Enable internal debug messages',
type: 'boolean'
}).option('alt', {
default: false,
describe: 'Use alternate tokenizer, & instead of $',
type: 'boolean'
}).option('dry', {
default: false,
describe: 'Run without conversion',
type: 'boolean'
}).option('verbose', {
default: false,
describe: 'Show internal messages',
type: 'boolean'
}).option('percent', {
default: false,
describe: 'Resize image with percent',
type: 'number'
}).option('width', {
default: false,
describe: 'Resize image with',
type: 'number'
}).option('height', {
default: false,
describe: 'Resize image height',
type: 'number'
}).option('minHeight', {
describe: 'Resize image minimum height',
type: 'number'
}).option('minWidth', {
describe: 'Resize image minimum width',
type: 'number'
}).option('minSize', {
describe: 'Resize image size (bytes)',
type: 'number'
}).option('percent', {
describe: 'Resize image in percent (width)',
type: 'number'
}).option('key', {
describe: 'API Key',
type: 'string'
})
}
const options = (yargs: CLI.Argv) => defaultOptions(yargs)
export const register = (cli: CLI.Argv) => {
return cli.command('watermark', 'Remove watermark : FILE|GLOB', options, async (argv: CLI.Arguments) => {
defaults()
const options = sanitize(argv) as IOptions
const config: any = CONFIG_DEFAULT()
if (!config.novita) {
logger.error("Novita key not found");
return
}
options.debug && logger.info("Watermark Options " + argv.dst, options)
return watermark({ ...options, key: config.novita.key })
})
}

View File

@ -1,83 +1,141 @@
import { CONFIG_DEFAULT } from '@polymech/commons'
import * as CLI from 'yargs' import * as CLI from 'yargs'
import { logger } from '../index.js' import { logger } from '../index.js'
import { cli } from '../cli.js'
import { import {
watermark sanitize,
} from '../lib/media/images/watermark.js' defaults
import {
sanitize,
defaults
} from '../_cli.js' } from '../_cli.js'
import { import {
IOptions IOptions
} from '../types.js' } from '../types.js'
import {
watermark,
WatermarkOptions
} from '../lib/media/images/watermark.js'
export const defaultOptions = (yargs: CLI.Argv) => { export const defaultOptions = (yargs: CLI.Argv) => {
return yargs.option('src', { return yargs.option('src', {
describe: 'FILE|FOLDER|GLOB', describe: 'FILE|FOLDER|GLOB',
demandOption: true demandOption: true
}).option('dst', { }).option('dst', {
describe: 'FILE|FOLDER|GLOB' describe: 'FILE|FOLDER|GLOB'
}).option('debug', { }).option('debug', {
default: false, default: false,
describe: 'Enable internal debug messages', describe: 'Enable internal debug messages',
type: 'boolean' type: 'boolean'
}).option('alt', { }).option('alt', {
default: false, default: false,
describe: 'Use alternate tokenizer, & instead of $', describe: 'Use alternate tokenizer, & instead of $',
type: 'boolean' type: 'boolean'
}).option('dry', { }).option('dry', {
default: false, default: false,
describe: 'Run without conversion', describe: 'Run without conversion',
type: 'boolean' type: 'boolean'
}).option('verbose', { }).option('verbose', {
default: false, default: false,
describe: 'Show internal messages', describe: 'Show internal messages',
type: 'boolean' type: 'boolean'
}).option('percent', { }).option('logLevel', {
default: false, describe: 'Log level : warn, info, debug, error',
describe: 'Resize image with percent', type: 'string',
type: 'number' default: 'info'
}).option('width', { }).option('watermarkType', {
default: false, describe: 'Type of watermark: text or image',
describe: 'Resize image with', choices: ['text', 'image'],
type: 'number' demandOption: true
}).option('height', { }).option('text', {
default: false, describe: 'Text to use for text watermark',
describe: 'Resize image height', type: 'string'
type: 'number' }).option('logoPath', {
}).option('minHeight', { describe: 'Path to logo image for image watermark',
describe: 'Resize image minimum height', type: 'string'
type: 'number' }).option('position', {
}).option('minWidth', { describe: 'Position of watermark',
describe: 'Resize image minimum width', choices: ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'],
type: 'number' default: 'bottom-right'
}).option('minSize', { }).option('margin', {
describe: 'Resize image size (bytes)', describe: 'Margin from edges in pixels',
type: 'number' type: 'number',
}).option('percent', { default: 24
describe: 'Resize image in percent (width)', }).option('opacity', {
type: 'number' describe: 'Opacity of watermark (0-1)',
}).option('key', { type: 'number',
describe: 'API Key', default: 0.85
type: 'string' }).option('sizePct', {
}) describe: 'Size of image watermark as percentage of base image width (0-1)',
type: 'number',
default: 0.2
}).option('fontSize', {
describe: 'Font size for text watermark in pixels',
type: 'number',
default: 48
}).option('color', {
describe: 'Text color (hex format, e.g., #ffffff)',
type: 'string',
default: '#ffffff'
}).option('fontFamily', {
describe: 'Font family for text watermark',
type: 'string',
default: 'Arial'
}).option('strokeColor', {
describe: 'Text stroke color (hex format, e.g., #000000)',
type: 'string',
default: '#000000'
}).option('strokeWidth', {
describe: 'Text stroke width in pixels',
type: 'number',
default: 2
})
} }
const options = (yargs: CLI.Argv) => defaultOptions(yargs)
export const register = (cli: CLI.Argv) => {
return cli.command('watermark', 'Remove watermark : FILE|GLOB', options, async (argv: CLI.Arguments) => { export const command = 'watermark';
export const desc = 'Adds watermarks to images';
export const builder = defaultOptions;
export async function handler(argv: CLI.Arguments) {
defaults() defaults()
const options = sanitize(argv) as IOptions const options = sanitize(argv) as WatermarkOptions
const config: any = CONFIG_DEFAULT() logger.settings.minLevel = options.logLevel as any
if (!config.novita) {
logger.error("Novita key not found"); // Validate required options based on watermark type
return if (options.watermarkType === 'text' && !options.text) {
logger.error('Text is required when using text watermark type')
process.exit(1)
} }
options.debug && logger.info("Watermark Options " + argv.dst, options)
return watermark({ ...options, key: config.novita.key }) if (options.watermarkType === 'image' && !options.logoPath) {
}) logger.error('Logo path is required when using image watermark type')
process.exit(1)
}
// Set up watermark options based on type
if (options.watermarkType === 'text') {
options.textOptions = {
position: argv.position as any,
margin: argv.margin as number,
fontSize: argv.fontSize as number,
opacity: argv.opacity as number,
color: argv.color as string,
fontFamily: argv.fontFamily as string,
strokeColor: argv.strokeColor as string,
strokeWidth: argv.strokeWidth as number,
}
} else if (options.watermarkType === 'image') {
options.imageOptions = {
position: argv.position as any,
margin: argv.margin as number,
sizePct: argv.sizePct as number,
opacity: argv.opacity as number,
blend: 'over'
}
}
logger.info("Adding watermark with options:", options)
await watermark(options)
} }
cli.command(command, desc, builder, handler)

View File

@ -0,0 +1,146 @@
import * as fs from 'fs';
import * as path from 'path';
import pMap from 'p-map';
import { logger } from '../../../index.js';
import { IOptions } from '../../../types.js';
import { targets } from '../../index.js';
import { sync as mkdir } from '@polymech/fs/dir';
// https://replicate.com/cjwbw/rembg
export interface BackgroundRemoveOptions extends IOptions {
apiKey?: string;
model?: string;
alpha_matting?: boolean;
alpha_matting_foreground_threshold?: number;
alpha_matting_background_threshold?: number;
alpha_matting_erode_size?: number;
}
// Base64 encode image file
function encodeImageToBase64(filePath: string): string {
const imageBuffer = fs.readFileSync(filePath);
return `data:image/${path.extname(filePath).slice(1)};base64,${imageBuffer.toString('base64')}`;
}
// Save FileOutput from Replicate API to file
async function saveReplicateOutput(output: any, outputPath: string): Promise<void> {
// Ensure output directory exists
mkdir(path.dirname(outputPath));
// Handle FileOutput from Replicate API
if (output && typeof output.url === 'function') {
// This is a FileOutput object from Replicate
logger.debug(`Saving FileOutput to: ${outputPath}`);
await fs.promises.writeFile(outputPath, output);
} else if (typeof output === 'string' && output.startsWith('http')) {
// This is a URL, fetch and save the image
logger.debug(`Downloading image from URL: ${output}`);
const response = await fetch(output);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
fs.writeFileSync(outputPath, buffer);
} else if (typeof output === 'string') {
// This might be base64 data
let base64String = output.replace(/^data:image\/[a-z]+;base64,/, '');
const imageBuffer = Buffer.from(base64String, 'base64');
fs.writeFileSync(outputPath, imageBuffer);
} else if (Buffer.isBuffer(output)) {
// Already a buffer
fs.writeFileSync(outputPath, output);
} else {
throw new Error(`Unexpected output format: ${typeof output}, ${JSON.stringify(output).substring(0, 200)}`);
}
}
export async function removeBackgroundFile(
inputPath: string,
outputPath: string,
options: BackgroundRemoveOptions
): Promise<void> {
try {
if (!options.apiKey) {
throw new Error('Replicate API key is required. Set it via --apiKey or REPLICATE_API_TOKEN environment variable');
}
// Import Replicate dynamically to handle potential installation issues
let Replicate;
try {
const replicateModule = await import('replicate');
Replicate = replicateModule.default;
} catch (error) {
throw new Error('Replicate package not found. Please install it with: npm install replicate');
}
const replicate = new Replicate({
auth: options.apiKey,
});
logger.debug(`Removing background from ${inputPath}`);
// Encode input image to base64 data URL
const inputImageBase64 = encodeImageToBase64(inputPath);
// Prepare input for the model
const input = {
image: inputImageBase64,
model: options.model || 'u2net',
alpha_matting: options.alpha_matting || false,
alpha_matting_foreground_threshold: options.alpha_matting_foreground_threshold || 270,
alpha_matting_background_threshold: options.alpha_matting_background_threshold || 10,
alpha_matting_erode_size: options.alpha_matting_erode_size || 10,
};
// Run the background removal model
const output = await replicate.run("cjwbw/rembg:fb8af171cfa1616ddcf1242c093f9c46bcada5ad4cf6f2fbe8b81b330ec5c003", {
input
});
logger.debug(`API response type: ${typeof output}`);
logger.debug(`API response has url method: ${typeof output?.url}`);
if (output && typeof output.url === 'function') {
logger.debug(`Output URL: ${output.url()}`);
}
// Save the result
await saveReplicateOutput(output, outputPath);
logger.info(`Background removed: ${inputPath}${outputPath}`);
} catch (error) {
logger.error(`Failed to remove background from ${inputPath}:`, error.message);
throw error;
}
}
const _backgroundRemove = async (
file: string,
targets: string[],
onNode: (data: any) => void = () => {},
options: BackgroundRemoveOptions
) => {
return pMap(targets, async (target) => {
options.verbose && logger.debug(`Removing background ${file} to ${target}`);
if (options.dry) {
logger.info(`[DRY RUN] Would remove background: ${file}${target}`);
return;
}
return await removeBackgroundFile(file, target, options);
}, { concurrency: 1 });
};
export const backgroundRemove = async (options: BackgroundRemoveOptions) => {
// reporting, stub
let reports: any = [];
const onNode = (data: any) => reports.push(data);
if (options.srcInfo) {
options.verbose && logger.info(`Removing background from ${options.srcInfo.FILES.length} files`);
return await pMap(options.srcInfo.FILES, async (f) => {
const outputs = targets(f, options);
options.verbose && logger.info(`Removing background ${f} to`, outputs);
return _backgroundRemove(f, outputs, onNode, options);
}, { concurrency: 1 });
} else {
options.debug && logger.error(`Invalid source info`);
}
};

View File

@ -1,65 +1,247 @@
// https://novita.ai/playground#remove-watermark import sharp, { OverlayOptions } from "sharp";
import * as fs from 'fs' import * as path from 'path';
import * as path from 'path' import * as fs from 'fs';
import { CONFIG_DEFAULT } from '@polymech/commons' import { glob } from 'glob';
import BPromise from 'bluebird' import pMap from 'p-map';
import { async as write } from "@polymech/fs/write" import { logger } from '../../../index.js';
import { import { IOptions } from '../../../types.js';
logger import { targets } from '../../index.js';
} from '../../../index.js' import { sync as mkdir } from '@polymech/fs/dir'
import { type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center";
IOptions,
IResizeOptions
} from '../../../types.js'
import { export interface LogoWatermarkOptions {
imageToBase64, position?: Corner;
base64ToBuffer margin?: number; // px
} from './lib.js' sizePct?: number; // of base image width (01)
opacity?: number; // 01
blend?: OverlayOptions["blend"];
}
export interface TextWatermarkOptions {
position?: Corner;
margin?: number; // px
fontSize?: number; // px
opacity?: number; // 01
color?: string; // hex color like '#ffffff'
fontFamily?: string; // font family
strokeColor?: string; // outline color
strokeWidth?: number; // outline width
}
import { NovitaSDK } from "novita-sdk" export interface WatermarkOptions extends IOptions {
import { targets, targetsNext } from '../../index.js' // Watermark type
watermarkType: 'text' | 'image';
// Text watermark options
text?: string;
textOptions?: TextWatermarkOptions;
// Image watermark options
logoPath?: string;
imageOptions?: LogoWatermarkOptions;
}
const removeWatermark = async (file, target, onNode: (data: any) => void = () => { }, options: IResizeOptions) => { export async function addLogoWatermark(
const novitaClient = new NovitaSDK(options.key) inputPath: string,
const params = { logoPath: string,
image_file: await imageToBase64(file) outputPath: string,
//"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD", opts: LogoWatermarkOptions = {}
} ): Promise<void> {
try { const {
const wMark = await novitaClient.removeWatermark(params) position = "bottom-right",
logger.info(`Watermark removed: ${file} to ${target}`) margin = 24,
write(target,base64ToBuffer(wMark.image_file)) sizePct = 0.2,
} catch (error) { opacity = 0.85,
logger.error(`Failed to remove watermark: ${error.msg}`) blend = "over",
} = opts;
const base = sharp(inputPath);
const { width: W = 0, height: H = 0 } = await base.metadata();
if (!W || !H) throw new Error("Could not read base image size");
// Resize logo to sizePct of base width
const logoWidth = Math.max(1, Math.round(W * sizePct));
const logoBuf = await sharp(logoPath).resize({ width: logoWidth }).toBuffer();
const { width: w = 0, height: h = 0 } = await sharp(logoBuf).metadata();
// Compute pixel placement
const pos = (() => {
switch (position) {
case "top-left": return { left: margin, top: margin };
case "top-right": return { left: W - w - margin, top: margin };
case "bottom-left": return { left: margin, top: H - h - margin };
case "center": return { left: Math.round((W - w) / 2), top: Math.round((H - h) / 2) };
case "bottom-right":
default: return { left: W - w - margin, top: H - h - margin };
} }
})();
// Ensure output directory exists
mkdir(path.dirname(outputPath));
await base
.composite([{
input: logoBuf,
left: pos.left,
top: pos.top,
blend,
...(opacity < 1 ? { blend: 'multiply' } : {}),
}])
.toFile(outputPath);
} }
const _watermark = async (file, targets: string[], onNode: (data: any) => void = () => { }, options: IOptions) => { export async function addTextWatermark(
return BPromise.resolve(targets).map((target) => { inputPath: string,
options.verbose && logger.debug(`Removing Watermark ${file} to ${target}`) text: string,
if (options.dry) { outputPath: string,
return BPromise.resolve() opts: TextWatermarkOptions = {}
} ): Promise<void> {
return removeWatermark(file, target, onNode, options); const {
}, { concurrency: 1 }) position = "bottom-right",
margin = 24,
fontSize = 48,
opacity = 0.8,
color = '#ffffff',
fontFamily = 'Arial',
strokeColor = '#000000',
strokeWidth = 2,
} = opts;
const base = sharp(inputPath);
const { width: W = 0, height: H = 0 } = await base.metadata();
if (!W || !H) throw new Error("Could not read base image size");
// Create SVG text element
const svgText = `
<svg width="${W}" height="${H}" xmlns="http://www.w3.org/2000/svg">
<text
x="${getTextX(position, W, margin)}"
y="${getTextY(position, H, margin, fontSize)}"
font-family="${fontFamily}"
font-size="${fontSize}"
fill="${color}"
opacity="${opacity}"
stroke="${strokeColor}"
stroke-width="${strokeWidth}"
text-anchor="${getTextAnchor(position)}"
dominant-baseline="${getTextBaseline(position)}"
>
${text}
</text>
</svg>
`;
const textBuffer = Buffer.from(svgText);
// Ensure output directory exists
mkdir(path.dirname(outputPath));
await base
.composite([{
input: textBuffer,
left: 0,
top: 0,
blend: 'over',
}])
.toFile(outputPath);
} }
export const watermark = async (options: IOptions) => { function getTextX(position: Corner, width: number, margin: number): number {
switch (position) {
// reporting, stub case "top-left":
let reports: any = [] case "bottom-left":
const onNode = (data: any) => reports.push(data) return margin;
if (options.srcInfo) { case "top-right":
options.verbose && logger.info(`Convert ${options.srcInfo.FILES.length} files`) case "bottom-right":
return await BPromise.resolve(options.srcInfo.FILES).map((f) => { return width - margin;
const outputs = targets(f, options) case "center":
options.verbose && logger.info(`Convert ${f} to `, outputs) default:
return _watermark(f, outputs, onNode, options) return width / 2;
}, { concurrency: 1 }) }
}
function getTextY(position: Corner, height: number, margin: number, fontSize: number): number {
switch (position) {
case "top-left":
case "top-right":
return margin + fontSize;
case "bottom-left":
case "bottom-right":
return height - margin;
case "center":
default:
return height / 2;
}
}
function getTextAnchor(position: Corner): string {
switch (position) {
case "top-left":
case "bottom-left":
return "start";
case "top-right":
case "bottom-right":
return "end";
case "center":
default:
return "middle";
}
}
function getTextBaseline(position: Corner): string {
switch (position) {
case "top-left":
case "top-right":
return "hanging";
case "bottom-left":
case "bottom-right":
return "auto";
case "center":
default:
return "middle";
}
}
const _watermark = async (file: string, targets: string[], onNode: (data: any) => void = () => { }, options: WatermarkOptions) => {
return pMap(targets, async (target) => {
options.verbose && logger.debug(`Adding watermark ${file} to ${target}`);
if (options.dry) {
return;
}
if (options.watermarkType === 'text') {
if (!options.text) {
throw new Error('Text is required for text watermark');
}
return addTextWatermark(file, options.text, target, options.textOptions);
} else if (options.watermarkType === 'image') {
if (!options.logoPath) {
throw new Error('Logo path is required for image watermark');
}
if (!fs.existsSync(options.logoPath)) {
throw new Error(`Logo file not found: ${options.logoPath}`);
}
return addLogoWatermark(file, options.logoPath, target, options.imageOptions);
} else { } else {
options.debug && logger.error(`Invalid source info`) throw new Error('Invalid watermark type. Must be "text" or "image"');
} }
} }, { concurrency: 1 });
};
export const watermark = async (options: WatermarkOptions) => {
// reporting, stub
let reports: any = [];
const onNode = (data: any) => reports.push(data);
if (options.srcInfo) {
options.verbose && logger.info(`Adding watermark to ${options.srcInfo.FILES.length} files`);
return await pMap(options.srcInfo.FILES, async (f) => {
const outputs = targets(f, options);
options.verbose && logger.info(`Adding watermark ${f} to `, outputs);
return _watermark(f, outputs, onNode, options);
}, { concurrency: 1 });
} else {
options.debug && logger.error(`Invalid source info`);
}
};

View File

@ -2,8 +2,11 @@
import { defaults } from './_cli.js'; defaults() import { defaults } from './_cli.js'; defaults()
import { cli } from './cli.js' import { cli } from './cli.js'
import './commands/resize.js' import './commands/resize.js'
import './commands/pdf2jpg.js' import './commands/pdf2jpg.js'
import './commands/watermark.js'
import './commands/background-remove.js'
const argv: any = cli.argv; const argv: any = cli.argv;

View File

@ -54,4 +54,10 @@ export type IConvertVideoOptions = IOptions & {
interval?: number interval?: number
verb: string verb: string
audio: string audio: string
} }
// Re-export watermark types from the watermark module
export type { WatermarkOptions, LogoWatermarkOptions, TextWatermarkOptions } from './lib/media/images/watermark.js'
// Re-export background removal types
export type { BackgroundRemoveOptions } from './lib/media/images/background-remove.js'

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Some files were not shown because too many files have changed in this diff Show More