ai-functions 0.1.4 → 0.2.0
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/LICENSE +21 -0
- package/README.md +7 -6
- package/db/cache.ts +6 -0
- package/db/mongo.ts +75 -0
- package/examples/data.ts +1105 -0
- package/functions/ai.test.ts +31 -0
- package/functions/ai.ts +99 -0
- package/functions/gpt.ts +12 -0
- package/functions/list.ts +84 -0
- package/index.ts +3 -0
- package/package.json +23 -6
- package/queue/memory.ts +0 -0
- package/queue/mongo.ts +88 -0
- package/streams/kafka.ts +0 -0
- package/streams/memory.ts +0 -0
- package/streams/mongo.ts +0 -0
- package/streams/types.ts +0 -0
- package/tsconfig.json +105 -0
- package/types.ts +12 -0
- package/utils/completion.ts +28 -0
- package/utils/schema.test.ts +69 -0
- package/utils/schema.ts +62 -0
- package/utils/state.ts +23 -0
- package/example.js +0 -38
- package/fetcher.js +0 -48
- package/functions/generateBlogPost.js +0 -12
- package/functions/generateLandingPage.js +0 -11
- package/functions/generatePossibleBlogPostTitles.js +0 -11
- package/index.js +0 -3
- package/index.test.js +0 -64
- package/proxy.js +0 -121
- package/schema.js +0 -50
- package/withAI.js +0 -8
- /package/{test.d.ts → queue/kafka.ts} +0 -0
package/utils/schema.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { JSONSchema7 } from 'json-schema-to-ts'
|
|
2
|
+
|
|
3
|
+
// This is a helper function to generate a JSON schema for string properties.
|
|
4
|
+
// It checks if a string includes '|' which would indicate an enum,
|
|
5
|
+
// or if it starts with 'number: ' or 'boolean: ' which would indicate
|
|
6
|
+
// a number or boolean type respectively, otherwise it defaults to string.
|
|
7
|
+
export const parseStringDescription = (description: string): JSONSchema7 => {
|
|
8
|
+
// Check if the description indicates an enum for string type
|
|
9
|
+
if (description.includes('|')) {
|
|
10
|
+
return { type: 'string', enum: description.split('|').map((v) => v.trim()) }
|
|
11
|
+
} else {
|
|
12
|
+
// Check for 'number: ' prefix
|
|
13
|
+
if (description.startsWith('number: ')) {
|
|
14
|
+
return {
|
|
15
|
+
type: 'number',
|
|
16
|
+
description: description.replace('number: ', ''),
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Check for 'boolean: ' prefix
|
|
20
|
+
else if (description.startsWith('boolean: ')) {
|
|
21
|
+
return {
|
|
22
|
+
type: 'boolean',
|
|
23
|
+
description: description.replace('boolean: ', ''),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Default to string type
|
|
27
|
+
else {
|
|
28
|
+
return { type: 'string', description }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Given a property description object, generate a JSON schema.
|
|
35
|
+
*
|
|
36
|
+
* @param propDescriptions - A record object with keys as property names
|
|
37
|
+
* and values as descriptions or nested property description objects.
|
|
38
|
+
* @returns A JSON schema object based on the provided descriptions.
|
|
39
|
+
*/
|
|
40
|
+
export const generateSchema = (propDescriptions: Record<string, string | Record<string, any>>): JSONSchema7 => {
|
|
41
|
+
// If the propDescriptions is for an object structure
|
|
42
|
+
if (typeof propDescriptions !== 'object' || propDescriptions === null || Array.isArray(propDescriptions)) {
|
|
43
|
+
throw new Error('The propDescriptions parameter should be an object.')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const properties: Record<string, JSONSchema7> = {}
|
|
47
|
+
const required: string[] = Object.keys(propDescriptions)
|
|
48
|
+
|
|
49
|
+
for (const [key, description] of Object.entries(propDescriptions)) {
|
|
50
|
+
if (typeof description === 'string') {
|
|
51
|
+
// Handle the string description
|
|
52
|
+
properties[key] = parseStringDescription(description)
|
|
53
|
+
} else if (typeof description === 'object' && !Array.isArray(description)) {
|
|
54
|
+
// Recursive call for nested objects
|
|
55
|
+
properties[key] = generateSchema(description)
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error(`Invalid description for key "${key}".`)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { type: 'object', properties, required }
|
|
62
|
+
}
|
package/utils/state.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createMachine, createActor } from 'xstate'
|
|
2
|
+
|
|
3
|
+
// Stateless machine definition
|
|
4
|
+
// machine.transition(...) is a pure function used by the interpreter.
|
|
5
|
+
const toggleMachine = createMachine({
|
|
6
|
+
id: 'Switch',
|
|
7
|
+
initial: 'inactive',
|
|
8
|
+
states: {
|
|
9
|
+
inactive: { on: { Toggle: 'active' } },
|
|
10
|
+
active: { on: { Toggle: 'inactive' } },
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
// Machine instance with internal state
|
|
15
|
+
const toggleService = createActor(toggleMachine).start()
|
|
16
|
+
toggleService.subscribe((state) => console.log(state.value))
|
|
17
|
+
// => 'inactive'
|
|
18
|
+
|
|
19
|
+
toggleService.send({ type: 'Toggle' })
|
|
20
|
+
// => 'active'
|
|
21
|
+
|
|
22
|
+
toggleService.send({ type: 'Toggle' })
|
|
23
|
+
// => 'inactive'
|
package/example.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { AI } from './proxy.js'
|
|
2
|
-
|
|
3
|
-
const { ai, list, gpt } = AI()
|
|
4
|
-
|
|
5
|
-
for await (const item of list`synonyms for "fun"`) {
|
|
6
|
-
console.log(item)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
for await (const item of list`fun things to do in Miami`) {
|
|
11
|
-
console.log(item)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const listBlogPosts = (count, topic) => list`${count} blog post titles about ${topic}`
|
|
15
|
-
const writeBlogPost = title => gpt`write a blog post in markdown starting with "# ${title}"`
|
|
16
|
-
|
|
17
|
-
async function* writeBlog(count, topic) {
|
|
18
|
-
for await (const title of listBlogPosts(count, topic)) {
|
|
19
|
-
const contentPromise = writeBlogPost(title).then(content => {
|
|
20
|
-
console.log({ title, content })
|
|
21
|
-
return { title, content }
|
|
22
|
-
})
|
|
23
|
-
yield { title, contentPromise }
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
for await (const post of writeBlog(3, 'future of car sales')) {
|
|
28
|
-
console.log({ post })
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const product = await ai.categorizeProduct({
|
|
32
|
-
productType: 'App | API | Marketplace | Platform | Packaged Service | Professional Service | Website',
|
|
33
|
-
customer: 'ideal customer profile in 3-5 words',
|
|
34
|
-
solution: 'describe the offer in 4-10 words',
|
|
35
|
-
description: 'website meta description',
|
|
36
|
-
})({ domain: 'OpenSaaS.org' })
|
|
37
|
-
|
|
38
|
-
console.log({ product })
|
package/fetcher.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const headers = {
|
|
2
|
-
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
|
|
3
|
-
'Content-Type': 'application/json',
|
|
4
|
-
}
|
|
5
|
-
const openaiFetch = obj => fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(obj) }).then(res => res.json())
|
|
6
|
-
|
|
7
|
-
const openaiStream = obj => fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(obj) })
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const response = await openaiStream({
|
|
11
|
-
model: 'gpt-3.5-turbo',
|
|
12
|
-
messages: [{ role: 'user', content: 'Tell me a funny joke about OpenAI' }],
|
|
13
|
-
stream: true
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
const decoder = new TextDecoder('utf-8')
|
|
17
|
-
let completion = ''
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
for await (const chunk of response.body) {
|
|
21
|
-
let done = false
|
|
22
|
-
const currentChunk = decoder.decode(chunk)
|
|
23
|
-
const lines = currentChunk.split('\n').filter(Boolean)
|
|
24
|
-
// console.log(lines)
|
|
25
|
-
for (const line of lines) {
|
|
26
|
-
if (line.includes('[DONE]')) {
|
|
27
|
-
done = true
|
|
28
|
-
break
|
|
29
|
-
}
|
|
30
|
-
try {
|
|
31
|
-
const data = JSON.parse(line.replace('data: ', ''))
|
|
32
|
-
if (data.choices[0].delta.content) {
|
|
33
|
-
const deltaContent = data.choices[0].delta.content
|
|
34
|
-
completion += deltaContent
|
|
35
|
-
console.log(deltaContent)
|
|
36
|
-
}
|
|
37
|
-
// console.log(chunks)
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.log(error.message, line)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (done) break
|
|
43
|
-
}
|
|
44
|
-
} catch (err) {
|
|
45
|
-
console.error(err.stack);
|
|
46
|
-
}
|
|
47
|
-
console.log({ completion })
|
|
48
|
-
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export const generateBlogPost = {
|
|
2
|
-
name: 'generateBlogPost',
|
|
3
|
-
description: 'Generate high-converting marketing content for a landing page',
|
|
4
|
-
parameters: {
|
|
5
|
-
type: 'object',
|
|
6
|
-
properties: {
|
|
7
|
-
title: { type: 'string', description: 'The title of the Blog Post' },
|
|
8
|
-
tags: { type: 'array', items: { type: 'string' } },
|
|
9
|
-
markdown: { type: 'string', description: 'The content of the Blog Post in Markdown format' },
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export const generateLandingPage = {
|
|
2
|
-
name: 'generateLandingPage',
|
|
3
|
-
description: 'Generate high-converting marketing content for a landing page',
|
|
4
|
-
parameters: {
|
|
5
|
-
type: 'object',
|
|
6
|
-
properties: {
|
|
7
|
-
title: { type: 'string', description: 'The title of the landing page' },
|
|
8
|
-
description: { type: 'string', description: 'The description of the landing page' },
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export const generateLandingPage = {
|
|
2
|
-
name: 'generateLandingPage',
|
|
3
|
-
description: 'Generate high-converting marketing content for a landing page',
|
|
4
|
-
parameters: {
|
|
5
|
-
type: 'object',
|
|
6
|
-
properties: {
|
|
7
|
-
titles: { type: 'array', items: { type: 'string' }, description: 'The title of the landing page' },
|
|
8
|
-
description: { type: 'string', description: 'The description of the landing page' },
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
package/index.js
DELETED
package/index.test.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { describe, test, it, expect } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { AI } from './index.js'
|
|
4
|
-
const { ai, list, gpt } = AI()
|
|
5
|
-
|
|
6
|
-
test('Math.sqrt()', () => {
|
|
7
|
-
expect(Math.sqrt(4)).toBe(2)
|
|
8
|
-
expect(Math.sqrt(144)).toBe(12)
|
|
9
|
-
expect(Math.sqrt(2)).toBe(Math.SQRT2)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test('getJsonSchema', () => {
|
|
13
|
-
|
|
14
|
-
const jsonSchema = schema({
|
|
15
|
-
name: 'The name of the person',
|
|
16
|
-
age: 'The age of the person'
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
expect(jsonSchema).toEqual({
|
|
20
|
-
type: 'object',
|
|
21
|
-
properties: {
|
|
22
|
-
name: { type: 'string', description: 'The name of the person' },
|
|
23
|
-
age: { type: 'string', description: 'The age of the person' } },
|
|
24
|
-
required: ['name', 'age']
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('list', () => {
|
|
30
|
-
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('ai', () => {
|
|
34
|
-
expect(ai.writeLandingPage({
|
|
35
|
-
brand: 'Auto.dev',
|
|
36
|
-
audience: 'developers',
|
|
37
|
-
offers: 'Automotive Data APIs',
|
|
38
|
-
})).toEqual({
|
|
39
|
-
functionName: 'writeLandingPage',
|
|
40
|
-
args: {
|
|
41
|
-
brand: 'Auto.dev',
|
|
42
|
-
audience: 'developers',
|
|
43
|
-
offers: 'Automotive Data APIs',
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
// AI('writeLandingPage', ({ title, description, heroTitle, heroDescription, featuresTitle, featuresDescription }) =>
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('A thing', () => {
|
|
51
|
-
it('should work', () => {
|
|
52
|
-
expect(3).toBe(3)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('should be ok', () => {
|
|
56
|
-
expect(2).toBe(2)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
describe('a nested thing', () => {
|
|
60
|
-
it('should work', () => {
|
|
61
|
-
expect(3).toBe(3)
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
})
|
package/proxy.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
// import { OpenAI } from 'openai'
|
|
2
|
-
// import camelcaseKeys from 'camelcase-keys'
|
|
3
|
-
import { dump } from 'js-yaml'
|
|
4
|
-
import { schema } from './schema.js'
|
|
5
|
-
|
|
6
|
-
export const AI = opts => {
|
|
7
|
-
const { system, model = 'gpt-3.5-turbo', apiKey, OPENAI_API_KEY, ...rest } = opts || {}
|
|
8
|
-
|
|
9
|
-
// const openai = new OpenAI({ apiKey: apiKey ?? OPENAI_API_KEY, ...rest })
|
|
10
|
-
const headers = {
|
|
11
|
-
'Authorization': `Bearer ${apiKey ?? OPENAI_API_KEY ?? globalThis.process?.env?.OPENAI_API_KEY}`,
|
|
12
|
-
'Content-Type': 'application/json',
|
|
13
|
-
}
|
|
14
|
-
const openaiFetch = obj => fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(obj) }).then(res => res.json())
|
|
15
|
-
|
|
16
|
-
const gpt = async (strings, ...values) => {
|
|
17
|
-
const user = values.map((value, i) => strings[i] + value).join('') + strings[strings.length - 1]
|
|
18
|
-
const prompt = {
|
|
19
|
-
model,
|
|
20
|
-
messages: [
|
|
21
|
-
{ role: 'user', content: user },
|
|
22
|
-
],
|
|
23
|
-
}
|
|
24
|
-
if (system) prompt.messages.unshift({ role: 'system', content: system })
|
|
25
|
-
const completion = await openaiFetch(prompt)
|
|
26
|
-
return completion.choices?.[0].message.content
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const ai = new Proxy({}, {
|
|
30
|
-
get: (target, functionName, receiver) => {
|
|
31
|
-
return (returnSchema, options) => async args => {
|
|
32
|
-
console.log(schema(returnSchema))
|
|
33
|
-
const { system, description, model = 'gpt-3.5-turbo', meta = false, ...rest } = options || {}
|
|
34
|
-
const prompt = {
|
|
35
|
-
model,
|
|
36
|
-
messages: [
|
|
37
|
-
{ role: 'user', content: `Call ${functionName} given the context:\n${dump(args)}` }, // \nThere is no additional information, so make assumptions/guesses as necessary` },
|
|
38
|
-
],
|
|
39
|
-
functions: [{
|
|
40
|
-
name: functionName,
|
|
41
|
-
description,
|
|
42
|
-
parameters: schema(returnSchema),
|
|
43
|
-
}],
|
|
44
|
-
...rest,
|
|
45
|
-
}
|
|
46
|
-
if (system) prompt.messages.unshift({ role: 'system', content: system })
|
|
47
|
-
const completion = await openaiFetch(prompt)
|
|
48
|
-
let data, error
|
|
49
|
-
const { message } = completion.choices?.[0]
|
|
50
|
-
prompt.messages.push(message)
|
|
51
|
-
const { content, function_call } = message
|
|
52
|
-
if (function_call) {
|
|
53
|
-
try {
|
|
54
|
-
data = JSON.parse(function_call.arguments)
|
|
55
|
-
} catch (err) {
|
|
56
|
-
error = err.message
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const gpt4 = model.includes('gpt-4')
|
|
60
|
-
const cost = Math.round((gpt4
|
|
61
|
-
? completion.usage.prompt_tokens * 0.003 + completion.usage.completion_tokens * 0.006
|
|
62
|
-
: completion.usage.prompt_tokens * 0.00015 + completion.usage.completion_tokens * 0.0002) * 100000) / 100000
|
|
63
|
-
// completion.usage = camelcaseKeys(completion.usage)
|
|
64
|
-
console.log({ data, content, error, cost })
|
|
65
|
-
return meta ? { prompt, content, data, error, cost, ...completion } : data ?? content
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
async function* list(strings, ...values) {
|
|
71
|
-
const listPrompt = values.map((value, i) => strings[i] + value).join('') + strings[strings.length - 1]
|
|
72
|
-
const prompt = {
|
|
73
|
-
model,
|
|
74
|
-
messages: [{ role: 'user', content: 'List ' + listPrompt }],
|
|
75
|
-
stream: true,
|
|
76
|
-
}
|
|
77
|
-
if (system) prompt.messages.unshift({ role: 'system', content: system })
|
|
78
|
-
const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(prompt) })
|
|
79
|
-
const decoder = new TextDecoder('utf-8')
|
|
80
|
-
|
|
81
|
-
let content = ''
|
|
82
|
-
let seperator = undefined
|
|
83
|
-
let numberedList = undefined
|
|
84
|
-
|
|
85
|
-
for await (const chunk of response.body) {
|
|
86
|
-
const lines = decoder.decode(chunk).split('\n').filter(Boolean)
|
|
87
|
-
for (const line of lines) {
|
|
88
|
-
try {
|
|
89
|
-
if (line.includes('[DONE]')) break
|
|
90
|
-
const part = JSON.parse(line.replace('data: ', ''))
|
|
91
|
-
const { delta, finish_reason } = part.choices[0]
|
|
92
|
-
content += delta?.content || ''
|
|
93
|
-
if (seperator === undefined && content.length > 4) {
|
|
94
|
-
numberedList = content.match(/(\d+\.\s)/g)
|
|
95
|
-
seperator = numberedList ? '\n' : ', '
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const numberedRegex = /\d+\.\s(?:")?([^"]+)(?:")?/
|
|
99
|
-
|
|
100
|
-
if (content.includes(seperator)) {
|
|
101
|
-
// get the string before the newline, and modify `content` to be the string after the newline
|
|
102
|
-
// then yield the string before the newline
|
|
103
|
-
const items = content.split(seperator)
|
|
104
|
-
while (items.length > 1) {
|
|
105
|
-
const item = items.shift()
|
|
106
|
-
yield numberedList ? item.match(numberedRegex)?.[1] : item
|
|
107
|
-
}
|
|
108
|
-
content = items[0]
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (finish_reason) yield numberedList ? content.match(numberedRegex)?.[1] : content
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.log(error.message, line)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return { ai, list, gpt }
|
|
121
|
-
}
|
package/schema.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
export const schema = propDescriptions => {
|
|
2
|
-
// assume an object like this: { name: 'The name of the person', age: 'The age of the person' }
|
|
3
|
-
// return an object like this: { type: 'object', properties: { name: { type: 'string', description: 'The name of the person' }, age: { type: 'number', description: 'The age of the person' } } required: ['name', 'age'] }
|
|
4
|
-
if (Array.isArray(propDescriptions)) {
|
|
5
|
-
const [ itemValue ] = propDescriptions
|
|
6
|
-
const itemType = typeof itemValue
|
|
7
|
-
if (itemType == 'string') {
|
|
8
|
-
return { type: 'array', description: itemValue, items: { type: 'string' }}
|
|
9
|
-
} else if (itemType == 'object') {
|
|
10
|
-
const { _description, itemSchema } = itemValue
|
|
11
|
-
return { type: 'array', description: _description, items: schema(itemSchema)}
|
|
12
|
-
}
|
|
13
|
-
} else {
|
|
14
|
-
const properties = Object.entries(propDescriptions).reduce((acc, [key, value]) => {
|
|
15
|
-
const type = typeof value
|
|
16
|
-
if (Array.isArray(value)) {
|
|
17
|
-
const [ itemValue ] = value
|
|
18
|
-
const itemType = typeof itemValue
|
|
19
|
-
if (itemType == 'string') {
|
|
20
|
-
if (itemValue.includes('|')) {
|
|
21
|
-
acc[key] = { type: 'string', enum: itemValue.split('|').map(value => value.trim()) }
|
|
22
|
-
} else {
|
|
23
|
-
acc[key] = { type: 'array', description: itemValue, items: { type: 'string' }}
|
|
24
|
-
}
|
|
25
|
-
} else if (itemType == 'object') {
|
|
26
|
-
// const { _description, itemSchema } = itemValue
|
|
27
|
-
const description = itemValue._description ? `${itemValue._description}` : undefined
|
|
28
|
-
if (description) delete itemValue._description
|
|
29
|
-
acc[key] = { type: 'array', description, items: schema(itemValue)}
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
if (type == 'string') {
|
|
33
|
-
if (value.includes('|')) {
|
|
34
|
-
acc[key] = { type: 'string', enum: value.split('|').map(value => value.trim()) }
|
|
35
|
-
} else {
|
|
36
|
-
acc[key] = { type, description: value }
|
|
37
|
-
}
|
|
38
|
-
} else if (type == 'object') {
|
|
39
|
-
if (value._description) value._description = undefined
|
|
40
|
-
acc[key] = schema(value)
|
|
41
|
-
} else {
|
|
42
|
-
acc[key] = { type, description: value }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return acc
|
|
46
|
-
}, {})
|
|
47
|
-
const required = Object.keys(properties)
|
|
48
|
-
return { type: 'object', properties, required }
|
|
49
|
-
}
|
|
50
|
-
}
|
package/withAI.js
DELETED
|
File without changes
|