@intlayer/backend 5.4.2 → 5.5.0-canary.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/dist/cjs/controllers/ai.controller.cjs +60 -52
- package/dist/cjs/controllers/ai.controller.cjs.map +1 -1
- package/dist/cjs/controllers/dictionary.controller.cjs +5 -0
- package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
- package/dist/cjs/export.cjs +4 -2
- package/dist/cjs/export.cjs.map +1 -1
- package/dist/cjs/routes/ai.routes.cjs +6 -0
- package/dist/cjs/routes/ai.routes.cjs.map +1 -1
- package/dist/cjs/services/dictionary.service.cjs +6 -1
- package/dist/cjs/services/dictionary.service.cjs.map +1 -1
- package/dist/cjs/utils/AI/aiSdk.cjs +140 -0
- package/dist/cjs/utils/AI/aiSdk.cjs.map +1 -0
- package/dist/cjs/utils/AI/askDocQuestion/PROMPT.md +2 -1
- package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs +32 -27
- package/dist/cjs/utils/AI/askDocQuestion/askDocQuestion.cjs.map +1 -1
- package/dist/cjs/utils/AI/askDocQuestion/embeddings.json +7374 -0
- package/dist/cjs/utils/AI/auditDictionary/PROMPT.md +4 -0
- package/dist/cjs/utils/AI/auditDictionary/index.cjs +36 -43
- package/dist/cjs/utils/AI/auditDictionary/index.cjs.map +1 -1
- package/dist/cjs/utils/AI/auditDictionaryField/PROMPT.md +4 -0
- package/dist/cjs/utils/AI/auditDictionaryField/index.cjs +34 -28
- package/dist/cjs/utils/AI/auditDictionaryField/index.cjs.map +1 -1
- package/dist/cjs/utils/AI/auditDictionaryMetadata/PROMPT.md +4 -0
- package/dist/cjs/utils/AI/auditDictionaryMetadata/index.cjs +23 -23
- package/dist/cjs/utils/AI/auditDictionaryMetadata/index.cjs.map +1 -1
- package/dist/cjs/utils/{auditTag → AI/auditTag}/PROMPT.md +4 -0
- package/dist/cjs/utils/{auditTag → AI/auditTag}/index.cjs +27 -27
- package/dist/cjs/utils/AI/auditTag/index.cjs.map +1 -0
- package/dist/cjs/utils/AI/autocomplete/PROMPT.md +4 -0
- package/dist/cjs/utils/AI/autocomplete/index.cjs +25 -22
- package/dist/cjs/utils/AI/autocomplete/index.cjs.map +1 -1
- package/dist/cjs/utils/AI/translateJSON/PROMPT.md +53 -0
- package/dist/cjs/utils/AI/translateJSON/index.cjs +106 -0
- package/dist/cjs/utils/AI/translateJSON/index.cjs.map +1 -0
- package/dist/cjs/utils/extractJSON.cjs +52 -0
- package/dist/cjs/utils/extractJSON.cjs.map +1 -0
- package/dist/esm/controllers/ai.controller.mjs +58 -51
- package/dist/esm/controllers/ai.controller.mjs.map +1 -1
- package/dist/esm/controllers/dictionary.controller.mjs +5 -0
- package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
- package/dist/esm/export.mjs +3 -2
- package/dist/esm/export.mjs.map +1 -1
- package/dist/esm/routes/ai.routes.mjs +8 -1
- package/dist/esm/routes/ai.routes.mjs.map +1 -1
- package/dist/esm/services/dictionary.service.mjs +6 -1
- package/dist/esm/services/dictionary.service.mjs.map +1 -1
- package/dist/esm/utils/AI/aiSdk.mjs +115 -0
- package/dist/esm/utils/AI/aiSdk.mjs.map +1 -0
- package/dist/esm/utils/AI/askDocQuestion/PROMPT.md +2 -1
- package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs +32 -27
- package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs.map +1 -1
- package/dist/esm/utils/AI/askDocQuestion/embeddings.json +7374 -0
- package/dist/esm/utils/AI/auditDictionary/PROMPT.md +4 -0
- package/dist/esm/utils/AI/auditDictionary/index.mjs +36 -43
- package/dist/esm/utils/AI/auditDictionary/index.mjs.map +1 -1
- package/dist/esm/utils/AI/auditDictionaryField/PROMPT.md +4 -0
- package/dist/esm/utils/AI/auditDictionaryField/index.mjs +34 -28
- package/dist/esm/utils/AI/auditDictionaryField/index.mjs.map +1 -1
- package/dist/esm/utils/AI/auditDictionaryMetadata/PROMPT.md +4 -0
- package/dist/esm/utils/AI/auditDictionaryMetadata/index.mjs +23 -23
- package/dist/esm/utils/AI/auditDictionaryMetadata/index.mjs.map +1 -1
- package/dist/esm/utils/{auditTag → AI/auditTag}/PROMPT.md +4 -0
- package/dist/esm/utils/AI/auditTag/index.mjs +49 -0
- package/dist/esm/utils/AI/auditTag/index.mjs.map +1 -0
- package/dist/esm/utils/AI/autocomplete/PROMPT.md +4 -0
- package/dist/esm/utils/AI/autocomplete/index.mjs +25 -22
- package/dist/esm/utils/AI/autocomplete/index.mjs.map +1 -1
- package/dist/esm/utils/AI/translateJSON/PROMPT.md +53 -0
- package/dist/esm/utils/AI/translateJSON/index.mjs +81 -0
- package/dist/esm/utils/AI/translateJSON/index.mjs.map +1 -0
- package/dist/esm/utils/extractJSON.mjs +28 -0
- package/dist/esm/utils/extractJSON.mjs.map +1 -0
- package/dist/types/controllers/ai.controller.d.ts +12 -21
- package/dist/types/controllers/ai.controller.d.ts.map +1 -1
- package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
- package/dist/types/export.d.ts +12 -11
- package/dist/types/export.d.ts.map +1 -1
- package/dist/types/routes/ai.routes.d.ts +5 -0
- package/dist/types/routes/ai.routes.d.ts.map +1 -1
- package/dist/types/services/dictionary.service.d.ts +2 -2
- package/dist/types/services/dictionary.service.d.ts.map +1 -1
- package/dist/types/utils/AI/aiSdk.d.ts +41 -0
- package/dist/types/utils/AI/aiSdk.d.ts.map +1 -0
- package/dist/types/utils/AI/askDocQuestion/askDocQuestion.d.ts +1 -1
- package/dist/types/utils/AI/askDocQuestion/askDocQuestion.d.ts.map +1 -1
- package/dist/types/utils/AI/auditDictionary/index.d.ts +10 -15
- package/dist/types/utils/AI/auditDictionary/index.d.ts.map +1 -1
- package/dist/types/utils/AI/auditDictionaryField/index.d.ts +9 -14
- package/dist/types/utils/AI/auditDictionaryField/index.d.ts.map +1 -1
- package/dist/types/utils/AI/auditDictionaryMetadata/index.d.ts +7 -13
- package/dist/types/utils/AI/auditDictionaryMetadata/index.d.ts.map +1 -1
- package/dist/types/utils/AI/auditTag/index.d.ts +18 -0
- package/dist/types/utils/AI/auditTag/index.d.ts.map +1 -0
- package/dist/types/utils/AI/autocomplete/index.d.ts +6 -12
- package/dist/types/utils/AI/autocomplete/index.d.ts.map +1 -1
- package/dist/types/utils/AI/translateJSON/index.d.ts +24 -0
- package/dist/types/utils/AI/translateJSON/index.d.ts.map +1 -0
- package/dist/types/utils/extractJSON.d.ts +6 -0
- package/dist/types/utils/extractJSON.d.ts.map +1 -0
- package/package.json +13 -7
- package/dist/cjs/utils/auditTag/index.cjs.map +0 -1
- package/dist/esm/utils/auditTag/index.mjs +0 -49
- package/dist/esm/utils/auditTag/index.mjs.map +0 -1
- package/dist/types/utils/auditTag/index.d.ts +0 -30
- package/dist/types/utils/auditTag/index.d.ts.map +0 -1
|
@@ -138,6 +138,10 @@ You are an expert in internationalization, copy writing and content management.
|
|
|
138
138
|
- The import of the `t` function was imported from `react-intlayer` instead of `intlayer`.
|
|
139
139
|
- A type `Dictionary` was added to the file to strengthen the content declaration.
|
|
140
140
|
|
|
141
|
+
**Application Context**
|
|
142
|
+
|
|
143
|
+
{{applicationContext}}
|
|
144
|
+
|
|
141
145
|
**Tags Instructions:**
|
|
142
146
|
|
|
143
147
|
{{tagsInstructions}}
|
|
@@ -1,69 +1,62 @@
|
|
|
1
|
+
import { getLocaleName } from "@intlayer/core";
|
|
2
|
+
import { logger } from "./../../../logger/index.mjs";
|
|
3
|
+
import { generateText } from "ai";
|
|
1
4
|
import { readFileSync } from "fs";
|
|
2
5
|
import { dirname, join } from "path";
|
|
3
6
|
import { fileURLToPath } from "url";
|
|
4
|
-
import {
|
|
5
|
-
import { logger } from "./../../../logger/index.mjs";
|
|
6
|
-
import { OpenAI } from "openai";
|
|
7
|
+
import { AIProvider, getAIConfig } from "../aiSdk.mjs";
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const getFileContent = (
|
|
9
|
-
|
|
10
|
-
const fileContent = readFileSync(absolutePath, "utf-8");
|
|
11
|
-
return fileContent;
|
|
12
|
-
};
|
|
13
|
-
const FILE_TEMPLATE = {
|
|
14
|
-
ts: getFileContent("./TS_FORMAT.md"),
|
|
15
|
-
tsx: getFileContent("./TSX_FORMAT.md"),
|
|
16
|
-
js: getFileContent("./MJS_FORMAT.md"),
|
|
17
|
-
mjs: getFileContent("./MJS_FORMAT.md"),
|
|
18
|
-
cjs: getFileContent("./CJS_FORMAT.md"),
|
|
19
|
-
jsx: getFileContent("./JSX_FORMAT.md"),
|
|
20
|
-
json: getFileContent("./JSON_FORMAT.md")
|
|
9
|
+
const getFileContent = (filePath) => {
|
|
10
|
+
return readFileSync(join(__dirname, filePath), { encoding: "utf-8" });
|
|
21
11
|
};
|
|
22
12
|
const CHAT_GPT_PROMPT = getFileContent("./PROMPT.md");
|
|
23
13
|
const formatLocaleWithName = (locale) => {
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
return `${locale}: ${getLocaleName(locale)}`;
|
|
15
|
+
};
|
|
16
|
+
const formatTagInstructions = (tags) => {
|
|
17
|
+
if (!tags || tags.length === 0) {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
return `Based on the dictionary content, identify specific tags from the list below that would be relevant:
|
|
21
|
+
|
|
22
|
+
${tags.map(({ key, description }) => `- ${key}: ${description}`).join("\n\n")}`;
|
|
26
23
|
};
|
|
27
|
-
const formatTagInstructions = (tags = []) => tags.map((tag) => `- ${tag.key}: ${tag.instructions}`).join("\n\n");
|
|
28
24
|
const auditDictionary = async ({
|
|
29
25
|
fileContent,
|
|
30
26
|
filePath,
|
|
31
|
-
|
|
32
|
-
openAiApiKey,
|
|
33
|
-
customPrompt,
|
|
34
|
-
temperature,
|
|
27
|
+
aiOptions,
|
|
35
28
|
locales,
|
|
36
29
|
defaultLocale,
|
|
37
30
|
tags
|
|
38
31
|
}) => {
|
|
39
32
|
try {
|
|
40
|
-
const
|
|
41
|
-
|
|
33
|
+
const otherLocales = locales.filter((locale) => locale !== defaultLocale);
|
|
34
|
+
const aiConfig = await getAIConfig({
|
|
35
|
+
provider: AIProvider.OPENAI,
|
|
36
|
+
model: "gpt-4o-mini",
|
|
37
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
38
|
+
...aiOptions
|
|
42
39
|
});
|
|
43
|
-
const
|
|
44
|
-
const fileExtension = splitted[splitted.length - 1];
|
|
45
|
-
const prompt = customPrompt ?? CHAT_GPT_PROMPT.replace("{{filePath}}", filePath ?? "Not provided").replace(
|
|
40
|
+
const prompt = CHAT_GPT_PROMPT.replace(
|
|
46
41
|
"{{defaultLocale}}",
|
|
47
|
-
|
|
42
|
+
formatLocaleWithName(defaultLocale)
|
|
48
43
|
).replace(
|
|
49
44
|
"{{otherLocales}}",
|
|
50
|
-
`{${
|
|
51
|
-
).replace(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
45
|
+
`{${otherLocales.map(formatLocaleWithName).join(", ")}}`
|
|
46
|
+
).replace("{{filePath}}", filePath ?? "").replace("{{fileContent}}", fileContent).replace("{{applicationContext}}", aiOptions?.applicationContext ?? "").replace("{{tagsInstructions}}", formatTagInstructions(tags));
|
|
47
|
+
if (!aiConfig) {
|
|
48
|
+
logger.error("Failed to configure AI model");
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
const { text: newContent, usage } = await generateText({
|
|
52
|
+
model: aiConfig.model,
|
|
53
|
+
temperature: aiConfig.temperature,
|
|
58
54
|
messages: [{ role: "system", content: prompt }]
|
|
59
55
|
});
|
|
60
|
-
|
|
61
|
-
logger.info(
|
|
62
|
-
`${chatCompletion.usage?.total_tokens} tokens used in the request`
|
|
63
|
-
);
|
|
56
|
+
logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);
|
|
64
57
|
return {
|
|
65
|
-
fileContent: newContent
|
|
66
|
-
tokenUsed:
|
|
58
|
+
fileContent: newContent,
|
|
59
|
+
tokenUsed: usage?.totalTokens ?? 0
|
|
67
60
|
};
|
|
68
61
|
} catch (error) {
|
|
69
62
|
console.error(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/utils/AI/auditDictionary/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../../../../src/utils/AI/auditDictionary/index.ts"],"sourcesContent":["import type { Tag } from '@/types/tag.types';\nimport { getLocaleName } from '@intlayer/core';\nimport { logger } from '@logger';\nimport { generateText } from 'ai';\nimport { readFileSync } from 'fs';\nimport type { Locales } from 'intlayer';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { AIOptions, AIProvider, getAIConfig } from '../aiSdk';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Get the content of a file at the specified path\nconst getFileContent = (filePath: string) => {\n return readFileSync(join(__dirname, filePath), { encoding: 'utf-8' });\n};\n\nexport type AuditOptions = {\n fileContent: string;\n filePath?: string;\n locales: Locales[];\n defaultLocale: Locales;\n tags: Tag[];\n aiOptions?: AIOptions;\n};\n\nexport type AuditFileResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = getFileContent('./PROMPT.md');\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locales): string => {\n return `${locale}: ${getLocaleName(locale)}`;\n};\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n // Prepare the tag instructions.\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionary = async ({\n fileContent,\n filePath,\n aiOptions,\n locales,\n defaultLocale,\n tags,\n}: AuditOptions): Promise<AuditFileResultData | undefined> => {\n try {\n const otherLocales = locales.filter((locale) => locale !== defaultLocale);\n\n // Get the appropriate AI model configuration\n const aiConfig = await getAIConfig({\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n apiKey: process.env.OPENAI_API_KEY,\n ...aiOptions,\n });\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{defaultLocale}}',\n formatLocaleWithName(defaultLocale)\n )\n .replace(\n '{{otherLocales}}',\n `{${otherLocales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace('{{filePath}}', filePath ?? '')\n .replace('{{fileContent}}', fileContent)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags));\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n model: aiConfig.model,\n temperature: aiConfig.temperature,\n messages: [{ role: 'system', content: prompt }],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n } catch (error) {\n console.error(error);\n }\n};\n"],"mappings":"AACA,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAE7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAoB,YAAY,mBAAmB;AAEnD,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAGxD,MAAM,iBAAiB,CAAC,aAAqB;AAC3C,SAAO,aAAa,KAAK,WAAW,QAAQ,GAAG,EAAE,UAAU,QAAQ,CAAC;AACtE;AAiBA,MAAM,kBAAkB,eAAe,aAAa;AAQpD,MAAM,uBAAuB,CAAC,WAA4B;AACxD,SAAO,GAAG,MAAM,KAAK,cAAc,MAAM,CAAC;AAC5C;AASA,MAAM,wBAAwB,CAAC,SAAwB;AACrD,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AAGA,SAAO;AAAA;AAAA,EAEP,KAAK,IAAI,CAAC,EAAE,KAAK,YAAY,MAAM,KAAK,GAAG,KAAK,WAAW,EAAE,EAAE,KAAK,MAAM,CAAC;AAC7E;AAOO,MAAM,kBAAkB,OAAO;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA8D;AAC5D,MAAI;AACF,UAAM,eAAe,QAAQ,OAAO,CAAC,WAAW,WAAW,aAAa;AAGxE,UAAM,WAAW,MAAM,YAAY;AAAA,MACjC,UAAU,WAAW;AAAA,MACrB,OAAO;AAAA,MACP,QAAQ,QAAQ,IAAI;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAGD,UAAM,SAAS,gBAAgB;AAAA,MAC7B;AAAA,MACA,qBAAqB,aAAa;AAAA,IACpC,EACG;AAAA,MACC;AAAA,MACA,IAAI,aAAa,IAAI,oBAAoB,EAAE,KAAK,IAAI,CAAC;AAAA,IACvD,EACC,QAAQ,gBAAgB,YAAY,EAAE,EACtC,QAAQ,mBAAmB,WAAW,EACtC,QAAQ,0BAA0B,WAAW,sBAAsB,EAAE,EACrE,QAAQ,wBAAwB,sBAAsB,IAAI,CAAC;AAE9D,QAAI,CAAC,UAAU;AACb,aAAO,MAAM,8BAA8B;AAC3C,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,MAAM,YAAY,MAAM,IAAI,MAAM,aAAa;AAAA,MACrD,OAAO,SAAS;AAAA,MAChB,aAAa,SAAS;AAAA,MACtB,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAChD,CAAC;AAED,WAAO,KAAK,GAAG,OAAO,eAAe,CAAC,6BAA6B;AAEnE,WAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW,OAAO,eAAe;AAAA,IACnC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,KAAK;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -108,6 +108,10 @@ You are an expert in internationalization, copy writing and content management.
|
|
|
108
108
|
|
|
109
109
|
Développeurs, Responsables de contenu
|
|
110
110
|
|
|
111
|
+
**Application Context**
|
|
112
|
+
|
|
113
|
+
{{applicationContext}}
|
|
114
|
+
|
|
111
115
|
**Tags Instructions:**
|
|
112
116
|
|
|
113
117
|
{{tagsInstructions}}
|
|
@@ -1,51 +1,57 @@
|
|
|
1
|
+
import { getLocaleName } from "@intlayer/core";
|
|
2
|
+
import { logger } from "./../../../logger/index.mjs";
|
|
3
|
+
import { generateText } from "ai";
|
|
1
4
|
import { readFileSync } from "fs";
|
|
2
5
|
import { dirname, join } from "path";
|
|
3
6
|
import { fileURLToPath } from "url";
|
|
4
|
-
import {
|
|
5
|
-
import { logger } from "./../../../logger/index.mjs";
|
|
6
|
-
import { OpenAI } from "openai";
|
|
7
|
+
import { AIProvider, getAIConfig } from "../aiSdk.mjs";
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const getFileContent = (
|
|
9
|
-
|
|
10
|
-
const fileContent = readFileSync(absolutePath, "utf-8");
|
|
11
|
-
return fileContent;
|
|
9
|
+
const getFileContent = (filePath) => {
|
|
10
|
+
return readFileSync(join(__dirname, filePath), { encoding: "utf-8" });
|
|
12
11
|
};
|
|
13
12
|
const CHAT_GPT_PROMPT = getFileContent("./PROMPT.md");
|
|
14
13
|
const formatLocaleWithName = (locale) => {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
return `${locale}: ${getLocaleName(locale)}`;
|
|
15
|
+
};
|
|
16
|
+
const formatTagInstructions = (tags) => {
|
|
17
|
+
if (!tags || tags.length === 0) {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
return `Based on the dictionary content, identify specific tags from the list below that would be relevant:
|
|
21
|
+
|
|
22
|
+
${tags.map(({ key, description }) => `- ${key}: ${description}`).join("\n\n")}`;
|
|
17
23
|
};
|
|
18
|
-
const formatTagInstructions = (tags = []) => tags.map((tag) => `- ${tag.key}: ${tag.instructions}`).join("\n\n");
|
|
19
24
|
const auditDictionaryField = async ({
|
|
20
25
|
fileContent,
|
|
21
|
-
|
|
22
|
-
openAiApiKey,
|
|
23
|
-
temperature,
|
|
24
|
-
customPrompt,
|
|
26
|
+
aiOptions,
|
|
25
27
|
locales,
|
|
26
28
|
keyPath,
|
|
27
29
|
tags
|
|
28
30
|
}) => {
|
|
29
31
|
try {
|
|
30
|
-
const
|
|
31
|
-
apiKey: openAiApiKey ?? process.env.OPENAI_API_KEY
|
|
32
|
-
});
|
|
33
|
-
const prompt = customPrompt ?? CHAT_GPT_PROMPT.replace(
|
|
32
|
+
const prompt = CHAT_GPT_PROMPT.replace(
|
|
34
33
|
"{{otherLocales}}",
|
|
35
34
|
`{${locales.map(formatLocaleWithName).join(", ")}}`
|
|
36
|
-
).replace("{{keyPath}}", JSON.stringify(keyPath)).replace("{{fileContent}}", fileContent).replace("{{tagsInstructions}}", formatTagInstructions(tags));
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
).replace("{{keyPath}}", JSON.stringify(keyPath)).replace("{{fileContent}}", fileContent).replace("{{applicationContext}}", aiOptions?.applicationContext ?? "").replace("{{tagsInstructions}}", formatTagInstructions(tags));
|
|
36
|
+
const aiConfig = await getAIConfig({
|
|
37
|
+
provider: AIProvider.OPENAI,
|
|
38
|
+
model: "gpt-4o-mini",
|
|
39
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
40
|
+
...aiOptions
|
|
41
|
+
});
|
|
42
|
+
if (!aiConfig) {
|
|
43
|
+
logger.error("Failed to configure AI model");
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
const { text: newContent, usage } = await generateText({
|
|
47
|
+
model: aiConfig.model,
|
|
48
|
+
temperature: aiConfig.temperature,
|
|
40
49
|
messages: [{ role: "system", content: prompt }]
|
|
41
50
|
});
|
|
42
|
-
|
|
43
|
-
logger.info(
|
|
44
|
-
`${chatCompletion.usage?.total_tokens} tokens used in the request`
|
|
45
|
-
);
|
|
51
|
+
logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);
|
|
46
52
|
return {
|
|
47
|
-
fileContent: newContent
|
|
48
|
-
tokenUsed:
|
|
53
|
+
fileContent: newContent,
|
|
54
|
+
tokenUsed: usage?.totalTokens ?? 0
|
|
49
55
|
};
|
|
50
56
|
} catch (error) {
|
|
51
57
|
console.error(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/utils/AI/auditDictionaryField/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../../../../src/utils/AI/auditDictionaryField/index.ts"],"sourcesContent":["import type { Tag } from '@/types/tag.types';\nimport { getLocaleName, type KeyPath } from '@intlayer/core';\nimport { logger } from '@logger';\nimport { generateText } from 'ai';\nimport { readFileSync } from 'fs';\nimport type { Locales } from 'intlayer';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { AIOptions, AIProvider, getAIConfig } from '../aiSdk';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Get the content of a file at the specified path\nconst getFileContent = (filePath: string) => {\n return readFileSync(join(__dirname, filePath), { encoding: 'utf-8' });\n};\n\nexport type AuditDictionaryFieldOptions = {\n fileContent: string;\n locales: Locales[];\n keyPath: KeyPath[];\n tags: Tag[];\n aiOptions?: AIOptions;\n};\n\nexport type AuditDictionaryFieldResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = getFileContent('./PROMPT.md');\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locales): string => {\n return `${locale}: ${getLocaleName(locale)}`;\n};\n\n/**\n * Formats tag instructions for the AI prompt.\n *\n * @param tags - Array of tags to format\n * @returns A formatted string with tag instructions\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryField = async ({\n fileContent,\n aiOptions,\n locales,\n keyPath,\n tags,\n}: AuditDictionaryFieldOptions): Promise<\n AuditDictionaryFieldResultData | undefined\n> => {\n try {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{otherLocales}}',\n `{${locales.map(formatLocaleWithName).join(', ')}}`\n )\n .replace('{{keyPath}}', JSON.stringify(keyPath))\n .replace('{{fileContent}}', fileContent)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags));\n\n // Get the appropriate AI model configuration\n const aiConfig = await getAIConfig({\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n apiKey: process.env.OPENAI_API_KEY,\n ...aiOptions,\n });\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n model: aiConfig.model,\n temperature: aiConfig.temperature,\n messages: [{ role: 'system', content: prompt }],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n } catch (error) {\n console.error(error);\n }\n};\n"],"mappings":"AACA,SAAS,qBAAmC;AAC5C,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAE7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAoB,YAAY,mBAAmB;AAEnD,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAGxD,MAAM,iBAAiB,CAAC,aAAqB;AAC3C,SAAO,aAAa,KAAK,WAAW,QAAQ,GAAG,EAAE,UAAU,QAAQ,CAAC;AACtE;AAgBA,MAAM,kBAAkB,eAAe,aAAa;AAQpD,MAAM,uBAAuB,CAAC,WAA4B;AACxD,SAAO,GAAG,MAAM,KAAK,cAAc,MAAM,CAAC;AAC5C;AAQA,MAAM,wBAAwB,CAAC,SAAwB;AACrD,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,SAAO;AAAA;AAAA,EAEP,KAAK,IAAI,CAAC,EAAE,KAAK,YAAY,MAAM,KAAK,GAAG,KAAK,WAAW,EAAE,EAAE,KAAK,MAAM,CAAC;AAC7E;AAOO,MAAM,uBAAuB,OAAO;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAEK;AACH,MAAI;AAEF,UAAM,SAAS,gBAAgB;AAAA,MAC7B;AAAA,MACA,IAAI,QAAQ,IAAI,oBAAoB,EAAE,KAAK,IAAI,CAAC;AAAA,IAClD,EACG,QAAQ,eAAe,KAAK,UAAU,OAAO,CAAC,EAC9C,QAAQ,mBAAmB,WAAW,EACtC,QAAQ,0BAA0B,WAAW,sBAAsB,EAAE,EACrE,QAAQ,wBAAwB,sBAAsB,IAAI,CAAC;AAG9D,UAAM,WAAW,MAAM,YAAY;AAAA,MACjC,UAAU,WAAW;AAAA,MACrB,OAAO;AAAA,MACP,QAAQ,QAAQ,IAAI;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAED,QAAI,CAAC,UAAU;AACb,aAAO,MAAM,8BAA8B;AAC3C,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,MAAM,YAAY,MAAM,IAAI,MAAM,aAAa;AAAA,MACrD,OAAO,SAAS;AAAA,MAChB,aAAa,SAAS;AAAA,MACtB,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAChD,CAAC;AAED,WAAO,KAAK,GAAG,OAAO,eAAe,CAAC,6BAA6B;AAEnE,WAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW,OAAO,eAAe;AAAA,IACnC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,KAAK;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -1,47 +1,47 @@
|
|
|
1
1
|
import { logger } from "./../../../logger/index.mjs";
|
|
2
|
+
import { generateText } from "ai";
|
|
2
3
|
import { readFileSync } from "fs";
|
|
3
|
-
import { OpenAI } from "openai";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { AIProvider, getAIConfig } from "../aiSdk.mjs";
|
|
6
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const getFileContent = (
|
|
8
|
-
|
|
9
|
-
const fileContent = readFileSync(absolutePath, "utf-8");
|
|
10
|
-
return fileContent;
|
|
8
|
+
const getFileContent = (filePath) => {
|
|
9
|
+
return readFileSync(join(__dirname, filePath), { encoding: "utf-8" });
|
|
11
10
|
};
|
|
12
11
|
const CHAT_GPT_PROMPT = getFileContent("./PROMPT.md");
|
|
13
12
|
const auditDictionaryMetadata = async ({
|
|
14
|
-
|
|
15
|
-
openAiApiKey,
|
|
16
|
-
temperature,
|
|
17
|
-
customPrompt,
|
|
13
|
+
aiOptions,
|
|
18
14
|
tags,
|
|
19
15
|
fileContent
|
|
20
16
|
}) => {
|
|
21
17
|
try {
|
|
22
|
-
const
|
|
23
|
-
apiKey: openAiApiKey ?? process.env.OPENAI_API_KEY
|
|
24
|
-
});
|
|
25
|
-
const prompt = customPrompt ?? CHAT_GPT_PROMPT.replace(
|
|
18
|
+
const prompt = CHAT_GPT_PROMPT.replace(
|
|
26
19
|
"{{tags}}",
|
|
27
20
|
`${JSON.stringify(
|
|
28
21
|
tags.map(({ key, description }) => `- ${key}: ${description}`).join("\n\n"),
|
|
29
22
|
null,
|
|
30
23
|
2
|
|
31
24
|
)}`
|
|
32
|
-
).replace("{{contentDeclaration}}", fileContent);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
).replace("{{contentDeclaration}}", fileContent).replace("{{applicationContext}}", aiOptions?.applicationContext ?? "");
|
|
26
|
+
const aiConfig = await getAIConfig({
|
|
27
|
+
provider: AIProvider.OPENAI,
|
|
28
|
+
model: "gpt-4o-mini",
|
|
29
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
30
|
+
...aiOptions
|
|
31
|
+
});
|
|
32
|
+
if (!aiConfig) {
|
|
33
|
+
logger.error("Failed to configure AI model");
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
const { text: newContent, usage } = await generateText({
|
|
37
|
+
model: aiConfig.model,
|
|
38
|
+
temperature: aiConfig.temperature,
|
|
36
39
|
messages: [{ role: "system", content: prompt }]
|
|
37
40
|
});
|
|
38
|
-
|
|
39
|
-
logger.info(
|
|
40
|
-
`${chatCompletion.usage?.total_tokens} tokens used in the request`
|
|
41
|
-
);
|
|
41
|
+
logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);
|
|
42
42
|
return {
|
|
43
|
-
fileContent: newContent
|
|
44
|
-
tokenUsed:
|
|
43
|
+
fileContent: newContent,
|
|
44
|
+
tokenUsed: usage?.totalTokens ?? 0
|
|
45
45
|
};
|
|
46
46
|
} catch (error) {
|
|
47
47
|
console.error(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/utils/AI/auditDictionaryMetadata/index.ts"],"sourcesContent":["import type { Tag } from '@/types/tag.types';\nimport { logger } from '@logger';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../../src/utils/AI/auditDictionaryMetadata/index.ts"],"sourcesContent":["import type { Tag } from '@/types/tag.types';\nimport { logger } from '@logger';\nimport { generateText } from 'ai';\nimport { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { AIOptions, AIProvider, getAIConfig } from '../aiSdk';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Get the content of a file at the specified path\nconst getFileContent = (filePath: string) => {\n return readFileSync(join(__dirname, filePath), { encoding: 'utf-8' });\n};\n\nexport type AuditOptions = {\n fileContent: string;\n tags: Tag[];\n aiOptions?: AIOptions;\n};\n\nexport type AuditFileResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to AI models\nconst CHAT_GPT_PROMPT = getFileContent('./PROMPT.md');\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async ({\n aiOptions,\n tags,\n fileContent,\n}: AuditOptions): Promise<AuditFileResultData | undefined> => {\n try {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{tags}}',\n `${JSON.stringify(\n tags\n .map(({ key, description }) => `- ${key}: ${description}`)\n .join('\\n\\n'),\n null,\n 2\n )}`\n )\n .replace('{{contentDeclaration}}', fileContent)\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '');\n\n // Get the appropriate AI model configuration\n const aiConfig = await getAIConfig({\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n apiKey: process.env.OPENAI_API_KEY,\n ...aiOptions,\n });\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n model: aiConfig.model,\n temperature: aiConfig.temperature,\n messages: [{ role: 'system', content: prompt }],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n } catch (error) {\n console.error(error);\n }\n};\n"],"mappings":"AACA,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAoB,YAAY,mBAAmB;AAEnD,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAGxD,MAAM,iBAAiB,CAAC,aAAqB;AAC3C,SAAO,aAAa,KAAK,WAAW,QAAQ,GAAG,EAAE,UAAU,QAAQ,CAAC;AACtE;AAcA,MAAM,kBAAkB,eAAe,aAAa;AAO7C,MAAM,0BAA0B,OAAO;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AACF,MAA8D;AAC5D,MAAI;AAEF,UAAM,SAAS,gBAAgB;AAAA,MAC7B;AAAA,MACA,GAAG,KAAK;AAAA,QACN,KACG,IAAI,CAAC,EAAE,KAAK,YAAY,MAAM,KAAK,GAAG,KAAK,WAAW,EAAE,EACxD,KAAK,MAAM;AAAA,QACd;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,EACG,QAAQ,0BAA0B,WAAW,EAC7C,QAAQ,0BAA0B,WAAW,sBAAsB,EAAE;AAGxE,UAAM,WAAW,MAAM,YAAY;AAAA,MACjC,UAAU,WAAW;AAAA,MACrB,OAAO;AAAA,MACP,QAAQ,QAAQ,IAAI;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAED,QAAI,CAAC,UAAU;AACb,aAAO,MAAM,8BAA8B;AAC3C,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,MAAM,YAAY,MAAM,IAAI,MAAM,aAAa;AAAA,MACrD,OAAO,SAAS;AAAA,MAChB,aAAa,SAAS;AAAA,MACtB,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAChD,CAAC;AAED,WAAO,KAAK,GAAG,OAAO,eAAe,CAAC,6BAA6B;AAEnE,WAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW,OAAO,eAAe;AAAA,IACnC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,KAAK;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -21,6 +21,10 @@ Your role is to review a tag. A tag is attached to a content declaration and is
|
|
|
21
21
|
- **Do Not Alter Structure:** If the file structure is correct, do not modify it. Only add, update, or remove content declarations as necessary.
|
|
22
22
|
- **Return Only Final File Content:** Provide the updated file content without any additional comments or explanations.
|
|
23
23
|
|
|
24
|
+
**Application Context**
|
|
25
|
+
|
|
26
|
+
{{applicationContext}}
|
|
27
|
+
|
|
24
28
|
**Tags to Audit:**
|
|
25
29
|
|
|
26
30
|
{{tag}}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { logger } from "./../../../logger/index.mjs";
|
|
2
|
+
import { generateText } from "ai";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { AIProvider, getAIConfig } from "../aiSdk.mjs";
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const getFileContent = (filePath) => {
|
|
9
|
+
return readFileSync(join(__dirname, filePath), { encoding: "utf-8" });
|
|
10
|
+
};
|
|
11
|
+
const CHAT_GPT_PROMPT = getFileContent("./PROMPT.md");
|
|
12
|
+
const auditTag = async ({
|
|
13
|
+
aiOptions,
|
|
14
|
+
dictionaries,
|
|
15
|
+
tag
|
|
16
|
+
}) => {
|
|
17
|
+
try {
|
|
18
|
+
const prompt = CHAT_GPT_PROMPT.replace(
|
|
19
|
+
"{{tag.description}}",
|
|
20
|
+
tag.description ?? ""
|
|
21
|
+
).replace("{{tag.key}}", tag.key).replace("{{dictionaries}}", JSON.stringify(dictionaries, null, 2)).replace("{{applicationContext}}", aiOptions?.applicationContext ?? "");
|
|
22
|
+
const aiConfig = await getAIConfig({
|
|
23
|
+
provider: AIProvider.OPENAI,
|
|
24
|
+
model: "gpt-4o-mini",
|
|
25
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
26
|
+
...aiOptions
|
|
27
|
+
});
|
|
28
|
+
if (!aiConfig) {
|
|
29
|
+
logger.error("Failed to configure AI model");
|
|
30
|
+
return void 0;
|
|
31
|
+
}
|
|
32
|
+
const { text: newContent, usage } = await generateText({
|
|
33
|
+
model: aiConfig.model,
|
|
34
|
+
temperature: aiConfig.temperature,
|
|
35
|
+
messages: [{ role: "system", content: prompt }]
|
|
36
|
+
});
|
|
37
|
+
logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);
|
|
38
|
+
return {
|
|
39
|
+
fileContent: newContent,
|
|
40
|
+
tokenUsed: usage?.totalTokens ?? 0
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(error);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
export {
|
|
47
|
+
auditTag
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/utils/AI/auditTag/index.ts"],"sourcesContent":["import type { Dictionary } from '@/types/dictionary.types';\nimport type { Tag } from '@/types/tag.types';\nimport { logger } from '@logger';\nimport { generateText } from 'ai';\nimport { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { AIOptions, AIProvider, getAIConfig } from '../aiSdk';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Get the content of a file at the specified path\nconst getFileContent = (filePath: string) => {\n return readFileSync(join(__dirname, filePath), { encoding: 'utf-8' });\n};\n\nexport type AuditOptions = {\n dictionaries: Dictionary[];\n tag: Tag;\n aiOptions?: AIOptions;\n};\n\nexport type TranslateJSONResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to AI models\nconst CHAT_GPT_PROMPT = getFileContent('./PROMPT.md');\n\n/**\n * Audits a tag by constructing a prompt for AI models.\n * The prompt includes details about the tag and related dictionaries.\n */\nexport const auditTag = async ({\n aiOptions,\n dictionaries,\n tag,\n}: AuditOptions): Promise<TranslateJSONResultData | undefined> => {\n try {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{tag.description}}',\n tag.description ?? ''\n )\n .replace('{{tag.key}}', tag.key)\n .replace('{{dictionaries}}', JSON.stringify(dictionaries, null, 2))\n .replace('{{applicationContext}}', aiOptions?.applicationContext ?? '');\n\n // Get the appropriate AI model configuration\n const aiConfig = await getAIConfig({\n provider: AIProvider.OPENAI,\n model: 'gpt-4o-mini',\n apiKey: process.env.OPENAI_API_KEY,\n ...aiOptions,\n });\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n model: aiConfig.model,\n temperature: aiConfig.temperature,\n messages: [{ role: 'system', content: prompt }],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n } catch (error) {\n console.error(error);\n }\n};\n"],"mappings":"AAEA,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAoB,YAAY,mBAAmB;AAEnD,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAGxD,MAAM,iBAAiB,CAAC,aAAqB;AAC3C,SAAO,aAAa,KAAK,WAAW,QAAQ,GAAG,EAAE,UAAU,QAAQ,CAAC;AACtE;AAcA,MAAM,kBAAkB,eAAe,aAAa;AAM7C,MAAM,WAAW,OAAO;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF,MAAkE;AAChE,MAAI;AAEF,UAAM,SAAS,gBAAgB;AAAA,MAC7B;AAAA,MACA,IAAI,eAAe;AAAA,IACrB,EACG,QAAQ,eAAe,IAAI,GAAG,EAC9B,QAAQ,oBAAoB,KAAK,UAAU,cAAc,MAAM,CAAC,CAAC,EACjE,QAAQ,0BAA0B,WAAW,sBAAsB,EAAE;AAGxE,UAAM,WAAW,MAAM,YAAY;AAAA,MACjC,UAAU,WAAW;AAAA,MACrB,OAAO;AAAA,MACP,QAAQ,QAAQ,IAAI;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAED,QAAI,CAAC,UAAU;AACb,aAAO,MAAM,8BAA8B;AAC3C,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,MAAM,YAAY,MAAM,IAAI,MAAM,aAAa;AAAA,MACrD,OAAO,SAAS;AAAA,MAChB,aAAa,SAAS;AAAA,MACtB,UAAU,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,IAChD,CAAC;AAED,WAAO,KAAK,GAAG,OAAO,eAAe,CAAC,6BAA6B;AAEnE,WAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW,OAAO,eAAe;AAAA,IACnC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,KAAK;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -11,3 +11,7 @@ Your completion should not exceed one sentence. Minimize the completion length i
|
|
|
11
11
|
The user input will be provided in the next user message: { role: 'user', content: 'xxx' }
|
|
12
12
|
|
|
13
13
|
You should return your autocompletion without any additional text or formatting.
|
|
14
|
+
|
|
15
|
+
**Application Context**
|
|
16
|
+
|
|
17
|
+
{{applicationContext}}
|
|
@@ -1,42 +1,45 @@
|
|
|
1
|
+
import { logger } from "./../../../logger/index.mjs";
|
|
2
|
+
import { generateText } from "ai";
|
|
1
3
|
import { readFileSync } from "fs";
|
|
2
4
|
import { dirname, join } from "path";
|
|
3
5
|
import { fileURLToPath } from "url";
|
|
4
|
-
import {
|
|
5
|
-
import { OpenAI } from "openai";
|
|
6
|
+
import { AIProvider, getAIConfig } from "../aiSdk.mjs";
|
|
6
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const getFileContent = (
|
|
8
|
-
|
|
9
|
-
const fileContent = readFileSync(absolutePath, "utf-8");
|
|
10
|
-
return fileContent;
|
|
8
|
+
const getFileContent = (filePath) => {
|
|
9
|
+
return readFileSync(join(__dirname, filePath), { encoding: "utf-8" });
|
|
11
10
|
};
|
|
12
11
|
const CHAT_GPT_PROMPT = getFileContent("./PROMPT.md");
|
|
13
12
|
const autocomplete = async ({
|
|
14
13
|
text,
|
|
15
|
-
|
|
16
|
-
openAiApiKey,
|
|
17
|
-
temperature,
|
|
18
|
-
customPrompt
|
|
14
|
+
aiOptions
|
|
19
15
|
}) => {
|
|
20
16
|
try {
|
|
21
|
-
const
|
|
22
|
-
|
|
17
|
+
const prompt = CHAT_GPT_PROMPT.replace(
|
|
18
|
+
"{{applicationContext}}",
|
|
19
|
+
aiOptions?.applicationContext ?? ""
|
|
20
|
+
);
|
|
21
|
+
const aiConfig = await getAIConfig({
|
|
22
|
+
model: "gpt-4o-mini",
|
|
23
|
+
provider: AIProvider.OPENAI,
|
|
24
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
25
|
+
...aiOptions
|
|
23
26
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
if (!aiConfig) {
|
|
28
|
+
logger.error("Failed to configure AI model");
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
const { text: newContent, usage } = await generateText({
|
|
32
|
+
model: aiConfig.model,
|
|
33
|
+
temperature: aiConfig.temperature,
|
|
28
34
|
messages: [
|
|
29
35
|
{ role: "system", content: prompt },
|
|
30
36
|
{ role: "user", content: text }
|
|
31
37
|
]
|
|
32
38
|
});
|
|
33
|
-
|
|
34
|
-
logger.info(
|
|
35
|
-
`${chatCompletion.usage?.total_tokens} tokens used in the request`
|
|
36
|
-
);
|
|
39
|
+
logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);
|
|
37
40
|
return {
|
|
38
|
-
autocompletion: newContent
|
|
39
|
-
tokenUsed:
|
|
41
|
+
autocompletion: newContent,
|
|
42
|
+
tokenUsed: usage?.totalTokens ?? 0
|
|
40
43
|
};
|
|
41
44
|
} catch (error) {
|
|
42
45
|
console.error(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/utils/AI/autocomplete/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../../../../src/utils/AI/autocomplete/index.ts"],"sourcesContent":["import { logger } from '@logger';\nimport { generateText } from 'ai';\nimport { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { AIOptions, AIProvider, getAIConfig } from '../aiSdk';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Get the content of a file at the specified path\nconst getFileContent = (filePath: string) => {\n return readFileSync(join(__dirname, filePath), { encoding: 'utf-8' });\n};\n\nexport type AutocompleteOptions = {\n text: string;\n aiOptions?: AIOptions;\n};\n\nexport type AutocompleteFileResultData = {\n autocompletion: string;\n tokenUsed: number;\n};\n\n// The prompt template to send to the AI model\nconst CHAT_GPT_PROMPT = getFileContent('./PROMPT.md');\n\n/**\n * Autocompletes a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const autocomplete = async ({\n text,\n aiOptions,\n}: AutocompleteOptions): Promise<AutocompleteFileResultData | undefined> => {\n try {\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n aiOptions?.applicationContext ?? ''\n );\n\n // Get the appropriate AI model configuration\n const aiConfig = await getAIConfig({\n model: 'gpt-4o-mini',\n provider: AIProvider.OPENAI,\n apiKey: process.env.OPENAI_API_KEY,\n ...aiOptions,\n });\n\n if (!aiConfig) {\n logger.error('Failed to configure AI model');\n return undefined;\n }\n\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n model: aiConfig.model,\n temperature: aiConfig.temperature,\n messages: [\n { role: 'system', content: prompt },\n { role: 'user', content: text },\n ],\n });\n\n logger.info(`${usage?.totalTokens ?? 0} tokens used in the request`);\n\n return {\n autocompletion: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n } catch (error) {\n console.error(error);\n }\n};\n"],"mappings":"AAAA,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAoB,YAAY,mBAAmB;AAEnD,MAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAGxD,MAAM,iBAAiB,CAAC,aAAqB;AAC3C,SAAO,aAAa,KAAK,WAAW,QAAQ,GAAG,EAAE,UAAU,QAAQ,CAAC;AACtE;AAaA,MAAM,kBAAkB,eAAe,aAAa;AAO7C,MAAM,eAAe,OAAO;AAAA,EACjC;AAAA,EACA;AACF,MAA4E;AAC1E,MAAI;AAEF,UAAM,SAAS,gBAAgB;AAAA,MAC7B;AAAA,MACA,WAAW,sBAAsB;AAAA,IACnC;AAGA,UAAM,WAAW,MAAM,YAAY;AAAA,MACjC,OAAO;AAAA,MACP,UAAU,WAAW;AAAA,MACrB,QAAQ,QAAQ,IAAI;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAED,QAAI,CAAC,UAAU;AACb,aAAO,MAAM,8BAA8B;AAC3C,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,MAAM,YAAY,MAAM,IAAI,MAAM,aAAa;AAAA,MACrD,OAAO,SAAS;AAAA,MAChB,aAAa,SAAS;AAAA,MACtB,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,QAClC,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,MAChC;AAAA,IACF,CAAC;AAED,WAAO,KAAK,GAAG,OAAO,eAAe,CAAC,6BAA6B;AAEnE,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,WAAW,OAAO,eAAe;AAAA,IACnC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,KAAK;AAAA,EACrB;AACF;","names":[]}
|