const fs = require('fs'); const path = require('path'); const OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY; const ALL_BEST_PRACTICES_DIR = path.join( __dirname, '../src/data/best-practices' ); const BEST_PRACTICE_JSON_DIR = path.join( __dirname, '../public/jsons/best-practices' ); const bestPracticeId = process.argv[2]; const bestPracticeTitle = bestPracticeId.replace(/-/g, ' '); const allowedBestPracticeIds = fs.readdirSync(ALL_BEST_PRACTICES_DIR); if (!bestPracticeId) { console.error('bestPracticeId is required'); process.exit(1); } if (!allowedBestPracticeIds.includes(bestPracticeId)) { console.error(`Invalid bestPractice key ${bestPracticeId}`); console.error(`Allowed keys are ${allowedBestPracticeIds.join(', ')}`); process.exit(1); } const BEST_PRACTICE_CONTENT_DIR = path.join( ALL_BEST_PRACTICES_DIR, bestPracticeId, 'content' ); const { Configuration, OpenAIApi } = require('openai'); const configuration = new Configuration({ apiKey: OPEN_AI_API_KEY, }); const openai = new OpenAIApi(configuration); function getFilesInFolder(folderPath, fileList = {}) { const files = fs.readdirSync(folderPath); files.forEach((file) => { const filePath = path.join(folderPath, file); const stats = fs.statSync(filePath); if (stats.isDirectory()) { getFilesInFolder(filePath, fileList); } else if (stats.isFile()) { const fileUrl = filePath .replace(BEST_PRACTICE_CONTENT_DIR, '') // Remove the content folder .replace(/\/\d+-/g, '/') // Remove ordering info `/101-ecosystem` .replace(/\/index\.md$/, '') // Make the `/index.md` to become the parent folder only .replace(/\.md$/, ''); // Remove `.md` from the end of file fileList[fileUrl] = filePath; } }); return fileList; } function writeTopicContent(topicTitle) { let prompt = `I am reading a guide that has best practices about "${bestPracticeTitle}". I want to know more about "${topicTitle}". Write me a brief introductory paragraph about this and some tips on how I make sure of this? Behave as if you are the author of the guide.`; console.log(`Generating '${topicTitle}'...`); return new Promise((resolve, reject) => { openai .createChatCompletion({ model: 'gpt-4', messages: [ { role: 'user', content: prompt, }, ], }) .then((response) => { const article = response.data.choices[0].message.content; resolve(article); }) .catch((err) => { reject(err); }); }); } async function writeFileForGroup(group, topicUrlToPathMapping) { const topicId = group?.properties?.controlName; const topicTitle = group?.children?.controls?.control?.find( (control) => control?.typeID === 'Label' )?.properties?.text; const currTopicUrl = `/${topicId}`; if (currTopicUrl.startsWith('/check:')) { return; } const contentFilePath = topicUrlToPathMapping[currTopicUrl]; if (!contentFilePath) { console.log(`Missing file for: ${currTopicUrl}`); process.exit(0); return; } const currentFileContent = fs.readFileSync(contentFilePath, 'utf8'); const isFileEmpty = currentFileContent.replace(/^#.+/, ``).trim() === ''; if (!isFileEmpty) { console.log(`Ignoring ${topicId}. Not empty.`); return; } let newFileContent = `# ${topicTitle}`; if (!OPEN_AI_API_KEY) { console.log(`Writing ${topicId}..`); fs.writeFileSync(contentFilePath, newFileContent, 'utf8'); return; } const topicContent = await writeTopicContent(topicTitle); newFileContent += `\n\n${topicContent}`; console.log(`Writing ${topicId}..`); fs.writeFileSync(contentFilePath, newFileContent, 'utf8'); // console.log(currentFileContent); // console.log(currTopicUrl); // console.log(topicTitle); // console.log(topicUrlToPathMapping[currTopicUrl]); } async function run() { const topicUrlToPathMapping = getFilesInFolder(BEST_PRACTICE_CONTENT_DIR); const bestPracticeJson = require(path.join( BEST_PRACTICE_JSON_DIR, `${bestPracticeId}.json` )); const groups = bestPracticeJson?.mockup?.controls?.control?.filter( (control) => control.typeID === '__group__' && !control.properties?.controlName?.startsWith('ext_link') ); if (!OPEN_AI_API_KEY) { console.log('----------------------------------------'); console.log('OPEN_AI_API_KEY not found. Skipping openai api calls...'); console.log('----------------------------------------'); } const writePromises = []; for (let group of groups) { writePromises.push(writeFileForGroup(group, topicUrlToPathMapping)); } console.log('Waiting for all files to be written...'); await Promise.all(writePromises); } run() .then(() => { console.log('Done'); }) .catch((err) => { console.error(err); process.exit(1); });