@aj-archipelago/cortex 1.1.24 → 1.1.26

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.
@@ -1,18 +1,21 @@
1
1
  import { selectEndpoint } from './requestExecutor.js';
2
2
 
3
3
  class CortexRequest {
4
- constructor( { url, urlSuffix, data, params, headers, cache, model, pathwayResolver, selectedEndpoint, stream } = {}) {
4
+ constructor( { url, urlSuffix, data, params, headers, auth, cache, model, pathwayResolver, selectedEndpoint, stream, initCallback } = {}) {
5
5
  this._url = url || '';
6
6
  this._urlSuffix = urlSuffix || '';
7
7
  this._data = data || {};
8
8
  this._params = params || {};
9
9
  this._headers = headers || {};
10
+ this._addHeaders = {};
11
+ this._auth = auth || {};
10
12
  this._cache = cache || {};
11
13
  this._model = model || '';
12
14
  this._pathwayResolver = pathwayResolver || {};
13
15
  this._selectedEndpoint = selectedEndpoint || {};
14
16
  this._stream = stream || false;
15
17
  this._method = 'POST';
18
+ this._initCallback = initCallback || null;
16
19
 
17
20
  if (this._pathwayResolver) {
18
21
  this._model = this._pathwayResolver.model;
@@ -23,14 +26,22 @@ class CortexRequest {
23
26
  }
24
27
  }
25
28
 
29
+ initRequest() {
30
+ if (typeof this._initCallback === 'function') {
31
+ this._initCallback(this);
32
+ }
33
+ }
34
+
26
35
  selectNewEndpoint() {
27
36
  const sep = selectEndpoint(this._model);
28
37
  if (sep) {
29
38
  this._selectedEndpoint = sep;
30
39
  this._url = sep.url;
31
- this._data = { ...this._data, ...sep.params };
32
- this._headers = { ...this._headers, ...sep.headers };
33
- this._params = { ...this._params, ...sep.params };
40
+ this._data = { ...this._data, ...sep.data, ...sep.params };
41
+ if (sep.auth) {
42
+ this._auth = { ...sep.auth };
43
+ }
44
+ this.initRequest();
34
45
  }
35
46
  }
36
47
 
@@ -70,9 +81,22 @@ class CortexRequest {
70
81
  this._data = value;
71
82
  }
72
83
 
84
+ // initCallback getter and setter
85
+ get initCallback() {
86
+ return this._initCallback;
87
+ }
88
+
89
+ set initCallback(value) {
90
+ if (typeof value !== 'function') {
91
+ throw new Error('initCallback must be a function');
92
+ }
93
+ this._initCallback = value;
94
+ this.initRequest();
95
+ }
96
+
73
97
  // params getter and setter
74
98
  get params() {
75
- return this._params;
99
+ return {...this._params, ...this._selectedEndpoint.params};
76
100
  }
77
101
 
78
102
  set params(value) {
@@ -81,13 +105,38 @@ class CortexRequest {
81
105
 
82
106
  // headers getter and setter
83
107
  get headers() {
84
- return this._headers;
108
+ return { ...this._headers, ...this._selectedEndpoint.headers, ...this._auth, ...this._addHeaders };
85
109
  }
86
110
 
87
111
  set headers(value) {
88
112
  this._headers = value;
89
113
  }
90
114
 
115
+ // addheaders getter and setter
116
+ get addHeaders() {
117
+ return this._addHeaders;
118
+ }
119
+
120
+ set addHeaders(value) {
121
+ // Create a new object to store the processed headers
122
+ this._addHeaders = {};
123
+
124
+ // Iterate over the input headers and convert keys to title case
125
+ for (const [key, val] of Object.entries(value)) {
126
+ const titleCaseKey = key.replace(/(^|-)./g, m => m.toUpperCase());
127
+ this._addHeaders[titleCaseKey] = val;
128
+ }
129
+ }
130
+
131
+ // auth getter and setter
132
+ get auth() {
133
+ return this._auth;
134
+ }
135
+
136
+ set auth(value) {
137
+ this._auth = value;
138
+ }
139
+
91
140
  // cache getter and setter
92
141
  get cache() {
93
142
  return this._cache;
@@ -311,9 +311,9 @@ const makeRequest = async (cortexRequest) => {
311
311
  throw new Error(`Received error response: ${response.status}`);
312
312
  }
313
313
  } catch (error) {
314
- const { response, duration } = error;
315
- if (response) {
316
- const status = response.status;
314
+ const { response, duration, code } = error;
315
+ if (response || code === 'ECONNRESET') {
316
+ const status = response?.status || 502; // default to 502 if ECONNRESET
317
317
  // if there is only one endpoint, only retry select error codes
318
318
  if (cortexRequest.model.endpoints.length === 1) {
319
319
  if (status !== 429 &&
@@ -323,6 +323,8 @@ const makeRequest = async (cortexRequest) => {
323
323
  status !== 504) {
324
324
  return { response, duration };
325
325
  }
326
+ // set up for a retry by reinitializing the request
327
+ cortexRequest.initRequest();
326
328
  } else {
327
329
  // if there are multiple endpoints, retry everything by default
328
330
  // as it could be a temporary issue with one endpoint
@@ -331,6 +333,7 @@ const makeRequest = async (cortexRequest) => {
331
333
  if (status == 400) {
332
334
  return { response, duration };
333
335
  }
336
+ // set up for a retry by selecting a new endpoint, which will also reinitialize the request
334
337
  cortexRequest.selectNewEndpoint();
335
338
  }
336
339
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
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
  "private": false,
6
6
  "repository": {
@@ -263,7 +263,7 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
263
263
 
264
264
  const gcpAuthTokenHelper = this.config.get("gcpAuthTokenHelper");
265
265
  const authToken = await gcpAuthTokenHelper.getAccessToken();
266
- cortexRequest.headers.Authorization = `Bearer ${authToken}`;
266
+ cortexRequest.auth.Authorization = `Bearer ${authToken}`;
267
267
 
268
268
  return this.executeRequest(cortexRequest);
269
269
  }
@@ -164,7 +164,7 @@ class Gemini15ChatPlugin extends ModelPlugin {
164
164
 
165
165
  const gcpAuthTokenHelper = this.config.get('gcpAuthTokenHelper');
166
166
  const authToken = await gcpAuthTokenHelper.getAccessToken();
167
- cortexRequest.headers.Authorization = `Bearer ${authToken}`;
167
+ cortexRequest.auth.Authorization = `Bearer ${authToken}`;
168
168
 
169
169
  return this.executeRequest(cortexRequest);
170
170
  }
@@ -159,7 +159,7 @@ class GeminiChatPlugin extends ModelPlugin {
159
159
 
160
160
  const gcpAuthTokenHelper = this.config.get('gcpAuthTokenHelper');
161
161
  const authToken = await gcpAuthTokenHelper.getAccessToken();
162
- cortexRequest.headers.Authorization = `Bearer ${authToken}`;
162
+ cortexRequest.auth.Authorization = `Bearer ${authToken}`;
163
163
 
164
164
  return this.executeRequest(cortexRequest);
165
165
  }
@@ -117,49 +117,52 @@ class NeuralSpacePlugin extends ModelPlugin {
117
117
  const cortexRequest = new CortexRequest({ pathwayResolver });
118
118
  cortexRequest.url = this.requestUrl();
119
119
 
120
- const formData = new FormData();
121
- formData.append("files", fs.createReadStream(chunk));
122
- const configObj = {
123
- file_transcription: {
124
- mode: "advanced",
125
- },
126
- };
127
-
128
- //phrase/segment level
129
- if ((responseFormat && !wordTimestamped) || maxLineWidth) {
130
- configObj.speaker_diarization = {
131
- // mode: "speakers",
132
- // num_speakers: numSpeakers,
133
- // overrides: {
134
- // clustering: {
135
- // threshold: clusteringThreshold,
136
- // },
137
- // },
120
+ const nsInitCallback = (requestInstance) => {
121
+ const formData = new FormData();
122
+ formData.append("files", fs.createReadStream(chunk));
123
+ const configObj = {
124
+ file_transcription: {
125
+ mode: "advanced",
126
+ },
138
127
  };
139
128
 
140
- configObj.subtitles_guidelines = {
141
- line_count: 1
142
- };
143
- }
144
-
145
- if (maxLineWidth) {
146
- configObj.subtitles_guidelines = {
147
- character_count: maxLineWidth,
129
+ //phrase/segment level
130
+ if ((responseFormat && !wordTimestamped) || maxLineWidth) {
131
+ configObj.speaker_diarization = {
132
+ // mode: "speakers",
133
+ // num_speakers: numSpeakers,
134
+ // overrides: {
135
+ // clustering: {
136
+ // threshold: clusteringThreshold,
137
+ // },
138
+ // },
139
+ };
140
+
141
+ configObj.subtitles_guidelines = {
142
+ line_count: 1,
143
+ };
144
+ }
145
+
146
+ if (maxLineWidth) {
147
+ configObj.subtitles_guidelines = {
148
+ character_count: maxLineWidth,
149
+ };
150
+ }
151
+
152
+ if (language) {
153
+ configObj.file_transcription.language_id = language;
154
+ }
155
+ formData.append("config", JSON.stringify(configObj));
156
+
157
+ requestInstance.data = formData;
158
+ requestInstance.params = {};
159
+ requestInstance.addHeaders = {
160
+ ...formData.getHeaders(),
148
161
  };
149
- }
150
-
151
- if (language) {
152
- configObj.file_transcription.language_id = language;
153
- }
154
- formData.append("config", JSON.stringify(configObj));
155
-
156
- cortexRequest.data = formData;
157
- cortexRequest.params = {};
158
- cortexRequest.headers = {
159
- ...cortexRequest.headers,
160
- ...formData.getHeaders(),
161
162
  };
162
163
 
164
+ cortexRequest.initCallback = nsInitCallback;
165
+
163
166
  const result = await this.executeRequest(cortexRequest);
164
167
 
165
168
  const jobId = result?.data?.jobId;
@@ -37,22 +37,26 @@ class OpenAIWhisperPlugin extends ModelPlugin {
37
37
  chunks.push(chunk);
38
38
 
39
39
  const { language, responseFormat } = parameters;
40
- const params = {};
41
40
  const { modelPromptText } = this.getCompiledPrompt(text, parameters, prompt);
42
41
  const response_format = responseFormat || 'text';
43
42
 
44
- const formData = new FormData();
45
- formData.append('file', fs.createReadStream(chunk));
46
- formData.append('model', cortexRequest.params.model);
47
- formData.append('response_format', response_format);
48
- language && formData.append('language', language);
49
- modelPromptText && formData.append('prompt', modelPromptText);
43
+ const whisperInitCallback = (requestInstance) => {
50
44
 
51
- cortexRequest.data = formData;
52
- cortexRequest.params = params;
53
- cortexRequest.headers = { ...cortexRequest.headers, ...formData.getHeaders() };
45
+ const formData = new FormData();
46
+ formData.append('file', fs.createReadStream(chunk));
47
+ formData.append('model', requestInstance.params.model);
48
+ formData.append('response_format', response_format);
49
+ language && formData.append('language', language);
50
+ modelPromptText && formData.append('prompt', modelPromptText);
54
51
 
52
+ requestInstance.data = formData;
53
+ requestInstance.addHeaders = { ...formData.getHeaders() };
54
+
55
+ };
56
+
57
+ cortexRequest.initCallback = whisperInitCallback;
55
58
  return this.executeRequest(cortexRequest);
59
+
56
60
  } catch (err) {
57
61
  logger.error(`Error getting word timestamped data from api: ${err}`);
58
62
  throw err;
@@ -147,7 +147,7 @@ class PalmChatPlugin extends ModelPlugin {
147
147
 
148
148
  const gcpAuthTokenHelper = this.config.get('gcpAuthTokenHelper');
149
149
  const authToken = await gcpAuthTokenHelper.getAccessToken();
150
- cortexRequest.headers.Authorization = `Bearer ${authToken}`;
150
+ cortexRequest.auth.Authorization = `Bearer ${authToken}`;
151
151
 
152
152
  return this.executeRequest(cortexRequest);
153
153
  }
@@ -61,7 +61,7 @@ class PalmCompletionPlugin extends ModelPlugin {
61
61
 
62
62
  const gcpAuthTokenHelper = this.config.get('gcpAuthTokenHelper');
63
63
  const authToken = await gcpAuthTokenHelper.getAccessToken();
64
- cortexRequest.headers.Authorization = `Bearer ${authToken}`;
64
+ cortexRequest.auth.Authorization = `Bearer ${authToken}`;
65
65
 
66
66
  return this.executeRequest(cortexRequest);
67
67
  }