@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.
- package/.env.sample +3 -1
- package/config/default.example.json +2 -2
- package/config.js +32 -0
- package/helper-apps/mogrt-handler/.env.example +24 -0
- package/helper-apps/mogrt-handler/README.md +166 -0
- package/helper-apps/mogrt-handler/glossaryHandler.js +218 -0
- package/helper-apps/mogrt-handler/index.js +213 -0
- package/helper-apps/mogrt-handler/package-lock.json +7106 -0
- package/helper-apps/mogrt-handler/package.json +34 -0
- package/helper-apps/mogrt-handler/s3Handler.js +444 -0
- package/helper-apps/mogrt-handler/start.js +98 -0
- package/helper-apps/mogrt-handler/swagger.js +42 -0
- package/helper-apps/mogrt-handler/swagger.yaml +436 -0
- package/helper-apps/mogrt-handler/tests/integration/api.test.js +226 -0
- package/helper-apps/mogrt-handler/tests/integration/glossary.test.js +106 -0
- package/helper-apps/mogrt-handler/tests/setup.js +8 -0
- package/helper-apps/mogrt-handler/tests/test-files/test.gif +1 -0
- package/helper-apps/mogrt-handler/tests/test-files/test.mogrt +1 -0
- package/helper-apps/mogrt-handler/tests/test-files/test.mp4 +1 -0
- package/helper-apps/mogrt-handler/tests/unit/glossary.unit.test.js +118 -0
- package/helper-apps/mogrt-handler/tests/unit/index.test.js +349 -0
- package/helper-apps/mogrt-handler/tests/unit/s3Handler.test.js +204 -0
- package/helper-apps/mogrt-handler/tests/unit/sample.test.js +28 -0
- package/helper-apps/mogrt-handler/vitest.config.js +15 -0
- package/lib/entityConstants.js +1 -1
- package/lib/requestExecutor.js +1 -1
- package/package.json +1 -1
- package/pathways/list_translation_models.js +67 -0
- package/pathways/system/sys_test_response_reasonableness.js +20 -0
- package/pathways/system/workspaces/workspace_applet_edit.js +187 -0
- package/pathways/translate_apptek.js +11 -0
- package/pathways/translate_google.js +10 -0
- package/pathways/translate_groq.js +36 -0
- package/pathways/video_seedance.js +17 -0
- package/pathways/video_veo.js +31 -0
- package/server/modelExecutor.js +16 -0
- package/server/plugins/apptekTranslatePlugin.js +189 -0
- package/server/plugins/googleTranslatePlugin.js +121 -0
- package/server/plugins/groqChatPlugin.js +108 -0
- package/server/plugins/replicateApiPlugin.js +22 -0
- package/server/plugins/veoVideoPlugin.js +218 -0
- package/tests/apptekTranslatePlugin.test.js +228 -0
- package/tests/integration/apptekTranslatePlugin.integration.test.js +156 -0
- package/tests/translate_apptek.test.js +117 -0
package/.env.sample
CHANGED
|
@@ -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
|
|
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
|
|
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
|
+
}
|