指定したテキストファイルを結合して、生成AIに渡しやすい補足を加えるためのスクリプト
CosenseのExport for AIのテキストを参考に。
by Gemini
code:combine-for-ai.mjs
import fs from 'fs/promises';
import path from 'path';
// ==========================================
// 設定項目
// ==========================================
const INPUT_DIR = './'; // テキストファイルが入っているフォルダ
// ==========================================
// タイムスタンプ付きの出力ファイル名を生成
// ==========================================
function getTimestampedFileName() {
const now = new Date();
// 日本時間(JST)など、ローカル環境のタイムゾーンに合わせた日時を取得
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const date = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
// 例: export_for_ai_20260517-140236.txt
return ./export_for_ai_${year}${month}${date}-${hours}${minutes}${seconds}.txt;
}
// ==========================================
// AI向けのガイドライン定義
// ==========================================
const AI_GUIDE = `== GUIDE FOR AI AGENTS ==
1. READ the <PageList> in order - pages are sorted by relevance and importance.
2. USE internal brackets or references to understand connections between concepts.
3. NAVIGATE by searching for "<Page title=" to jump to specific pages.
4. REFERENCE created/updated timestamps when handling conflicting information.`;
async function combineFiles() {
try {
// コマンドライン引数からファイル名リストを取得
const specifiedFiles = process.argv.slice(2);
let targetFiles = [];
if (specifiedFiles.length > 0) {
// 【パターンA】引数がある場合は、そのまま採用(2026/20260517.md など)
targetFiles = specifiedFiles;
console.log(指定されたファイル(${targetFiles.length}個)を処理します...);
} else {
// 【パターンB】引数がない場合は、現在の「年」のフォルダを自動で対象にする
const currentYear = new Date().getFullYear().toString(); // "2026" を自動取得
const yearDir = path.join(INPUT_DIR, currentYear); // "./2026"
try {
const files = await fs.readdir(yearDir);
// フォルダ名付きのパス(2026/xxxxx.md)に変換してリスト化
targetFiles = files
.filter(file => {
const ext = path.extname(file).toLowerCase();
return ext === '.txt' || ext === '.md';
})
.map(file => path.join(currentYear, file));
console.log(${currentYear} フォルダ内のすべてのファイルを処理します...);
} catch (err) {
console.log(引数の指定がなく、かつ「${currentYear}」フォルダも見つかりませんでした。);
return;
}
}
if (targetFiles.length === 0) {
console.log('対象となるテキストファイルが見つかりませんでした。');
return;
}
let pageListContent = '';
let successCount = 0;
for (const file of targetFiles) {
const filePath = path.join(INPUT_DIR, file);
try {
const stats = await fs.stat(filePath);
const content = await fs.readFile(filePath, 'utf-8');
const title = path.basename(filePath, path.extname(filePath));
const createdStr = stats.birthtime.toISOString();
const updatedStr = stats.mtime.toISOString();
pageListContent += <Page title="${title}" updated="${updatedStr}" created="${createdStr}" type="page">\n;
pageListContent += ${title}\n;
pageListContent += ${content.trim()}\n;
pageListContent += </Page>\n\n\n;
successCount++;
} catch (err) {
console.error(【警告】ファイル「${file}」の読み込みに失敗しました(スキップします):, err.message);
}
}
if (successCount === 0) {
console.log('有効なファイルが1つも処理されませんでした。結合を中止します。');
return;
}
// 最終的な出力テキストを合成
let finalOutput = '';
finalOutput += This text contains combined resources for AI training and analysis.\n;
finalOutput += Total pages included: ${successCount}\n;
finalOutput += ${AI_GUIDE}\n\n;
finalOutput += <PageList>\n;
finalOutput += pageListContent;
finalOutput += </PageList>;
// タイムスタンプ付きのファイル名を決定して書き込み
const outputFileName = getTimestampedFileName();
await fs.writeFile(outputFileName, finalOutput, 'utf-8');
console.log(\n成功しました! ${successCount} 個のファイルを結合して作成しました: ${outputFileName});
} catch (error) {
console.error('致命的なエラーが発生しました:', error);
}
}
combineFiles();
今年のフォルダをすべて対象にするなら
$ node combine-for-ai.mjs
連結したいファイルを直接指定するなら
$ node combine-for-ai.mjs 2026/20260517.md 2026/20260518.md