@aj-archipelago/cortex 1.3.55 → 1.3.57

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.
Files changed (44) hide show
  1. package/.env.sample +3 -1
  2. package/config/default.example.json +2 -2
  3. package/config.js +32 -0
  4. package/helper-apps/mogrt-handler/.env.example +24 -0
  5. package/helper-apps/mogrt-handler/README.md +166 -0
  6. package/helper-apps/mogrt-handler/glossaryHandler.js +218 -0
  7. package/helper-apps/mogrt-handler/index.js +213 -0
  8. package/helper-apps/mogrt-handler/package-lock.json +7106 -0
  9. package/helper-apps/mogrt-handler/package.json +34 -0
  10. package/helper-apps/mogrt-handler/s3Handler.js +444 -0
  11. package/helper-apps/mogrt-handler/start.js +98 -0
  12. package/helper-apps/mogrt-handler/swagger.js +42 -0
  13. package/helper-apps/mogrt-handler/swagger.yaml +436 -0
  14. package/helper-apps/mogrt-handler/tests/integration/api.test.js +226 -0
  15. package/helper-apps/mogrt-handler/tests/integration/glossary.test.js +106 -0
  16. package/helper-apps/mogrt-handler/tests/setup.js +8 -0
  17. package/helper-apps/mogrt-handler/tests/test-files/test.gif +1 -0
  18. package/helper-apps/mogrt-handler/tests/test-files/test.mogrt +1 -0
  19. package/helper-apps/mogrt-handler/tests/test-files/test.mp4 +1 -0
  20. package/helper-apps/mogrt-handler/tests/unit/glossary.unit.test.js +118 -0
  21. package/helper-apps/mogrt-handler/tests/unit/index.test.js +349 -0
  22. package/helper-apps/mogrt-handler/tests/unit/s3Handler.test.js +204 -0
  23. package/helper-apps/mogrt-handler/tests/unit/sample.test.js +28 -0
  24. package/helper-apps/mogrt-handler/vitest.config.js +15 -0
  25. package/lib/entityConstants.js +1 -1
  26. package/lib/requestExecutor.js +1 -1
  27. package/package.json +1 -1
  28. package/pathways/list_translation_models.js +67 -0
  29. package/pathways/system/sys_test_response_reasonableness.js +20 -0
  30. package/pathways/system/workspaces/workspace_applet_edit.js +187 -0
  31. package/pathways/translate_apptek.js +11 -0
  32. package/pathways/translate_google.js +10 -0
  33. package/pathways/translate_groq.js +36 -0
  34. package/pathways/video_seedance.js +17 -0
  35. package/pathways/video_veo.js +31 -0
  36. package/server/modelExecutor.js +16 -0
  37. package/server/plugins/apptekTranslatePlugin.js +189 -0
  38. package/server/plugins/googleTranslatePlugin.js +121 -0
  39. package/server/plugins/groqChatPlugin.js +108 -0
  40. package/server/plugins/replicateApiPlugin.js +22 -0
  41. package/server/plugins/veoVideoPlugin.js +218 -0
  42. package/tests/apptekTranslatePlugin.test.js +228 -0
  43. package/tests/integration/apptekTranslatePlugin.integration.test.js +156 -0
  44. package/tests/translate_apptek.test.js +117 -0
package/.env.sample CHANGED
@@ -1 +1,3 @@
1
- AZURE_OAI_API_KEY=_______________________
1
+ AZURE_OAI_API_KEY=_______________________
2
+ APPTEK_API_KEY=""
3
+ APPTEK_API_ENDPOINT="https://api.apptek.com"
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "gemini-pro-15-vision": {
39
39
  "type": "GEMINI-VISION",
40
- "url": "https://us-central1-aiplatform.googleapis.com/v1/projects/project-id/locations/us-central1/publishers/google/models/gemini-1.5-pro-preview-0215:streamGenerateContent",
40
+ "url": "https://us-central1-aiplatform.googleapis.com/v1/projects/project-id/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent",
41
41
  "headers": {
42
42
  "Content-Type": "application/json"
43
43
  },
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "gemini-pro-25-vision": {
50
50
  "type": "GEMINI-VISION",
51
- "url": "https://us-central1-aiplatform.googleapis.com/v1/projects/project-id/locations/us-central1/publishers/google/models/gemini-2.5-pro-exp-03-25:streamGenerateContent",
51
+ "url": "https://us-central1-aiplatform.googleapis.com/v1/projects/project-id/locations/us-central1/publishers/google/models/gemini-2.5-pro:streamGenerateContent",
52
52
  "headers": {
53
53
  "Content-Type": "application/json"
54
54
  },
package/config.js CHANGED
@@ -290,6 +290,15 @@ var config = convict({
290
290
  "Content-Type": "application/json"
291
291
  },
292
292
  },
293
+ "replicate-seedance-1-pro": {
294
+ "type": "REPLICATE-API",
295
+ "url": "https://api.replicate.com/v1/models/bytedance/seedance-1-pro/predictions",
296
+ "headers": {
297
+ "Prefer": "wait",
298
+ "Authorization": "Token {{REPLICATE_API_KEY}}",
299
+ "Content-Type": "application/json"
300
+ },
301
+ },
293
302
  "replicate-flux-11-pro": {
294
303
  "type": "REPLICATE-API",
295
304
  "url": "https://api.replicate.com/v1/models/black-forest-labs/flux-1.1-pro/predictions",
@@ -380,6 +389,29 @@ var config = convict({
380
389
  "maxTokenLength": 131072,
381
390
  "supportsStreaming": true
382
391
  },
392
+ "google-translate": {
393
+ "type": "GOOGLE-TRANSLATE",
394
+ "url": "https://translation.googleapis.com/language/translate/v2",
395
+ "headers": {
396
+ "Content-Type": "application/json"
397
+ },
398
+ "requestsPerSecond": 10
399
+ },
400
+ "groq-chat": {
401
+ "type": "GROQ-CHAT",
402
+ "url": "https://api.groq.com/openai/v1/chat/completions",
403
+ "headers": {
404
+ "Authorization": "Bearer {{GROQ_API_KEY}}",
405
+ "Content-Type": "application/json"
406
+ },
407
+ "params": {
408
+ "model": "meta-llama/llama-4-scout-17b-16e-instruct"
409
+ },
410
+ "requestsPerSecond": 10,
411
+ "maxTokenLength": 65536,
412
+ "maxReturnTokens": 4096,
413
+ "supportsStreaming": true
414
+ },
383
415
  "claude-35-sonnet-vertex": {
384
416
  "type": "CLAUDE-3-VERTEX",
385
417
  "url": "{{claudeVertexUrl}}",
@@ -0,0 +1,24 @@
1
+ # Server Configuration
2
+ # Port number for the MOGRT handler service
3
+ PORT=7072
4
+
5
+ # AWS Configuration
6
+ # AWS Region for S3 bucket (default: us-east-1)
7
+ AWS_REGION=us-east-1
8
+
9
+ # S3 bucket name where MOGRT files and manifests will be stored
10
+ S3_BUCKET_NAME=your-bucket-name
11
+
12
+ # AWS credentials for S3 access
13
+ AWS_ACCESS_KEY_ID=your-access-key-id
14
+ AWS_SECRET_ACCESS_KEY=your-secret-access-key
15
+
16
+ # Signed URL Configuration
17
+ # Expiration time for signed URLs in seconds (default: 3600 = 1 hour)
18
+ SIGNED_URL_EXPIRY_SECONDS=3600
19
+
20
+ # Optional: Node environment (development/production)
21
+ NODE_ENV=development
22
+
23
+ APPTEK_TOKEN=
24
+ BASE_URL
@@ -0,0 +1,166 @@
1
+ # MOGRT Handler Service
2
+
3
+ A service for managing Motion Graphics Templates (MOGRT) files and their preview GIFs with S3 storage integration.
4
+
5
+ ## Table of Contents
6
+ - [Setup](#setup)
7
+ - [Environment Variables](#environment-variables)
8
+ - [API Documentation](#api-documentation)
9
+ - [Upload MOGRT Files](#upload-mogrt-files)
10
+ - [Get Master Manifest](#get-master-manifest)
11
+ - [Get Individual Manifest](#get-individual-manifest)
12
+ - [File Structure](#file-structure)
13
+ - [Error Handling](#error-handling)
14
+
15
+ ## Setup
16
+
17
+ 1. Install dependencies:
18
+ ```bash
19
+ npm install
20
+ ```
21
+
22
+ 2. Set up environment variables (see [Environment Variables](#environment-variables) section)
23
+
24
+ 3. Start the server:
25
+ ```bash
26
+ npm start
27
+ ```
28
+
29
+ The server will start on port 7072 by default.
30
+
31
+ ## Environment Variables
32
+
33
+ | Variable | Description | Default | Required |
34
+ |----------|-------------|---------|----------|
35
+ | `PORT` | Server port | 7072 | No |
36
+ | `AWS_REGION` | AWS region for S3 | us-east-1 | No |
37
+ | `S3_BUCKET_NAME` | S3 bucket name for file storage | - | Yes |
38
+ | `AWS_ACCESS_KEY_ID` | AWS access key | - | Yes |
39
+ | `AWS_SECRET_ACCESS_KEY` | AWS secret key | - | Yes |
40
+ | `SIGNED_URL_EXPIRY_SECONDS` | Expiration time for signed URLs | 3600 (1 hour) | No |
41
+
42
+ ## API Documentation
43
+
44
+ ### Upload MOGRT Files
45
+
46
+ Upload a MOGRT file with its preview GIF.
47
+
48
+ **Endpoint:** `POST /api/MogrtHandler`
49
+
50
+ **Content-Type:** `multipart/form-data`
51
+
52
+ **Required Files:**
53
+ - A `.mogrt` file
54
+ - A `.gif` preview file
55
+
56
+ **Example Request:**
57
+ ```bash
58
+ curl -X POST http://localhost:7072/api/MogrtHandler \
59
+ -F "mogrt=@/path/to/template.mogrt" \
60
+ -F "preview=@/path/to/preview.gif"
61
+ ```
62
+
63
+ **Success Response:**
64
+ ```json
65
+ {
66
+ "id": "550e8400-e29b-41d4-a716-446655440000",
67
+ "mogrtFile": "uploads/550e8400-e29b-41d4-a716-446655440000/template.mogrt",
68
+ "previewFile": "uploads/550e8400-e29b-41d4-a716-446655440000/preview.gif",
69
+ "uploadDate": "2025-02-05T14:05:39Z",
70
+ "mogrtUrl": "https://bucket.s3.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000/template.mogrt?[signed-url-params]",
71
+ "previewUrl": "https://bucket.s3.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000/preview.gif?[signed-url-params]"
72
+ }
73
+ ```
74
+
75
+ **Error Responses:**
76
+ - `400 Bad Request`: Missing required files or invalid file types
77
+ - `500 Internal Server Error`: Server or S3 error
78
+
79
+ ### Get Master Manifest
80
+
81
+ Retrieve a list of all uploaded MOGRT files.
82
+
83
+ **Endpoint:** `GET /api/MogrtHandler`
84
+
85
+ **Example Request:**
86
+ ```bash
87
+ curl http://localhost:7072/api/MogrtHandler
88
+ ```
89
+
90
+ **Success Response:**
91
+ ```json
92
+ [
93
+ {
94
+ "id": "550e8400-e29b-41d4-a716-446655440000",
95
+ "mogrtFile": "uploads/550e8400-e29b-41d4-a716-446655440000/template.mogrt",
96
+ "previewFile": "uploads/550e8400-e29b-41d4-a716-446655440000/preview.gif",
97
+ "uploadDate": "2025-02-05T14:05:39Z",
98
+ "mogrtUrl": "https://bucket.s3.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000/template.mogrt?[signed-url-params]",
99
+ "previewUrl": "https://bucket.s3.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000/preview.gif?[signed-url-params]"
100
+ }
101
+ ]
102
+ ```
103
+
104
+ **Error Response:**
105
+ - `500 Internal Server Error`: Server or S3 error
106
+
107
+ ### Get Individual Manifest
108
+
109
+ Retrieve information about a specific MOGRT upload.
110
+
111
+ **Endpoint:** `GET /api/MogrtHandler?manifestId=<uuid>`
112
+
113
+ **Parameters:**
114
+ - `manifestId` (required): UUID of the upload
115
+
116
+ **Example Request:**
117
+ ```bash
118
+ curl http://localhost:7072/api/MogrtHandler?manifestId=550e8400-e29b-41d4-a716-446655440000
119
+ ```
120
+
121
+ **Success Response:**
122
+ ```json
123
+ {
124
+ "id": "550e8400-e29b-41d4-a716-446655440000",
125
+ "mogrtFile": "uploads/550e8400-e29b-41d4-a716-446655440000/template.mogrt",
126
+ "previewFile": "uploads/550e8400-e29b-41d4-a716-446655440000/preview.gif",
127
+ "uploadDate": "2025-02-05T14:05:39Z",
128
+ "mogrtUrl": "https://bucket.s3.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000/template.mogrt?[signed-url-params]",
129
+ "previewUrl": "https://bucket.s3.amazonaws.com/uploads/550e8400-e29b-41d4-a716-446655440000/preview.gif?[signed-url-params]"
130
+ }
131
+ ```
132
+
133
+ **Error Responses:**
134
+ - `404 Not Found`: Manifest not found
135
+ - `500 Internal Server Error`: Server or S3 error
136
+
137
+ ## File Structure
138
+
139
+ Files are organized in S3 with the following structure:
140
+
141
+ ```
142
+ bucket/
143
+ ├── master-manifest.json
144
+ └── uploads/
145
+ └── <uuid>/
146
+ ├── template.mogrt
147
+ ├── preview.gif
148
+ └── manifest.json
149
+ ```
150
+
151
+ ## Error Handling
152
+
153
+ All endpoints return errors in the following format:
154
+
155
+ ```json
156
+ {
157
+ "error": "Error message description"
158
+ }
159
+ ```
160
+
161
+ Common error scenarios:
162
+ 1. Missing required files in upload
163
+ 2. Invalid file types (only .mogrt and .gif allowed)
164
+ 3. S3 access or permission issues
165
+ 4. Missing or invalid manifest ID
166
+ 5. Server configuration errors (missing environment variables)
@@ -0,0 +1,218 @@
1
+ import fetch from 'node-fetch';
2
+ import dotenv from 'dotenv';
3
+ import { saveGlossaryId, getGlossaryVersions, getGlossaryVersion } from './s3Handler.js';
4
+
5
+ dotenv.config();
6
+
7
+ const APPTEK_BASE_URL = process.env.APPTEK_API_URL || 'https://api.apptek.com/api/v2/glossary';
8
+ const APPTEK_TOKEN = process.env.APPTEK_TOKEN;
9
+
10
+ export default async function GlossaryHandler(context, req) {
11
+ const { method, url, body, query, headers } = req;
12
+ // Use token from header if present, else from env
13
+ const token = APPTEK_TOKEN;
14
+ if (!token) {
15
+ context.res = { status: 401, body: { error: 'Missing x-token or APPTEK_TOKEN' } };
16
+ return;
17
+ }
18
+ try {
19
+ // List glossaries
20
+ if (method === 'GET' && url.includes('/list')) {
21
+ const resp = await fetch(`${APPTEK_BASE_URL}/list`, {
22
+ method: 'GET',
23
+ headers: { 'accept': 'application/json', 'x-token': token }
24
+ });
25
+ const data = await resp.json();
26
+ context.res = { status: resp.status, body: data };
27
+ return;
28
+ }
29
+ // Create glossary
30
+ if (method === 'POST' && url.match(/\/api\/glossary\/[a-z]{2}-[a-z]{2}/)) {
31
+ const langPair = url.match(/\/api\/glossary\/([a-z]{2}-[a-z]{2})/)[1];
32
+ body.name = ""
33
+
34
+ for (const entry of body.entries) {
35
+ entry.target_alternatives = [];
36
+ }
37
+ const resp = await fetch(`${APPTEK_BASE_URL}/${langPair}`, {
38
+ method: 'POST',
39
+ headers: { 'accept': 'application/json', 'x-token': token, 'content-type': 'application/json' },
40
+ body: JSON.stringify(body)
41
+ });
42
+ console.log(resp)
43
+ const data = await resp.json();
44
+
45
+ // If successful, save the glossary ID to S3 with versioning
46
+ if (resp.status === 200 && data.glossary_id) {
47
+ try {
48
+ const versionInfo = await saveGlossaryId(data.glossary_id, langPair, name);
49
+ // Add version info to the response
50
+ data.version = {
51
+ versionId: versionInfo.versionId,
52
+ key: versionInfo.key
53
+ };
54
+ } catch (s3Error) {
55
+ console.error('Error saving glossary ID to S3:', s3Error);
56
+ // Don't fail the request if S3 storage fails
57
+ data.versioningError = 'Failed to save glossary version to S3';
58
+ }
59
+ }
60
+
61
+ context.res = { status: resp.status, body: data };
62
+ return;
63
+ }
64
+ // Delete glossary
65
+ if (method === 'DELETE' && url.match(/\/api\/glossary\/.+/)) {
66
+ const glossaryId = url.split('/').pop();
67
+ console.log(`🗑️ Attempting to delete glossary with ID: ${glossaryId}`);
68
+
69
+ try {
70
+ const resp = await fetch(`${APPTEK_BASE_URL}/${glossaryId}`, {
71
+ method: 'DELETE',
72
+ headers: { 'accept': 'application/json', 'x-token': token }
73
+ });
74
+
75
+ console.log(`📤 Delete request sent, response status: ${resp.status}`);
76
+
77
+ const data = await resp.json().catch(() => {
78
+ console.log(`⚠️ No JSON in delete response, using empty object`);
79
+ return {};
80
+ });
81
+
82
+ if (resp.status === 200) {
83
+ console.log(`✅ Successfully deleted glossary ${glossaryId}`);
84
+ } else {
85
+ console.error(`❌ Failed to delete glossary ${glossaryId}, status: ${resp.status}`, data);
86
+ }
87
+
88
+ context.res = { status: resp.status, body: data };
89
+ } catch (error) {
90
+ console.error(`❌ Error during glossary deletion: ${error.message}`);
91
+ context.res = { status: 500, body: { error: `Error deleting glossary: ${error.message}` } };
92
+ }
93
+ return;
94
+ }
95
+ // Edit glossary: delete then create
96
+ if (method === 'POST' && url.includes('/edit/')) {
97
+ const glossaryId = url.split('/edit/').pop();
98
+ // 1. Delete
99
+ console.log(`🗑️ Deleting glossary with ID: ${glossaryId} as part of edit operation`);
100
+ try {
101
+ const deleteResp = await fetch(`${APPTEK_BASE_URL}/${glossaryId}`, {
102
+ method: 'DELETE',
103
+ headers: { 'accept': 'application/json', 'x-token': token }
104
+ });
105
+
106
+ console.log(`📤 Delete request (for edit) sent, response status: ${deleteResp.status}`);
107
+
108
+ if (deleteResp.status === 200) {
109
+ console.log(`✅ Successfully deleted glossary ${glossaryId} for edit operation`);
110
+ } else {
111
+ console.warn(`⚠️ Non-200 status when deleting glossary for edit: ${deleteResp.status}`);
112
+ }
113
+ } catch (deleteError) {
114
+ console.error(`❌ Error during glossary deletion for edit: ${deleteError.message}`);
115
+ // Continue with create even if delete fails
116
+ }
117
+ // 2. Create (reuse create logic)
118
+ const { source_lang_code, target_lang_code, entries } = body;
119
+ body.name = ""
120
+ const langPair = `${source_lang_code}-${target_lang_code}`;
121
+ const resp = await fetch(`${APPTEK_BASE_URL}/${langPair}`, {
122
+ method: 'POST',
123
+ headers: { 'accept': 'application/json', 'x-token': token, 'content-type': 'application/json' },
124
+ body: JSON.stringify(body)
125
+ });
126
+ const data = await resp.json();
127
+
128
+ // If successful, save the glossary ID to S3 with versioning
129
+ if (resp.status === 200 && data.glossary_id) {
130
+ try {
131
+ const versionInfo = await saveGlossaryId(data.glossary_id, langPair);
132
+ // Add version info to the response
133
+ data.version = {
134
+ versionId: versionInfo.versionId,
135
+ key: versionInfo.key
136
+ };
137
+ } catch (s3Error) {
138
+ console.error('Error saving glossary ID to S3:', s3Error);
139
+ // Don't fail the request if S3 storage fails
140
+ data.versioningError = 'Failed to save glossary version to S3';
141
+ }
142
+ }
143
+
144
+ context.res = { status: resp.status, body: data };
145
+ return;
146
+ }
147
+ // Get versions of a glossary
148
+ if (method === 'GET' && url.match(/\/api\/glossary\/([a-z]{2}-[a-z]{2})\/versions\/(.*)/)) {
149
+ const matches = url.match(/\/api\/glossary\/([a-z]{2}-[a-z]{2})\/versions\/(.*)/);
150
+ const langPair = matches[1];
151
+ const glossaryId = matches[2];
152
+ const name = query.name || '';
153
+
154
+ try {
155
+ const versions = await getGlossaryVersions(glossaryId, langPair, name);
156
+ context.res = { status: 200, body: { versions } };
157
+ } catch (error) {
158
+ context.res = { status: 500, body: { error: error.message } };
159
+ }
160
+ return;
161
+ }
162
+
163
+ // Get a specific version of a glossary
164
+ if (method === 'GET' && url.match(/\/api\/glossary\/([a-z]{2}-[a-z]{2})\/version\/(.*)\/(.*)/))
165
+ {
166
+ const matches = url.match(/\/api\/glossary\/([a-z]{2}-[a-z]{2})\/version\/(.*)\/(.*)/);
167
+ const langPair = matches[1];
168
+ const glossaryId = matches[2];
169
+ const versionId = matches[3];
170
+ const name = query.name || '';
171
+
172
+ try {
173
+ const version = await getGlossaryVersion(glossaryId, langPair, versionId, name);
174
+ context.res = { status: 200, body: version };
175
+ } catch (error) {
176
+ context.res = { status: 500, body: { error: error.message } };
177
+ }
178
+ return;
179
+ }
180
+
181
+ // Get glossary by ID
182
+ if (method === 'GET' && url.match(/\/api\/glossary\/([^/]+)$/))
183
+ {
184
+ const glossaryId = url.match(/\/api\/glossary\/([^/]+)$/)[1];
185
+ console.log(`📖 Fetching glossary with ID: ${glossaryId}`);
186
+
187
+ try {
188
+ const resp = await fetch(`${APPTEK_BASE_URL}/${glossaryId}`, {
189
+ method: 'GET',
190
+ headers: {'x-token': token }
191
+ });
192
+
193
+ console.log(`📤 Get glossary request sent, response status: ${resp.status}`);
194
+
195
+ const data = await resp.json().catch(() => {
196
+ console.log(`⚠️ No JSON in response, using empty object`);
197
+ return {};
198
+ });
199
+
200
+ if (resp.status === 200) {
201
+ console.log(`✅ Successfully retrieved glossary ${glossaryId}`);
202
+ } else {
203
+ console.error(`❌ Failed to retrieve glossary ${glossaryId}, status: ${resp.status}`, data);
204
+ }
205
+
206
+ context.res = { status: resp.status, body: data };
207
+ } catch (error) {
208
+ console.error(`❌ Error retrieving glossary: ${error.message}`);
209
+ context.res = { status: 500, body: { error: `Error retrieving glossary: ${error.message}` } };
210
+ }
211
+ return;
212
+ }
213
+
214
+ context.res = { status: 404, body: { error: 'Not found' } };
215
+ } catch (error) {
216
+ context.res = { status: 500, body: { error: error.message } };
217
+ }
218
+ }