The blogAboutCode
function generates a blog post about a project's code history, using a specified timeframe and model. It retrieves the commit history, extracts commits, and logs the first and last commit hashes.
npm run import -- "blog about code"
const path = require('path')
const fs = require('fs')
const {Remarkable} = require('remarkable');
const md = new Remarkable({html: true, xhtmlOut: true, breaks: true});
const selectModel = importer.import("select llm")
const {spawnSync} = require('child_process')
const parsePatch = importer.import("parse patch file")
const {safeurl} = importer.import("domain cache tools")
const PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE || '';
const PROJECT_PATH = path.join(__dirname, '..', 'Resources', 'Projects', 'code-summaries')
async function blogAboutCode(project, timeframe = 3, promptModel = 'Meta') {
if(typeof project == 'undefined') {
project = path.basename(path.resolve(path.join(__dirname, '..')))
}
if(typeof promptModel != 'function') {
promptModel = await selectModel(promptModel)
}
// TODO: local pull
if(!fs.existsSync(project)
&& fs.existsSync(path.join(PROFILE_PATH, project))) {
project = path.join(PROFILE_PATH, project)
}
if(project.includes('://')
&& fs.existsSync(path.basename(project).replace('.git', ''))
) {
project = path.join(PROFILE_PATH, path.basename(project).replace('.git', ''))
}
if(!fs.existsSync(project)) {
console.error('No project')
return
}
let result = await spawnSync('git', ['log', '--since=' + timeframe + '.days'], {
cwd: project,
timeout: 3000,
stdio: ['pipe', 'pipe', 'pipe']
})
let commits = result.stdout.toString()
//console.log(commits)
const matches = [...commits.matchAll(/commit ([a-z0-9]+)/gi)]
let first = matches[0]
let last = matches[matches.length - 1]
if(!first || !last) {
console.error('No commits!')
return
}
console.log(first[1], last[1])
if(first == last) {
result = await spawnSync('git', ['diff', '-U5', first[1]], {
cwd: project,
timeout: 3000,
stdio: ['pipe', 'pipe', 'pipe']
})
} else {
result = await spawnSync('git', ['diff', '-U5', last[1], first[1]], {
cwd: project,
timeout: 3000,
stdio: ['pipe', 'pipe', 'pipe']
})
}
let codePatch = result.stdout.toString()
summary = parsePatch(codePatch)
summaryOutputs = []
let files = Object.keys(summary.files)
for(let i = 0; i < files.length; i++) {
if(files[i].match('cache')) {
continue
}
console.log('Working on: ' + files[i])
let q1 = 'Summerize this code like you\'re writing for a fun coding blog, include code excerpts as context:\n'
+ files[i] + '\nAdditions that were made:\n' + summary.files[files[i]].additions.join('')
+ '\nDeletions that were made:\n' + summary.files[files[i]].deletions.join('')
console.log('User: ' + q1)
let a1 = await promptModel(q1)
console.log('AI: ' + a1)
summaryOutputs.push('#' + files[i] + '\n\n' + a1)
}
const mdHtml = md.render(summaryOutputs.join('\n'))
let now = new Date()
const filename = path.join(PROJECT_PATH, safeurl(path.basename(project) + now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate()) + '.html')
fs.writeFileSync(filename, mdHtml)
return mdHtml
}
module.exports = blogAboutCode
```javascript
const fs = require('fs');
const path = require('path');
const { Remarkable } = require('remarkable');
const { safeurl } = require('./domain-cache-tools');
const { selectModel, importer } = require('./llm-importer');
const { parsePatch } = require('./parse-patch-file');
const { spawnSync } = require('child_process');
const PROJECT_PATH = (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE) || '';
const DEFAULT_PROJECT_PATH = path.join(PROJECT_PATH, 'Resources', 'Projects', 'code-summaries');
const defaultProject = (project = path.basename(path.resolve(path.join(process.cwd(), '..')))) => {
if (!fs.existsSync(project) && fs.existsSync(path.join(PROFILE_PATH, project))) {
return path.join(PROFILE_PATH, project);
}
if (project.includes('://') && fs.existsSync(path.basename(project).replace('.git', ''))) {
return path.join(PROFILE_PATH, path.basename(project).replace('.git', ''));
}
return project;
};
const getCommits = async (project, timeframe = 3) => {
const result = await spawnSync('git', ['log', '--since=' + timeframe + '.days'], {
cwd: project,
timeout: 3000,
stdio: ['pipe', 'pipe', 'pipe']
});
const commits = result.stdout.toString();
const matches = [...commits.matchAll(/commit ([a-z0-9]+)/gi)];
return matches;
};
const getDiff = async (first, last, project) => {
if (first === last) {
return await spawnSync('git', ['diff', '-U5', first[1]], {
cwd: project,
timeout: 3000,
stdio: ['pipe', 'pipe', 'pipe']
});
}
return await spawnSync('git', ['diff', '-U5', last[1], first[1]], {
cwd: project,
timeout: 3000,
stdio: ['pipe', 'pipe', 'pipe']
});
};
const processFiles = async (files, project, promptModel) => {
const summaryOutputs = [];
for (const file of files) {
if (file.match('cache')) {
continue;
}
const q1 = `Summerize this code like you're writing for a fun coding blog, include code excerpts as context:
${file}
Additions that were made:
${summary.files[file].additions.join('')}
Deletions that were made:
${summary.files[file].deletions.join('')}
`;
const a1 = await promptModel(q1);
summaryOutputs.push(`# ${file}\n\n${a1}`);
}
return summaryOutputs;
};
const blogAboutCode = async (project, timeframe = 3, promptModel = 'Meta') => {
project = defaultProject(project);
if (!fs.existsSync(project)) {
console.error('No project');
return;
}
const commits = await getCommits(project, timeframe);
if (!commits.length) {
console.error('No commits!');
return;
}
console.log(commits[0][1], commits[commits.length - 1][1]);
const result = await getDiff(commits[0], commits[commits.length - 1], project);
const codePatch = result.stdout.toString();
const summary = parsePatch(codePatch);
const summaryOutputs = await processFiles(Object.keys(summary.files), project, promptModel);
const md = new Remarkable({ html: true, xhtmlOut: true, breaks: true });
const mdHtml = md.render(summaryOutputs.join('\n'));
const now = new Date();
const filename = path.join(DEFAULT_PROJECT_PATH, safeurl(path.basename(project) + now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate()) + '.html');
fs.writeFileSync(filename, mdHtml);
return mdHtml;
};
module.exports = blogAboutCode;
```
Function Overview
blogAboutCode
is an asynchronous function that generates blog posts about a given project's code history.
Parameters
project
: The path to the project directory (optional, defaults to the current project's directory if not provided)timeframe
: The time period to consider in the code history (default: 3 days)promptModel
: The model to use for generating the blog post (default: 'Meta')Function Flow
git log
to retrieve the commit history of the project, filtered by the specified timeframe.git diff
to retrieve the changes between the first and last commits (if they are different).Error Handling
Notes
child_process.spawnSync
to run Git commands, which returns a buffer containing the output.Remarkable
library is imported but not used in this function.safeurl
function is imported but not used in this function.parsePatch
function is imported but not used in this function.