aimyapi 0.1.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/.prettierrc +3 -0
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/dist/example/example1.d.ts +1 -0
- package/dist/example/example1.js +52 -0
- package/dist/example/example2.d.ts +1 -0
- package/dist/example/example2.js +66 -0
- package/dist/example/example3.d.ts +1 -0
- package/dist/example/example3.js +79 -0
- package/dist/example/ordering_api.d.ts +36 -0
- package/dist/example/ordering_api.js +125 -0
- package/dist/example/ordering_api_impl.d.ts +23 -0
- package/dist/example/ordering_api_impl.js +128 -0
- package/dist/example/sales_api.d.ts +16 -0
- package/dist/example/sales_api.js +5 -0
- package/dist/example/sales_api_impl.d.ts +7 -0
- package/dist/example/sales_api_impl.js +59 -0
- package/dist/lib/index.d.ts +26 -0
- package/dist/lib/index.js +179 -0
- package/dist/lib/sandbox-wrappers.d.ts +9 -0
- package/dist/lib/sandbox-wrappers.js +237 -0
- package/dist/lib/sandbox.d.ts +14 -0
- package/dist/lib/sandbox.js +161 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +7 -0
- package/example/example1.ts +33 -0
- package/example/example2.ts +50 -0
- package/example/example3.ts +64 -0
- package/example/ordering_api.md +106 -0
- package/example/ordering_api.ts +194 -0
- package/example/ordering_api_impl.ts +194 -0
- package/example/sales_api.md +15 -0
- package/example/sales_api.ts +29 -0
- package/example/sales_api_impl.ts +60 -0
- package/lib/index.ts +247 -0
- package/lib/sandbox-wrappers.ts +250 -0
- package/lib/sandbox.ts +184 -0
- package/lib/utils.ts +3 -0
- package/package.json +41 -0
- package/prompts/create-task-prompt.md +21 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ChatCompletionRequestMessage } from "openai";
|
|
2
|
+
import { delay } from "../lib/utils";
|
|
3
|
+
import {
|
|
4
|
+
Customization,
|
|
5
|
+
Menu,
|
|
6
|
+
MenuItemBase,
|
|
7
|
+
OrderingAPIInterface,
|
|
8
|
+
} from "./ordering_api";
|
|
9
|
+
|
|
10
|
+
// TODO: make functions to print out an item, and print out the current order with the price totals.
|
|
11
|
+
|
|
12
|
+
export class OrderingAPI implements OrderingAPIInterface {
|
|
13
|
+
private _order: MenuItemBase[] = [];
|
|
14
|
+
private _lastOrderIdNumber: number = 0;
|
|
15
|
+
public _isCompleted:boolean = false;
|
|
16
|
+
|
|
17
|
+
private _history: ChatCompletionRequestMessage[] = [];
|
|
18
|
+
|
|
19
|
+
// Mock implementation, doesn't actually send an email
|
|
20
|
+
sendEmail(to: string, subject: string, body: string): Promise<void> {
|
|
21
|
+
console.log(
|
|
22
|
+
`Sending email to "${to}" with subject "${subject}" and body\n"${body}"`
|
|
23
|
+
);
|
|
24
|
+
return delay(1000);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
respondToUser(text: string): void {
|
|
28
|
+
console.log(text);
|
|
29
|
+
this._history.push({
|
|
30
|
+
role: "assistant",
|
|
31
|
+
content: "Response output: " + text,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
delay(milliseconds: number): Promise<void> {
|
|
36
|
+
return delay(milliseconds);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getCurrentOrder(): MenuItemBase[] {
|
|
40
|
+
return this._order;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// addItemToOrder(item: MenuItemBase) {
|
|
44
|
+
// item.orderId = "" + (this._lastOrderIdNumber++);
|
|
45
|
+
// this._order.push(item);
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
getCustomizationByName(
|
|
49
|
+
itemName: string,
|
|
50
|
+
name: string
|
|
51
|
+
): Customization | undefined {
|
|
52
|
+
const item = Menu.find((item) => item.name === itemName);
|
|
53
|
+
if (!item) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return item.allowedCustomizations.find(
|
|
58
|
+
(customization) => customization.name === name
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
addItemToOrder(
|
|
63
|
+
itemName: string,
|
|
64
|
+
customizationNames: string[],
|
|
65
|
+
toppings: string[]
|
|
66
|
+
) {
|
|
67
|
+
const item = Menu.find((item) => item.name === itemName);
|
|
68
|
+
if (!item) {
|
|
69
|
+
throw new Error(`Item with name "${itemName}" not found`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const customizations = customizationNames
|
|
73
|
+
.map((customizationName) => {
|
|
74
|
+
return this.getCustomizationByName(itemName, customizationName);
|
|
75
|
+
})
|
|
76
|
+
.filter(
|
|
77
|
+
(customization) => customization !== undefined
|
|
78
|
+
) as Customization[];
|
|
79
|
+
|
|
80
|
+
const newItem = {
|
|
81
|
+
...item,
|
|
82
|
+
customizations,
|
|
83
|
+
toppings: toppings,
|
|
84
|
+
orderId: "" + this._lastOrderIdNumber++,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
this._order.push(newItem);
|
|
88
|
+
|
|
89
|
+
this.respondToUser(`Added ${itemName} with id ${newItem.orderId}`);
|
|
90
|
+
this.displayItem(newItem);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getItemInOrder(itemOrderId: string): MenuItemBase {
|
|
94
|
+
const item = this._order.find((item) => item.orderId === itemOrderId);
|
|
95
|
+
if (!item) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return item;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
removeItemFromOrder(itemOrderId: string) {
|
|
103
|
+
this._order = this._order.filter((item) => item.orderId !== itemOrderId);
|
|
104
|
+
|
|
105
|
+
this.respondToUser(`Removed item ${itemOrderId}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
modifyItemInOrder(
|
|
109
|
+
itemOrderId: string,
|
|
110
|
+
customizationNames: string[],
|
|
111
|
+
toppings: string[]
|
|
112
|
+
) {
|
|
113
|
+
const existingIndex = this._order.findIndex(
|
|
114
|
+
(item) => item.orderId === itemOrderId
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (existingIndex !== -1) {
|
|
118
|
+
const customizations = customizationNames
|
|
119
|
+
.map((customizationName) => {
|
|
120
|
+
return this.getCustomizationByName(
|
|
121
|
+
this._order[existingIndex].name,
|
|
122
|
+
customizationName
|
|
123
|
+
);
|
|
124
|
+
})
|
|
125
|
+
.filter(
|
|
126
|
+
(customization) => customization !== undefined
|
|
127
|
+
) as Customization[];
|
|
128
|
+
|
|
129
|
+
this._order[existingIndex].customizations = customizations;
|
|
130
|
+
this._order[existingIndex].toppings = toppings;
|
|
131
|
+
} else {
|
|
132
|
+
throw new Error(`Item with id #"${itemOrderId}" not found in order`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.respondToUser(`Modified item ${itemOrderId}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getOrderTotal() {
|
|
139
|
+
const total = this._order.reduce((total, item) => {
|
|
140
|
+
const customizationTotal = item.customizations.reduce(
|
|
141
|
+
(total, customization) => {
|
|
142
|
+
return total + customization?.priceAdjustment || 0;
|
|
143
|
+
},
|
|
144
|
+
0
|
|
145
|
+
);
|
|
146
|
+
return total + item.price + customizationTotal;
|
|
147
|
+
}, 0);
|
|
148
|
+
|
|
149
|
+
return total;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
completeOrder(): void {
|
|
153
|
+
this.displayOrder();
|
|
154
|
+
this.respondToUser("Order completed!");
|
|
155
|
+
|
|
156
|
+
this._lastOrderIdNumber = 0;
|
|
157
|
+
// clear history
|
|
158
|
+
this._history = []
|
|
159
|
+
|
|
160
|
+
this._isCompleted = true;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
displayItem(item: MenuItemBase) {
|
|
164
|
+
this.respondToUser(
|
|
165
|
+
`\t#${item.orderId || ""} ${item.name}...\t\t$${item.price.toFixed(2)}`
|
|
166
|
+
);
|
|
167
|
+
item.toppings.forEach((topping) => {
|
|
168
|
+
this.respondToUser(`\t\t${topping}`);
|
|
169
|
+
});
|
|
170
|
+
item.customizations.forEach((customization) => {
|
|
171
|
+
this.respondToUser(
|
|
172
|
+
`\t\t${customization.name}...\t$${customization.priceAdjustment.toFixed(
|
|
173
|
+
2
|
|
174
|
+
)}`
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
displayOrder() {
|
|
180
|
+
this.respondToUser("----\n\nDisplaying order:\n\n");
|
|
181
|
+
this._order.forEach((item) => this.displayItem(item));
|
|
182
|
+
this.respondToUser(`--\tTotal:\t\t$${this.getOrderTotal()}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
_addMessageToHistory(message: ChatCompletionRequestMessage) {
|
|
186
|
+
this._history.push(message);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_getHistory(): ChatCompletionRequestMessage[] {
|
|
190
|
+
return this._history;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const API_VERSION="1.0.1";
|
|
2
|
+
|
|
3
|
+
// Sales data for each month, per business unit
|
|
4
|
+
export interface SalesData {
|
|
5
|
+
sales: number;
|
|
6
|
+
month: number; // 1...12
|
|
7
|
+
year: number;
|
|
8
|
+
businessUnit: "Advertising" | "Hardware" | "Software";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface APIInterface {
|
|
12
|
+
|
|
13
|
+
sendEmail(to: string, subject: string, body: string): Promise<void>;
|
|
14
|
+
|
|
15
|
+
getSalesData(): SalesData[];
|
|
16
|
+
// Returns an array of sales data.
|
|
17
|
+
|
|
18
|
+
print(text: string): void;
|
|
19
|
+
// Prints the specified text to the user.
|
|
20
|
+
|
|
21
|
+
delay(milliseconds: number): Promise<void>;
|
|
22
|
+
// waits for the specified number of milliseconds before resolving the promise.
|
|
23
|
+
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Global object you will use for accessing the APIInterface
|
|
27
|
+
declare global {
|
|
28
|
+
var api: APIInterface;
|
|
29
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { delay } from "../lib/utils";
|
|
2
|
+
import { APIInterface, SalesData } from "./sales_api";
|
|
3
|
+
|
|
4
|
+
export class API implements APIInterface {
|
|
5
|
+
|
|
6
|
+
// Mock implementation, doesn't actually send an email
|
|
7
|
+
sendEmail(to: string, subject: string, body: string): Promise<void> {
|
|
8
|
+
console.log(`Sending email to "${to}" with subject "${subject}" and body\n"${body}"`);
|
|
9
|
+
return delay(1000);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getSalesData(): SalesData[] {
|
|
13
|
+
return [
|
|
14
|
+
{ sales: 100, month: 1, year: 2020, businessUnit: "Advertising" },
|
|
15
|
+
{ sales: 200, month: 2, year: 2020, businessUnit: "Advertising" },
|
|
16
|
+
{ sales: 300, month: 3, year: 2020, businessUnit: "Advertising" },
|
|
17
|
+
{ sales: 400, month: 4, year: 2020, businessUnit: "Advertising" },
|
|
18
|
+
{ sales: 500, month: 5, year: 2020, businessUnit: "Advertising" },
|
|
19
|
+
{ sales: 600, month: 6, year: 2020, businessUnit: "Advertising" },
|
|
20
|
+
{ sales: 700, month: 7, year: 2020, businessUnit: "Advertising" },
|
|
21
|
+
{ sales: 800, month: 8, year: 2020, businessUnit: "Advertising" },
|
|
22
|
+
{ sales: 900, month: 9, year: 2020, businessUnit: "Advertising" },
|
|
23
|
+
{ sales: 1000, month: 10, year: 2020, businessUnit: "Advertising" },
|
|
24
|
+
{ sales: 1100, month: 11, year: 2020, businessUnit: "Advertising" },
|
|
25
|
+
{ sales: 1100, month: 12, year: 2020, businessUnit: "Advertising" },
|
|
26
|
+
{ sales: 1200, month: 1, year: 2020, businessUnit: "Software" },
|
|
27
|
+
{ sales: 1300, month: 2, year: 2020, businessUnit: "Software" },
|
|
28
|
+
{ sales: 1400, month: 3, year: 2020, businessUnit: "Software" },
|
|
29
|
+
{ sales: 1500, month: 4, year: 2020, businessUnit: "Software" },
|
|
30
|
+
{ sales: 1600, month: 5, year: 2020, businessUnit: "Software" },
|
|
31
|
+
{ sales: 1700, month: 6, year: 2020, businessUnit: "Software" },
|
|
32
|
+
{ sales: 1800, month: 7, year: 2020, businessUnit: "Software" },
|
|
33
|
+
{ sales: 1800, month: 8, year: 2020, businessUnit: "Software" },
|
|
34
|
+
{ sales: 1500, month: 9, year: 2020, businessUnit: "Software" },
|
|
35
|
+
{ sales: 1200, month: 10, year: 2020, businessUnit: "Software" },
|
|
36
|
+
{ sales: 1000, month: 11, year: 2020, businessUnit: "Software" },
|
|
37
|
+
{ sales: 100, month: 12, year: 2020, businessUnit: "Software" },
|
|
38
|
+
{ sales: 1200, month: 1, year: 2020, businessUnit: "Hardware" },
|
|
39
|
+
{ sales: 1300, month: 2, year: 2020, businessUnit: "Hardware" },
|
|
40
|
+
{ sales: 1400, month: 3, year: 2020, businessUnit: "Hardware" },
|
|
41
|
+
{ sales: 1500, month: 4, year: 2020, businessUnit: "Hardware" },
|
|
42
|
+
{ sales: 1600, month: 5, year: 2020, businessUnit: "Hardware" },
|
|
43
|
+
{ sales: 1700, month: 6, year: 2020, businessUnit: "Hardware" },
|
|
44
|
+
{ sales: 1800, month: 7, year: 2020, businessUnit: "Hardware" },
|
|
45
|
+
{ sales: 1800, month: 8, year: 2020, businessUnit: "Hardware" },
|
|
46
|
+
{ sales: 1500, month: 9, year: 2020, businessUnit: "Hardware" },
|
|
47
|
+
{ sales: 1200, month: 10, year: 2020, businessUnit: "Hardware" },
|
|
48
|
+
{ sales: 1000, month: 11, year: 2020, businessUnit: "Hardware" },
|
|
49
|
+
{ sales: 100, month: 12, year: 2020, businessUnit: "Hardware" },
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
print(text: string): void {
|
|
54
|
+
console.log(text);
|
|
55
|
+
}
|
|
56
|
+
delay(milliseconds: number): Promise<void> {
|
|
57
|
+
return delay(milliseconds);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
require('dotenv').config()
|
|
2
|
+
import { ChatCompletionRequestMessage, Configuration, OpenAIApi } from "openai";
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
import createSandbox from "./sandbox";
|
|
7
|
+
import { rejectOpenPromises } from './sandbox-wrappers';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import { QuickJSWASMModule, getQuickJS } from "quickjs-emscripten";
|
|
12
|
+
|
|
13
|
+
const configuration = new Configuration({
|
|
14
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const openai = new OpenAIApi(configuration);
|
|
18
|
+
|
|
19
|
+
// function formatObject(obj: any): string {
|
|
20
|
+
// return Object.keys(obj).reduce((acc, key) => {
|
|
21
|
+
// return `${acc}${key}:\n${obj[key]}\n\n`;
|
|
22
|
+
// }, "");
|
|
23
|
+
// }
|
|
24
|
+
|
|
25
|
+
export function createBasePrompt(apiFilePath:string, documentationPath: string): string {
|
|
26
|
+
const apiText: string = fs.readFileSync(apiFilePath, 'utf8');
|
|
27
|
+
const documentationText: string = documentationPath ? fs.readFileSync(documentationPath, 'utf8') : '';
|
|
28
|
+
|
|
29
|
+
//console.time("Loading templates");
|
|
30
|
+
|
|
31
|
+
const createTaskPrompt: string = fs.readFileSync( path.join(__dirname, '../prompts/create-task-prompt.md'), 'utf8').replace("{{DOCUMENTATION}}", documentationText).replace("{{API}}", apiText);
|
|
32
|
+
|
|
33
|
+
//console.timeEnd("Loading templates")
|
|
34
|
+
|
|
35
|
+
return createTaskPrompt;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// userChatHistory is not currently used but could be in the future.
|
|
39
|
+
export const generateCode = async function(queryText:string, userChatHistory:ChatCompletionRequestMessage[], createTaskPrompt:string, apiPath:string, debug:boolean = false): Promise<string> {
|
|
40
|
+
if(!queryText)
|
|
41
|
+
return;
|
|
42
|
+
|
|
43
|
+
let generatedCode = '';
|
|
44
|
+
const prompt = createTaskPrompt.replace("{{QUERY_TEXT}}", queryText);
|
|
45
|
+
|
|
46
|
+
// TODO: I should switch this back to gpt3.5 turbo since it's cheaper
|
|
47
|
+
try {
|
|
48
|
+
// const task = await openai.createCompletion(
|
|
49
|
+
// {
|
|
50
|
+
// model: "text-davinci-003",
|
|
51
|
+
// prompt,
|
|
52
|
+
// temperature: 0.1,
|
|
53
|
+
// max_tokens: 1100,
|
|
54
|
+
// }
|
|
55
|
+
// );
|
|
56
|
+
|
|
57
|
+
const results = await openai.createChatCompletion({
|
|
58
|
+
model: "gpt-3.5-turbo",
|
|
59
|
+
messages: [
|
|
60
|
+
{
|
|
61
|
+
role: "system",
|
|
62
|
+
content: prompt,
|
|
63
|
+
},
|
|
64
|
+
...userChatHistory,
|
|
65
|
+
{
|
|
66
|
+
role: "user",
|
|
67
|
+
content: `${queryText}`,
|
|
68
|
+
name: "user"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
temperature: 0.1,
|
|
72
|
+
max_tokens: 800,
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if(debug)
|
|
78
|
+
console.log(results.data.usage);
|
|
79
|
+
|
|
80
|
+
const response = results.data.choices[0].message.content;
|
|
81
|
+
|
|
82
|
+
if(debug)
|
|
83
|
+
console.log(response);
|
|
84
|
+
|
|
85
|
+
// Return only the code between ``` and ``` (usually at the end of the completion)
|
|
86
|
+
const codeStart = response.indexOf('```');
|
|
87
|
+
const codeEnd = response.lastIndexOf('```');
|
|
88
|
+
|
|
89
|
+
if(codeStart === -1 || codeEnd === -1 || codeStart === codeEnd)
|
|
90
|
+
return '';
|
|
91
|
+
|
|
92
|
+
generatedCode = response.substring(codeStart + 3, codeEnd).replace('typescript', '');
|
|
93
|
+
|
|
94
|
+
generatedCode = `// Query=${queryText}\n` + generatedCode.replace("./api.ts", apiPath);
|
|
95
|
+
return generatedCode;
|
|
96
|
+
} catch(err) {
|
|
97
|
+
console.error(err);
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
let QuickJS:QuickJSWASMModule = null;
|
|
104
|
+
|
|
105
|
+
export interface AIMyAPIOptions {
|
|
106
|
+
apiObject: object;
|
|
107
|
+
apiExports: object;
|
|
108
|
+
apiGlobals?: object;
|
|
109
|
+
apiDefFilePath: string; // Full path to the api definition file so that it can be loaded into the prompt
|
|
110
|
+
apiGlobalName?: string;
|
|
111
|
+
apiDocsPath?: string;
|
|
112
|
+
debug?: boolean;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export interface CreateWithAPIExports {
|
|
116
|
+
// see xample 2
|
|
117
|
+
generateCode: (queryText:string, userChatHistory:ChatCompletionRequestMessage[]) => Promise<string>;
|
|
118
|
+
runCode: (task:string) => Promise<void>;
|
|
119
|
+
// run a single request with no history
|
|
120
|
+
processRequest: (userQuery:string, context?: object) => Promise<string>;
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function createWithAPI(options:AIMyAPIOptions): Promise<CreateWithAPIExports> {
|
|
125
|
+
// extend options with defaults
|
|
126
|
+
options = {
|
|
127
|
+
apiGlobalName: "api",
|
|
128
|
+
apiGlobals: {},
|
|
129
|
+
debug: false,
|
|
130
|
+
...options
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
if(!options.apiObject || !options.apiDefFilePath) {
|
|
134
|
+
throw new Error("apiObject and apiFilePath are required");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const {apiObject, apiGlobalName, apiExports, apiDefFilePath, apiDocsPath, debug} = options;
|
|
138
|
+
|
|
139
|
+
const whitelist = Object.getOwnPropertyNames(Object.getPrototypeOf(apiObject)).filter((f) => f !== "constructor" && !f.startsWith("_"));
|
|
140
|
+
const createTaskPrompt = createBasePrompt( apiDefFilePath, apiDocsPath);
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
generateCode: async function(queryText:string, userChatHistory:ChatCompletionRequestMessage[], currentContext:any = undefined) {
|
|
144
|
+
if(!queryText)
|
|
145
|
+
return '';
|
|
146
|
+
|
|
147
|
+
return await generateCode(queryText, userChatHistory, createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : ""), apiDefFilePath, debug);
|
|
148
|
+
},
|
|
149
|
+
runCode: async function(generatedCode:string) {
|
|
150
|
+
if(!QuickJS) {
|
|
151
|
+
// Create QuickJS
|
|
152
|
+
if(debug)
|
|
153
|
+
console.log("Creating quick.js");
|
|
154
|
+
QuickJS = await getQuickJS();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let apiGlobals = {}
|
|
158
|
+
|
|
159
|
+
for(const key in options.apiGlobals) {
|
|
160
|
+
apiGlobals[key] = {
|
|
161
|
+
value: options.apiGlobals[key],
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Create sandbox
|
|
166
|
+
// NOTE: not sure why I have to replace the backslash here
|
|
167
|
+
const {vm, runTask, isAsyncProcessRunning} = await createSandbox(QuickJS, {
|
|
168
|
+
[apiDefFilePath.replaceAll("\\", "")]: apiExports,
|
|
169
|
+
}, {
|
|
170
|
+
...apiGlobals,
|
|
171
|
+
[apiGlobalName]: {
|
|
172
|
+
value: apiObject,
|
|
173
|
+
whitelist
|
|
174
|
+
}
|
|
175
|
+
}, options.debug);
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const res = await runTask(generatedCode);
|
|
179
|
+
|
|
180
|
+
if(!res) {
|
|
181
|
+
console.error("Task unsuccessful");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
while(isAsyncProcessRunning()) {
|
|
185
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if(debug) {
|
|
189
|
+
console.log("Completed");
|
|
190
|
+
}
|
|
191
|
+
} catch(err) {
|
|
192
|
+
if(debug) {
|
|
193
|
+
console.error("Error running task:", err);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
198
|
+
|
|
199
|
+
rejectOpenPromises(vm);
|
|
200
|
+
vm.dispose()
|
|
201
|
+
|
|
202
|
+
},
|
|
203
|
+
processRequest: async function (userQuery, currentContext:any = undefined):Promise<string> {
|
|
204
|
+
// Create prompt
|
|
205
|
+
|
|
206
|
+
if(debug) {
|
|
207
|
+
console.log("Query:", userQuery);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Generate Code
|
|
211
|
+
console.time("Generate Task")
|
|
212
|
+
const generatedCode = await generateCode(userQuery, [], createTaskPrompt.replace("{{CONTEXT}}", currentContext ? "```" + JSON.stringify(currentContext, null, 2) + "```" : "" ), apiDefFilePath);
|
|
213
|
+
console.timeEnd("Generate Task")
|
|
214
|
+
|
|
215
|
+
if(debug) {
|
|
216
|
+
console.log("Generated Code:", generatedCode);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.time("Run Code")
|
|
220
|
+
await this.runCode(generatedCode);
|
|
221
|
+
console.timeEnd("Run Code")
|
|
222
|
+
|
|
223
|
+
return generatedCode;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface AIMyAPIExports {
|
|
230
|
+
createWithAPI: (options:AIMyAPIOptions) => Promise<CreateWithAPIExports>;
|
|
231
|
+
|
|
232
|
+
createBasePrompt: (apiFilePath:string, documentationPath: string) => string;
|
|
233
|
+
generateTask: (queryText:string, userChatHistory:any[], createTaskPrompt:string, apiPath:string) => Promise<string>;
|
|
234
|
+
createSandbox: (QuickJS:QuickJSWASMModule, globals: any) => Promise<any>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const aimyapi:AIMyAPIExports = {
|
|
238
|
+
// Standard way of using the library
|
|
239
|
+
createWithAPI,
|
|
240
|
+
|
|
241
|
+
// functions for customized usage
|
|
242
|
+
createBasePrompt,
|
|
243
|
+
generateTask: generateCode,
|
|
244
|
+
createSandbox,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export default aimyapi;
|