93 lines
4.1 KiB
JavaScript
93 lines
4.1 KiB
JavaScript
import { execSync } from 'child_process'
|
|
import { readFileSync, writeFileSync } from 'fs'
|
|
import { randomUUID } from 'crypto'
|
|
|
|
const BASE = "/Users/nate.emmert/Documents/github/Siteforge/Verse by Verse with Nate Complete Series"
|
|
const CHATBOT_FILE = "/Users/nate.emmert/Documents/github/Siteforge/data/chatbot-content.json"
|
|
|
|
const FILES = [
|
|
{ file: `${BASE}/Done/Verse_by_Verse_with_Nate_Episode02.docx`, ep: 2 },
|
|
{ file: `${BASE}/Done/Verse_by_Verse_with_Nate_Episode03.docx`, ep: 3 },
|
|
{ file: `${BASE}/Done/Verse_by_Verse_with_Nate_Episode04_Updated.docx`, ep: 4 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode05.docx`, ep: 5 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode06_expanded.docx`, ep: 6 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode07.docx`, ep: 7 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode08.docx`, ep: 8 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode09.docx`, ep: 9 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode10.docx`, ep: 10 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode11.docx`, ep: 11 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode12.docx`, ep: 12 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode13.docx`, ep: 13 },
|
|
{ file: `${BASE}/Verse_by_Verse_with_Nate_Episode14.docx`, ep: 14 },
|
|
]
|
|
|
|
function extractText(filePath) {
|
|
const xml = execSync(`unzip -p "${filePath}" word/document.xml 2>/dev/null`, { encoding: 'utf8' })
|
|
return xml
|
|
.replace(/<[^>]+>/g, ' ')
|
|
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'")
|
|
.replace(/\s+/g, ' ')
|
|
.trim()
|
|
}
|
|
|
|
function parseEpisode(raw, epNum) {
|
|
// Extract episode subtitle and passage reference from header
|
|
const headerMatch = raw.match(/EPISODE\s+\d+\s*[—\-\u2013\u2014]+\s*(.+?)\s+(Titus\s+[\d:]+(?:\s*[\-\u2013\u2014]+\s*[\d:]+)?)\s*·/i)
|
|
const subtitle = headerMatch ? headerMatch[1].trim().replace(/\s+/g, ' ') : ''
|
|
const passageRef = headerMatch ? headerMatch[2].trim() : 'Titus'
|
|
const episodeTitle = `Episode ${epNum} — ${subtitle || 'Verse by Verse with Nate'}`
|
|
|
|
// Find where the actual teaching content starts
|
|
let contentStart = raw.indexOf('SEGMENT 1')
|
|
if (contentStart === -1) contentStart = raw.indexOf('WHO WAS PAUL')
|
|
if (contentStart === -1) contentStart = raw.indexOf('COLD OPEN')
|
|
if (contentStart === -1) contentStart = 400
|
|
|
|
const rawContent = raw.slice(contentStart, contentStart + 4000)
|
|
const content = rawContent
|
|
.replace(/\[[^\]]{0,100}\]/g, '') // remove [stage directions]
|
|
.replace(/[✝🎙️📖💬🧠💡🔑✅◀▶]/gu, '') // remove emoji
|
|
.replace(/SEGMENT\s+\d+\s*[—\-\u2013]+\s*/g, '\n\n') // turn SEGMENT headers into breaks
|
|
.replace(/\s{2,}/g, ' ')
|
|
.trim()
|
|
|
|
// Build keyword list
|
|
const verseRefs = [...new Set((raw.match(/Titus\s+\d+:\d+/g) || []))].slice(0, 5).map(k => k.toLowerCase())
|
|
const titleWords = subtitle.toLowerCase().replace(/[^a-z0-9\s]/g, ' ').split(/\s+/).filter(w => w.length > 3)
|
|
const keywords = [...new Set([
|
|
'titus', `episode ${epNum}`, passageRef.toLowerCase(),
|
|
...verseRefs, ...titleWords
|
|
])].slice(0, 20)
|
|
|
|
return {
|
|
id: randomUUID(),
|
|
type: 'episode',
|
|
title: `${episodeTitle} (${passageRef})`,
|
|
content: content.slice(0, 3900),
|
|
keywords,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString(),
|
|
}
|
|
}
|
|
|
|
// Load existing entries (keep the 8 hand-written ones)
|
|
const existing = JSON.parse(readFileSync(CHATBOT_FILE, 'utf8'))
|
|
// Remove any previously generated episode entries to avoid duplication
|
|
const baseEntries = existing.filter(e => e.type !== 'episode')
|
|
|
|
const newEntries = []
|
|
for (const { file, ep } of FILES) {
|
|
try {
|
|
const raw = extractText(file)
|
|
const entry = parseEpisode(raw, ep)
|
|
newEntries.push(entry)
|
|
console.log(`✓ Ep ${ep}: ${entry.title.slice(0, 80)}`)
|
|
} catch (err) {
|
|
console.error(`✗ Ep ${ep}: ${err.message}`)
|
|
}
|
|
}
|
|
|
|
const combined = [...baseEntries, ...newEntries]
|
|
writeFileSync(CHATBOT_FILE, JSON.stringify(combined, null, 2), 'utf8')
|
|
console.log(`\nDone. ${newEntries.length} episode entries added. Total: ${combined.length}`)
|