@far-world-labs/verblets 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +42 -0
- package/.husky/pre-commit +4 -0
- package/.release-it.json +9 -0
- package/.vite.config.examples.js +8 -0
- package/.vite.config.js +8 -0
- package/docker-compose.yml +7 -0
- package/docs/README.md +41 -0
- package/docs/babel.config.js +3 -0
- package/docs/blog/2019-05-28-first-blog-post.md +12 -0
- package/docs/blog/2019-05-29-long-blog-post.md +44 -0
- package/docs/blog/2021-08-01-mdx-blog-post.mdx +20 -0
- package/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- package/docs/blog/2021-08-26-welcome/index.md +25 -0
- package/docs/blog/authors.yml +17 -0
- package/docs/docs/api/bool.md +74 -0
- package/docs/docs/api/search.md +51 -0
- package/docs/docs/intro.md +47 -0
- package/docs/docs/tutorial-basics/_category_.json +8 -0
- package/docs/docs/tutorial-basics/congratulations.md +23 -0
- package/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
- package/docs/docs/tutorial-basics/create-a-document.md +57 -0
- package/docs/docs/tutorial-basics/create-a-page.md +43 -0
- package/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
- package/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
- package/docs/docs/tutorial-extras/_category_.json +7 -0
- package/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
- package/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
- package/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
- package/docs/docs/tutorial-extras/translate-your-site.md +88 -0
- package/docs/docusaurus.config.js +120 -0
- package/docs/package.json +44 -0
- package/docs/sidebars.js +31 -0
- package/docs/src/components/HomepageFeatures/index.js +61 -0
- package/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- package/docs/src/css/custom.css +30 -0
- package/docs/src/pages/index.js +43 -0
- package/docs/src/pages/index.module.css +23 -0
- package/docs/src/pages/markdown-page.md +7 -0
- package/docs/static/.nojekyll +0 -0
- package/docs/static/img/docusaurus-social-card.jpg +0 -0
- package/docs/static/img/docusaurus.png +0 -0
- package/docs/static/img/favicon.ico +0 -0
- package/docs/static/img/logo.svg +1 -0
- package/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- package/docs/static/img/undraw_docusaurus_react.svg +170 -0
- package/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- package/package.json +75 -0
- package/scripts/generate-chain/index.js +111 -0
- package/scripts/generate-lib/index.js +68 -0
- package/scripts/generate-test/index.js +111 -0
- package/scripts/generate-verblet/README.md +17 -0
- package/scripts/generate-verblet/index.js +110 -0
- package/scripts/run.sh +15 -0
- package/scripts/runner/index.js +30 -0
- package/scripts/simple-editor/README.md +34 -0
- package/scripts/simple-editor/index.js +68 -0
- package/scripts/summarize-files/index.js +46 -0
- package/src/chains/dismantle/dismantle.examples.js +0 -0
- package/src/chains/dismantle/index.examples.js +30 -0
- package/src/chains/dismantle/index.js +314 -0
- package/src/chains/dismantle/index.spec.js +33 -0
- package/src/chains/list/index.examples.js +72 -0
- package/src/chains/list/index.js +161 -0
- package/src/chains/list/index.spec.js +68 -0
- package/src/chains/list/schema.json +24 -0
- package/src/chains/questions/index.examples.js +68 -0
- package/src/chains/questions/index.js +136 -0
- package/src/chains/questions/index.spec.js +29 -0
- package/src/chains/scan-js/index.js +119 -0
- package/src/chains/sort/index.examples.js +40 -0
- package/src/chains/sort/index.js +113 -0
- package/src/chains/sort/index.spec.js +115 -0
- package/src/chains/summary-map/README.md +33 -0
- package/src/chains/summary-map/index.examples.js +57 -0
- package/src/chains/summary-map/index.js +208 -0
- package/src/chains/summary-map/index.spec.js +78 -0
- package/src/chains/test/index.js +118 -0
- package/src/chains/test-advice/index.js +36 -0
- package/src/constants/common.js +9 -0
- package/src/constants/messages.js +3 -0
- package/src/constants/openai.js +65 -0
- package/src/index.js +33 -0
- package/src/json-schemas/cars-test.json +11 -0
- package/src/json-schemas/index.js +18 -0
- package/src/json-schemas/intent.json +38 -0
- package/src/json-schemas/schema-dot-org-photograph.json +127 -0
- package/src/json-schemas/schema-dot-org-place.json +56 -0
- package/src/lib/any-signal/index.js +28 -0
- package/src/lib/chatgpt/index.js +143 -0
- package/src/lib/editor/index.js +31 -0
- package/src/lib/parse-js-parts/index.js +333 -0
- package/src/lib/parse-js-parts/index.spec.js +156 -0
- package/src/lib/path-aliases/index.js +39 -0
- package/src/lib/path-aliases/index.spec.js +70 -0
- package/src/lib/pave/index.js +34 -0
- package/src/lib/pave/index.spec.js +73 -0
- package/src/lib/prompt-cache/index.js +46 -0
- package/src/lib/retry/index.js +63 -0
- package/src/lib/retry/index.spec.js +86 -0
- package/src/lib/search-best-first/index.js +66 -0
- package/src/lib/search-js-files/code-features-property-definitions.json +123 -0
- package/src/lib/search-js-files/index.examples.js +22 -0
- package/src/lib/search-js-files/index.js +158 -0
- package/src/lib/search-js-files/index.spec.js +34 -0
- package/src/lib/search-js-files/scan-file.js +253 -0
- package/src/lib/shorten-text/index.js +30 -0
- package/src/lib/shorten-text/index.spec.js +68 -0
- package/src/lib/strip-numeric/index.js +5 -0
- package/src/lib/strip-response/index.js +35 -0
- package/src/lib/timed-abort-controller/index.js +41 -0
- package/src/lib/to-bool/index.js +8 -0
- package/src/lib/to-enum/index.js +14 -0
- package/src/lib/to-number/index.js +12 -0
- package/src/lib/to-number-with-units/index.js +51 -0
- package/src/lib/transcribe/index.js +61 -0
- package/src/prompts/README.md +15 -0
- package/src/prompts/as-enum.js +5 -0
- package/src/prompts/as-json-schema.js +9 -0
- package/src/prompts/as-object-with-schema.js +31 -0
- package/src/prompts/as-schema-org-text.js +17 -0
- package/src/prompts/as-schema-org-type.js +1 -0
- package/src/prompts/blog-post.js +7 -0
- package/src/prompts/code-features.js +28 -0
- package/src/prompts/constants.js +101 -0
- package/src/prompts/features-json-schema.js +27 -0
- package/src/prompts/generate-collection.js +26 -0
- package/src/prompts/generate-list.js +48 -0
- package/src/prompts/generate-questions.js +19 -0
- package/src/prompts/index.js +20 -0
- package/src/prompts/intent.js +66 -0
- package/src/prompts/output-succinct-names.js +3 -0
- package/src/prompts/select-from-threshold.js +18 -0
- package/src/prompts/sort.js +35 -0
- package/src/prompts/style.js +41 -0
- package/src/prompts/summarize.js +13 -0
- package/src/prompts/token-budget.js +3 -0
- package/src/prompts/wrap-list.js +14 -0
- package/src/prompts/wrap-variable.js +36 -0
- package/src/services/llm-model/index.js +114 -0
- package/src/services/llm-model/model.js +21 -0
- package/src/services/redis/index.js +84 -0
- package/src/verblets/auto/index.examples.js +28 -0
- package/src/verblets/auto/index.js +28 -0
- package/src/verblets/auto/index.spec.js +34 -0
- package/src/verblets/bool/index.examples.js +28 -0
- package/src/verblets/bool/index.js +28 -0
- package/src/verblets/bool/index.schema.json +14 -0
- package/src/verblets/bool/index.spec.js +35 -0
- package/src/verblets/enum/index.examples.js +33 -0
- package/src/verblets/enum/index.js +15 -0
- package/src/verblets/enum/index.spec.js +35 -0
- package/src/verblets/intent/index.examples.js +51 -0
- package/src/verblets/intent/index.js +72 -0
- package/src/verblets/intent/index.spec.js +31 -0
- package/src/verblets/number/index.examples.js +33 -0
- package/src/verblets/number/index.js +22 -0
- package/src/verblets/number/index.spec.js +35 -0
- package/src/verblets/number-with-units/index.examples.js +34 -0
- package/src/verblets/number-with-units/index.js +19 -0
- package/src/verblets/number-with-units/index.spec.js +46 -0
- package/src/verblets/schema-org/index.examples.js +56 -0
- package/src/verblets/schema-org/index.js +8 -0
- package/src/verblets/schema-org/index.spec.js +39 -0
- package/src/verblets/to-object/README.md +38 -0
- package/src/verblets/to-object/index.examples.js +29 -0
- package/src/verblets/to-object/index.js +136 -0
- package/src/verblets/to-object/index.spec.js +74 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createClient } from 'redis';
|
|
2
|
+
|
|
3
|
+
let client;
|
|
4
|
+
let constructingClient;
|
|
5
|
+
|
|
6
|
+
class NullRedisClient {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.store = {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async get(key) {
|
|
12
|
+
// Redis returns null, not undefined
|
|
13
|
+
return this.store[key] ?? null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async del(key) {
|
|
17
|
+
delete this.store[key];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async set(key, value) {
|
|
21
|
+
this.store[key] = value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// eslint-disable-next-line class-methods-use-this, no-empty-function
|
|
25
|
+
async disconnect() {
|
|
26
|
+
// no implementation
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const constructClient = async () => {
|
|
31
|
+
if (process.env.TEST === 'true' && process.env.EXAMPLES !== 'true') {
|
|
32
|
+
client = new NullRedisClient();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const redisClient = createClient({
|
|
37
|
+
host: process.env.REDIS_HOST ?? 'localhost',
|
|
38
|
+
port: process.env.REDIS_PORT ?? 6379,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
redisClient.on('error', (error) => {
|
|
42
|
+
if (client instanceof NullRedisClient) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (/ECONNREFUSED/.test(error.message)) {
|
|
47
|
+
console.error(
|
|
48
|
+
`Redis service [warning]: "${error.message}" Falling back to mock Redis client. This may incur greater usage costs and have slower response times.`
|
|
49
|
+
);
|
|
50
|
+
client = new NullRedisClient();
|
|
51
|
+
} else {
|
|
52
|
+
console.error(`Redis service [error]: ${error.message}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
redisClient.disconnect();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await redisClient.connect();
|
|
60
|
+
client = redisClient;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(
|
|
63
|
+
`Redis service create [warning]: "${error.message}" Falling back to mock Redis client. This may incur greater usage costs and have slower response times.`
|
|
64
|
+
);
|
|
65
|
+
client = new NullRedisClient();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const getClient = async () => {
|
|
70
|
+
if (client) {
|
|
71
|
+
return client;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!constructingClient) {
|
|
75
|
+
constructingClient = constructClient();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await constructingClient;
|
|
79
|
+
return client;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const setClient = (newClient) => {
|
|
83
|
+
client = newClient;
|
|
84
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import auto from './index.js';
|
|
4
|
+
|
|
5
|
+
const examples = [
|
|
6
|
+
{
|
|
7
|
+
inputs: { text: 'test' },
|
|
8
|
+
want: { result: true }
|
|
9
|
+
}
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
describe('Auto verblet', () => {
|
|
13
|
+
examples.forEach((example) => {
|
|
14
|
+
it(example.inputs.text, async () => {
|
|
15
|
+
const result = await auto(example.inputs.text)
|
|
16
|
+
|
|
17
|
+
if (example.want.typeOfResult) {
|
|
18
|
+
expect(typeof result)
|
|
19
|
+
.toStrictEqual(example.want.typeOfResult);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (example.want.result) {
|
|
23
|
+
expect(result)
|
|
24
|
+
.toStrictEqual(example.want.result);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
+
import toObject from '../../verblets/to-object/index.js';
|
|
3
|
+
import schemas from '../../json-schemas/index.js'
|
|
4
|
+
|
|
5
|
+
export default async (text, options={}) => {
|
|
6
|
+
const tools = schemas
|
|
7
|
+
.map(schema => ({
|
|
8
|
+
type: 'function',
|
|
9
|
+
function: schema
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
const functionFound = await chatGPT(text, {
|
|
13
|
+
modelOptions: {
|
|
14
|
+
// toolChoice: 'auto' // by default
|
|
15
|
+
tools,
|
|
16
|
+
},
|
|
17
|
+
...options
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const functionArgs = functionFound.arguments;
|
|
21
|
+
|
|
22
|
+
const functionArgsAsArray = Array.isArray(functionArgs) ? functionArgs : [functionArgs];
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
...functionFound,
|
|
26
|
+
functionArgsAsArray
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import auto from './index.js';
|
|
4
|
+
|
|
5
|
+
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
+
default: vi.fn().mockImplementation((text) => {
|
|
7
|
+
if (/prompt text to match/.test(text)) {
|
|
8
|
+
return 'True';
|
|
9
|
+
} else {
|
|
10
|
+
return 'undefined';
|
|
11
|
+
}
|
|
12
|
+
}),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
const examples = [
|
|
16
|
+
{
|
|
17
|
+
name: 'Basic usage',
|
|
18
|
+
inputs: { text: 'test' },
|
|
19
|
+
want: { result: true }
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
describe('Auto verblet', () => {
|
|
24
|
+
examples.forEach((example) => {
|
|
25
|
+
it(example.name, async () => {
|
|
26
|
+
const result = await auto(example.inputs.text);
|
|
27
|
+
|
|
28
|
+
if (example.want.typeOfResult) {
|
|
29
|
+
expect(typeof result)
|
|
30
|
+
.toStrictEqual(example.want.typeOfResult);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import bool from './index.js';
|
|
4
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
+
|
|
6
|
+
const examples = [
|
|
7
|
+
{
|
|
8
|
+
inputs: { text: 'Does Mace Windu have a blue lightsaber?' },
|
|
9
|
+
want: { result: false },
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
inputs: { text: 'Does Mace Windu have a purple lightsaber?' },
|
|
13
|
+
want: { result: true },
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe('Bool verblet', () => {
|
|
18
|
+
examples.forEach((example) => {
|
|
19
|
+
it(
|
|
20
|
+
`${example.inputs.text}`,
|
|
21
|
+
async () => {
|
|
22
|
+
const result = await bool(example.inputs.text);
|
|
23
|
+
expect(result).toStrictEqual(example.want.result);
|
|
24
|
+
},
|
|
25
|
+
longTestTimeout
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
+
import stripResponse from '../../lib/strip-response/index.js';
|
|
3
|
+
import toBool from '../../lib/to-bool/index.js';
|
|
4
|
+
import { constants as promptConstants } from '../../prompts/index.js';
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
asBool,
|
|
8
|
+
asUndefinedByDefault,
|
|
9
|
+
contentIsQuestion,
|
|
10
|
+
explainAndSeparate,
|
|
11
|
+
explainAndSeparatePrimitive,
|
|
12
|
+
} = promptConstants;
|
|
13
|
+
|
|
14
|
+
export default async (text, options={}) => {
|
|
15
|
+
const systemPrompt = `
|
|
16
|
+
${explainAndSeparate} ${explainAndSeparatePrimitive}
|
|
17
|
+
|
|
18
|
+
${asBool} ${asUndefinedByDefault}
|
|
19
|
+
`
|
|
20
|
+
const response = await chatGPT(text, {
|
|
21
|
+
modelOptions: {
|
|
22
|
+
systemPrompt,
|
|
23
|
+
},
|
|
24
|
+
...options,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return toBool(stripResponse(response));
|
|
28
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bool",
|
|
3
|
+
"description": "Interpret a question seen as a yes/no question, and return a boolean value answer.",
|
|
4
|
+
"parameters": {
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"text": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "A question to be answered."
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"required": ["text"]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import bool from './index.js';
|
|
4
|
+
|
|
5
|
+
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
+
default: vi.fn().mockImplementation((text) => {
|
|
7
|
+
if (/purple lightsaber/.test(text)) {
|
|
8
|
+
return 'True';
|
|
9
|
+
}
|
|
10
|
+
return 'False';
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
const examples = [
|
|
15
|
+
{
|
|
16
|
+
title: 'True values',
|
|
17
|
+
inputs: { text: 'Does Mace Windu have a purple lightsaber' },
|
|
18
|
+
want: { result: true },
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
title: 'False values',
|
|
22
|
+
inputs: { text: 'Does Mace Windu have a blue lightsaber' },
|
|
23
|
+
want: { result: false },
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
describe('bool verblet', () => {
|
|
28
|
+
examples.forEach((example) => {
|
|
29
|
+
it(example.name, async () => {
|
|
30
|
+
expect(await bool(example.inputs.text)).toStrictEqual(
|
|
31
|
+
example.want.result
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import enumValue from './index.js';
|
|
4
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
+
|
|
6
|
+
const examples = [
|
|
7
|
+
{
|
|
8
|
+
inputs: {
|
|
9
|
+
text: 'What is the top color on a traffic light',
|
|
10
|
+
enum: { green: 1, yellow: 1, red: 1, purple: 1 },
|
|
11
|
+
},
|
|
12
|
+
want: { result: 'red' },
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
describe('Enum verblet', () => {
|
|
17
|
+
examples.forEach((example) => {
|
|
18
|
+
it(
|
|
19
|
+
example.inputs.text,
|
|
20
|
+
async () => {
|
|
21
|
+
const result = await enumValue(
|
|
22
|
+
example.inputs.text,
|
|
23
|
+
example.inputs.enum
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (example.want.result) {
|
|
27
|
+
expect(result).toStrictEqual(example.want.result);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
longTestTimeout
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
+
import stripResponse from '../../lib/strip-response/index.js';
|
|
3
|
+
import toEnum from '../../lib/to-enum/index.js';
|
|
4
|
+
import { asEnum, constants } from '../../prompts/index.js';
|
|
5
|
+
|
|
6
|
+
const { asUndefinedByDefault, contentIsQuestion, explainAndSeparate } =
|
|
7
|
+
constants;
|
|
8
|
+
|
|
9
|
+
export default async (text, enumVal) => {
|
|
10
|
+
const enumText = `${contentIsQuestion} ${text}\n\n${explainAndSeparate}
|
|
11
|
+
|
|
12
|
+
${asEnum(enumVal)} ${asUndefinedByDefault}`;
|
|
13
|
+
|
|
14
|
+
return toEnum(stripResponse(await chatGPT(enumText)), enumVal);
|
|
15
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import enumValue from './index.js';
|
|
4
|
+
|
|
5
|
+
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
+
default: vi.fn().mockImplementation((text) => {
|
|
7
|
+
if (/traffic light/.test(text)) {
|
|
8
|
+
return 'red';
|
|
9
|
+
}
|
|
10
|
+
return 'undefined';
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
const examples = [
|
|
15
|
+
{
|
|
16
|
+
name: 'Basic usage',
|
|
17
|
+
inputs: {
|
|
18
|
+
text: 'What is the top color on a traffic light',
|
|
19
|
+
enum: { green: 1, yellow: 1, red: 1, purple: 1 },
|
|
20
|
+
},
|
|
21
|
+
want: { result: 'red' },
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
describe('Enum verblet', () => {
|
|
26
|
+
examples.forEach((example) => {
|
|
27
|
+
it(example.name, async () => {
|
|
28
|
+
const result = await enumValue(example.inputs.text, example.inputs.enum);
|
|
29
|
+
|
|
30
|
+
if (example.want.result) {
|
|
31
|
+
expect(result).toStrictEqual(example.want.result);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
6
|
+
import intent from './index.js';
|
|
7
|
+
|
|
8
|
+
const resultSchema = async () => {
|
|
9
|
+
return JSON.parse(await fs.readFile('./src/json-schemas/intent.json'));
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const examples = [
|
|
13
|
+
{
|
|
14
|
+
inputs: { text: 'Give me a flight to Burgas' },
|
|
15
|
+
want: { resultSchema },
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
inputs: {
|
|
19
|
+
text: 'Lookup a song by the quote \
|
|
20
|
+
"I just gotta tell you how I\'m feeling"',
|
|
21
|
+
},
|
|
22
|
+
want: { resultSchema },
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
describe('Intent verblet', () => {
|
|
27
|
+
examples.forEach((example) => {
|
|
28
|
+
it(
|
|
29
|
+
example.inputs.text,
|
|
30
|
+
async () => {
|
|
31
|
+
const result = await intent({ text: example.inputs.text });
|
|
32
|
+
|
|
33
|
+
if (example.want.resultSchema) {
|
|
34
|
+
const schema = await example.want.resultSchema();
|
|
35
|
+
const ajv = new Ajv();
|
|
36
|
+
const validate = ajv.compile(schema);
|
|
37
|
+
|
|
38
|
+
const isValid = validate(result);
|
|
39
|
+
if (!isValid) {
|
|
40
|
+
console.error('Validation errors:');
|
|
41
|
+
console.error(validate.errors);
|
|
42
|
+
console.error('Returned result:');
|
|
43
|
+
console.error(JSON.stringify(result, null, 2));
|
|
44
|
+
}
|
|
45
|
+
expect(isValid).toStrictEqual(true);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
longTestTimeout
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import enums from '../enum/index.js';
|
|
2
|
+
import toObject from '../to-object/index.js';
|
|
3
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
4
|
+
import stripResponse from '../../lib/strip-response/index.js';
|
|
5
|
+
|
|
6
|
+
import { constants, intent, wrapVariable } from '../../prompts/index.js';
|
|
7
|
+
|
|
8
|
+
const { contentHasIntent } = constants;
|
|
9
|
+
const example1 =
|
|
10
|
+
'The intent of "Buy me a flight to Burgas" might be "buy-flight"';
|
|
11
|
+
const example2 =
|
|
12
|
+
'The intent of "What is the tempature outside" might be "get-temperature"';
|
|
13
|
+
|
|
14
|
+
const enumPrompt = (text) => `${contentHasIntent} ${wrapVariable(text, {
|
|
15
|
+
tag: 'message',
|
|
16
|
+
})}
|
|
17
|
+
|
|
18
|
+
${wrapVariable(example1, { tag: 'example' })}
|
|
19
|
+
${wrapVariable(example2, { tag: 'example' })}`;
|
|
20
|
+
|
|
21
|
+
const completionIntent = (text) => ({
|
|
22
|
+
queryText: text,
|
|
23
|
+
intent: {
|
|
24
|
+
operation: 'completion',
|
|
25
|
+
displayName: 'Completion',
|
|
26
|
+
},
|
|
27
|
+
parameters: {
|
|
28
|
+
text,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export default async ({
|
|
33
|
+
text,
|
|
34
|
+
operations,
|
|
35
|
+
defaultIntent = completionIntent,
|
|
36
|
+
options,
|
|
37
|
+
} = {}) => {
|
|
38
|
+
let operationsFound;
|
|
39
|
+
let parametersFound;
|
|
40
|
+
if (operations) {
|
|
41
|
+
const operationsEnum = operations.reduce(
|
|
42
|
+
(acc, item, idx) => ({
|
|
43
|
+
...acc,
|
|
44
|
+
[item.name]: idx,
|
|
45
|
+
}),
|
|
46
|
+
{}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const operationNameFound = await enums(enumPrompt(text), operationsEnum);
|
|
50
|
+
|
|
51
|
+
const operationFound = operations.find(
|
|
52
|
+
(o) => o.name === operationNameFound
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (!operationFound) {
|
|
56
|
+
return defaultIntent(text);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
operationsFound = [operationFound.name];
|
|
60
|
+
parametersFound = operationFound.parameters;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const result = await chatGPT(
|
|
64
|
+
intent(text, {
|
|
65
|
+
operations: operationsFound,
|
|
66
|
+
parameters: parametersFound,
|
|
67
|
+
}),
|
|
68
|
+
options
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return toObject(stripResponse(result));
|
|
72
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import intent from './index.js';
|
|
4
|
+
|
|
5
|
+
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
+
default: vi.fn().mockImplementation((text) => {
|
|
7
|
+
if (/a flight to/.test(text)) {
|
|
8
|
+
return '{}';
|
|
9
|
+
}
|
|
10
|
+
return 'undefined';
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
const examples = [
|
|
15
|
+
{
|
|
16
|
+
name: 'Basic usage',
|
|
17
|
+
inputs: { text: 'Give me a flight to Burgas' },
|
|
18
|
+
want: { typeOfResult: 'object' },
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
describe('Intent verblet', () => {
|
|
23
|
+
examples.forEach((example) => {
|
|
24
|
+
it(example.name, async () => {
|
|
25
|
+
const result = await intent({ text: example.inputs.text });
|
|
26
|
+
if (example.want.typeOfResult) {
|
|
27
|
+
expect(typeof result).toStrictEqual(example.want.typeOfResult);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import number from './index.js';
|
|
4
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
+
|
|
6
|
+
const examples = [
|
|
7
|
+
{
|
|
8
|
+
inputs: { text: 'What is the height of Everest in feet' },
|
|
9
|
+
want: { result: 29029 },
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
inputs: { text: 'What is the length of the Nile in km' },
|
|
13
|
+
want: { result: 6650 },
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
inputs: { text: 'What is the my age in years' },
|
|
17
|
+
want: { result: undefined },
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
describe('Number verblet', () => {
|
|
22
|
+
examples.forEach((example) => {
|
|
23
|
+
it(
|
|
24
|
+
example.inputs.text,
|
|
25
|
+
async () => {
|
|
26
|
+
expect(await number(example.inputs.text)).toStrictEqual(
|
|
27
|
+
example.want.result
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
longTestTimeout
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
+
import stripResponse from '../../lib/strip-response/index.js';
|
|
3
|
+
import toNumber from '../../lib/to-number/index.js';
|
|
4
|
+
import { constants as promptConstants } from '../../prompts/index.js';
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
asNumber,
|
|
8
|
+
asUndefinedByDefault,
|
|
9
|
+
contentIsQuestion,
|
|
10
|
+
explainAndSeparate,
|
|
11
|
+
explainAndSeparatePrimitive,
|
|
12
|
+
} = promptConstants;
|
|
13
|
+
|
|
14
|
+
export default async (text) => {
|
|
15
|
+
const numberText = `${contentIsQuestion} ${text}
|
|
16
|
+
|
|
17
|
+
${explainAndSeparate} ${explainAndSeparatePrimitive}
|
|
18
|
+
|
|
19
|
+
${asNumber} ${asUndefinedByDefault}`;
|
|
20
|
+
|
|
21
|
+
return toNumber(stripResponse(await chatGPT(numberText)));
|
|
22
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import number from './index.js';
|
|
4
|
+
|
|
5
|
+
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
+
default: vi.fn().mockImplementation((text) => {
|
|
7
|
+
if (/Everest/.test(text)) {
|
|
8
|
+
return '29029';
|
|
9
|
+
}
|
|
10
|
+
return 'undefined';
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
const examples = [
|
|
15
|
+
{
|
|
16
|
+
name: 'Basic usage',
|
|
17
|
+
inputs: { text: 'What is the height of Everest in feet' },
|
|
18
|
+
want: { result: 29029 },
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'Unanswerable question',
|
|
22
|
+
inputs: { text: 'What is the my age in years' },
|
|
23
|
+
want: { result: undefined },
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
describe('Number verblet', () => {
|
|
28
|
+
examples.forEach((example) => {
|
|
29
|
+
it(example.name, async () => {
|
|
30
|
+
expect(await number(example.inputs.text)).toStrictEqual(
|
|
31
|
+
example.want.result
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import numberWithUnits from './index.js';
|
|
4
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
+
|
|
6
|
+
const examples = [
|
|
7
|
+
{
|
|
8
|
+
inputs: { text: 'What is the height of Everest in feet' },
|
|
9
|
+
want: { value: 29029, unit: 'feet' },
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
inputs: { text: 'What is my age in years' },
|
|
13
|
+
want: { value: undefined, unit: 'years' },
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe('Number with units verblet', () => {
|
|
18
|
+
examples.forEach((example) => {
|
|
19
|
+
it(
|
|
20
|
+
example.inputs.text,
|
|
21
|
+
async () => {
|
|
22
|
+
const result = await numberWithUnits(example.inputs.text);
|
|
23
|
+
|
|
24
|
+
if (example.want.value) {
|
|
25
|
+
expect(result?.value).toStrictEqual(example.want.value);
|
|
26
|
+
}
|
|
27
|
+
if (example.want.unit) {
|
|
28
|
+
expect(result?.unit).toStrictEqual(example.want.unit);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
longTestTimeout
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
+
import stripResponse from '../../lib/strip-response/index.js';
|
|
3
|
+
import toNumberWithUnits from '../../lib/to-number-with-units/index.js';
|
|
4
|
+
import { constants as promptConstants } from '../../prompts/index.js';
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
asNumberWithUnits,
|
|
8
|
+
contentIsQuestion,
|
|
9
|
+
explainAndSeparate,
|
|
10
|
+
explainAndSeparateJSON,
|
|
11
|
+
} = promptConstants;
|
|
12
|
+
|
|
13
|
+
export default async (text) => {
|
|
14
|
+
const numberText = `${contentIsQuestion} ${text} \n\n${explainAndSeparate} ${explainAndSeparateJSON}
|
|
15
|
+
|
|
16
|
+
${asNumberWithUnits}`;
|
|
17
|
+
|
|
18
|
+
return toNumberWithUnits(stripResponse(await chatGPT(numberText)));
|
|
19
|
+
};
|