kbot cache implementations
This commit is contained in:
parent
4c40bcdbac
commit
e2ba560720
16
packages/kbot/dist-in/iterator-cache.d.ts
vendored
Normal file
16
packages/kbot/dist-in/iterator-cache.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export interface CacheProvider {
|
||||||
|
get(key: object, namespace: string): Promise<any | null>;
|
||||||
|
set(key: object, namespace: string, value: any, options?: {
|
||||||
|
expiration?: number;
|
||||||
|
}): Promise<void>;
|
||||||
|
delete(key: object, namespace: string): Promise<void>;
|
||||||
|
}
|
||||||
|
export interface CacheConfig {
|
||||||
|
enabled?: boolean;
|
||||||
|
provider?: 'default' | 'redis';
|
||||||
|
namespace?: string;
|
||||||
|
expiration?: number;
|
||||||
|
redisUrl?: string;
|
||||||
|
}
|
||||||
|
export declare const DEFAULT_CACHE_CONFIG: Required<Omit<CacheConfig, 'redisUrl'>>;
|
||||||
|
export declare function createCacheProvider(config?: CacheConfig): CacheProvider;
|
||||||
114
packages/kbot/dist-in/iterator-cache.js
Normal file
114
packages/kbot/dist-in/iterator-cache.js
Normal file
File diff suppressed because one or more lines are too long
7
packages/kbot/dist-in/iterator.d.ts
vendored
7
packages/kbot/dist-in/iterator.d.ts
vendored
@ -1,5 +1,6 @@
|
|||||||
import { IKBotTask } from '@polymech/ai-tools';
|
import { IKBotTask } from '@polymech/ai-tools';
|
||||||
import { AsyncTransformer, ErrorCallback, FilterCallback, OnTransformCallback, OnTransformedCallback, INetworkOptions } from './async-iterator.js';
|
import { AsyncTransformer, ErrorCallback, FilterCallback, OnTransformCallback, OnTransformedCallback, INetworkOptions } from './async-iterator.js';
|
||||||
|
import { CacheConfig } from './iterator-cache.js';
|
||||||
/**
|
/**
|
||||||
* Notes for LLM modifications
|
* Notes for LLM modifications
|
||||||
*
|
*
|
||||||
@ -22,11 +23,6 @@ export interface IteratorFactory {
|
|||||||
transform: (mappings: FieldMapping[]) => Promise<void>;
|
transform: (mappings: FieldMapping[]) => Promise<void>;
|
||||||
createTransformer: (options: IKBotTask) => AsyncTransformer;
|
createTransformer: (options: IKBotTask) => AsyncTransformer;
|
||||||
}
|
}
|
||||||
export interface CacheConfig {
|
|
||||||
enabled?: boolean;
|
|
||||||
namespace?: string;
|
|
||||||
expiration?: number;
|
|
||||||
}
|
|
||||||
export interface IOptions {
|
export interface IOptions {
|
||||||
network?: INetworkOptions;
|
network?: INetworkOptions;
|
||||||
errorCallback?: ErrorCallback;
|
errorCallback?: ErrorCallback;
|
||||||
@ -38,6 +34,7 @@ export interface IOptions {
|
|||||||
onTransformed?: OnTransformedCallback;
|
onTransformed?: OnTransformedCallback;
|
||||||
}
|
}
|
||||||
export { INetworkOptions };
|
export { INetworkOptions };
|
||||||
|
export { CacheConfig };
|
||||||
export declare function createLLMTransformer(options: IKBotTask, logger?: ILogger, cacheConfig?: CacheConfig): AsyncTransformer;
|
export declare function createLLMTransformer(options: IKBotTask, logger?: ILogger, cacheConfig?: CacheConfig): AsyncTransformer;
|
||||||
export declare function createIterator(obj: Record<string, any>, optionsMixin: Partial<IKBotTask>, globalOptions?: IOptions): IteratorFactory;
|
export declare function createIterator(obj: Record<string, any>, optionsMixin: Partial<IKBotTask>, globalOptions?: IOptions): IteratorFactory;
|
||||||
export declare function transformWithMappings(obj: Record<string, any>, createTransformer: (options: IKBotTask) => AsyncTransformer, mappings: FieldMapping[], globalOptions?: IOptions): Promise<void>;
|
export declare function transformWithMappings(obj: Record<string, any>, createTransformer: (options: IKBotTask) => AsyncTransformer, mappings: FieldMapping[], globalOptions?: IOptions): Promise<void>;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -17,12 +17,15 @@ export const preferences = async (opts) => {
|
|||||||
let preferencesPath = path.resolve(path.join(process.cwd(), PREFERENCES_FILE_NAME));
|
let preferencesPath = path.resolve(path.join(process.cwd(), PREFERENCES_FILE_NAME));
|
||||||
if (!exists(preferencesPath)) {
|
if (!exists(preferencesPath)) {
|
||||||
// Fall back to specified preferences path if local file doesn't exist
|
// Fall back to specified preferences path if local file doesn't exist
|
||||||
preferencesPath = path.resolve(resolve(opts.preferences, false, env_vars()));
|
// Only resolve if opts.preferences is actually defined
|
||||||
|
preferencesPath = opts.preferences ? path.resolve(resolve(opts.preferences, false, env_vars())) : '';
|
||||||
}
|
}
|
||||||
const preferences = read(preferencesPath, 'string');
|
// Only read if preferencesPath is valid and exists
|
||||||
|
const preferencesContent = preferencesPath && exists(preferencesPath) ? read(preferencesPath, 'string') : '';
|
||||||
return {
|
return {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: `USER Preferences : ${preferences}` || ''
|
// Only include content if preferences were actually loaded
|
||||||
|
content: preferencesContent ? `USER Preferences : ${preferencesContent}` : ''
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbXB0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Byb21wdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUsSUFBSSxJQUFJLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQzNDLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFBO0FBRWpDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDekMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFdEQsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLEtBQUssRUFBRSxJQUFlLEVBQW1ELEVBQUU7SUFDN0YsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDdEMsT0FBTztRQUNILElBQUksRUFBRSxNQUFNO1FBQ1osT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFO0tBQ3ZCLENBQUE7QUFDTCxDQUFDLENBQUE7QUFFRCxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsS0FBSyxFQUFFLElBQWUsRUFBbUQsRUFBRTtJQUNsRyw4QkFBOEI7SUFDOUIsSUFBSSxlQUFlLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDLENBQUE7SUFDbkYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO1FBQzNCLHNFQUFzRTtRQUN0RSxlQUFlLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ2hGLENBQUM7SUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLFFBQVEsQ0FBVyxDQUFBO0lBQzdELE9BQU87UUFDSCxJQUFJLEVBQUUsTUFBTTtRQUNaLE9BQU8sRUFBRSxzQkFBc0IsV0FBVyxFQUFFLElBQUksRUFBRTtLQUNyRCxDQUFBO0FBQ0wsQ0FBQyxDQUFBIn0=
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbXB0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Byb21wdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUsSUFBSSxJQUFJLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQzNDLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFBO0FBRWpDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUMvQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDekMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFdEQsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLEtBQUssRUFBRSxJQUFlLEVBQW1ELEVBQUU7SUFDN0YsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDdEMsT0FBTztRQUNILElBQUksRUFBRSxNQUFNO1FBQ1osT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFO0tBQ3ZCLENBQUE7QUFDTCxDQUFDLENBQUE7QUFFRCxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsS0FBSyxFQUFFLElBQWUsRUFBbUQsRUFBRTtJQUNsRyw4QkFBOEI7SUFDOUIsSUFBSSxlQUFlLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDLENBQUE7SUFDbkYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO1FBQzNCLHNFQUFzRTtRQUN0RSx1REFBdUQ7UUFDdkQsZUFBZSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQ3hHLENBQUM7SUFDRCxtREFBbUQ7SUFDbkQsTUFBTSxrQkFBa0IsR0FBRyxlQUFlLElBQUksTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLFFBQVEsQ0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7SUFDdEgsT0FBTztRQUNILElBQUksRUFBRSxNQUFNO1FBQ1osMkRBQTJEO1FBQzNELE9BQU8sRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsc0JBQXNCLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUU7S0FDaEYsQ0FBQTtBQUNMLENBQUMsQ0FBQSJ9
|
||||||
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"model": "mistralai/mistral-tiny",
|
"model": "openai/chatgpt-4o-latest",
|
||||||
"messages": [
|
"messages": [
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": "Generate a random number"
|
"content": "Analyze this product review and extract key information\n\nText to transform: \"Great selection of fruits with good prices and quality. Some items were out of stock.\""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": "USER Preferences : undefined"
|
"content": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tools": []
|
"tools": []
|
||||||
|
|||||||
89
packages/kbot/package-lock.json
generated
89
packages/kbot/package-lock.json
generated
@ -7,6 +7,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "@polymech/kbot-d",
|
"name": "@polymech/kbot-d",
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@polymech/ai-tools": "file:../ai-tools",
|
"@polymech/ai-tools": "file:../ai-tools",
|
||||||
"@polymech/cache": "file:../cache",
|
"@polymech/cache": "file:../cache",
|
||||||
@ -22,6 +23,7 @@
|
|||||||
"emojilib": "4.0.1",
|
"emojilib": "4.0.1",
|
||||||
"env-var": "7.5.0",
|
"env-var": "7.5.0",
|
||||||
"glob": "11.0.1",
|
"glob": "11.0.1",
|
||||||
|
"ioredis": "^5.4.1",
|
||||||
"json-schema-to-zod": "2.6.0",
|
"json-schema-to-zod": "2.6.0",
|
||||||
"jsonpath-plus": "10.3.0",
|
"jsonpath-plus": "10.3.0",
|
||||||
"marked": "14.1.4",
|
"marked": "14.1.4",
|
||||||
@ -1085,6 +1087,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ioredis/commands": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@isaacs/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||||
@ -3128,6 +3136,15 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cluster-key-slot": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@ -3287,6 +3304,15 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dequal": {
|
"node_modules/dequal": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
@ -4435,6 +4461,30 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ioredis": {
|
||||||
|
"version": "5.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.0.tgz",
|
||||||
|
"integrity": "sha512-tBZlIIWbndeWBWCXWZiqtOF/yxf6yZX3tAlTJ7nfo5jhd6dctNxF7QnYlZLZ1a0o0pDoen7CgZqO+zjNaFbJAg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ioredis/commands": "^1.1.1",
|
||||||
|
"cluster-key-slot": "^1.1.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"lodash.defaults": "^4.2.0",
|
||||||
|
"lodash.isarguments": "^3.1.0",
|
||||||
|
"redis-errors": "^1.2.0",
|
||||||
|
"redis-parser": "^3.0.0",
|
||||||
|
"standard-as-callback": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ioredis"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
@ -4817,6 +4867,18 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.defaults": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isarguments": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@ -6347,6 +6409,27 @@
|
|||||||
"node": ">= 10.13.0"
|
"node": ">= 10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redis-errors": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redis-parser": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"redis-errors": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/remark-parse": {
|
"node_modules/remark-parse": {
|
||||||
"version": "11.0.0",
|
"version": "11.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
|
||||||
@ -6766,6 +6849,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/standard-as-callback": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
|||||||
@ -63,6 +63,7 @@
|
|||||||
"emojilib": "4.0.1",
|
"emojilib": "4.0.1",
|
||||||
"env-var": "7.5.0",
|
"env-var": "7.5.0",
|
||||||
"glob": "11.0.1",
|
"glob": "11.0.1",
|
||||||
|
"ioredis": "^5.4.1",
|
||||||
"json-schema-to-zod": "2.6.0",
|
"json-schema-to-zod": "2.6.0",
|
||||||
"jsonpath-plus": "10.3.0",
|
"jsonpath-plus": "10.3.0",
|
||||||
"marked": "14.1.4",
|
"marked": "14.1.4",
|
||||||
|
|||||||
139
packages/kbot/src/iterator-cache.ts
Normal file
139
packages/kbot/src/iterator-cache.ts
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import { get_cached_object, set_cached_object, rm_cached_object } from "@polymech/cache";
|
||||||
|
import { Redis } from 'ioredis';
|
||||||
|
|
||||||
|
export interface CacheProvider {
|
||||||
|
get(key: object, namespace: string): Promise<any | null>;
|
||||||
|
set(key: object, namespace: string, value: any, options?: { expiration?: number }): Promise<void>;
|
||||||
|
delete(key: object, namespace: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CacheConfig {
|
||||||
|
enabled?: boolean;
|
||||||
|
provider?: 'default' | 'redis';
|
||||||
|
namespace?: string;
|
||||||
|
expiration?: number; // in seconds
|
||||||
|
redisUrl?: string; // e.g., 'redis://localhost:6379'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_CACHE_CONFIG: Required<Omit<CacheConfig, 'redisUrl'>> = {
|
||||||
|
enabled: true,
|
||||||
|
provider: 'default',
|
||||||
|
namespace: 'default-cache',
|
||||||
|
expiration: 7 * 24 * 60 * 60 // 7 days in seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Default Cache Provider (using @polymech/cache) ---
|
||||||
|
|
||||||
|
class DefaultCacheProvider implements CacheProvider {
|
||||||
|
async get(key: object, namespace: string): Promise<any | null> {
|
||||||
|
try {
|
||||||
|
return await get_cached_object({ ca_options: key }, namespace);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`DefaultCache: Error getting cache for key ${JSON.stringify(key)} in namespace ${namespace}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(key: object, namespace: string, value: any, options?: { expiration?: number }): Promise<void> {
|
||||||
|
try {
|
||||||
|
await set_cached_object({ ca_options: key }, namespace, value, options);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`DefaultCache: Error setting cache for key ${JSON.stringify(key)} in namespace ${namespace}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(key: object, namespace: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await rm_cached_object({ ca_options: key }, namespace);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`DefaultCache: Error deleting cache for key ${JSON.stringify(key)} in namespace ${namespace}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Redis Cache Provider ---
|
||||||
|
|
||||||
|
class RedisCacheProvider implements CacheProvider {
|
||||||
|
private redis: Redis;
|
||||||
|
|
||||||
|
constructor(redisUrl?: string) {
|
||||||
|
// Default to local instance if no URL is provided
|
||||||
|
this.redis = new Redis(redisUrl || 'redis://localhost:6379');
|
||||||
|
this.redis.on('error', (err) => console.error('Redis Client Error', err));
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateKey(key: object, namespace: string): string {
|
||||||
|
// Simple serialization; consider a more robust hashing function for complex keys
|
||||||
|
return `${namespace}:${JSON.stringify(key)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(key: object, namespace: string): Promise<any | null> {
|
||||||
|
const redisKey = this.generateKey(key, namespace);
|
||||||
|
try {
|
||||||
|
const data = await this.redis.get(redisKey);
|
||||||
|
return data ? JSON.parse(data) : null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`RedisCache: Error getting cache for key ${redisKey}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(key: object, namespace: string, value: any, options?: { expiration?: number }): Promise<void> {
|
||||||
|
const redisKey = this.generateKey(key, namespace);
|
||||||
|
try {
|
||||||
|
const stringValue = JSON.stringify(value);
|
||||||
|
if (options?.expiration) {
|
||||||
|
await this.redis.set(redisKey, stringValue, 'EX', options.expiration);
|
||||||
|
} else {
|
||||||
|
await this.redis.set(redisKey, stringValue);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`RedisCache: Error setting cache for key ${redisKey}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(key: object, namespace: string): Promise<void> {
|
||||||
|
const redisKey = this.generateKey(key, namespace);
|
||||||
|
try {
|
||||||
|
await this.redis.del(redisKey);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`RedisCache: Error deleting cache for key ${redisKey}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(): Promise<void> {
|
||||||
|
await this.redis.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Factory Function ---
|
||||||
|
|
||||||
|
let defaultCacheProviderInstance: CacheProvider | null = null;
|
||||||
|
let redisCacheProviderInstance: CacheProvider | null = null;
|
||||||
|
|
||||||
|
export function createCacheProvider(config?: CacheConfig): CacheProvider {
|
||||||
|
const mergedConfig = { ...DEFAULT_CACHE_CONFIG, ...config };
|
||||||
|
|
||||||
|
if (!mergedConfig.enabled) {
|
||||||
|
// Return a dummy provider if caching is disabled
|
||||||
|
return {
|
||||||
|
get: async () => null,
|
||||||
|
set: async () => {},
|
||||||
|
delete: async () => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergedConfig.provider === 'redis') {
|
||||||
|
if (!redisCacheProviderInstance) {
|
||||||
|
// Pass redisUrl if provided in config
|
||||||
|
redisCacheProviderInstance = new RedisCacheProvider(config?.redisUrl);
|
||||||
|
}
|
||||||
|
return redisCacheProviderInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default provider
|
||||||
|
if (!defaultCacheProviderInstance) {
|
||||||
|
defaultCacheProviderInstance = new DefaultCacheProvider();
|
||||||
|
}
|
||||||
|
return defaultCacheProviderInstance;
|
||||||
|
}
|
||||||
@ -13,8 +13,8 @@ import {
|
|||||||
DEFAULT_NETWORK_OPTIONS
|
DEFAULT_NETWORK_OPTIONS
|
||||||
} from './async-iterator.js'
|
} from './async-iterator.js'
|
||||||
import { run } from './commands/run.js'
|
import { run } from './commands/run.js'
|
||||||
import { get_cached_object, set_cached_object, rm_cached_object } from "@polymech/cache"
|
|
||||||
import { deepClone } from "@polymech/core/objects"
|
import { deepClone } from "@polymech/core/objects"
|
||||||
|
import { CacheConfig, createCacheProvider, CacheProvider, DEFAULT_CACHE_CONFIG } from './iterator-cache.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notes for LLM modifications
|
* Notes for LLM modifications
|
||||||
@ -64,12 +64,6 @@ export interface IteratorFactory {
|
|||||||
createTransformer: (options: IKBotTask) => AsyncTransformer
|
createTransformer: (options: IKBotTask) => AsyncTransformer
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CacheConfig {
|
|
||||||
enabled?: boolean;
|
|
||||||
namespace?: string;
|
|
||||||
expiration?: number; // in seconds
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IOptions {
|
export interface IOptions {
|
||||||
network?: INetworkOptions;
|
network?: INetworkOptions;
|
||||||
errorCallback?: ErrorCallback;
|
errorCallback?: ErrorCallback;
|
||||||
@ -81,21 +75,18 @@ export interface IOptions {
|
|||||||
onTransformed?: OnTransformedCallback;
|
onTransformed?: OnTransformedCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_CACHE_CONFIG: Required<CacheConfig> = {
|
|
||||||
enabled: true,
|
|
||||||
namespace: 'llm-responses',
|
|
||||||
expiration: 7 * 24 * 60 * 60 // 7 days in seconds
|
|
||||||
};
|
|
||||||
|
|
||||||
// Re-export INetworkOptions for other modules to use
|
// Re-export INetworkOptions for other modules to use
|
||||||
export { INetworkOptions };
|
export { INetworkOptions };
|
||||||
|
// Re-export CacheConfig as well
|
||||||
|
export { CacheConfig };
|
||||||
|
|
||||||
export function createLLMTransformer(
|
export function createLLMTransformer(
|
||||||
options: IKBotTask,
|
options: IKBotTask,
|
||||||
logger: ILogger = dummyLogger,
|
logger: ILogger = dummyLogger,
|
||||||
cacheConfig?: CacheConfig
|
cacheConfig?: CacheConfig
|
||||||
): AsyncTransformer {
|
): AsyncTransformer {
|
||||||
const config: Required<CacheConfig> = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
|
const mergedCacheConfig = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
|
||||||
|
const cacheProvider = createCacheProvider(mergedCacheConfig);
|
||||||
|
|
||||||
return async (input: string, jsonPath: string): Promise<string> => {
|
return async (input: string, jsonPath: string): Promise<string> => {
|
||||||
logger.info(`Transforming field at path: ${jsonPath}`);
|
logger.info(`Transforming field at path: ${jsonPath}`);
|
||||||
@ -117,8 +108,8 @@ export function createLLMTransformer(
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (config.enabled) {
|
if (mergedCacheConfig.enabled) {
|
||||||
const cachedResponse = await get_cached_object({ ca_options: cacheKeyObj }, config.namespace) as { content: string };
|
const cachedResponse = await cacheProvider.get(cacheKeyObj, 'llm-responses') as { content: string };
|
||||||
if (cachedResponse?.content) {
|
if (cachedResponse?.content) {
|
||||||
logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
|
logger.info(`Using cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
|
||||||
return cachedResponse.content;
|
return cachedResponse.content;
|
||||||
@ -129,12 +120,12 @@ export function createLLMTransformer(
|
|||||||
if (results && results.length > 0 && typeof results[0] === 'string') {
|
if (results && results.length > 0 && typeof results[0] === 'string') {
|
||||||
const result = results[0].trim();
|
const result = results[0].trim();
|
||||||
|
|
||||||
if (config.enabled) {
|
if (mergedCacheConfig.enabled) {
|
||||||
await set_cached_object(
|
await cacheProvider.set(
|
||||||
{ ca_options: cacheKeyObj },
|
cacheKeyObj,
|
||||||
config.namespace,
|
'llm-responses',
|
||||||
{ content: result },
|
{ content: result },
|
||||||
{ expiration: config.expiration }
|
{ expiration: mergedCacheConfig.expiration }
|
||||||
);
|
);
|
||||||
logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
|
logger.info(`Cached LLM response for prompt: ${kbotTask.prompt.substring(0, 100)}...`);
|
||||||
}
|
}
|
||||||
@ -173,7 +164,9 @@ export function createIterator(
|
|||||||
...network
|
...network
|
||||||
};
|
};
|
||||||
|
|
||||||
const config: Required<CacheConfig> = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
|
const mergedCacheConfig = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
|
||||||
|
const cacheProvider = createCacheProvider(mergedCacheConfig);
|
||||||
|
const objCacheNamespace = 'transformed-objects';
|
||||||
|
|
||||||
const defaultTransformerFactory = (options: IKBotTask): AsyncTransformer => {
|
const defaultTransformerFactory = (options: IKBotTask): AsyncTransformer => {
|
||||||
return async (input: string): Promise<string> => input;
|
return async (input: string): Promise<string> => input;
|
||||||
@ -213,16 +206,15 @@ export function createIterator(
|
|||||||
transform: async (mappings: FieldMapping[]): Promise<void> => {
|
transform: async (mappings: FieldMapping[]): Promise<void> => {
|
||||||
// *** Object Cache Check (Start) ***
|
// *** Object Cache Check (Start) ***
|
||||||
let objectCacheKey: any;
|
let objectCacheKey: any;
|
||||||
if (config.enabled) {
|
if (mergedCacheConfig.enabled) {
|
||||||
objectCacheKey = createObjectCacheKey(obj, mappings); // Key based on initial state
|
objectCacheKey = createObjectCacheKey(obj, mappings);
|
||||||
const cachedObject = await get_cached_object(
|
const cachedObject = await cacheProvider.get(
|
||||||
{ ca_options: objectCacheKey },
|
objectCacheKey,
|
||||||
'transformed-objects'
|
objCacheNamespace
|
||||||
) as { content: Record<string, any> };
|
) as { content: Record<string, any> };
|
||||||
|
|
||||||
if (cachedObject?.content) {
|
if (cachedObject?.content) {
|
||||||
logger.info('Using cached transformed object');
|
logger.info('Using cached transformed object');
|
||||||
// Clear the original object before merging cache to avoid partial states
|
|
||||||
Object.keys(obj).forEach(key => delete obj[key]);
|
Object.keys(obj).forEach(key => delete obj[key]);
|
||||||
deepMerge(obj, cachedObject.content);
|
deepMerge(obj, cachedObject.content);
|
||||||
return;
|
return;
|
||||||
@ -230,16 +222,13 @@ export function createIterator(
|
|||||||
}
|
}
|
||||||
// *** Object Cache Check (End) ***
|
// *** Object Cache Check (End) ***
|
||||||
|
|
||||||
// If no cache hit or caching disabled, perform the transformations directly on 'obj'
|
|
||||||
// REMOVED: const transformedObj = JSON.parse(JSON.stringify(obj));
|
|
||||||
for (const mapping of mappings) {
|
for (const mapping of mappings) {
|
||||||
const mergedOptions = { ...optionsMixin, ...mapping.options } as IKBotTask;
|
const mergedOptions = { ...optionsMixin, ...mapping.options } as IKBotTask;
|
||||||
const { jsonPath, targetPath = null } = mapping;
|
const { jsonPath, targetPath = null } = mapping;
|
||||||
const transformer = createTransformer(mergedOptions);
|
const transformer = createTransformer(mergedOptions);
|
||||||
|
|
||||||
// Call transformObjectWithOptions directly on the original 'obj'
|
|
||||||
await transformObjectWithOptions(
|
await transformObjectWithOptions(
|
||||||
obj, // <<< Operate directly on obj
|
obj,
|
||||||
transformer,
|
transformer,
|
||||||
{
|
{
|
||||||
jsonPath,
|
jsonPath,
|
||||||
@ -255,19 +244,16 @@ export function createIterator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// *** Object Cache Setting (Start) ***
|
// *** Object Cache Setting (Start) ***
|
||||||
// Cache the final state of the modified 'obj'
|
if (mergedCacheConfig.enabled && objectCacheKey) {
|
||||||
if (config.enabled && objectCacheKey) { // Ensure key was generated
|
await cacheProvider.set(
|
||||||
await set_cached_object(
|
objectCacheKey,
|
||||||
{ ca_options: objectCacheKey },
|
objCacheNamespace,
|
||||||
'transformed-objects',
|
{ content: obj },
|
||||||
{ content: obj }, // <<< Cache the final obj
|
{ expiration: mergedCacheConfig.expiration }
|
||||||
{ expiration: config.expiration }
|
|
||||||
);
|
);
|
||||||
logger.info('Cached transformed object');
|
logger.info('Cached transformed object');
|
||||||
}
|
}
|
||||||
// *** Object Cache Setting (End) ***
|
// *** Object Cache Setting (End) ***
|
||||||
|
|
||||||
// REMOVED: deepMerge(obj, transformedObj);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -278,7 +264,6 @@ export async function transformWithMappings(
|
|||||||
mappings: FieldMapping[],
|
mappings: FieldMapping[],
|
||||||
globalOptions: IOptions = {}
|
globalOptions: IOptions = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Pass the provided createTransformer as the transformerFactory in options
|
|
||||||
const optionsWithTransformer: IOptions = {
|
const optionsWithTransformer: IOptions = {
|
||||||
...globalOptions,
|
...globalOptions,
|
||||||
transformerFactory: createTransformer
|
transformerFactory: createTransformer
|
||||||
|
|||||||
@ -24,11 +24,14 @@ export const preferences = async (opts: IKBotTask): Promise<ChatCompletionMessag
|
|||||||
let preferencesPath = path.resolve(path.join(process.cwd(), PREFERENCES_FILE_NAME))
|
let preferencesPath = path.resolve(path.join(process.cwd(), PREFERENCES_FILE_NAME))
|
||||||
if (!exists(preferencesPath)) {
|
if (!exists(preferencesPath)) {
|
||||||
// Fall back to specified preferences path if local file doesn't exist
|
// Fall back to specified preferences path if local file doesn't exist
|
||||||
preferencesPath = path.resolve(resolve(opts.preferences, false, env_vars()))
|
// Only resolve if opts.preferences is actually defined
|
||||||
|
preferencesPath = opts.preferences ? path.resolve(resolve(opts.preferences, false, env_vars())) : ''
|
||||||
}
|
}
|
||||||
const preferences = read(preferencesPath, 'string') as string
|
// Only read if preferencesPath is valid and exists
|
||||||
|
const preferencesContent = preferencesPath && exists(preferencesPath) ? read(preferencesPath, 'string') as string : ''
|
||||||
return {
|
return {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: `USER Preferences : ${preferences}` || ''
|
// Only include content if preferences were actually loaded
|
||||||
|
content: preferencesContent ? `USER Preferences : ${preferencesContent}` : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,24 +4,24 @@
|
|||||||
{
|
{
|
||||||
"id": "f1",
|
"id": "f1",
|
||||||
"name": "apple",
|
"name": "apple",
|
||||||
"description": "A deliciously sweet, crisp, and refreshing fruit packed with flavor.",
|
"description": "A lusciously sweet, vibrantly colored fruit with irresistible crunch.",
|
||||||
"details": {
|
"details": {
|
||||||
"color": "red",
|
"color": "red",
|
||||||
"origin": "Worldwide",
|
"origin": "Worldwide",
|
||||||
"nutrition": "Rich in fiber and vitamin D, this food supports healthy digestion, helps regulate blood sugar levels, and promotes strong bones by enhancing calcium absorption and supporting the immune system. [HEALTH FOCUS]"
|
"nutrition": "Rich in fiber and vitamin D, this food supports healthy digestion and promotes regular bowel movements. Vitamin D also strengthens bones, boosts immune function, and may help improve mood and energy levels. [HEALTH FOCUS]"
|
||||||
},
|
},
|
||||||
"marketingName": "Sure! Here are a few appealing marketing name options for \"apple\":\n\n1. Crimson Bliss\n2. Orchard Jewel\n3. Scarlet Crunch\n4. Nature’s Candy\n5. Ruby Crisp\n6. SweetHarvest\n7. Eden Bite\n8. Golden Orchard (if it’s a yellow variety)\n9. PurePom\n10. FreshMuse\n\nLet me know if you'd like names tailored to a specific apple variety or target audience!"
|
"marketingName": "Sure! Here are a few more appealing marketing name ideas for the product \"apple\":\n\n1. **Crimson Orchard Delight**\n2. **Eden’s Bite**\n3. **Ruby Crisp**\n4. **Nature’s Jewel**\n5. **SweetHarvest**\n6. **BlushBloom**\n7. **Golden Grove**\n8. **Scarlet Whisper**\n9. **FreshMuse**\n10. **Core Essence**\n\nLet me know the specific tone or target audience you're going for, and I can tailor the names further!"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "f2",
|
"id": "f2",
|
||||||
"name": "banana",
|
"name": "banana",
|
||||||
"description": "Vibrant, sun-kissed yellow tropical fruit bursting with sweet flavor",
|
"description": "A vibrant, sun-kissed tropical fruit bursting with sweet, exotic flavor.",
|
||||||
"details": {
|
"details": {
|
||||||
"color": "yellow",
|
"color": "yellow",
|
||||||
"origin": "Southeast Asia",
|
"origin": "Southeast Asia",
|
||||||
"nutrition": "High in potassium, which helps regulate blood pressure, supports proper muscle function, and maintains fluid balance in the body, contributing to overall cardiovascular and muscular health. [HEALTH FOCUS]"
|
"nutrition": "High in potassium, which helps regulate blood pressure, supports proper muscle function, and maintains fluid balance. It also plays a key role in nerve signaling and can reduce the risk of stroke. [HEALTH FOCUS]"
|
||||||
},
|
},
|
||||||
"marketingName": "Golden Delight"
|
"marketingName": "Sure! Here are several appealing marketing name ideas for \"banana,\" tailored to different branding styles:\n\n1. **Golden Bliss** – Emphasizes natural sweetness and luxury.\n2. **SunBurst Banana** – Suggests freshness and energy.\n3. **TropiSweet** – A fun, tropical twist with a focus on sweetness.\n4. **Nature’s Smile** – Highlights natural origins and positive feelings.\n5. **Bananza** – A playful and memorable take on \"banana.\"\n6. **Yellow Zest** – A zippy, vibrant name suggesting flavor and fun.\n7. **Velvet Peel** – Evokes a smooth, premium experience.\n8. **Bananique** – A more exotic, alluring twist on the original name.\n9. **Sunshine Fruit** – Warm and inviting, focuses on natural appeal.\n10. **GoGo Banana** – Youthful and energetic, ideal for snacking products.\n\nLet me know if you'd like names tailored to a specific use case or audience!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -47,12 +47,12 @@
|
|||||||
30,
|
30,
|
||||||
60
|
60
|
||||||
],
|
],
|
||||||
"pricingAnalysis": "Prices show moderate volatility with a peak at 12 and a low at 3, indicating fluctuating demand. Overall trend is slightly upward with intermittent dips, suggesting cautious market optimism.",
|
"pricingAnalysis": "The market shows moderate volatility with prices fluctuating between 3 and 12. A peak at 12 suggests potential upward momentum, but inconsistent trends indicate uncertainty.",
|
||||||
"ratingsSummary": "Average rating is 4.3, indicating generally positive user feedback with minor variations in satisfaction.",
|
"ratingsSummary": "Consistently high ratings averaging around 4.3 indicate strong overall customer satisfaction with the product.",
|
||||||
"inventoryStatus": "Stock levels are moderately balanced, though the lowest item at 30 units may need restocking soon."
|
"inventoryStatus": "Stock levels are adequate overall, but the lowest item may need restocking soon to avoid shortages."
|
||||||
},
|
},
|
||||||
"productReview": {
|
"productReview": {
|
||||||
"reviewText": "Great selection of fruits with good prices and quality. Some items were out of stock.",
|
"reviewText": "Great selection of fruits with good prices and quality. Some items were out of stock.",
|
||||||
"analysis": "Key Information Extracted:\n\n- Positive Aspects:\n - Good selection of fruits\n - Competitive prices\n - High quality\n\n- Negative Aspects:\n - Some items were out of stock"
|
"analysis": "Here is the extracted key information from the product review:\n\n- Positive Aspects:\n - Wide/great selection of fruits\n - Good prices\n - High quality of products\n\n- Negative Aspects:\n - Some items were out of stock\n\nSummary:\nThe review praises the variety, affordability, and quality of the fruit selection but notes limited availability due to out-of-stock items."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -633,14 +633,7 @@
|
|||||||
"offset": 1193
|
"offset": 1193
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"manualAnalysisResult": {
|
"tempId": "analyze-me"
|
||||||
"keywords": [
|
|
||||||
"sunny weather",
|
|
||||||
"ideal",
|
|
||||||
"park walk"
|
|
||||||
],
|
|
||||||
"sentiment": "positive"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "heading",
|
"type": "heading",
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"importHelpers": false,
|
"importHelpers": false,
|
||||||
"inlineSourceMap": true,
|
"inlineSourceMap": true,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user