import * as path from "node:path"; import * as fs from "node:fs/promises"; import { existsSync } from "node:fs"; import { config as dotenvConfig } from "dotenv"; import { ConceptPipeline } from "@mintel/concept-engine"; import { EstimationPipeline } from "@mintel/estimation-engine"; import { PdfEngine } from "@mintel/pdf/server"; import { fileURLToPath } from "node:url"; import { createRequire } from "node:module"; dotenvConfig({ path: path.resolve(process.cwd(), "../../.env") }); dotenvConfig({ path: path.resolve(process.cwd(), ".env") }); try { const require = createRequire(import.meta.url); const conceptPkg = require.resolve("@mintel/concept-engine"); const atMintelEnv = path.resolve(path.dirname(conceptPkg), "../../../.env"); if (existsSync(atMintelEnv)) { dotenvConfig({ path: atMintelEnv }); } } catch { /* @mintel/concept-engine not resolvable — skip */ } async function main() { const OPENROUTER_KEY = process.env.OPENROUTER_API_KEY || process.env.OPENROUTER_KEY; if (!OPENROUTER_KEY) { console.error("āŒ Error: OPENROUTER_API_KEY not found in environment."); process.exit(1); } const args = process.argv.slice(2); const briefingArg = args[0]; if (!briefingArg) { console.error( "āŒ Error: Provide a briefing file or text as the first argument.", ); process.exit(1); } let targetUrl = ""; let budget = ""; let comments = ""; const clearCache = args.includes("--clear-cache"); for (let i = 1; i < args.length; i++) { if (args[i] === "--url") targetUrl = args[++i]; if (args[i] === "--budget") budget = args[++i]; if (args[i] === "--comments") comments = args[++i]; } let briefing = briefingArg; if (briefing.startsWith("@")) { const rawPath = briefing.substring(1); const filePath = rawPath.startsWith("/") ? rawPath : path.resolve(process.cwd(), rawPath); if (existsSync(filePath)) { briefing = await fs.readFile(filePath, "utf8"); console.log(`šŸ“„ Loaded briefing from: ${filePath}`); } else { console.error(`āŒ Briefing file not found: ${filePath}`); process.exit(1); } } if (!targetUrl) { const urlMatch = briefing.match(/https?:\/\/[^\s]+/); if (urlMatch) targetUrl = urlMatch[0]; } const monorepoRoot = path.resolve(process.cwd(), "../../"); const crawlDir = path.join( path.resolve(monorepoRoot, "../at-mintel"), "data/crawls", ); const outputDir = path.join(monorepoRoot, "out"); const konzeptDir = path.join(outputDir, "konzept"); const schaetzungDir = path.join(outputDir, "schaetzung"); const agbDir = path.join(outputDir, "agb"); const infoDir = path.join(outputDir, "info"); const deckblattDir = path.join(outputDir, "deckblatt"); const abschlussDir = path.join(outputDir, "abschluss"); await fs.mkdir(outputDir, { recursive: true }); await fs.mkdir(konzeptDir, { recursive: true }); await fs.mkdir(schaetzungDir, { recursive: true }); await fs.mkdir(agbDir, { recursive: true }); await fs.mkdir(infoDir, { recursive: true }); await fs.mkdir(deckblattDir, { recursive: true }); await fs.mkdir(abschlussDir, { recursive: true }); const conceptPipeline = new ConceptPipeline({ openrouterKey: OPENROUTER_KEY, zyteApiKey: process.env.ZYTE_API_KEY, outputDir, crawlDir, }); const engine = new PdfEngine() as any; const headerIcon = path.join( monorepoRoot, "apps/web/src/assets/logo/Icon-Black-Transparent.png", ); const footerLogo = path.join( monorepoRoot, "apps/web/src/assets/logo/Logo-Black-Transparent.png", ); try { const conceptResult = await conceptPipeline.run({ briefing, url: targetUrl, comments, clearCache, }); const companyName = conceptResult.auditedFacts?.companyName || "unknown"; const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); console.log("\nšŸ“„ Generating Concept PDF..."); const conceptPdfPath = path.join( konzeptDir, `${companyName}_Konzept_${timestamp}.pdf`, ); await engine.generateConceptPdf(conceptResult, conceptPdfPath, { headerIcon, footerLogo, }); console.log(`āœ… Created Concept PDF at: ${conceptPdfPath}`); console.log("\n=================================================="); console.log("šŸ’° PART 2: ESTIMATION ENGINE"); console.log("=================================================="); const estimationPipeline = new EstimationPipeline({ openrouterKey: OPENROUTER_KEY, outputDir, crawlDir: "", }); const estimationResult = await estimationPipeline.run({ concept: conceptResult, budget, }); if (estimationResult.formState) { console.log("\nšŸ“„ Generating Estimation PDF..."); const estimationPdfPath = path.join( schaetzungDir, `${companyName}_Angebot_${timestamp}.pdf`, ); await engine.generateEstimatePdf( estimationResult.formState, estimationPdfPath, { headerIcon, footerLogo }, ); console.log(`āœ… Created Angebot PDF at: ${estimationPdfPath}`); console.log("\nšŸ“„ Generating AGBs PDF..."); const agbPdfPath = path.join( agbDir, `${companyName}_AGBs_${timestamp}.pdf`, ); await engine.generateAgbsPdf(agbPdfPath, { headerIcon, footerLogo }); console.log(`āœ… Created AGBs PDF at: ${agbPdfPath}`); console.log("\nšŸ“„ Generating Deckblatt PDF..."); const deckblattPdfPath = path.join( deckblattDir, `${companyName}_Deckblatt_${timestamp}.pdf`, ); await engine.generateFrontPagePdf( estimationResult.formState, deckblattPdfPath, { headerIcon }, ); console.log(`āœ… Created Deckblatt PDF at: ${deckblattPdfPath}`); console.log("\nšŸ“„ Generating Abschluss PDF..."); const abschlussPdfPath = path.join( abschlussDir, `${companyName}_Abschluss_${timestamp}.pdf`, ); await engine.generateClosingPdf(abschlussPdfPath, { headerIcon, footerLogo, }); console.log(`āœ… Created Abschluss PDF at: ${abschlussPdfPath}`); } else { console.log("\nāš ļø No formState generated, skipping Estimation PDF."); } // Generate Info PDF console.log("\nšŸ“„ Generating Arbeitsweise PDF..."); const infoPdfPath = path.join( infoDir, `${companyName}_Arbeitsweise_${timestamp}.pdf`, ); await engine.generateInfoPdf(infoPdfPath, { headerIcon, footerLogo }); console.log(`āœ… Created Arbeitsweise PDF at: ${infoPdfPath}`); } catch (e) { console.error(`\nāŒ Pipeline failed: ${(e as Error).message}`); process.exit(1); } } main();