kbot cache

This commit is contained in:
lovebird 2025-04-07 10:50:14 +02:00
parent 0a3ee28ca2
commit ad216c888d
6 changed files with 100 additions and 94 deletions

File diff suppressed because one or more lines are too long

View File

@ -12,11 +12,16 @@ export interface IteratorFactory {
transform: (mappings: FieldMapping[]) => Promise<void>;
createTransformer: (options: IKBotTask) => AsyncTransformer;
}
export interface CacheConfig {
enabled?: boolean;
namespace?: string;
expiration?: number;
}
export declare function createLLMTransformer(options: IKBotTask, logger?: {
info: (message: string) => void;
warn: (message: string) => void;
error: (message: string, error?: any) => void;
}): AsyncTransformer;
}, cacheConfig?: CacheConfig): AsyncTransformer;
export declare function createIterator(obj: Record<string, any>, optionsMixin: Partial<IKBotTask>, globalOptions?: {
throttleDelay?: number;
concurrentTasks?: number;
@ -28,6 +33,7 @@ export declare function createIterator(obj: Record<string, any>, optionsMixin: P
logger?: {
error: (message: string, error?: any) => void;
};
cacheConfig?: CacheConfig;
}): IteratorFactory;
export declare function transformWithMappings(obj: Record<string, any>, createTransformer: (options: IKBotTask) => AsyncTransformer, mappings: FieldMapping[], globalOptions?: {
throttleDelay?: number;
@ -39,4 +45,5 @@ export declare function transformWithMappings(obj: Record<string, any>, createTr
logger?: {
error: (message: string, error?: any) => void;
};
cacheConfig?: CacheConfig;
}): Promise<void>;

File diff suppressed because one or more lines are too long

View File

@ -4,8 +4,7 @@ import * as fs from 'fs';
import type { IKBotTask } from '@polymech/ai-tools';
import { E_OPENROUTER_MODEL } from '../../models/cache/openrouter-models.js';
import { E_Mode } from '../../zod_schema.js';
import { FieldMapping, createIterator, createLLMTransformer } from '../../iterator.js';
import { FieldMapping, createIterator, createLLMTransformer, CacheConfig } from '../../iterator.js';
const MODEL = E_OPENROUTER_MODEL.MODEL_OPENROUTER_QUASAR_ALPHA;
const ROUTER = 'openrouter';
@ -77,6 +76,13 @@ const errorCallback = (path: string, value: string, error: any) => {
logger.error(`Error transforming ${path}: ${error.message}`);
};
// Cache configuration
const cacheConfig: CacheConfig = {
enabled: true,
namespace: 'product-transformations',
expiration: 7 * 24 * 60 * 60 // 7 days in seconds
};
export async function factoryExample() {
console.log("========================================");
console.log("Starting iterator factory example");
@ -113,12 +119,9 @@ export async function factoryExample() {
concurrentTasks: 1,
errorCallback,
filterCallback: async () => true,
transformerFactory: (options) => createLLMTransformer(options, logger),
transformerFactory: (options) => createLLMTransformer(options, logger, cacheConfig),
logger: logger,
cache: {
enabled: true,
namespace: 'product-transformations'
}
cacheConfig
}
);
@ -148,12 +151,9 @@ export async function factoryExample() {
concurrentTasks: 1,
errorCallback,
filterCallback: async () => true,
transformerFactory: (options) => createLLMTransformer(options, logger),
transformerFactory: (options) => createLLMTransformer(options, logger, cacheConfig),
logger: logger,
cache: {
enabled: true,
namespace: 'product-transformations'
}
cacheConfig
}
);

View File

@ -33,14 +33,29 @@ export interface IteratorFactory {
createTransformer: (options: IKBotTask) => AsyncTransformer
}
export interface CacheConfig {
enabled?: boolean;
namespace?: string;
expiration?: number; // in seconds
}
const DEFAULT_CACHE_CONFIG: Required<CacheConfig> = {
enabled: true,
namespace: 'llm-responses',
expiration: 7 * 24 * 60 * 60 // 7 days in seconds
};
export function createLLMTransformer(
options: IKBotTask,
logger?: {
info: (message: string) => void;
warn: (message: string) => void;
error: (message: string, error?: any) => void;
}
},
cacheConfig?: CacheConfig
): AsyncTransformer {
const config: Required<CacheConfig> = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
return async (input: string, jsonPath: string): Promise<string> => {
if (logger) {
logger.info(`Transforming field at path: ${jsonPath}`);
@ -53,7 +68,6 @@ export function createLLMTransformer(
prompt: `${options.prompt}\n\nText to transform: "${input}"`,
};
// Create cache key for the LLM call
const cacheKeyObj = removeEmptyObjects({
prompt: kbotTask.prompt,
model: kbotTask.model,
@ -64,17 +78,27 @@ export function createLLMTransformer(
});
try {
const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, 'llm-responses') as { content: string };
if (cachedResponse?.content) {
if (logger) logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
return cachedResponse.content;
if (config.enabled) {
const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, config.namespace) as { content: string };
if (cachedResponse?.content) {
if (logger) logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
return cachedResponse.content;
}
}
const results = await run(kbotTask)
const results = await run(kbotTask);
if (results && results.length > 0 && typeof results[0] === 'string') {
const result = results[0].trim();
await set_cached_object({ ca_options: cacheKeyObj }, 'llm-responses', { content: result }, {});
if (logger) logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
const result = results[0].trim();
if (config.enabled) {
await set_cached_object(
{ ca_options: cacheKeyObj },
config.namespace,
{ content: result },
{ expiration: config.expiration }
);
if (logger) logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
}
if (logger) logger.info(`Result: ${result}`);
return result;
@ -105,6 +129,7 @@ export function createIterator(
maxRetries?: number
retryDelay?: number
logger?: { error: (message: string, error?: any) => void }
cacheConfig?: CacheConfig
} = {}
): IteratorFactory {
const {
@ -115,12 +140,11 @@ export function createIterator(
transformerFactory,
maxRetries = 3,
retryDelay = 2000,
logger
logger,
cacheConfig
} = globalOptions;
const defaultTransformerFactory = (options: IKBotTask): AsyncTransformer => {
// This is a placeholder transformer that just returns the input
// In real usage, this would be replaced by the provided transformerFactory
return async (input: string): Promise<string> => input;
};
@ -133,6 +157,7 @@ export function createIterator(
const mergedOptions = { ...optionsMixin, ...mapping.options } as IKBotTask;
const { jsonPath, targetPath = null, maxRetries: mappingRetries, retryDelay: mappingRetryDelay } = mapping;
const transformer = createTransformer(mergedOptions);
await transformObjectWithOptions(
obj,
transformer,
@ -164,32 +189,9 @@ export async function transformWithMappings(
maxRetries?: number
retryDelay?: number
logger?: { error: (message: string, error?: any) => void }
cacheConfig?: CacheConfig
} = {}
): Promise<void> {
const {
throttleDelay = 1000,
concurrentTasks = 1,
errorCallback = defaultError,
filterCallback = testFilters(defaultFilters()),
maxRetries = 3,
retryDelay = 2000,
logger
} = globalOptions;
const iterator = createIterator(
obj,
{},
{
throttleDelay,
concurrentTasks,
errorCallback,
filterCallback,
transformerFactory: createTransformer,
maxRetries,
retryDelay,
logger
}
);
const iterator = createIterator(obj, {}, globalOptions);
await iterator.transform(mappings);
}

View File

@ -4,24 +4,24 @@
{
"id": "f1",
"name": "apple",
"description": "A deliciously juicy fruit bursting with natural sweetness, offering a satisfying crunch with every bite—a perfect refreshing snack packed with vitamins and vibrant flavor.",
"description": "A deliciously sweet fruit with a satisfying crunch, bursting with juicy flavor and vibrant freshness in every bite, perfect for a refreshing and healthy snack.",
"details": {
"color": "red",
"origin": "Worldwide",
"nutrition": "Rich in fiber and vitamin C, which supports a healthy digestive system, aids in maintaining stable blood sugar levels, strengthens the immune system, and promotes collagen production for healthier skin and faster wound healing."
"nutrition": "Rich in fiber and vitamin C, this food supports digestive health by promoting regularity, boosts immune function, and provides antioxidant protection to help reduce inflammation and support overall wellness."
},
"marketingName": "Crimson Orchard Essence"
"marketingName": "Crimson Orchard Delight"
},
{
"id": "f2",
"name": "banana",
"description": "A vibrant, sun-kissed tropical fruit with a bright yellow hue, boasting a sweet, juicy flavor that bursts with refreshing tropical essence in every delicious bite.",
"description": "A vibrant, sun-kissed yellow tropical fruit bursting with juicy sweetness, offering a refreshing taste of paradise with every succulent bite and an irresistibly fragrant aroma.",
"details": {
"color": "yellow",
"origin": "Southeast Asia",
"nutrition": "High in potassium, which supports healthy nerve and muscle function, helps maintain normal blood pressure, and reduces the risk of stroke by balancing sodium levels in the body for overall cardiovascular health."
"nutrition": "High in potassium, which helps regulate blood pressure, supports proper muscle and nerve function, and maintains fluid balance in the body, contributing to overall heart health and reduced risk of stroke."
},
"marketingName": "Golden Sun Banana"
"marketingName": "Golden Tropic Delight"
}
]
}