@aj-archipelago/cortex 1.0.1 → 1.0.2
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/.eslintignore +30 -0
- package/.eslintrc +31 -0
- package/README.md +10 -0
- package/config/default.example.json +70 -0
- package/config.js +0 -6
- package/graphql/chunker.js +1 -1
- package/graphql/graphql.js +1 -1
- package/graphql/parser.js +1 -0
- package/graphql/pathwayPrompter.js +6 -2
- package/graphql/pathwayResolver.js +0 -2
- package/graphql/plugins/localModelPlugin.js +54 -5
- package/graphql/plugins/modelPlugin.js +2 -2
- package/graphql/prompt.js +1 -0
- package/graphql/resolver.js +2 -2
- package/graphql/subscriptions.js +1 -1
- package/lib/fileChunker.js +0 -13
- package/lib/request.js +0 -1
- package/package.json +6 -2
- package/pathways/lc_test.mjs +9 -5
- package/pathways/summary.js +1 -1
package/.eslintignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Ignore build artifacts
|
|
2
|
+
/dist
|
|
3
|
+
/build
|
|
4
|
+
|
|
5
|
+
# Ignore node_modules
|
|
6
|
+
/node_modules
|
|
7
|
+
|
|
8
|
+
# Ignore log files
|
|
9
|
+
*.log
|
|
10
|
+
|
|
11
|
+
# Ignore any config files
|
|
12
|
+
.env
|
|
13
|
+
.env.*
|
|
14
|
+
|
|
15
|
+
# Ignore coverage reports
|
|
16
|
+
/coverage
|
|
17
|
+
|
|
18
|
+
# Ignore documentation
|
|
19
|
+
/docs
|
|
20
|
+
|
|
21
|
+
# Ignore any generated or bundled files
|
|
22
|
+
*.min.js
|
|
23
|
+
*.bundle.js
|
|
24
|
+
|
|
25
|
+
# Ignore any files generated by your IDE or text editor
|
|
26
|
+
.idea/
|
|
27
|
+
.vscode/
|
|
28
|
+
*.sublime-*
|
|
29
|
+
*.iml
|
|
30
|
+
*.swp
|
package/.eslintrc
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true,
|
|
5
|
+
"node": true
|
|
6
|
+
},
|
|
7
|
+
"extends": [
|
|
8
|
+
"eslint:recommended"
|
|
9
|
+
],
|
|
10
|
+
"parserOptions": {
|
|
11
|
+
"ecmaVersion": 12,
|
|
12
|
+
"sourceType": "module"
|
|
13
|
+
},
|
|
14
|
+
"plugins": [
|
|
15
|
+
"import"
|
|
16
|
+
],
|
|
17
|
+
"rules": {
|
|
18
|
+
"import/no-unresolved": "error",
|
|
19
|
+
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}],
|
|
20
|
+
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
|
|
21
|
+
},
|
|
22
|
+
"settings": {
|
|
23
|
+
"import/resolver": {
|
|
24
|
+
"node": {
|
|
25
|
+
"extensions": [".js"],
|
|
26
|
+
"moduleDirectory": ["node_modules", "src"]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"import/core-modules": ["ava"]
|
|
30
|
+
}
|
|
31
|
+
}
|
package/README.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
Cortex simplifies and accelerates the process of creating applications that harness the power of modern AI models like chatGPT and GPT-4 by providing a structured interface (GraphQL or REST) to a powerful prompt execution environment. This enables complex augmented prompting and abstracts away most of the complexity of managing model connections like chunking input, rate limiting, formatting output, caching, and handling errors.
|
|
3
3
|
## Why build Cortex?
|
|
4
4
|
Modern AI models are transformational, but a number of complexities emerge when developers start using them to deliver application-ready functions. Most models require precisely formatted, carefully engineered and sequenced prompts to produce consistent results, and the responses are typically largely unstructured text without validation or formatting. Additionally, these models are evolving rapidly, are typically costly and slow to query and implement hard request size and rate restrictions that need to be carefully navigated for optimum throughput. Cortex offers a solution to these problems and provides a simple and extensible package for interacting with NL AI models.
|
|
5
|
+
|
|
6
|
+
## Okay, but what can I really do with this thing?
|
|
7
|
+
Yikes. Everything! It's kind of an LLM swiss army knife. Here are some ideas:
|
|
8
|
+
* Create custom chat agents with memory and personalization and then expose it to a bunch of different UIs (custom chat portals, Slack, teams, etc. - anything that can speak to a REST or GraphQL endpoint)
|
|
9
|
+
* Create custom coding assistants (code generation, code reviews, test writing, AI pair programming) and easily integrate them with your existing editing tools.
|
|
10
|
+
* Create powerful AI editing tools (copy editing, paraphrasing, summarization, etc.) tools for your company and then integrate them with your existing workflow tools without having to build all the LLM-handling logic into those tools.
|
|
11
|
+
* Make LLM chains and agents from LangChain.js available via scalable REST or GraphQL endpoints.
|
|
12
|
+
* Put a REST or GraphQL front end on your locally-run models (e.g. llama.cpp) and use them in concert with other tools.
|
|
13
|
+
* The sky is the limit!
|
|
14
|
+
|
|
5
15
|
## Features
|
|
6
16
|
|
|
7
17
|
* Simple architecture to build custom functional endpoints (called `pathways`), that implement common NL AI tasks. Default pathways include chat, summarization, translation, paraphrasing, completion, spelling and grammar correction, entity extraction, sentiment analysis, and bias analysis.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultModelName": "oai-td3",
|
|
3
|
+
"models": {
|
|
4
|
+
"azure-translate": {
|
|
5
|
+
"type": "AZURE-TRANSLATE",
|
|
6
|
+
"url": "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0",
|
|
7
|
+
"headers": {
|
|
8
|
+
"Ocp-Apim-Subscription-Key": "{{ARCHIPELAGO_TRANSLATE_KEY}}",
|
|
9
|
+
"Ocp-Apim-Subscription-Region": "eastus",
|
|
10
|
+
"Content-Type": "application/json"
|
|
11
|
+
},
|
|
12
|
+
"requestsPerSecond": 10,
|
|
13
|
+
"maxTokenLength": 2000
|
|
14
|
+
},
|
|
15
|
+
"oai-td3": {
|
|
16
|
+
"type": "OPENAI-COMPLETION",
|
|
17
|
+
"url": "https://api.openai.com/v1/completions",
|
|
18
|
+
"headers": {
|
|
19
|
+
"Authorization": "Bearer {{OPENAI_API_KEY}}",
|
|
20
|
+
"Content-Type": "application/json"
|
|
21
|
+
},
|
|
22
|
+
"params": {
|
|
23
|
+
"model": "text-davinci-003"
|
|
24
|
+
},
|
|
25
|
+
"requestsPerSecond": 10,
|
|
26
|
+
"maxTokenLength": 4096
|
|
27
|
+
},
|
|
28
|
+
"oai-gpturbo": {
|
|
29
|
+
"type": "OPENAI-CHAT",
|
|
30
|
+
"url": "https://api.openai.com/v1/chat/completions",
|
|
31
|
+
"headers": {
|
|
32
|
+
"Authorization": "Bearer {{OPENAI_API_KEY}}",
|
|
33
|
+
"Content-Type": "application/json"
|
|
34
|
+
},
|
|
35
|
+
"params": {
|
|
36
|
+
"model": "gpt-3.5-turbo"
|
|
37
|
+
},
|
|
38
|
+
"requestsPerSecond": 10,
|
|
39
|
+
"maxTokenLength": 8192
|
|
40
|
+
},
|
|
41
|
+
"oai-gpt4": {
|
|
42
|
+
"type": "OPENAI-CHAT",
|
|
43
|
+
"url": "https://api.openai.com/v1/chat/completions",
|
|
44
|
+
"headers": {
|
|
45
|
+
"Authorization": "Bearer {{OPENAI_API_KEY}}",
|
|
46
|
+
"Content-Type": "application/json"
|
|
47
|
+
},
|
|
48
|
+
"params": {
|
|
49
|
+
"model": "gpt-4"
|
|
50
|
+
},
|
|
51
|
+
"requestsPerSecond": 10,
|
|
52
|
+
"maxTokenLength": 8192
|
|
53
|
+
},
|
|
54
|
+
"local-llama13B": {
|
|
55
|
+
"type": "LOCAL-CPP-MODEL",
|
|
56
|
+
"executablePath": "../llm/llama.cpp/main",
|
|
57
|
+
"args": [
|
|
58
|
+
"-m", "../llm/llama.cpp/models/13B/ggml-model-q4_0.bin",
|
|
59
|
+
"--repeat_penalty", "1.0",
|
|
60
|
+
"--keep", "0",
|
|
61
|
+
"-t", "8",
|
|
62
|
+
"--mlock"
|
|
63
|
+
],
|
|
64
|
+
"requestsPerSecond": 10,
|
|
65
|
+
"maxTokenLength": 1024
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"enableCache": false,
|
|
69
|
+
"enableRestEndpoints": false
|
|
70
|
+
}
|
package/config.js
CHANGED
|
@@ -110,12 +110,6 @@ var config = convict({
|
|
|
110
110
|
default: null,
|
|
111
111
|
env: 'CORTEX_CONFIG_FILE'
|
|
112
112
|
},
|
|
113
|
-
serpApiKey: {
|
|
114
|
-
format: String,
|
|
115
|
-
default: null,
|
|
116
|
-
env: 'SERPAPI_API_KEY',
|
|
117
|
-
sensitive: true
|
|
118
|
-
},
|
|
119
113
|
});
|
|
120
114
|
|
|
121
115
|
// Read in environment variables and set up service configuration
|
package/graphql/chunker.js
CHANGED
|
@@ -43,7 +43,7 @@ const getSemanticChunks = (text, chunkSize) => {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
const breakByParagraphs = (str) => breakByRegex(str, /[\r\n]+/, true);
|
|
46
|
-
const breakBySentences = (str) => breakByRegex(str, /(?<=[
|
|
46
|
+
const breakBySentences = (str) => breakByRegex(str, /(?<=[.。؟!?!\n])\s+/, true);
|
|
47
47
|
const breakByWords = (str) => breakByRegex(str, /(\s,;:.+)/);
|
|
48
48
|
|
|
49
49
|
const createChunks = (tokens) => {
|
package/graphql/graphql.js
CHANGED
|
@@ -48,7 +48,7 @@ const buildRestEndpoints = (pathways, app, server, config) => {
|
|
|
48
48
|
|
|
49
49
|
app.post(`/rest/${name}`, async (req, res) => {
|
|
50
50
|
const variables = fieldVariableDefs.reduce((acc, variableDef) => {
|
|
51
|
-
if (
|
|
51
|
+
if (Object.prototype.hasOwnProperty.call(req.body, variableDef.name)) {
|
|
52
52
|
acc[variableDef.name] = req.body[variableDef.name];
|
|
53
53
|
}
|
|
54
54
|
return acc;
|
package/graphql/parser.js
CHANGED
|
@@ -6,6 +6,7 @@ const regexParser = (text, regex) => {
|
|
|
6
6
|
// parse numbered list text format into list
|
|
7
7
|
// this supports most common numbered list returns like "1.", "1)", "1-"
|
|
8
8
|
const parseNumberedList = (str) => {
|
|
9
|
+
// eslint-disable-next-line no-useless-escape
|
|
9
10
|
return regexParser(str, /^\s*[\[\{\(]*\d+[\s.=\-:,;\]\)\}]/gm);
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// PathwayPrompter.js
|
|
2
|
-
import OpenAIChatPlugin from './plugins/
|
|
3
|
-
import OpenAICompletionPlugin from './plugins/
|
|
2
|
+
import OpenAIChatPlugin from './plugins/openAiChatPlugin.js';
|
|
3
|
+
import OpenAICompletionPlugin from './plugins/openAiCompletionPlugin.js';
|
|
4
4
|
import AzureTranslatePlugin from './plugins/azureTranslatePlugin.js';
|
|
5
5
|
import OpenAIWhisperPlugin from './plugins/openAiWhisperPlugin.js';
|
|
6
|
+
import LocalModelPlugin from './plugins/localModelPlugin.js';
|
|
6
7
|
import handlebars from 'handlebars';
|
|
7
8
|
|
|
8
9
|
// register functions that can be called directly in the prompt markdown
|
|
@@ -44,6 +45,9 @@ class PathwayPrompter {
|
|
|
44
45
|
case 'OPENAI_WHISPER':
|
|
45
46
|
plugin = new OpenAIWhisperPlugin(config, pathway);
|
|
46
47
|
break;
|
|
48
|
+
case 'LOCAL-CPP-MODEL':
|
|
49
|
+
plugin = new LocalModelPlugin(config, pathway);
|
|
50
|
+
break;
|
|
47
51
|
default:
|
|
48
52
|
throw new handlebars.Exception(`Unsupported model type: ${model.type}`);
|
|
49
53
|
}
|
|
@@ -8,8 +8,6 @@ import { Prompt } from './prompt.js';
|
|
|
8
8
|
import { getv, setv } from '../lib/keyValueStorageClient.js';
|
|
9
9
|
import { requestState } from './requestState.js';
|
|
10
10
|
|
|
11
|
-
const MAX_PREVIOUS_RESULT_TOKEN_LENGTH = 1000;
|
|
12
|
-
|
|
13
11
|
const callPathway = async (config, pathwayName, args, requestState, { text, ...parameters }) => {
|
|
14
12
|
const pathwayResolver = new PathwayResolver({ config, pathway: config.get(`pathways.${pathwayName}`), args, requestState });
|
|
15
13
|
return await pathwayResolver.resolve({ text, ...parameters });
|
|
@@ -1,20 +1,69 @@
|
|
|
1
1
|
// localModelPlugin.js
|
|
2
2
|
import ModelPlugin from './modelPlugin.js';
|
|
3
3
|
import { execFileSync } from 'child_process';
|
|
4
|
+
import { encode } from 'gpt-3-encoder';
|
|
4
5
|
|
|
5
6
|
class LocalModelPlugin extends ModelPlugin {
|
|
6
7
|
constructor(config, pathway) {
|
|
7
8
|
super(config, pathway);
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
// if the input starts with a chatML response, just return that
|
|
12
|
+
filterFirstResponse(inputString) {
|
|
13
|
+
const regex = /^(.*?)(?=\n<\|im_end\|>|$)/;
|
|
14
|
+
const match = inputString.match(regex);
|
|
15
|
+
|
|
16
|
+
if (match) {
|
|
17
|
+
const firstAssistantResponse = match[1];
|
|
18
|
+
return firstAssistantResponse;
|
|
19
|
+
} else {
|
|
20
|
+
return inputString;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getRequestParameters(text, parameters, prompt) {
|
|
25
|
+
let { modelPromptMessages, modelPromptText, tokenLength } = this.getCompiledPrompt(text, parameters, prompt);
|
|
26
|
+
const modelTargetTokenLength = this.getModelMaxTokenLength() * this.getPromptTokenRatio();
|
|
27
|
+
|
|
28
|
+
if (modelPromptMessages) {
|
|
29
|
+
const minMsg = [{ role: "system", content: "" }];
|
|
30
|
+
const addAssistantTokens = encode(this.messagesToChatML(minMsg, true).replace(this.messagesToChatML(minMsg, false), '')).length;
|
|
31
|
+
const requestMessages = this.truncateMessagesToTargetLength(modelPromptMessages, (modelTargetTokenLength - addAssistantTokens));
|
|
32
|
+
modelPromptText = this.messagesToChatML(requestMessages);
|
|
33
|
+
tokenLength = encode(modelPromptText).length;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (tokenLength > modelTargetTokenLength) {
|
|
37
|
+
throw new Error(`Input is too long at ${tokenLength} tokens. The target token length for this pathway is ${modelTargetTokenLength} tokens because the response is expected to take up the rest of the ${this.getModelMaxTokenLength()} tokens that the model can handle. You must reduce the size of the prompt to continue.`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const max_tokens = this.getModelMaxTokenLength() - tokenLength;
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
prompt: modelPromptText,
|
|
44
|
+
max_tokens: max_tokens,
|
|
45
|
+
temperature: this.temperature ?? 0.7,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async execute(text, parameters, prompt, _pathwayResolver) {
|
|
50
|
+
const requestParameters = this.getRequestParameters(text, parameters, prompt);
|
|
51
|
+
const { executablePath, args } = this.model;
|
|
52
|
+
args.push("--prompt", requestParameters.prompt);
|
|
53
|
+
//args.push("--max-tokens", requestParameters.max_tokens);
|
|
54
|
+
//args.push("--temperature", requestParameters.temperature);
|
|
12
55
|
|
|
13
56
|
try {
|
|
14
|
-
|
|
15
|
-
|
|
57
|
+
console.log(`\x1b[36mRunning local model:\x1b[0m`, executablePath, args);
|
|
58
|
+
const result = execFileSync(executablePath, args, { encoding: 'utf8' });
|
|
59
|
+
// Remove only the first occurrence of requestParameters.prompt from the result
|
|
60
|
+
// Could have used regex here but then would need to escape the prompt
|
|
61
|
+
const parts = result.split(requestParameters.prompt, 2);
|
|
62
|
+
const modifiedResult = parts[0] + parts[1];
|
|
63
|
+
console.log(`\x1b[36mResult:\x1b[0m`, modifiedResult);
|
|
64
|
+
return this.filterFirstResponse(modifiedResult);
|
|
16
65
|
} catch (error) {
|
|
17
|
-
console.error(
|
|
66
|
+
console.error(`\x1b[31mError running local model:\x1b[0m`, error);
|
|
18
67
|
throw error;
|
|
19
68
|
}
|
|
20
69
|
}
|
|
@@ -40,7 +40,7 @@ class ModelPlugin {
|
|
|
40
40
|
this.shouldCache = config.get('enableCache') && (pathway.enableCache || pathway.temperature == 0);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
truncateMessagesToTargetLength
|
|
43
|
+
truncateMessagesToTargetLength(messages, targetTokenLength) {
|
|
44
44
|
// Calculate the token length of each message
|
|
45
45
|
const tokenLengths = messages.map((message) => ({
|
|
46
46
|
message,
|
|
@@ -97,7 +97,7 @@ class ModelPlugin {
|
|
|
97
97
|
|
|
98
98
|
// Return the modified messages array
|
|
99
99
|
return tokenLengths.map(({ message }) => message);
|
|
100
|
-
}
|
|
100
|
+
}
|
|
101
101
|
|
|
102
102
|
//convert a messages array to a simple chatML format
|
|
103
103
|
messagesToChatML(messages, addAssistant = true) {
|
package/graphql/prompt.js
CHANGED
|
@@ -26,6 +26,7 @@ function promptContains(variable, prompt) {
|
|
|
26
26
|
// if it's an array, it's the messages format
|
|
27
27
|
if (Array.isArray(prompt)) {
|
|
28
28
|
prompt.forEach(p => {
|
|
29
|
+
// eslint-disable-next-line no-cond-assign
|
|
29
30
|
while (match = p.content && regexp.exec(p.content)) {
|
|
30
31
|
matches.push(match[1]);
|
|
31
32
|
}
|
package/graphql/resolver.js
CHANGED
|
@@ -26,12 +26,12 @@ const rootResolver = async (parent, args, contextValue, info) => {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// This resolver is used by the root resolver to process the request
|
|
29
|
-
const resolver = async (parent, args, contextValue,
|
|
29
|
+
const resolver = async (parent, args, contextValue, _info) => {
|
|
30
30
|
const { pathwayResolver } = contextValue;
|
|
31
31
|
return await pathwayResolver.resolve(args);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const cancelRequestResolver = (parent, args, contextValue,
|
|
34
|
+
const cancelRequestResolver = (parent, args, contextValue, _info) => {
|
|
35
35
|
const { requestId } = args;
|
|
36
36
|
const { requestState } = contextValue;
|
|
37
37
|
requestState[requestId] = { canceled: true };
|
package/graphql/subscriptions.js
CHANGED
|
@@ -10,7 +10,7 @@ import { requestState } from './requestState.js';
|
|
|
10
10
|
const subscriptions = {
|
|
11
11
|
requestProgress: {
|
|
12
12
|
subscribe: withFilter(
|
|
13
|
-
(_, args, __,
|
|
13
|
+
(_, args, __, _info) => {
|
|
14
14
|
const { requestIds } = args;
|
|
15
15
|
for (const requestId of requestIds) {
|
|
16
16
|
if (!requestState[requestId]) {
|
package/lib/fileChunker.js
CHANGED
|
@@ -42,10 +42,6 @@ const generateUniqueFolderName = () => {
|
|
|
42
42
|
return uniqueOutputPath;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const generateUniqueTempFileName = () => {
|
|
46
|
-
return path.join(os.tmpdir(), uuidv4());
|
|
47
|
-
}
|
|
48
|
-
|
|
49
45
|
async function splitMediaFile(inputPath, chunkDurationInSeconds = 600) {
|
|
50
46
|
try {
|
|
51
47
|
const metadata = await ffmpegProbe(inputPath);
|
|
@@ -146,15 +142,6 @@ const processYoutubeUrl = async (url) => {
|
|
|
146
142
|
return outputFileName;
|
|
147
143
|
}
|
|
148
144
|
|
|
149
|
-
function deleteFile(filePath) {
|
|
150
|
-
try {
|
|
151
|
-
fs.unlinkSync(filePath);
|
|
152
|
-
console.log(`File ${filePath} cleaned successfully.`);
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.error(`Error deleting file ${filePath}:`, error);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
145
|
export {
|
|
159
146
|
splitMediaFile, deleteTempPath, processYoutubeUrl, isValidYoutubeUrl
|
|
160
147
|
};
|
package/lib/request.js
CHANGED
|
@@ -64,7 +64,6 @@ const postWithMonitor = async (model, url, data, axiosConfigObj) => {
|
|
|
64
64
|
|
|
65
65
|
const MAX_RETRY = 10;
|
|
66
66
|
const postRequest = async ({ url, data, params, headers, cache }, model) => {
|
|
67
|
-
let retry = 0;
|
|
68
67
|
const errors = []
|
|
69
68
|
for (let i = 0; i < MAX_RETRY; i++) {
|
|
70
69
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aj-archipelago/cortex",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"compromise": "^14.8.1",
|
|
43
43
|
"compromise-paragraphs": "^0.1.0",
|
|
44
44
|
"convict": "^6.2.3",
|
|
45
|
+
"express": "^4.18.2",
|
|
45
46
|
"fluent-ffmpeg": "^2.1.2",
|
|
46
47
|
"form-data": "^4.0.0",
|
|
47
48
|
"gpt-3-encoder": "^1.1.4",
|
|
@@ -51,12 +52,15 @@
|
|
|
51
52
|
"handlebars": "^4.7.7",
|
|
52
53
|
"keyv": "^4.5.2",
|
|
53
54
|
"langchain": "^0.0.47",
|
|
55
|
+
"uuid": "^9.0.0",
|
|
54
56
|
"ws": "^8.12.0",
|
|
55
57
|
"ytdl-core": "^4.11.2"
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
58
60
|
"ava": "^5.2.0",
|
|
59
|
-
"dotenv": "^16.0.3"
|
|
61
|
+
"dotenv": "^16.0.3",
|
|
62
|
+
"eslint": "^8.38.0",
|
|
63
|
+
"eslint-plugin-import": "^2.27.5"
|
|
60
64
|
},
|
|
61
65
|
"publishConfig": {
|
|
62
66
|
"access": "restricted"
|
package/pathways/lc_test.mjs
CHANGED
|
@@ -3,20 +3,24 @@
|
|
|
3
3
|
|
|
4
4
|
// Import required modules
|
|
5
5
|
import { OpenAI } from "langchain/llms";
|
|
6
|
-
import { PromptTemplate } from "langchain/prompts";
|
|
7
|
-
import { LLMChain, ConversationChain } from "langchain/chains";
|
|
6
|
+
//import { PromptTemplate } from "langchain/prompts";
|
|
7
|
+
//import { LLMChain, ConversationChain } from "langchain/chains";
|
|
8
8
|
import { initializeAgentExecutor } from "langchain/agents";
|
|
9
9
|
import { SerpAPI, Calculator } from "langchain/tools";
|
|
10
|
-
import { BufferMemory } from "langchain/memory";
|
|
10
|
+
//import { BufferMemory } from "langchain/memory";
|
|
11
11
|
|
|
12
12
|
export default {
|
|
13
13
|
|
|
14
14
|
// Agent test case
|
|
15
|
-
resolver: async (parent, args, contextValue,
|
|
15
|
+
resolver: async (parent, args, contextValue, _info) => {
|
|
16
16
|
|
|
17
17
|
const { config } = contextValue;
|
|
18
|
+
const env = config.getEnv();
|
|
19
|
+
|
|
20
|
+
// example of reading from a predefined config variable
|
|
18
21
|
const openAIApiKey = config.get('openaiApiKey');
|
|
19
|
-
|
|
22
|
+
// example of reading straight from environment
|
|
23
|
+
const serpApiKey = env.SERPAPI_API_KEY;
|
|
20
24
|
|
|
21
25
|
const model = new OpenAI({ openAIApiKey: openAIApiKey, temperature: 0 });
|
|
22
26
|
const tools = [new SerpAPI( serpApiKey ), new Calculator()];
|
package/pathways/summary.js
CHANGED
|
@@ -16,7 +16,7 @@ export default {
|
|
|
16
16
|
},
|
|
17
17
|
|
|
18
18
|
// Custom resolver to generate summaries by reprompting if they are too long or too short.
|
|
19
|
-
resolver: async (parent, args, contextValue,
|
|
19
|
+
resolver: async (parent, args, contextValue, _info) => {
|
|
20
20
|
const { config, pathway, requestState } = contextValue;
|
|
21
21
|
const originalTargetLength = args.targetLength;
|
|
22
22
|
|