strapi-llm-translator 0.9.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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/_chunks/App-Boy_i56G.mjs +223 -0
- package/dist/_chunks/App-COSMdnpL.js +223 -0
- package/dist/_chunks/de-CvAR4QXO.js +29 -0
- package/dist/_chunks/de-D3VSS3Mq.mjs +29 -0
- package/dist/_chunks/en-BjVvIBv8.js +29 -0
- package/dist/_chunks/en-BnBUQVgF.mjs +29 -0
- package/dist/_chunks/index-BEhzLY5B.mjs +277 -0
- package/dist/_chunks/index-DuLkx3CK.js +276 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/admin/src/components/Initializer.d.ts +5 -0
- package/dist/admin/src/components/LLMButton.d.ts +2 -0
- package/dist/admin/src/components/PluginIcon.d.ts +18 -0
- package/dist/admin/src/index.d.ts +11 -0
- package/dist/admin/src/pages/App.d.ts +2 -0
- package/dist/admin/src/pages/HomePage.d.ts +2 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/utils/constants.d.ts +4 -0
- package/dist/admin/src/utils/getLocaleFromUrl.d.ts +1 -0
- package/dist/admin/src/utils/getTranslation.d.ts +2 -0
- package/dist/server/index.js +392 -0
- package/dist/server/index.mjs +393 -0
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/config/constants.d.ts +2 -0
- package/dist/server/src/config/index.d.ts +9 -0
- package/dist/server/src/content-types/index.d.ts +2 -0
- package/dist/server/src/controllers/admin.controller.d.ts +11 -0
- package/dist/server/src/controllers/index.d.ts +23 -0
- package/dist/server/src/destroy.d.ts +5 -0
- package/dist/server/src/index.d.ts +63 -0
- package/dist/server/src/middlewares/index.d.ts +2 -0
- package/dist/server/src/policies/index.d.ts +2 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/routes/admin.d.ts +9 -0
- package/dist/server/src/routes/index.d.ts +14 -0
- package/dist/server/src/services/index.d.ts +6 -0
- package/dist/server/src/services/llm-service.d.ts +6 -0
- package/dist/server/src/types/controllers.d.ts +22 -0
- package/dist/server/src/types/index.d.ts +41 -0
- package/package.json +70 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
const bootstrap = ({ strapi: strapi2 }) => {
|
|
3
|
+
};
|
|
4
|
+
const destroy = ({ strapi: strapi2 }) => {
|
|
5
|
+
};
|
|
6
|
+
const register = ({ strapi: strapi2 }) => {
|
|
7
|
+
};
|
|
8
|
+
const config = {
|
|
9
|
+
default: {
|
|
10
|
+
llmApiKey: process.env.LLM_TRANSLATOR_LLM_API_KEY,
|
|
11
|
+
llmEndpoint: process.env.STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL || "https://api.openai.com/v1/chat/completions",
|
|
12
|
+
llmModel: process.env.STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL || "gpt-4o"
|
|
13
|
+
},
|
|
14
|
+
validator() {
|
|
15
|
+
const {
|
|
16
|
+
LLM_TRANSLATOR_LLM_API_KEY,
|
|
17
|
+
STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL,
|
|
18
|
+
STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL
|
|
19
|
+
} = process.env;
|
|
20
|
+
if (!LLM_TRANSLATOR_LLM_API_KEY) {
|
|
21
|
+
throw new Error("LLM_TRANSLATOR_LLM_API_KEY is required");
|
|
22
|
+
}
|
|
23
|
+
if (!STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL) {
|
|
24
|
+
console.info(
|
|
25
|
+
"STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL is not set, using default: https://api.openai.com/v1/chat/completions"
|
|
26
|
+
);
|
|
27
|
+
} else {
|
|
28
|
+
console.info(
|
|
29
|
+
`STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL is set to: ${STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (!STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL) {
|
|
33
|
+
console.info("STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL is not set, using default: gpt-4o");
|
|
34
|
+
} else {
|
|
35
|
+
console.info(
|
|
36
|
+
`STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL is set to: ${STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const contentTypes = {};
|
|
42
|
+
const controllers$1 = ({ strapi: strapi2 }) => ({
|
|
43
|
+
// Genertate translations
|
|
44
|
+
async generate(ctx) {
|
|
45
|
+
try {
|
|
46
|
+
const { fields, components, targetLanguage, contentType } = ctx.request.body;
|
|
47
|
+
const result = await strapi2.plugin("strapi-llm-translator").service("llm-service").generateWithLLM(contentType, fields, components, {
|
|
48
|
+
targetLanguage
|
|
49
|
+
});
|
|
50
|
+
ctx.status = result.meta.status;
|
|
51
|
+
ctx.body = result;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Error in generate controller:", error);
|
|
54
|
+
ctx.status = 500;
|
|
55
|
+
ctx.body = {
|
|
56
|
+
meta: {
|
|
57
|
+
ok: false,
|
|
58
|
+
status: 500,
|
|
59
|
+
message: "Internal server error"
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
// Get the configuration
|
|
65
|
+
async getConfig(ctx) {
|
|
66
|
+
const pluginStore = strapi2.store({
|
|
67
|
+
environment: strapi2.config.environment,
|
|
68
|
+
type: "plugin",
|
|
69
|
+
name: "strapi-llm-translator"
|
|
70
|
+
// replace with your plugin name
|
|
71
|
+
});
|
|
72
|
+
const config2 = await pluginStore.get({ key: "configuration" });
|
|
73
|
+
ctx.body = config2 || {};
|
|
74
|
+
},
|
|
75
|
+
// Save the configuration
|
|
76
|
+
async setConfig(ctx) {
|
|
77
|
+
const { body } = ctx.request;
|
|
78
|
+
const pluginStore = strapi2.store({
|
|
79
|
+
environment: strapi2.config.environment,
|
|
80
|
+
type: "plugin",
|
|
81
|
+
name: "strapi-llm-translator"
|
|
82
|
+
// replace with your plugin name
|
|
83
|
+
});
|
|
84
|
+
await pluginStore.set({
|
|
85
|
+
key: "configuration",
|
|
86
|
+
value: { ...body }
|
|
87
|
+
});
|
|
88
|
+
ctx.body = await pluginStore.get({ key: "configuration" });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const controllers = {
|
|
92
|
+
admin: controllers$1
|
|
93
|
+
};
|
|
94
|
+
const middlewares = {};
|
|
95
|
+
const policies = {};
|
|
96
|
+
const adminRoutes = [
|
|
97
|
+
{
|
|
98
|
+
method: "POST",
|
|
99
|
+
path: "/generate",
|
|
100
|
+
handler: "admin.generate",
|
|
101
|
+
config: {
|
|
102
|
+
policies: []
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
method: "GET",
|
|
107
|
+
path: "/config",
|
|
108
|
+
handler: "admin.getConfig",
|
|
109
|
+
config: {
|
|
110
|
+
policies: []
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
method: "POST",
|
|
115
|
+
path: "/config",
|
|
116
|
+
handler: "admin.setConfig",
|
|
117
|
+
config: {
|
|
118
|
+
policies: []
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
const routes = {
|
|
123
|
+
admin: {
|
|
124
|
+
type: "admin",
|
|
125
|
+
routes: adminRoutes
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const DEFAULT_SYSTEM_PROMPT = "You are a professional translator. Your task is to translate the provided content accurately while preserving the original meaning and tone.";
|
|
129
|
+
const SYSTEM_PROMPT_APPENDIX = `The user asks you to translate the text to a specific language, the language is provided via short code like "en", "fr", "de", etc.`;
|
|
130
|
+
const openai = new OpenAI({
|
|
131
|
+
baseURL: process.env.STRAPI_ADMIN_LLM_TRANSLATOR_LLM_BASE_URL,
|
|
132
|
+
apiKey: process.env.LLM_TRANSLATOR_LLM_API_KEY
|
|
133
|
+
});
|
|
134
|
+
const model = process.env.STRAPI_ADMIN_LLM_TRANSLATOR_LLM_MODEL;
|
|
135
|
+
const isTranslatableField = (contentType, key, value) => {
|
|
136
|
+
if (typeof value !== "string") {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const fieldSchema = contentType?.attributes?.[key];
|
|
140
|
+
if (!fieldSchema) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const isStringOrText = ["string", "text"].includes(fieldSchema.type);
|
|
144
|
+
const isNotUID = fieldSchema.type !== "uid";
|
|
145
|
+
const isLocalizable = fieldSchema.pluginOptions?.i18n?.localized !== false;
|
|
146
|
+
return isStringOrText && isNotUID && isLocalizable;
|
|
147
|
+
};
|
|
148
|
+
const extractTranslatableFields = (contentType, fields, components = {}) => {
|
|
149
|
+
const translatableFields = [];
|
|
150
|
+
Object.entries(fields).forEach(([key, value]) => {
|
|
151
|
+
if (isTranslatableField(contentType, key, value)) {
|
|
152
|
+
translatableFields.push({
|
|
153
|
+
path: [key],
|
|
154
|
+
value,
|
|
155
|
+
originalPath: [key]
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
if (fields.blocks && Array.isArray(fields.blocks)) {
|
|
160
|
+
fields.blocks.forEach((block, blockIndex) => {
|
|
161
|
+
if (block.__component && components[block.__component]) {
|
|
162
|
+
const componentSchema = components[block.__component];
|
|
163
|
+
Object.entries(componentSchema.attributes).forEach(([fieldName, schema]) => {
|
|
164
|
+
if (block[fieldName] && typeof block[fieldName] === "string" && ["string", "text", "richtext"].includes(schema.type)) {
|
|
165
|
+
translatableFields.push({
|
|
166
|
+
path: ["blocks", String(blockIndex), fieldName],
|
|
167
|
+
value: block[fieldName],
|
|
168
|
+
originalPath: ["blocks", String(blockIndex), fieldName]
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return translatableFields;
|
|
176
|
+
};
|
|
177
|
+
const prepareTranslationPayload = (fields) => {
|
|
178
|
+
const payload = {};
|
|
179
|
+
fields.forEach((field) => {
|
|
180
|
+
let current = payload;
|
|
181
|
+
field.path.forEach((part, index2) => {
|
|
182
|
+
if (index2 === field.path.length - 1) {
|
|
183
|
+
current[part] = field.value;
|
|
184
|
+
} else {
|
|
185
|
+
current[part] = current[part] || {};
|
|
186
|
+
current = current[part];
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
return payload;
|
|
191
|
+
};
|
|
192
|
+
const mergeTranslatedContent = (originalData, translatedData, translatableFields) => {
|
|
193
|
+
const result = JSON.parse(JSON.stringify(originalData));
|
|
194
|
+
translatableFields.forEach((field) => {
|
|
195
|
+
let translatedValue = translatedData;
|
|
196
|
+
for (const part of field.path) {
|
|
197
|
+
translatedValue = translatedValue?.[part];
|
|
198
|
+
if (translatedValue === void 0) break;
|
|
199
|
+
}
|
|
200
|
+
if (translatedValue !== void 0) {
|
|
201
|
+
let current = result;
|
|
202
|
+
field.originalPath.forEach((part, index2) => {
|
|
203
|
+
if (index2 === field.originalPath.length - 1) {
|
|
204
|
+
current[part] = translatedValue;
|
|
205
|
+
} else {
|
|
206
|
+
current = current[part];
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return result;
|
|
212
|
+
};
|
|
213
|
+
const generateSlug = async (data, field, contentTypeUID) => {
|
|
214
|
+
const uidService = strapi.service("plugin::content-manager.uid");
|
|
215
|
+
const slug = await uidService.generateUIDField({
|
|
216
|
+
contentTypeUID,
|
|
217
|
+
field,
|
|
218
|
+
data
|
|
219
|
+
});
|
|
220
|
+
return slug;
|
|
221
|
+
};
|
|
222
|
+
const findUIDFields = (contentType) => {
|
|
223
|
+
const uidFields = [];
|
|
224
|
+
Object.entries(contentType.attributes || {}).forEach(([fieldName, schema]) => {
|
|
225
|
+
if (schema.type === "uid" && schema.targetField) {
|
|
226
|
+
uidFields.push({
|
|
227
|
+
fieldName,
|
|
228
|
+
targetField: schema.targetField
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
return uidFields;
|
|
233
|
+
};
|
|
234
|
+
const generateUIDsForTranslatedFields = async (uidFields, translatedData, contentTypeUID, mergedContent) => {
|
|
235
|
+
const translatedUIDs = {};
|
|
236
|
+
for (const { fieldName, targetField } of uidFields) {
|
|
237
|
+
if (translatedData[targetField] !== void 0) {
|
|
238
|
+
try {
|
|
239
|
+
const newUID = await generateSlug(
|
|
240
|
+
{
|
|
241
|
+
...mergedContent,
|
|
242
|
+
[targetField]: translatedData[targetField]
|
|
243
|
+
},
|
|
244
|
+
fieldName,
|
|
245
|
+
contentTypeUID
|
|
246
|
+
);
|
|
247
|
+
translatedUIDs[fieldName] = newUID;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error(`Failed to generate UID for field ${fieldName}:`, error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return translatedUIDs;
|
|
254
|
+
};
|
|
255
|
+
const llmService = ({ strapi: strapi2 }) => ({
|
|
256
|
+
async generateWithLLM(contentType, fields, components, config2) {
|
|
257
|
+
try {
|
|
258
|
+
const userConfig = await getUserConfig();
|
|
259
|
+
const translatableFields = extractTranslatableFields(contentType, fields, components);
|
|
260
|
+
const translationPayload = prepareTranslationPayload(translatableFields);
|
|
261
|
+
const prompt = buildPrompt(translationPayload, config2.targetLanguage);
|
|
262
|
+
const systemPrompt = await buildSystemPrompt(userConfig);
|
|
263
|
+
const response = await callLLMProvider(prompt, systemPrompt, model, userConfig);
|
|
264
|
+
const translatedData = parseLLMResponse(response);
|
|
265
|
+
const mergedContent = mergeTranslatedContent(fields, translatedData, translatableFields);
|
|
266
|
+
const uidFields = findUIDFields(contentType);
|
|
267
|
+
const translatedUIDs = await generateUIDsForTranslatedFields(
|
|
268
|
+
uidFields,
|
|
269
|
+
translatedData,
|
|
270
|
+
contentType.uid,
|
|
271
|
+
mergedContent
|
|
272
|
+
);
|
|
273
|
+
return {
|
|
274
|
+
data: {
|
|
275
|
+
...mergedContent,
|
|
276
|
+
...translatedUIDs
|
|
277
|
+
},
|
|
278
|
+
meta: {
|
|
279
|
+
ok: true,
|
|
280
|
+
status: 200,
|
|
281
|
+
message: "Translation completed successfully"
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
} catch (error) {
|
|
285
|
+
strapi2.log.error("LLM translation error:", error);
|
|
286
|
+
return {
|
|
287
|
+
data: fields,
|
|
288
|
+
// Return original fields in case of error
|
|
289
|
+
meta: {
|
|
290
|
+
ok: false,
|
|
291
|
+
status: 500,
|
|
292
|
+
message: error instanceof Error ? error.message : "Translation failed"
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
const buildPrompt = (fields, targetLanguage) => {
|
|
299
|
+
return `You are translating content from a CMS. Please translate the following JSON data to ${targetLanguage}.
|
|
300
|
+
|
|
301
|
+
IMPORTANT RULES:
|
|
302
|
+
1. Preserve all JSON structure and keys exactly as provided
|
|
303
|
+
2. Only translate string values
|
|
304
|
+
3. Maintain any markdown formatting within the text
|
|
305
|
+
4. Keep HTML tags intact if present
|
|
306
|
+
5. Preserve any special characters or placeholders
|
|
307
|
+
6. Return ONLY the translated JSON object
|
|
308
|
+
7. Do not add any explanations or comments
|
|
309
|
+
8. Ensure professional and culturally appropriate translations
|
|
310
|
+
|
|
311
|
+
SOURCE JSON:
|
|
312
|
+
${JSON.stringify(fields, null, 2)}`;
|
|
313
|
+
};
|
|
314
|
+
const getUserConfig = async () => {
|
|
315
|
+
const pluginStore = strapi.store({
|
|
316
|
+
environment: strapi.config.environment,
|
|
317
|
+
type: "plugin",
|
|
318
|
+
name: "strapi-llm-translator"
|
|
319
|
+
});
|
|
320
|
+
const config2 = await pluginStore.get({ key: "configuration" });
|
|
321
|
+
return config2;
|
|
322
|
+
};
|
|
323
|
+
const buildSystemPrompt = async (config2) => {
|
|
324
|
+
return `${config2.systemPrompt || DEFAULT_SYSTEM_PROMPT} ${SYSTEM_PROMPT_APPENDIX}`;
|
|
325
|
+
};
|
|
326
|
+
const callLLMProvider = async (prompt, systemPrompt, model2, config2) => {
|
|
327
|
+
const response = await openai.chat.completions.create({
|
|
328
|
+
model: model2,
|
|
329
|
+
messages: [
|
|
330
|
+
{
|
|
331
|
+
role: "system",
|
|
332
|
+
content: systemPrompt
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
role: "user",
|
|
336
|
+
content: prompt
|
|
337
|
+
}
|
|
338
|
+
],
|
|
339
|
+
temperature: config2.temperature
|
|
340
|
+
});
|
|
341
|
+
return response;
|
|
342
|
+
};
|
|
343
|
+
const parseLLMResponse = (response) => {
|
|
344
|
+
try {
|
|
345
|
+
const content = response.choices[0]?.message?.content;
|
|
346
|
+
if (!content) throw new Error("No content in response");
|
|
347
|
+
const cleanContent = content.replace(/^```json\s*\n/, "").replace(/^```\s*\n/, "").replace(/\n\s*```$/, "").replace(/\u200B/g, "").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"').trim();
|
|
348
|
+
try {
|
|
349
|
+
const parsed = JSON.parse(cleanContent);
|
|
350
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
351
|
+
return parsed;
|
|
352
|
+
}
|
|
353
|
+
throw new Error("Invalid response format - not an object");
|
|
354
|
+
} catch (parseError) {
|
|
355
|
+
const openBraces = (cleanContent.match(/{/g) || []).length;
|
|
356
|
+
const closeBraces = (cleanContent.match(/}/g) || []).length;
|
|
357
|
+
if (openBraces > closeBraces) {
|
|
358
|
+
const missingBraces = openBraces - closeBraces;
|
|
359
|
+
const fixedContent = cleanContent + "}".repeat(missingBraces);
|
|
360
|
+
try {
|
|
361
|
+
const parsed = JSON.parse(fixedContent);
|
|
362
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
363
|
+
return parsed;
|
|
364
|
+
}
|
|
365
|
+
} catch (secondError) {
|
|
366
|
+
console.error("Second parse attempt failed:", secondError);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
throw new Error(`JSON parsing failed: ${parseError.message}`);
|
|
370
|
+
}
|
|
371
|
+
} catch (error) {
|
|
372
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
373
|
+
throw new Error(`Translation failed: ${errorMessage}`);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
const services = {
|
|
377
|
+
"llm-service": llmService
|
|
378
|
+
};
|
|
379
|
+
const index = {
|
|
380
|
+
register,
|
|
381
|
+
bootstrap,
|
|
382
|
+
destroy,
|
|
383
|
+
config,
|
|
384
|
+
controllers,
|
|
385
|
+
routes,
|
|
386
|
+
services,
|
|
387
|
+
contentTypes,
|
|
388
|
+
policies,
|
|
389
|
+
middlewares
|
|
390
|
+
};
|
|
391
|
+
export {
|
|
392
|
+
index as default
|
|
393
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DEFAULT_SYSTEM_PROMPT = "You are a professional translator. Your task is to translate the provided content accurately while preserving the original meaning and tone.";
|
|
2
|
+
export declare const SYSTEM_PROMPT_APPENDIX = "The user asks you to translate the text to a specific language, the language is provided via short code like \"en\", \"fr\", \"de\", etc.";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RequestContext, StrapiContext, GenerateRequestBody } from 'src/types';
|
|
2
|
+
declare const controllers: ({ strapi }: StrapiContext) => {
|
|
3
|
+
generate(ctx: RequestContext & {
|
|
4
|
+
request: {
|
|
5
|
+
body: GenerateRequestBody;
|
|
6
|
+
};
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
getConfig(ctx: RequestContext): Promise<void>;
|
|
9
|
+
setConfig(ctx: RequestContext): Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export default controllers;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="koa" />
|
|
2
|
+
declare const _default: {
|
|
3
|
+
admin: ({ strapi }: import("../types").StrapiContext) => {
|
|
4
|
+
generate(ctx: Omit<import("koa").Context, "body" | "query" | "request"> & {
|
|
5
|
+
body: object;
|
|
6
|
+
query: object;
|
|
7
|
+
params: object;
|
|
8
|
+
request: Omit<import("koa").Request, "body"> & {
|
|
9
|
+
body: object;
|
|
10
|
+
};
|
|
11
|
+
state: {
|
|
12
|
+
user?: import("../types").AdminUser;
|
|
13
|
+
};
|
|
14
|
+
} & {
|
|
15
|
+
request: {
|
|
16
|
+
body: import("../types").GenerateRequestBody;
|
|
17
|
+
};
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
getConfig(ctx: import("../types").RequestContext): Promise<void>;
|
|
20
|
+
setConfig(ctx: import("../types").RequestContext): Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/// <reference types="koa" />
|
|
2
|
+
declare const _default: {
|
|
3
|
+
register: ({ strapi }: {
|
|
4
|
+
strapi: import("@strapi/types/dist/core").Strapi;
|
|
5
|
+
}) => void;
|
|
6
|
+
bootstrap: ({ strapi }: {
|
|
7
|
+
strapi: import("@strapi/types/dist/core").Strapi;
|
|
8
|
+
}) => void;
|
|
9
|
+
destroy: ({ strapi }: {
|
|
10
|
+
strapi: import("@strapi/types/dist/core").Strapi;
|
|
11
|
+
}) => void;
|
|
12
|
+
config: {
|
|
13
|
+
default: {
|
|
14
|
+
llmApiKey: string;
|
|
15
|
+
llmEndpoint: string;
|
|
16
|
+
llmModel: string;
|
|
17
|
+
};
|
|
18
|
+
validator(): void;
|
|
19
|
+
};
|
|
20
|
+
controllers: {
|
|
21
|
+
admin: ({ strapi }: import("./types").StrapiContext) => {
|
|
22
|
+
generate(ctx: Omit<import("koa").Context, "body" | "query" | "request"> & {
|
|
23
|
+
body: object;
|
|
24
|
+
query: object;
|
|
25
|
+
params: object;
|
|
26
|
+
request: Omit<import("koa").Request, "body"> & {
|
|
27
|
+
body: object;
|
|
28
|
+
};
|
|
29
|
+
state: {
|
|
30
|
+
user?: import("./types").AdminUser;
|
|
31
|
+
};
|
|
32
|
+
} & {
|
|
33
|
+
request: {
|
|
34
|
+
body: import("./types").GenerateRequestBody;
|
|
35
|
+
};
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
getConfig(ctx: import("./types").RequestContext): Promise<void>;
|
|
38
|
+
setConfig(ctx: import("./types").RequestContext): Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
routes: {
|
|
42
|
+
admin: {
|
|
43
|
+
type: string;
|
|
44
|
+
routes: {
|
|
45
|
+
method: string;
|
|
46
|
+
path: string;
|
|
47
|
+
handler: string;
|
|
48
|
+
config: {
|
|
49
|
+
policies: any[];
|
|
50
|
+
};
|
|
51
|
+
}[];
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
services: {
|
|
55
|
+
'llm-service': ({ strapi }: {
|
|
56
|
+
strapi: import("@strapi/types/dist/core").Strapi;
|
|
57
|
+
}) => import("./types").LLMServiceType;
|
|
58
|
+
};
|
|
59
|
+
contentTypes: {};
|
|
60
|
+
policies: {};
|
|
61
|
+
middlewares: {};
|
|
62
|
+
};
|
|
63
|
+
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context } from 'koa';
|
|
2
|
+
export type AdminUser = {
|
|
3
|
+
id: string | number;
|
|
4
|
+
email: string;
|
|
5
|
+
username: string;
|
|
6
|
+
avatar?: string;
|
|
7
|
+
};
|
|
8
|
+
export type RequestContext<Body = object, PathParams = object, QueryParams = object> = Omit<Context, 'body' | 'query' | 'request'> & {
|
|
9
|
+
body: Body;
|
|
10
|
+
query: QueryParams;
|
|
11
|
+
params: PathParams;
|
|
12
|
+
request: Omit<Context['request'], 'body'> & {
|
|
13
|
+
body: Body;
|
|
14
|
+
};
|
|
15
|
+
state: {
|
|
16
|
+
user?: AdminUser;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export interface PluginConfig {
|
|
20
|
+
systemPrompt: string;
|
|
21
|
+
temperature: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Core } from '@strapi/strapi';
|
|
2
|
+
export * from './controllers';
|
|
3
|
+
export type CoreStrapi = Omit<Core.Strapi, 'query' | 'plugin'> & {
|
|
4
|
+
plugin: (pluginName: string) => Omit<Core.Plugin, 'contentTypes'> & {
|
|
5
|
+
contentTypes: Record<string, Core.Plugin['contentTypes'][string] & {
|
|
6
|
+
uid: string;
|
|
7
|
+
}>;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export type StrapiContext = {
|
|
11
|
+
readonly strapi: CoreStrapi;
|
|
12
|
+
};
|
|
13
|
+
export interface TranslationResponse {
|
|
14
|
+
data: Record<string, any>;
|
|
15
|
+
meta: {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
status: number;
|
|
18
|
+
message?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface TranslationConfig {
|
|
22
|
+
targetLanguage: string;
|
|
23
|
+
}
|
|
24
|
+
export interface LLMServiceType {
|
|
25
|
+
generateWithLLM(contentType: Record<string, any>, fields: Record<string, any>, components: Record<string, any>, config: TranslationConfig): Promise<Record<string, any>>;
|
|
26
|
+
}
|
|
27
|
+
export interface GenerateRequestBody {
|
|
28
|
+
contentType: string;
|
|
29
|
+
fields: any;
|
|
30
|
+
components: any;
|
|
31
|
+
targetLanguage: string;
|
|
32
|
+
}
|
|
33
|
+
export interface TranslatableField {
|
|
34
|
+
path: string[];
|
|
35
|
+
value: string;
|
|
36
|
+
originalPath: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface UIDField {
|
|
39
|
+
fieldName: string;
|
|
40
|
+
targetField: string;
|
|
41
|
+
}
|