2023-03-27 03:44:54 +01:00
const fs = require ( 'fs' ) ;
const path = require ( 'path' ) ;
const OPEN _AI _API _KEY = process . env . OPEN _AI _API _KEY ;
const ALL _ROADMAPS _DIR = path . join ( _ _dirname , '../src/data/roadmaps' ) ;
const roadmapId = process . argv [ 2 ] ;
const allowedRoadmapIds = fs . readdirSync ( ALL _ROADMAPS _DIR ) ;
if ( ! roadmapId ) {
console . error ( 'roadmapId is required' ) ;
process . exit ( 1 ) ;
}
if ( ! allowedRoadmapIds . includes ( roadmapId ) ) {
console . error ( ` Invalid roadmap key ${ roadmapId } ` ) ;
console . error ( ` Allowed keys are ${ allowedRoadmapIds . join ( ', ' ) } ` ) ;
process . exit ( 1 ) ;
}
const ROADMAP _CONTENT _DIR = path . join ( ALL _ROADMAPS _DIR , roadmapId , 'content' ) ;
2023-10-24 20:57:54 +01:00
const OpenAI = require ( 'openai' ) ;
const openai = new OpenAI ( {
2023-03-27 04:11:34 +01:00
apiKey : OPEN _AI _API _KEY ,
} ) ;
2023-03-27 03:44:54 +01:00
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 ( ROADMAP _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 ;
}
2024-04-02 22:23:06 +01:00
/ * *
* Write the topic content for the given topic
* @ param currTopicUrl
* @ returns { Promise < string > }
* /
2023-03-27 06:04:38 +01:00
function writeTopicContent ( currTopicUrl ) {
const [ parentTopic , childTopic ] = currTopicUrl
. replace ( /^\d+-/g , '/' )
. replace ( /:/g , '/' )
. replace ( /^\// , '' )
. split ( '/' )
. slice ( - 2 )
. map ( ( topic ) => topic . replace ( /-/g , ' ' ) ) ;
2023-03-27 03:44:54 +01:00
2023-04-26 17:17:39 +01:00
const roadmapTitle = roadmapId . replace ( /-/g , ' ' ) ;
2023-03-27 06:04:38 +01:00
2024-04-02 22:23:06 +01:00
let prompt = ` I will give you a topic and you need to write a brief introduction for that with regards to " ${ roadmapTitle } ". Your format should be as follows and be in strictly markdown format:
2024-04-25 18:04:05 +01:00
# ( Put a heading for the topic without adding parent "Subtopic in Topic" or "Topic in Roadmap" etc . )
2024-04-02 22:23:06 +01:00
( Write me a brief introduction for the topic with regards to "${roadmapTitle}" )
2024-04-25 18:04:05 +01:00
( add any code snippets ONLY if necessary and makes sense )
2024-04-02 22:23:06 +01:00
` ;
2023-03-27 06:04:38 +01:00
if ( ! childTopic ) {
2024-04-02 22:23:06 +01:00
prompt += ` First topic is: ${ parentTopic } ` ;
} else {
prompt += ` First topic is: ${ childTopic } under ${ parentTopic } ` ;
2023-03-27 06:04:38 +01:00
}
2023-04-18 02:54:30 +01:00
console . log ( ` Generating ' ${ childTopic || parentTopic } '... ` ) ;
2023-03-27 03:44:54 +01:00
2023-03-27 04:11:34 +01:00
return new Promise ( ( resolve , reject ) => {
2023-10-24 20:57:54 +01:00
openai . chat . completions
. create ( {
2023-03-27 04:11:34 +01:00
model : 'gpt-4' ,
messages : [
{
role : 'user' ,
2023-03-27 06:04:38 +01:00
content : prompt ,
2023-03-27 04:11:34 +01:00
} ,
] ,
} )
. then ( ( response ) => {
2023-10-24 20:57:54 +01:00
const article = response . choices [ 0 ] . message . content ;
2023-03-27 03:44:54 +01:00
2023-03-27 04:11:34 +01:00
resolve ( article ) ;
} )
. catch ( ( err ) => {
reject ( err ) ;
} ) ;
} ) ;
}
2023-03-27 03:44:54 +01:00
2023-04-18 02:54:30 +01:00
async function writeFileForGroup ( group , topicUrlToPathMapping ) {
const topicId = group ? . properties ? . controlName ;
const topicTitle = group ? . children ? . controls ? . control ? . find (
2023-10-24 20:57:54 +01:00
( control ) => control ? . typeID === 'Label' ,
2023-04-18 02:54:30 +01:00
) ? . properties ? . text ;
const currTopicUrl = topicId ? . replace ( /^\d+-/g , '/' ) ? . replace ( /:/g , '/' ) ;
if ( ! currTopicUrl ) {
return ;
}
const contentFilePath = topicUrlToPathMapping [ currTopicUrl ] ;
if ( ! contentFilePath ) {
console . log ( ` Missing file for: ${ currTopicUrl } ` ) ;
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 ( currTopicUrl ) ;
console . log ( ` Writing ${ topicId } .. ` ) ;
2024-04-02 22:23:06 +01:00
fs . writeFileSync ( contentFilePath , topicContent , 'utf8' ) ;
2023-04-18 02:54:30 +01:00
// console.log(currentFileContent);
// console.log(currTopicUrl);
// console.log(topicTitle);
// console.log(topicUrlToPathMapping[currTopicUrl]);
}
2023-03-27 04:11:34 +01:00
async function run ( ) {
const topicUrlToPathMapping = getFilesInFolder ( ROADMAP _CONTENT _DIR ) ;
2023-03-27 03:44:54 +01:00
2023-10-24 20:57:54 +01:00
const roadmapJson = require (
path . join ( ALL _ROADMAPS _DIR , ` ${ roadmapId } / ${ roadmapId } ` ) ,
) ;
2023-06-07 23:08:32 +01:00
2023-03-27 04:11:34 +01:00
const groups = roadmapJson ? . mockup ? . controls ? . control ? . filter (
2023-03-30 01:23:01 +01:00
( control ) =>
control . typeID === '__group__' &&
2023-10-24 20:57:54 +01:00
! control . properties ? . controlName ? . startsWith ( 'ext_link' ) ,
2023-03-27 04:11:34 +01:00
) ;
2023-03-27 03:44:54 +01:00
if ( ! OPEN _AI _API _KEY ) {
2023-03-27 04:11:34 +01:00
console . log ( '----------------------------------------' ) ;
console . log ( 'OPEN_AI_API_KEY not found. Skipping openai api calls...' ) ;
console . log ( '----------------------------------------' ) ;
2023-03-27 03:44:54 +01:00
}
2023-04-18 02:54:30 +01:00
const writePromises = [ ] ;
2023-03-27 04:11:34 +01:00
for ( let group of groups ) {
2023-04-18 02:54:30 +01:00
writePromises . push ( writeFileForGroup ( group , topicUrlToPathMapping ) ) ;
2023-03-27 04:11:34 +01:00
}
2023-04-18 02:54:30 +01:00
console . log ( 'Waiting for all files to be written...' ) ;
await Promise . all ( writePromises ) ;
2023-03-27 04:11:34 +01:00
}
run ( )
. then ( ( ) => {
console . log ( 'Done' ) ;
} )
. catch ( ( err ) => {
console . error ( err ) ;
process . exit ( 1 ) ;
} ) ;