Files
mintel.me/apps/web/scripts/ai-estimate.ts
T
mmintel 905ce98bc4
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 54s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
chore: align deployment pipeline with klz-2026 standards
- Add branch deployment support

- Switch build platform to linux/amd64

- Extract checks to turbo pipeline

- Add pre/post-deploy scripts & cms-sync
2026-03-01 00:41:38 +01:00

211 lines
6.6 KiB
TypeScript

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();