@adobe/spacecat-shared-gpt-client 1.4.6 → 1.5.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [@adobe/spacecat-shared-gpt-client-v1.5.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-gpt-client-v1.4.7...@adobe/spacecat-shared-gpt-client-v1.5.0) (2025-02-17)
2
+
3
+
4
+ ### Features
5
+
6
+ * add Client to interact with Genvar APIs ([#596](https://github.com/adobe/spacecat-shared/issues/596)) ([cd69beb](https://github.com/adobe/spacecat-shared/commit/cd69beb153b543c59f70ea702c0d0c72c458515d))
7
+
8
+ # [@adobe/spacecat-shared-gpt-client-v1.4.7](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-gpt-client-v1.4.6...@adobe/spacecat-shared-gpt-client-v1.4.7) (2025-02-16)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** update external fixes ([#603](https://github.com/adobe/spacecat-shared/issues/603)) ([b58d4c7](https://github.com/adobe/spacecat-shared/commit/b58d4c7237fb2522bba9b722e9eed7b0ae9e5f70))
14
+
1
15
  # [@adobe/spacecat-shared-gpt-client-v1.4.6](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-gpt-client-v1.4.5...@adobe/spacecat-shared-gpt-client-v1.4.6) (2025-02-08)
2
16
 
3
17
 
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Spacecat Shared - GPT Client
2
2
 
3
+ ## Firefall
3
4
  The `FirefallClient` library offers a streamlined way to interact with the Firefall API, enabling applications to fetch insights, recommendations, and codes based on provided prompts. Designed with simplicity and efficiency in mind, this client handles all aspects of communication with the Firefall API, including request authentication, error handling, and response parsing.
4
5
 
5
- ## Configuration
6
+ ### Configuration
6
7
 
7
8
  To use the `FirefallClient`, you need to configure it with the following parameters:
8
9
 
@@ -24,9 +25,9 @@ Additionally, the configuration for the `@adobe/spacecat-shared-ims-client` libr
24
25
  - `IMS_CLIENT_CODE`: Your IMS client code, used for authentication.
25
26
  - `IMS_CLIENT_SECRET`: Your IMS client secret, used for authentication.
26
27
 
27
- ## Usage Examples
28
+ ### Usage Examples
28
29
 
29
- ### Instantiating the Firefall Client
30
+ #### Instantiating the Firefall Client
30
31
 
31
32
  ```javascript
32
33
  import FirefallClient from 'path/to/firefall-client';
@@ -45,9 +46,9 @@ try {
45
46
  }
46
47
  ```
47
48
 
48
- ### Fetching Insights
49
+ #### Fetching Insights
49
50
 
50
- #### Via Capability Execution endpoint
51
+ 1. Via Capability Execution endpoint
51
52
 
52
53
  ```javascript
53
54
  /**
@@ -78,7 +79,7 @@ async function fetchInsights(prompt) {
78
79
  fetchInsights('How can we improve customer satisfaction?');
79
80
  ```
80
81
 
81
- #### Via Chat Completions endpoint
82
+ 2. Via Chat Completions endpoint
82
83
 
83
84
  ```javascript
84
85
  /**
@@ -115,6 +116,78 @@ fetchCompletions('Identify all food items in this image', { imageUrls: ['data:im
115
116
 
116
117
  Ensure that you replace `'path/to/firefall-client'` with the actual path to the `FirefallClient` class in your project and adjust the configuration parameters according to your Firefall API credentials.
117
118
 
119
+ ## Genvar Client
120
+
121
+ The `Genvar client` library provides a convenient way to interact with the Genvar APIs.
122
+
123
+ ### Configuration
124
+ To use the `GenvarClient`, you need to configure it with the following parameters:
125
+
126
+ - `GENVAR_HOST`: The hostname for Genvar API.
127
+ - `GENVAR_IMS_ORG_ID`: The IMS ORG ID to use when calling the Genvar APIs and tracking the request.
128
+
129
+ These parameters can be set through environment variables or passed directly to the `GenvarClient.createFrom` method.
130
+
131
+ Additionally, the configuration for the `@adobe/spacecat-shared-ims-client` library is required to fetch the service access token from the IMS API:
132
+
133
+ - `IMS_HOST`: The hostname of the IMS API.
134
+ - `IMS_CLIENT_ID`: Your IMS client ID.
135
+ - `IMS_CLIENT_CODE`: Your IMS client code, used for authentication.
136
+ - `IMS_CLIENT_SECRET`: Your IMS client secret, used for authentication.
137
+
138
+ ### Usage Examples
139
+
140
+ #### Instantiating the Genvar Client
141
+ ```javascript
142
+ import GenvarClient from 'path/to/genvar-client';
143
+
144
+ // Assuming environment variables are set
145
+ const context = {
146
+ env: process.env,
147
+ log: console, // Using console for logging in this example
148
+ };
149
+
150
+ try {
151
+ const client = GenvarClient.createFrom(context);
152
+ console.log('GenvarClient created successfully.');
153
+ } catch (error) {
154
+ console.error('Error creating GenvarClient:', error.message);
155
+ }
156
+ ```
157
+
158
+ #### Calling Genvar API
159
+
160
+ - Using `generateSuggestions` method which first submits the job and then polls the job status
161
+ ```javascript
162
+ /**
163
+ * Call Genvar API with generate suggestions method
164
+ */
165
+ async function generateAISuggestions() {
166
+ try {
167
+ const client = GenvarClient.createFrom({
168
+ env: {
169
+ GENVAR_HOST: 'https://12345-genvarapi-seotest.adobeioruntime.net',
170
+ GENVAR_IMS_ORG_ID: 'abcd@AdobeOrg',
171
+ IMS_HOST: 'ims.example.com',
172
+ IMS_CLIENT_ID: 'yourClientId',
173
+ IMS_CLIENT_CODE: 'yourClientCode',
174
+ IMS_CLIENT_SECRET: 'yourClientSecret',
175
+ },
176
+ log: console,
177
+ });
178
+
179
+ const requestBody = {
180
+ param1: 'some-value',
181
+ };
182
+ const endpoint = '/some-endpoint';
183
+ const response = await client.generateSuggestions(requestBody, endpoint);
184
+ console.log('Genvar API response:', response);
185
+ } catch (error) {
186
+ console.error('Failed to call genvar API:', error.message);
187
+ }
188
+ }
189
+ ```
190
+
118
191
  ## Testing
119
192
 
120
193
  To run tests:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-gpt-client",
3
- "version": "1.4.6",
3
+ "version": "1.5.0",
4
4
  "description": "Shared modules of the Spacecat Services - GPT Client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -40,7 +40,7 @@
40
40
  "@adobe/spacecat-shared-utils": "1.26.4"
41
41
  },
42
42
  "devDependencies": {
43
- "chai": "5.1.2",
43
+ "chai": "5.2.0",
44
44
  "chai-as-promised": "8.0.1",
45
45
  "nock": "14.0.1",
46
46
  "sinon": "19.0.2",
@@ -0,0 +1,182 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { createUrl } from '@adobe/fetch';
14
+ import { ImsClient } from '@adobe/spacecat-shared-ims-client';
15
+ import {
16
+ hasText, isNonEmptyObject,
17
+ isValidUrl,
18
+ tracingFetch,
19
+ } from '@adobe/spacecat-shared-utils';
20
+
21
+ export default class GenvarClient {
22
+ static createFrom(context) {
23
+ const { log = console } = context;
24
+ const imsClient = ImsClient.createFrom(context);
25
+ const {
26
+ GENVAR_HOST: genvarHost,
27
+ GENVAR_IMS_ORG_ID: genvarImsOrgId,
28
+ GENVAR_API_POLL_INTERVAL: pollInterval = 3000,
29
+ } = context.env;
30
+
31
+ if (!isValidUrl(genvarHost)) {
32
+ throw new Error('Missing Genvar API endpoint');
33
+ }
34
+
35
+ if (!hasText(genvarImsOrgId)) {
36
+ throw new Error('Missing Genvar Ims org');
37
+ }
38
+
39
+ return new GenvarClient({
40
+ genvarHost,
41
+ imsClient,
42
+ imsOrg: genvarImsOrgId,
43
+ pollInterval,
44
+ }, log);
45
+ }
46
+
47
+ /**
48
+ * Creates a new Genvar client
49
+ *
50
+ * @param {Object} config - The configuration object.
51
+ * @param {string} config.apiEndpoint - The API endpoint for Genvar.
52
+ * @param {ImsClient} config.imsClient - The IMS Client.
53
+ * @param {string} config.imsOrg - The IMS Org for Genvar.
54
+ * @param {number} config.pollInterval - The interval to poll for job status.
55
+ * @param {Object} log - The Logger.
56
+ * @returns {GenvarClient} - the Genvar client.
57
+ */
58
+ constructor(config, log) {
59
+ this.config = config;
60
+ this.log = log;
61
+ this.imsClient = config.imsClient;
62
+ this.apiAuth = null;
63
+ }
64
+
65
+ async #getApiAuth() {
66
+ if (!this.apiAuth) {
67
+ this.apiAuth = (await this.imsClient.getServiceAccessToken()).access_token;
68
+ }
69
+ return this.apiAuth;
70
+ }
71
+
72
+ #logDuration(message, startTime) {
73
+ const endTime = process.hrtime.bigint();
74
+ const duration = (endTime - startTime) / BigInt(1e6);
75
+ this.log.debug(`${message}: took ${duration}ms`);
76
+ }
77
+
78
+ async #submitJob(body, path) {
79
+ const apiAuth = await this.#getApiAuth();
80
+ const url = createUrl(`${this.config.genvarHost}${path}`);
81
+ const headers = {
82
+ 'Content-Type': 'application/json',
83
+ Authorization: `Bearer ${apiAuth}`,
84
+ 'x-gw-ims-org-id': this.config.imsOrg,
85
+ };
86
+
87
+ this.log.info(`[Genvar API Call] URL: ${url}, Headers: ${JSON.stringify({ ...headers, Authorization: '***' })}`);
88
+
89
+ let response;
90
+ let responseJsonObj;
91
+ try {
92
+ response = await tracingFetch(url, {
93
+ method: 'POST',
94
+ headers,
95
+ body,
96
+ });
97
+ if (!response.ok) {
98
+ const errorMessage = await response.text();
99
+ throw new Error(`Job submission failed with status code ${response.status} and error: ${errorMessage}`);
100
+ }
101
+ responseJsonObj = await response.json();
102
+ } catch (err) {
103
+ this.log.error(`Genvar Job submit failed with error: ${err.message}`);
104
+ throw err;
105
+ }
106
+ return responseJsonObj;
107
+ }
108
+
109
+ /* eslint-disable no-await-in-loop */
110
+ async #pollJobStatus(jobId, path) {
111
+ const apiAuth = await this.#getApiAuth();
112
+ let jobStatusResponse;
113
+ do {
114
+ await new Promise(
115
+ (resolve) => { setTimeout(resolve, this.config.pollInterval); },
116
+ ); // Wait for 3 seconds(default) before polling
117
+
118
+ const url = `${this.config.genvarHost}${path}?jobId=${jobId}`;
119
+ const headers = {
120
+ Authorization: `Bearer ${apiAuth}`,
121
+ 'x-gw-ims-org-id': this.config.imsOrg,
122
+ };
123
+
124
+ this.log.info(`[Genvar API Call] URL: ${url}, Headers: ${JSON.stringify({ ...headers, Authorization: '***' })}`);
125
+
126
+ let response;
127
+ try {
128
+ response = await tracingFetch(
129
+ createUrl(url),
130
+ {
131
+ method: 'GET',
132
+ headers,
133
+ },
134
+ );
135
+ if (!response.ok) {
136
+ throw new Error(`Job polling failed with status code ${response.status}`);
137
+ }
138
+ jobStatusResponse = await response.json();
139
+ } catch (err) {
140
+ this.log.error(`Genvar Job poll failed with error: ${err.message}`);
141
+ throw err;
142
+ }
143
+ } while (jobStatusResponse.status === 'running');
144
+
145
+ if (jobStatusResponse.status !== 'completed') {
146
+ throw new Error(`Job did not succeed, status: ${jobStatusResponse.status}.\n${JSON.stringify(jobStatusResponse, null, 2)}`);
147
+ }
148
+
149
+ return jobStatusResponse;
150
+ }
151
+
152
+ /**
153
+ * Fetches data from Genvar API. Follows the flow: submit job and polls job status
154
+ * @param body The request body to provide to Genvar
155
+ * @param path The Genvar request path
156
+ * @returns {string} - API Response
157
+ */
158
+ async generateSuggestions(body, path) {
159
+ if (!body) {
160
+ throw new Error('Invalid body received');
161
+ }
162
+ if (!path) {
163
+ throw new Error('Invalid path received');
164
+ }
165
+ try {
166
+ const startTime = process.hrtime.bigint();
167
+
168
+ const jobSubmissionResponse = await this.#submitJob(body, path);
169
+ const jobStatusResponse = await this.#pollJobStatus(jobSubmissionResponse.jobId, path);
170
+ this.#logDuration('Genvar API Execution call took ms: ', startTime);
171
+
172
+ const { result } = jobStatusResponse;
173
+ if (!isNonEmptyObject(result)) {
174
+ throw new Error('Job completed but no output was found');
175
+ }
176
+ return result;
177
+ } catch (error) {
178
+ this.log.error('Error while calling Genvar API: ', error.message);
179
+ throw error;
180
+ }
181
+ }
182
+ }
package/src/index.d.ts CHANGED
@@ -11,7 +11,9 @@
11
11
  */
12
12
 
13
13
  import type { FirefallClient } from './clients';
14
+ import GenvarClient from './clients/genvar-client.js';
14
15
 
15
16
  export {
16
17
  FirefallClient,
18
+ GenvarClient,
17
19
  };
package/src/index.js CHANGED
@@ -11,7 +11,9 @@
11
11
  */
12
12
 
13
13
  import FirefallClient from './clients/firefall-client.js';
14
+ import GenvarClient from './clients/genvar-client.js';
14
15
 
15
16
  export {
16
17
  FirefallClient,
18
+ GenvarClient,
17
19
  };