@saltcorn/large-language-model 0.3.6 → 0.4.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/function-insert-action.js +150 -0
- package/generate.js +2 -1
- package/index.js +7 -0
- package/model.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const Workflow = require("@saltcorn/data/models/workflow");
|
|
2
|
+
const Form = require("@saltcorn/data/models/form");
|
|
3
|
+
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
4
|
+
const Field = require("@saltcorn/data/models/field");
|
|
5
|
+
const Table = require("@saltcorn/data/models/table");
|
|
6
|
+
const { getState } = require("@saltcorn/data/db/state");
|
|
7
|
+
const { interpolate } = require("@saltcorn/data/utils");
|
|
8
|
+
const { getCompletion, getEmbedding } = require("./generate");
|
|
9
|
+
const { eval_expression } = require("@saltcorn/data/models/expression");
|
|
10
|
+
|
|
11
|
+
const noSpaces = (s) => s.replaceAll(" ", "");
|
|
12
|
+
module.exports = (config) => ({
|
|
13
|
+
description: "Use LLM function call to insert rows in tables",
|
|
14
|
+
requireRow: true,
|
|
15
|
+
configFields: async ({ table }) => {
|
|
16
|
+
const tables = await Table.find();
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
name: "prompt_template",
|
|
20
|
+
label: "Prompt",
|
|
21
|
+
type: "String",
|
|
22
|
+
fieldview: "textarea",
|
|
23
|
+
sublabel: `Use interpolations {{ }} to access variables in ${table.name} table.`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "function_name",
|
|
27
|
+
label: "Function name",
|
|
28
|
+
type: "String",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "function_description",
|
|
32
|
+
label: "Function description",
|
|
33
|
+
sublabel: "Describe what you are trying to achieve in general terms",
|
|
34
|
+
type: "String",
|
|
35
|
+
},
|
|
36
|
+
new FieldRepeat({
|
|
37
|
+
name: "columns",
|
|
38
|
+
fields: [
|
|
39
|
+
{
|
|
40
|
+
name: "target_table",
|
|
41
|
+
label: "Target table",
|
|
42
|
+
type: "String",
|
|
43
|
+
required: true,
|
|
44
|
+
attributes: { options: tables.map((t) => t.name) },
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: "Fixed values",
|
|
48
|
+
name: "fixed_values",
|
|
49
|
+
type: "String",
|
|
50
|
+
fieldview: "textarea",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "cardinality",
|
|
54
|
+
label: "Cardinality",
|
|
55
|
+
type: "String",
|
|
56
|
+
required: true,
|
|
57
|
+
attributes: {
|
|
58
|
+
options: ["One", /*"Zero or one",*/ "Zero to many"],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
}),
|
|
63
|
+
];
|
|
64
|
+
},
|
|
65
|
+
run: async ({
|
|
66
|
+
row,
|
|
67
|
+
table,
|
|
68
|
+
configuration: {
|
|
69
|
+
prompt_template,
|
|
70
|
+
columns,
|
|
71
|
+
function_description,
|
|
72
|
+
function_name,
|
|
73
|
+
},
|
|
74
|
+
user,
|
|
75
|
+
}) => {
|
|
76
|
+
const prompt = interpolate(prompt_template, row, user);
|
|
77
|
+
let args = {};
|
|
78
|
+
const json_type = (ty) => {
|
|
79
|
+
if (ty?.js_type) return ty?.js_type;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
for (const col of columns) {
|
|
83
|
+
const target_table = Table.findOne({ name: col.target_table });
|
|
84
|
+
const tableArgs = {};
|
|
85
|
+
const fixed = eval_expression(
|
|
86
|
+
col.fixed_values,
|
|
87
|
+
row,
|
|
88
|
+
user,
|
|
89
|
+
"llm_function_call fixed values"
|
|
90
|
+
);
|
|
91
|
+
for (const field of target_table.fields) {
|
|
92
|
+
if (field.primary_key) continue;
|
|
93
|
+
if (typeof fixed[field.name] !== "undefined") continue;
|
|
94
|
+
tableArgs[field.name] = {
|
|
95
|
+
type: json_type(field.type),
|
|
96
|
+
description: field.description,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const argObj = { type: "object", properties: tableArgs };
|
|
100
|
+
args[noSpaces(target_table.name)] =
|
|
101
|
+
col.cardinality == "One" ? argObj : { type: "array", items: argObj };
|
|
102
|
+
}
|
|
103
|
+
if (columns.length === 1) {
|
|
104
|
+
//args = args[Object]
|
|
105
|
+
}
|
|
106
|
+
const expert_function = {
|
|
107
|
+
type: "function",
|
|
108
|
+
function: {
|
|
109
|
+
name: function_name,
|
|
110
|
+
description: function_description,
|
|
111
|
+
parameters: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: args,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
const toolargs = {
|
|
118
|
+
tools: [expert_function],
|
|
119
|
+
tool_choice: { type: "function", function: { name: function_name } },
|
|
120
|
+
};
|
|
121
|
+
//console.log(JSON.stringify(expert_function, null, 2));
|
|
122
|
+
const compl = await getCompletion(config, { prompt, ...toolargs });
|
|
123
|
+
|
|
124
|
+
const response = JSON.parse(compl.tool_calls[0].function.arguments);
|
|
125
|
+
//console.log("response: ", JSON.stringify(response, null, 2));
|
|
126
|
+
for (const col of columns) {
|
|
127
|
+
const target_table = Table.findOne({ name: col.target_table });
|
|
128
|
+
const fixed = eval_expression(
|
|
129
|
+
col.fixed_values,
|
|
130
|
+
row,
|
|
131
|
+
user,
|
|
132
|
+
"llm_function_call fixed values"
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (col.cardinality == "One") {
|
|
136
|
+
const row = {
|
|
137
|
+
...(response[noSpaces(target_table.name)] || {}),
|
|
138
|
+
...fixed,
|
|
139
|
+
};
|
|
140
|
+
await target_table.insertRow(row, user);
|
|
141
|
+
} else {
|
|
142
|
+
for (const resp of response[noSpaces(target_table.name)] || []) {
|
|
143
|
+
const row = { ...resp, ...fixed };
|
|
144
|
+
await target_table.insertRow(row, user);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {};
|
|
149
|
+
},
|
|
150
|
+
});
|
package/generate.js
CHANGED
|
@@ -109,7 +109,7 @@ const getCompletionOpenAICompatible = async (
|
|
|
109
109
|
if (bearer) headers.Authorization = "Bearer " + bearer;
|
|
110
110
|
const body = {
|
|
111
111
|
//prompt: "How are you?",
|
|
112
|
-
model,
|
|
112
|
+
model: rest.model || model,
|
|
113
113
|
messages: [
|
|
114
114
|
{
|
|
115
115
|
role: "system",
|
|
@@ -121,6 +121,7 @@ const getCompletionOpenAICompatible = async (
|
|
|
121
121
|
temperature: temperature || 0.7,
|
|
122
122
|
...rest,
|
|
123
123
|
};
|
|
124
|
+
if (debugResult) console.log("OpenAI request", JSON.stringify(body, null, 2));
|
|
124
125
|
const rawResponse = await fetch(chatCompleteEndpoint, {
|
|
125
126
|
method: "POST",
|
|
126
127
|
headers,
|
package/index.js
CHANGED
|
@@ -58,10 +58,14 @@ const configuration_workflow = () =>
|
|
|
58
58
|
options: [
|
|
59
59
|
"gpt-3.5-turbo",
|
|
60
60
|
"gpt-3.5-turbo-16k",
|
|
61
|
+
"gpt-3.5-turbo-1106",
|
|
62
|
+
"gpt-3.5-turbo-0125",
|
|
61
63
|
"gpt-4",
|
|
62
64
|
"gpt-4-32k",
|
|
63
65
|
"gpt-4-turbo-preview",
|
|
64
66
|
"gpt-4-1106-preview",
|
|
67
|
+
"gpt-4-0125-preview",
|
|
68
|
+
"gpt-4-turbo",
|
|
65
69
|
],
|
|
66
70
|
},
|
|
67
71
|
},
|
|
@@ -136,4 +140,7 @@ module.exports = {
|
|
|
136
140
|
configuration_workflow,
|
|
137
141
|
functions,
|
|
138
142
|
modelpatterns: require("./model.js"),
|
|
143
|
+
actions: (config) => ({
|
|
144
|
+
llm_function_call: require("./function-insert-action.js")(config),
|
|
145
|
+
}),
|
|
139
146
|
};
|
package/model.js
CHANGED
|
@@ -35,8 +35,14 @@ const configuration_workflow = (config) => (req) =>
|
|
|
35
35
|
models = [
|
|
36
36
|
"gpt-3.5-turbo",
|
|
37
37
|
"gpt-3.5-turbo-16k",
|
|
38
|
+
"gpt-3.5-turbo-1106",
|
|
39
|
+
"gpt-3.5-turbo-0125",
|
|
38
40
|
"gpt-4",
|
|
39
41
|
"gpt-4-32k",
|
|
42
|
+
"gpt-4-turbo-preview",
|
|
43
|
+
"gpt-4-1106-preview",
|
|
44
|
+
"gpt-4-0125-preview",
|
|
45
|
+
"gpt-4-turbo",
|
|
40
46
|
];
|
|
41
47
|
}
|
|
42
48
|
return new Form({
|