@aj-archipelago/cortex 0.0.5 → 0.0.7

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.
@@ -0,0 +1,79 @@
1
+ // OpenAICompletionPlugin.js
2
+ const ModelPlugin = require('./modelPlugin');
3
+ const handlebars = require("handlebars");
4
+ const { encode } = require("gpt-3-encoder");
5
+ const FormData = require('form-data');
6
+ const fs = require('fs');
7
+ const { splitMediaFile, isValidYoutubeUrl, processYoutubeUrl, deleteTempPath } = require('../../lib/fileChunker');
8
+ const pubsub = require('../pubsub');
9
+
10
+ class OpenAIWhisperPlugin extends ModelPlugin {
11
+ constructor(config, pathway) {
12
+ super(config, pathway);
13
+ }
14
+
15
+ getCompiledPrompt(text, parameters, prompt) {
16
+ const combinedParameters = { ...this.promptParameters, ...parameters };
17
+ const modelPrompt = this.getModelPrompt(prompt, parameters);
18
+ const modelPromptText = modelPrompt.prompt ? handlebars.compile(modelPrompt.prompt)({ ...combinedParameters, text }) : '';
19
+
20
+ return { modelPromptText, tokenLength: encode(modelPromptText).length };
21
+ }
22
+
23
+ // Execute the request to the OpenAI Whisper API
24
+ async execute(text, parameters, prompt, pathwayResolver) {
25
+ const url = this.requestUrl(text);
26
+ const params = {};
27
+ const { modelPromptText } = this.getCompiledPrompt(text, parameters, prompt);
28
+
29
+ const processChunk = async (chunk) => {
30
+ try {
31
+ const formData = new FormData();
32
+ formData.append('file', fs.createReadStream(chunk));
33
+ formData.append('model', this.model.params.model);
34
+ formData.append('response_format', 'text');
35
+ // formData.append('language', 'tr');
36
+ modelPromptText && formData.append('prompt', modelPromptText);
37
+
38
+ return this.executeRequest(url, formData, params, { ...this.model.headers, ...formData.getHeaders() });
39
+ } catch (err) {
40
+ console.log(err);
41
+ }
42
+ }
43
+
44
+ let result;
45
+ let { file } = parameters;
46
+ let folder;
47
+ const isYoutubeUrl = isValidYoutubeUrl(file);
48
+
49
+ try {
50
+ if (isYoutubeUrl) {
51
+ file = await processYoutubeUrl(file);
52
+ }
53
+
54
+ const mediaSplit = await splitMediaFile(file);
55
+
56
+ const { requestId } = pathwayResolver;
57
+ pubsub.publish('REQUEST_PROGRESS', {
58
+ requestProgress: {
59
+ requestId,
60
+ progress: 0.5,
61
+ data: null,
62
+ }
63
+ });
64
+
65
+ folder = mediaSplit.folder;
66
+ result = await Promise.all(mediaSplit.chunks.map(processChunk));
67
+
68
+ } catch (error) {
69
+ console.error("An error occurred:", error);
70
+ } finally {
71
+ isYoutubeUrl && (await deleteTempPath(file));
72
+ folder && (await deleteTempPath(folder));
73
+ }
74
+ return result.join('');
75
+ }
76
+ }
77
+
78
+ module.exports = OpenAIWhisperPlugin;
79
+
package/graphql/prompt.js CHANGED
@@ -12,6 +12,7 @@ class Prompt {
12
12
 
13
13
  this.usesTextInput = promptContains('text', this.prompt ? this.prompt : this.messages);
14
14
  this.usesPreviousResult = promptContains('previousResult', this.prompt ? this.prompt : this.messages);
15
+ this.debugInfo = '';
15
16
  }
16
17
  }
17
18
 
@@ -0,0 +1,5 @@
1
+ const requestState = {}; // Stores the state of each request
2
+
3
+ module.exports = {
4
+ requestState
5
+ };
@@ -5,23 +5,23 @@ const { PathwayResolver } = require("./pathwayResolver");
5
5
  // (parent, args, contextValue, info)
6
6
  const rootResolver = async (parent, args, contextValue, info) => {
7
7
  const { config, pathway, requestState } = contextValue;
8
- const { temperature } = pathway;
8
+ const { temperature, enableGraphqlCache } = pathway;
9
9
 
10
- // Turn off caching if temperature is 0
11
- if (temperature == 0) {
10
+ // Turn on graphql caching if enableGraphqlCache true and temperature is 0
11
+ if (enableGraphqlCache && temperature == 0) { // ||
12
12
  info.cacheControl.setCacheHint({ maxAge: 60 * 60 * 24, scope: 'PUBLIC' });
13
13
  }
14
14
 
15
- const pathwayResolver = new PathwayResolver({ config, pathway, requestState });
15
+ const pathwayResolver = new PathwayResolver({ config, pathway, args, requestState });
16
16
  contextValue.pathwayResolver = pathwayResolver;
17
17
 
18
- // Add request parameters back as debug
19
- const requestParameters = pathwayResolver.prompts.map((prompt) => pathwayResolver.pathwayPrompter.plugin.requestParameters(args.text, args, prompt));
20
- const debug = JSON.stringify(requestParameters);
21
-
22
18
  // Execute the request with timeout
23
19
  const result = await fulfillWithTimeout(pathway.resolver(parent, args, contextValue, info), pathway.timeout);
24
20
  const { warnings, previousResult, savedContextId } = pathwayResolver;
21
+
22
+ // Add request parameters back as debug
23
+ const debug = pathwayResolver.prompts.map(prompt => prompt.debugInfo || '').join('\n').trim();
24
+
25
25
  return { debug, result, warnings, previousResult, contextId: savedContextId }
26
26
  }
27
27
 
@@ -4,14 +4,27 @@
4
4
 
5
5
  const pubsub = require("./pubsub");
6
6
  const { withFilter } = require("graphql-subscriptions");
7
+ const { requestState } = require("./requestState");
7
8
 
8
9
  const subscriptions = {
9
10
  requestProgress: {
10
11
  subscribe: withFilter(
11
- () => pubsub.asyncIterator(['REQUEST_PROGRESS']),
12
+ (_, args, __, info) => {
13
+ const { requestIds } = args;
14
+ for (const requestId of requestIds) {
15
+ if (!requestState[requestId]) {
16
+ console.log(`requestProgress, requestId: ${requestId} not found`);
17
+ } else {
18
+ console.log(`starting async requestProgress, requestId: ${requestId}`);
19
+ const { resolver, args } = requestState[requestId];
20
+ resolver(args);
21
+ }
22
+ }
23
+ return pubsub.asyncIterator(['REQUEST_PROGRESS'])
24
+ },
12
25
  (payload, variables) => {
13
26
  return (
14
- payload.requestProgress.requestId === variables.requestId
27
+ variables.requestIds.includes(payload.requestProgress.requestId)
15
28
  );
16
29
  },
17
30
  ),
@@ -2,51 +2,60 @@ const GRAPHQL_TYPE_MAP = {
2
2
  boolean: 'Boolean',
3
3
  string: 'String',
4
4
  number: 'Int',
5
- }
6
-
7
-
8
- const typeDef = (pathway) => {
5
+ };
6
+
7
+ const typeDef = (pathway) => {
9
8
  const { name, objName, defaultInputParameters, inputParameters, format } = pathway;
10
-
9
+
11
10
  const fields = format ? format.match(/\b(\w+)\b/g) : null;
12
- const fieldsStr = !fields ? `` : fields.map(f => `${f}: String`).join('\n ');
13
-
11
+ const fieldsStr = !fields ? `` : fields.map((f) => `${f}: String`).join('\n ');
12
+
14
13
  const typeName = fields ? `${objName}Result` : `String`;
15
14
  const messageType = `input Message { role: String, content: String }`;
16
-
15
+
17
16
  const type = fields ? `type ${typeName} {
18
- ${fieldsStr}
19
- }` : ``;
20
-
17
+ ${fieldsStr}
18
+ }` : ``;
19
+
21
20
  const resultStr = pathway.list ? `[${typeName}]` : typeName;
22
-
21
+
23
22
  const responseType = `type ${objName} {
24
- debug: String
25
- result: ${resultStr}
26
- previousResult: String
27
- warnings: [String]
28
- contextId: String
29
- }`;
30
-
31
-
23
+ debug: String
24
+ result: ${resultStr}
25
+ previousResult: String
26
+ warnings: [String]
27
+ contextId: String
28
+ }`;
29
+
32
30
  const params = { ...defaultInputParameters, ...inputParameters };
33
-
34
- const paramsStr = Object.entries(params).map(
35
- ([key, value]) => {
36
- if (typeof value === 'object' && Array.isArray(value)) {
37
- return `${key}: [Message] = []`;
38
- } else {
39
- return `${key}: ${GRAPHQL_TYPE_MAP[typeof (value)]} = ${typeof (value) === 'string' ? `"${value}"` : value}`;
40
- }
31
+
32
+ const paramsStr = Object.entries(params)
33
+ .map(([key, value]) => {
34
+ if (typeof value === 'object' && Array.isArray(value)) {
35
+ return `${key}: [Message] = []`;
36
+ } else {
37
+ return `${key}: ${GRAPHQL_TYPE_MAP[typeof value]} = ${
38
+ typeof value === 'string' ? `"${value}"` : value
39
+ }`;
41
40
  }
42
- ).join('\n');
43
-
44
-
45
- const definition = `${messageType}\n\n${type}\n\n${responseType}\n\nextend type Query {${name}(${paramsStr}): ${objName}}`;
46
- //console.log(definition);
47
- return definition;
48
- }
49
-
50
- module.exports = {
41
+ })
42
+ .join('\n');
43
+
44
+ const restDefinition = Object.entries(params).map(([key, value]) => {
45
+ return {
46
+ name: key,
47
+ type: `${GRAPHQL_TYPE_MAP[typeof value]}${typeof value === 'object' && Array.isArray(value) ? '[]' : ''}`,
48
+ };
49
+ });
50
+
51
+ const gqlDefinition = `${messageType}\n\n${type}\n\n${responseType}\n\nextend type Query {${name}(${paramsStr}): ${objName}}`;
52
+
53
+ return {
54
+ gqlDefinition,
55
+ restDefinition,
56
+ };
57
+ };
58
+
59
+ module.exports = {
51
60
  typeDef,
52
- }
61
+ };
@@ -0,0 +1,152 @@
1
+ const fs = require('fs');
2
+ const ffmpeg = require('fluent-ffmpeg');
3
+ const path = require('path');
4
+ const { v4: uuidv4 } = require('uuid');
5
+ const os = require('os');
6
+ const util = require('util');
7
+ const ffmpegProbe = util.promisify(ffmpeg.ffprobe);
8
+ const pipeline = util.promisify(require('stream').pipeline);
9
+ const ytdl = require('ytdl-core');
10
+
11
+
12
+ async function processChunk(inputPath, outputFileName, start, duration) {
13
+ return new Promise((resolve, reject) => {
14
+ ffmpeg(inputPath)
15
+ .seekInput(start)
16
+ .duration(duration)
17
+ .on('start', (cmd) => {
18
+ console.log(`Started FFmpeg with command: ${cmd}`);
19
+ })
20
+ .on('error', (err) => {
21
+ console.error(`Error occurred while processing chunk:`, err);
22
+ reject(err);
23
+ })
24
+ .on('end', () => {
25
+ console.log(`Finished processing chunk`);
26
+ resolve(outputFileName);
27
+ })
28
+ .save(outputFileName);
29
+ });
30
+ }
31
+
32
+ const generateUniqueFolderName = () => {
33
+ const uniqueFolderName = uuidv4();
34
+ const tempFolderPath = os.tmpdir(); // Get the system's temporary folder
35
+ const uniqueOutputPath = path.join(tempFolderPath, uniqueFolderName);
36
+ return uniqueOutputPath;
37
+ }
38
+
39
+ const generateUniqueTempFileName = () => {
40
+ return path.join(os.tmpdir(), uuidv4());
41
+ }
42
+
43
+ async function splitMediaFile(inputPath, chunkDurationInSeconds = 600) {
44
+ try {
45
+ const metadata = await ffmpegProbe(inputPath);
46
+ const duration = metadata.format.duration;
47
+ const numChunks = Math.ceil((duration - 1) / chunkDurationInSeconds);
48
+
49
+ const chunkPromises = [];
50
+
51
+ const uniqueOutputPath = generateUniqueFolderName();
52
+
53
+ // Create unique folder
54
+ fs.mkdirSync(uniqueOutputPath, { recursive: true });
55
+
56
+
57
+ for (let i = 0; i < numChunks; i++) {
58
+ const outputFileName = path.join(
59
+ uniqueOutputPath,
60
+ `chunk-${i + 1}-${path.basename(inputPath)}`
61
+ );
62
+
63
+ const chunkPromise = processChunk(
64
+ inputPath,
65
+ outputFileName,
66
+ i * chunkDurationInSeconds,
67
+ chunkDurationInSeconds
68
+ );
69
+
70
+ chunkPromises.push(chunkPromise);
71
+ }
72
+
73
+ const chunkedFiles = await Promise.all(chunkPromises);
74
+ console.log('All chunks processed. Chunked file names:', chunkedFiles);
75
+ return { chunks: chunkedFiles, folder: uniqueOutputPath }
76
+ } catch (err) {
77
+ console.error('Error occurred during the splitting process:', err);
78
+ }
79
+ }
80
+
81
+ async function deleteTempPath(path) {
82
+ try {
83
+ if (!path) return;
84
+ const stats = fs.statSync(path);
85
+ if (stats.isFile()) {
86
+ fs.unlinkSync(path);
87
+ console.log(`Temporary file ${path} deleted successfully.`);
88
+ } else if (stats.isDirectory()) {
89
+ fs.rmdirSync(path, { recursive: true });
90
+ console.log(`Temporary folder ${path} and its contents deleted successfully.`);
91
+ }
92
+ } catch (err) {
93
+ console.error('Error occurred while deleting the temporary path:', err);
94
+ }
95
+ }
96
+
97
+
98
+ function isValidYoutubeUrl(url) {
99
+ const regex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$/;
100
+ return regex.test(url);
101
+ }
102
+
103
+ function convertYoutubeToMp3Stream(video) {
104
+ // Configure ffmpeg to convert the video to mp3
105
+ const mp3Stream = ffmpeg(video)
106
+ .withAudioCodec('libmp3lame')
107
+ .toFormat('mp3')
108
+ .on('error', (err) => {
109
+ console.error(`An error occurred during conversion: ${err.message}`);
110
+ });
111
+
112
+ return mp3Stream;
113
+ }
114
+
115
+ async function pipeStreamToFile(stream, filePath) {
116
+ try {
117
+ await pipeline(stream, fs.createWriteStream(filePath));
118
+ console.log('Stream piped to file successfully.');
119
+ } catch (error) {
120
+ console.error(`Error piping stream to file: ${error.message}`);
121
+ }
122
+ }
123
+
124
+
125
+ const processYoutubeUrl = async (url) => {
126
+ const info = await ytdl.getInfo(url);
127
+ const audioFormat = ytdl.chooseFormat(info.formats, { quality: 'highestaudio' });
128
+
129
+ if (!audioFormat) {
130
+ throw new Error('No suitable audio format found');
131
+ }
132
+
133
+ const stream = ytdl.downloadFromInfo(info, { format: audioFormat });
134
+
135
+ const mp3Stream = convertYoutubeToMp3Stream(stream);
136
+ const outputFileName = path.join(os.tmpdir(), `${uuidv4()}.mp3`);
137
+ await pipeStreamToFile(mp3Stream, outputFileName); // You can also pipe the stream to a file
138
+ return outputFileName;
139
+ }
140
+
141
+ function deleteFile(filePath) {
142
+ try {
143
+ fs.unlinkSync(filePath);
144
+ console.log(`File ${filePath} cleaned successfully.`);
145
+ } catch (error) {
146
+ console.error(`Error deleting file ${filePath}:`, error);
147
+ }
148
+ }
149
+
150
+ module.exports = {
151
+ splitMediaFile, deleteTempPath, processYoutubeUrl, isValidYoutubeUrl
152
+ };
package/lib/request.js CHANGED
@@ -1,20 +1,67 @@
1
- const axios = require('axios');
2
1
  const Bottleneck = require("bottleneck/es5");
2
+ const RequestMonitor = require('./requestMonitor');
3
+ const { config } = require('../config');
4
+ let axios = require('axios');
5
+
6
+ if (config.get('enableCache')) {
7
+ // Setup cache
8
+ const { setupCache } = require('axios-cache-interceptor');
9
+ axios = setupCache(axios, {
10
+ // enable cache for all requests by default
11
+ methods: ['get', 'post', 'put', 'delete', 'patch'],
12
+ interpretHeader: false,
13
+ ttl: 1000 * 60 * 60 * 24 * 7, // 7 days
14
+ });
15
+ }
3
16
 
4
17
  const limiters = {};
18
+ const monitors = {};
5
19
 
6
20
  const buildLimiters = (config) => {
7
21
  console.log('Building limiters...');
8
22
  for (const [name, model] of Object.entries(config.get('models'))) {
23
+ const rps = model.requestsPerSecond ?? 100;
9
24
  limiters[name] = new Bottleneck({
10
- minTime: 1000 / (model.requestsPerSecond ?? 100),
11
- // maxConcurrent: 20,
12
- })
25
+ minTime: 1000 / rps,
26
+ maxConcurrent: rps,
27
+ reservoir: rps, // Number of tokens available initially
28
+ reservoirRefreshAmount: rps, // Number of tokens added per interval
29
+ reservoirRefreshInterval: 1000, // Interval in milliseconds
30
+ });
31
+ monitors[name] = new RequestMonitor();
32
+ }
33
+ }
34
+
35
+ setInterval(() => {
36
+ const monitorKeys = Object.keys(monitors);
37
+
38
+ // Skip logging if the monitors object does not exist or is empty
39
+ if (!monitorKeys || monitorKeys.length === 0) {
40
+ return;
13
41
  }
42
+
43
+ monitorKeys.forEach((monitorName) => {
44
+ const monitor = monitors[monitorName];
45
+ const callRate = monitor.getPeakCallRate();
46
+ const error429Rate = monitor.getError429Rate();
47
+ if (callRate > 0) {
48
+ console.log('------------------------');
49
+ console.log(`${monitorName} Call rate: ${callRate} calls/sec, 429 errors: ${error429Rate * 100}%`);
50
+ console.log('------------------------');
51
+ // Reset the rate monitor to start a new monitoring interval.
52
+ monitor.reset();
53
+ }
54
+ });
55
+ }, 10000); // Log rates every 10 seconds (10000 ms).
56
+
57
+ const postWithMonitor = async (model, url, data, axiosConfigObj) => {
58
+ const monitor = monitors[model];
59
+ monitor.incrementCallCount();
60
+ return axios.post(url, data, axiosConfigObj);
14
61
  }
15
62
 
16
63
  const MAX_RETRY = 10;
17
- const postRequest = async ({ url, data, params, headers }, model) => {
64
+ const postRequest = async ({ url, data, params, headers, cache }, model) => {
18
65
  let retry = 0;
19
66
  const errors = []
20
67
  for (let i = 0; i < MAX_RETRY; i++) {
@@ -22,13 +69,20 @@ const postRequest = async ({ url, data, params, headers }, model) => {
22
69
  if (i > 0) {
23
70
  console.log(`Retrying request #retry ${i}: ${JSON.stringify(data)}...`);
24
71
  await new Promise(r => setTimeout(r, 200 * Math.pow(2, i))); // exponential backoff
25
- }
72
+ }
26
73
  if (!limiters[model]) {
27
74
  throw new Error(`No limiter for model ${model}!`);
28
75
  }
29
- return await limiters[model].schedule(() => axios.post(url, data, { params, headers }));
76
+ const axiosConfigObj = { params, headers, cache };
77
+ if (params.stream || data.stream) {
78
+ axiosConfigObj.responseType = 'stream';
79
+ }
80
+ return await limiters[model].schedule(() => postWithMonitor(model, url, data, axiosConfigObj));
30
81
  } catch (e) {
31
82
  console.error(`Failed request with data ${JSON.stringify(data)}: ${e}`);
83
+ if (e.response.status === 429) {
84
+ monitors[model].incrementError429Count();
85
+ }
32
86
  errors.push(e);
33
87
  }
34
88
  }
@@ -37,7 +91,10 @@ const postRequest = async ({ url, data, params, headers }, model) => {
37
91
 
38
92
  const request = async (params, model) => {
39
93
  const response = await postRequest(params, model);
40
- const { error, data } = response;
94
+ const { error, data, cached } = response;
95
+ if (cached) {
96
+ console.info('/Request served with cached response.');
97
+ }
41
98
  if (error && error.length > 0) {
42
99
  const lastError = error[error.length - 1];
43
100
  return { error: lastError.toJSON() ?? lastError ?? error };
@@ -0,0 +1,43 @@
1
+ class RequestMonitor {
2
+ constructor() {
3
+ this.callCount = 0;
4
+ this.peakCallRate = 0;
5
+ this.error429Count = 0;
6
+ this.startTime = new Date();
7
+ }
8
+
9
+ incrementCallCount() {
10
+ this.callCount++;
11
+ if (this.getCallRate() > this.peakCallRate) {
12
+ this.peakCallRate = this.getCallRate();
13
+ }
14
+ }
15
+
16
+ incrementError429Count() {
17
+ this.error429Count++;
18
+ }
19
+
20
+ getCallRate() {
21
+ const currentTime = new Date();
22
+ const timeElapsed = (currentTime - this.startTime) / 1000; // time elapsed in seconds
23
+ return timeElapsed < 1 ? this.callCount : this.callCount / timeElapsed;
24
+ }
25
+
26
+ getPeakCallRate() {
27
+ return this.peakCallRate;
28
+ }
29
+
30
+ getError429Rate() {
31
+ return this.error429Count / this.callCount;
32
+ }
33
+
34
+ reset() {
35
+ this.callCount = 0;
36
+ this.error429Count = 0;
37
+ this.peakCallRate = 0;
38
+ this.startTime = new Date();
39
+ }
40
+ }
41
+
42
+ module.exports = RequestMonitor;
43
+
package/package.json CHANGED
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "0.0.5",
4
- "description": "Project Cortex",
3
+ "version": "0.0.7",
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",
7
7
  "url": "git+https://github.com/aj-archipelago/cortex.git"
8
8
  },
9
9
  "keywords": [
10
10
  "cortex",
11
- "ai"
11
+ "AI",
12
+ "prompt engineering",
13
+ "LLM",
14
+ "OpenAI",
15
+ "Azure",
16
+ "GPT-3",
17
+ "GPT-4",
18
+ "chatGPT",
19
+ "GraphQL"
12
20
  ],
13
21
  "main": "index.js",
14
22
  "scripts": {
@@ -22,22 +30,26 @@
22
30
  "@apollo/utils.keyvadapter": "^1.1.2",
23
31
  "@graphql-tools/schema": "^9.0.12",
24
32
  "@keyv/redis": "^2.5.4",
25
- "apollo-server": "^3.11.1",
33
+ "apollo-server": "^3.12.0",
26
34
  "apollo-server-core": "^3.11.1",
27
35
  "apollo-server-express": "^3.11.1",
28
36
  "apollo-server-plugin-response-cache": "^3.8.1",
29
- "axios": "^1.2.0",
37
+ "axios": "^1.3.4",
38
+ "axios-cache-interceptor": "^1.0.1",
30
39
  "bottleneck": "^2.19.5",
31
40
  "compromise": "^14.8.1",
32
41
  "compromise-paragraphs": "^0.1.0",
33
42
  "convict": "^6.2.3",
43
+ "fluent-ffmpeg": "^2.1.2",
44
+ "form-data": "^4.0.0",
34
45
  "gpt-3-encoder": "^1.1.4",
35
46
  "graphql": "^16.6.0",
36
47
  "graphql-subscriptions": "^2.0.0",
37
48
  "graphql-ws": "^5.11.2",
38
49
  "handlebars": "^4.7.7",
39
50
  "keyv": "^4.5.2",
40
- "ws": "^8.12.0"
51
+ "ws": "^8.12.0",
52
+ "ytdl-core": "^4.11.2"
41
53
  },
42
54
  "devDependencies": {
43
55
  "dotenv": "^16.0.3",
@@ -1,4 +1,3 @@
1
- const { parseResponse } = require("../graphql/parser");
2
1
  const { rootResolver, resolver } = require("../graphql/resolver");
3
2
  const { typeDef } = require('../graphql/typeDef')
4
3
 
@@ -7,9 +6,9 @@ module.exports = {
7
6
  prompt: `{{text}}`,
8
7
  defaultInputParameters: {
9
8
  text: ``,
10
- // Add the option of making every call async
11
- async: false,
12
- contextId : ``, // used to identify the context of the request
9
+ async: false, // switch to enable async mode
10
+ contextId: ``, // used to identify the context of the request,
11
+ stream: false, // switch to enable stream mode
13
12
  },
14
13
  inputParameters: {},
15
14
  typeDef,
package/pathways/bias.js CHANGED
@@ -1,3 +1,10 @@
1
+ // bias.js
2
+ // Objectivity analysis of text
3
+ // This module exports a prompt that analyzes the given text and determines if it's written objectively. It also provides a detailed explanation of the decision.
4
+
1
5
  module.exports = {
6
+ // Uncomment the following line to enable caching for this prompt, if desired.
7
+ // enableCache: true,
8
+
2
9
  prompt: `{{text}}\n\nIs the above text written objectively? Why or why not, explain with details:\n`
3
10
  }
package/pathways/chat.js CHANGED
@@ -1,4 +1,7 @@
1
- // Description: Have a chat with a bot that uses context to understand the conversation
1
+ // chat.js
2
+ // Simple context-aware chat bot
3
+ // This is a two prompt implementation of a context aware chat bot. The first prompt generates content that will be stored in the previousResult variable and will be returned to the client. In the optimum implementation, the client will then update their chatContext variable for the next call. The second prompt actually responds to the user. The second prompt *could* use previousResult instead of chatContext, but in this situation previousResult will also include the current turn of the conversation to which it is responding. That can get a little confusing as it tends to overemphasize the current turn in the response.
4
+
2
5
  module.exports = {
3
6
  prompt:
4
7
  [
@@ -1,3 +1,7 @@
1
+ // complete.js
2
+ // Text completion module
3
+ // This module exports a prompt that takes an input text and completes it by generating a continuation of the given text.
4
+
1
5
  module.exports = {
2
6
  prompt: `Continue and complete the following:\n\n{{text}}`
3
7
  }