feat: content engine
This commit is contained in:
48
packages/content-engine/examples/generate-post.ts
Normal file
48
packages/content-engine/examples/generate-post.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { ContentGenerator } from "../src/index";
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
// Load .env from mintel.me (since that's where the key is)
|
||||
dotenv.config({
|
||||
path: path.resolve(__dirname, "../../../../mintel.me/apps/web/.env"),
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENROUTER_KEY;
|
||||
if (!apiKey) {
|
||||
console.error("❌ OPENROUTER_API_KEY not found");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const generator = new ContentGenerator(apiKey);
|
||||
|
||||
const topic = "Why traditional CMSs are dead for developers";
|
||||
console.log(`🚀 Generating post for: "${topic}"`);
|
||||
|
||||
try {
|
||||
const post = await generator.generatePost({
|
||||
topic,
|
||||
includeResearch: true,
|
||||
includeDiagrams: true,
|
||||
includeMemes: true,
|
||||
});
|
||||
|
||||
console.log("\n\n✅ GENERATION COMPLETE");
|
||||
console.log("--------------------------------------------------");
|
||||
console.log(`Title: ${post.title}`);
|
||||
console.log(`Research Points: ${post.research.length}`);
|
||||
console.log(`Memes Generated: ${post.memes.length}`);
|
||||
console.log(`Diagrams Generated: ${post.diagrams.length}`);
|
||||
console.log("--------------------------------------------------");
|
||||
|
||||
// Save to file
|
||||
const outputPath = path.join(__dirname, "output.md");
|
||||
fs.writeFileSync(outputPath, post.content);
|
||||
console.log(`📄 Saved output to: ${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error("❌ Generation failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
58
packages/content-engine/examples/optimize-post.ts
Normal file
58
packages/content-engine/examples/optimize-post.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { ContentGenerator } from "../src/index";
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// Fix __dirname for ESM
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Load .env from mintel.me (since that's where the key is)
|
||||
dotenv.config({
|
||||
path: path.resolve(__dirname, "../../../../mintel.me/apps/web/.env"),
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENROUTER_KEY;
|
||||
if (!apiKey) {
|
||||
console.error("❌ OPENROUTER_API_KEY not found");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const generator = new ContentGenerator(apiKey);
|
||||
|
||||
const draftContent = `# The Case for Static Sites
|
||||
|
||||
Static sites are faster and more secure. They don't have a database to hack.
|
||||
They are also cheaper to host. You can use a CDN to serve them globally.
|
||||
Dynamic sites are complex and prone to errors.`;
|
||||
|
||||
console.log("📄 Original Content:");
|
||||
console.log(draftContent);
|
||||
console.log("\n🚀 Optimizing content...\n");
|
||||
|
||||
try {
|
||||
const post = await generator.optimizePost(draftContent, {
|
||||
enhanceFacts: true,
|
||||
addDiagrams: true,
|
||||
addMemes: true,
|
||||
});
|
||||
|
||||
console.log("\n\n✅ OPTIMIZATION COMPLETE");
|
||||
console.log("--------------------------------------------------");
|
||||
console.log(`Research Points Added: ${post.research.length}`);
|
||||
console.log(`Memes Generated: ${post.memes.length}`);
|
||||
console.log(`Diagrams Generated: ${post.diagrams.length}`);
|
||||
console.log("--------------------------------------------------");
|
||||
|
||||
// Save to file
|
||||
const outputPath = path.join(__dirname, "optimized.md");
|
||||
fs.writeFileSync(outputPath, post.content);
|
||||
console.log(`📄 Saved output to: ${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error("❌ Optimization failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
132
packages/content-engine/examples/optimize-vendor-lockin.ts
Normal file
132
packages/content-engine/examples/optimize-vendor-lockin.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { ContentGenerator, ComponentDefinition } from "../src/index";
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// Fix __dirname for ESM
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Load .env from mintel.me
|
||||
dotenv.config({
|
||||
path: path.resolve(__dirname, "../../../../mintel.me/apps/web/.env"),
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENROUTER_KEY;
|
||||
if (!apiKey) {
|
||||
console.error("❌ OPENROUTER_API_KEY not found");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const generator = new ContentGenerator(apiKey);
|
||||
|
||||
const contentToOptimize = `
|
||||
"Wir können nicht wechseln, das wäre zu teuer."
|
||||
In meiner Arbeit als Digital Architect ist das der Anfang vom Ende jeder technologischen Innovation.
|
||||
Vendor Lock-In ist die digitale Version einer Geiselnahme.
|
||||
Ich zeige Ihnen, wie wir Systeme bauen, die Ihnen jederzeit die volle Freiheit lassen – technologisch und wirtschaftlich.
|
||||
|
||||
Die unsichtbaren Ketten proprietärer Systeme
|
||||
Viele Unternehmen lassen sich von der Bequemlichkeit großer SaaS-Plattformen oder Baukästen blenden.
|
||||
Man bekommt ein schnelles Feature, gibt aber dafür die Kontrolle über seine Daten und seine Codebasis ab.
|
||||
Nach zwei Jahren sind Sie so tief im Ökosystem eines Anbieters verstrickt, dass ein Auszug unmöglich scheint.
|
||||
Der Anbieter weiß das – und diktiert fortan die Preise und das Tempo Ihrer Entwicklung.
|
||||
Ich nenne das technologische Erpressbarkeit.
|
||||
Wahre Unabhängigkeit beginnt bei der strategischen Wahl der Architektur.
|
||||
|
||||
Technologische Souveränität als Asset
|
||||
Software sollte für Sie arbeiten, nicht umgekehrt.
|
||||
Indem wir auf offene Standards und portable Architekturen setzen, verwandeln wir Code in ein echtes Firmen-Asset.
|
||||
Sie können den Cloud-Anbieter wechseln, die Agentur tauschen oder das Team skalieren – ohne jemals bei Null anfangen zu müssen.
|
||||
Das ist das Privileg der technologischen Elite.
|
||||
Portabilität ist kein technisches Gimmick, sondern eine unternehmerische Notwendigkeit.
|
||||
|
||||
Meine Architektur der Ungebundenheit
|
||||
Ich baue keine "Käfige" aus fertigen Plugins.
|
||||
Mein Framework basiert auf Modularität und Klarheit.
|
||||
|
||||
Standard-basiertes Engineering: Wir nutzen Technologien, die weltweit verstanden werden. Keine geheimen "Spezial-Module" eines einzelnen Anbieters.
|
||||
Daten-Portabilität: Ihre Daten gehören Ihnen. Zu jeder Zeit. Wir bauen Schnittstellen, die den Export so einfach machen wie den Import.
|
||||
Cloud-agnostisches Hosting: Wir nutzen Container-Technologie. Ob AWS, Azure oder lokale Anbieter – Ihr Code läuft überall gleich perfekt.
|
||||
|
||||
Der strategische Hebel für langfristige Rendite
|
||||
Systeme ohne Lock-In altern besser.
|
||||
Sie lassen sich schrittweise modernisieren, statt alle fünf Jahre komplett neu gebaut werden zu müssen.
|
||||
Das spart Millionen an Opportunitätskosten und Fehl-Investitionen.
|
||||
Seien Sie der Herr über Ihr digitales Schicksal.
|
||||
Investieren Sie in intelligente Unabhängigkeit.
|
||||
|
||||
Für wen ich 'Freiheits-Systeme' erstelle
|
||||
Ich arbeite für Gründer, die ihr Unternehmen langfristig wertvoll aufstellen wollen.
|
||||
Ist digitale Exzellenz Teil Ihrer Exit-Strategie oder Ihres Erbes? Dann brauchen Sie meine Architektur.
|
||||
Ich baue keine Provisorien, sondern nachhaltige Werte.
|
||||
|
||||
Fazit: Freiheit ist eine Wahl
|
||||
Technologie sollte Ihnen Flügel verleihen, keine Fesseln anlegen.
|
||||
Lassen Sie uns gemeinsam ein System schaffen, das so flexibel ist wie Ihr Business.
|
||||
Werden Sie unersetzbar durch Qualität, nicht durch Abhängigkeit. Ihr Erfolg verdient absolute Freiheit.
|
||||
`;
|
||||
|
||||
// Define components available in mintel.me
|
||||
const availableComponents: ComponentDefinition[] = [
|
||||
{
|
||||
name: "LeadParagraph",
|
||||
description: "Large, introductory text for the beginning of the article.",
|
||||
usageExample: "<LeadParagraph>First meaningful sentence.</LeadParagraph>",
|
||||
},
|
||||
{
|
||||
name: "H2",
|
||||
description: "Section heading.",
|
||||
usageExample: "<H2>Section Title</H2>",
|
||||
},
|
||||
{
|
||||
name: "H3",
|
||||
description: "Subsection heading.",
|
||||
usageExample: "<H3>Subtitle</H3>",
|
||||
},
|
||||
{
|
||||
name: "Paragraph",
|
||||
description: "Standard body text paragraph.",
|
||||
usageExample: "<Paragraph>Some text...</Paragraph>",
|
||||
},
|
||||
{
|
||||
name: "ArticleBlockquote",
|
||||
description: "A prominent quote block for key insights.",
|
||||
usageExample: "<ArticleBlockquote>Important quote</ArticleBlockquote>",
|
||||
},
|
||||
{
|
||||
name: "Marker",
|
||||
description: "Yellow highlighter effect for very important phrases.",
|
||||
usageExample: "<Marker>Highlighted Text</Marker>",
|
||||
},
|
||||
{
|
||||
name: "ComparisonRow",
|
||||
description: "A component comparing a negative vs positive scenario.",
|
||||
usageExample:
|
||||
'<ComparisonRow description="Cost Comparison" negativeLabel="Lock-In" negativeText="High costs" positiveLabel="Open" positiveText="Control" />',
|
||||
},
|
||||
];
|
||||
|
||||
console.log('🚀 Optimizing "Vendor Lock-In" post...');
|
||||
|
||||
try {
|
||||
const post = await generator.optimizePost(contentToOptimize, {
|
||||
enhanceFacts: true,
|
||||
addDiagrams: true,
|
||||
addMemes: true,
|
||||
availableComponents,
|
||||
});
|
||||
|
||||
console.log("\n\n✅ OPTIMIZATION COMPLETE");
|
||||
// Save to a file in the package dir
|
||||
const outputPath = path.join(__dirname, "VendorLockIn_OPTIMIZED.md");
|
||||
fs.writeFileSync(outputPath, post.content);
|
||||
console.log(`📄 Saved output to: ${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error("❌ Optimization failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
71
packages/content-engine/examples/optimize-with-components.ts
Normal file
71
packages/content-engine/examples/optimize-with-components.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { ContentGenerator, ComponentDefinition } from "../src/index";
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// Fix __dirname for ESM
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// Load .env from mintel.me (since that's where the key is)
|
||||
dotenv.config({
|
||||
path: path.resolve(__dirname, "../../../../mintel.me/apps/web/.env"),
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENROUTER_KEY;
|
||||
if (!apiKey) {
|
||||
console.error("❌ OPENROUTER_API_KEY not found");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const generator = new ContentGenerator(apiKey);
|
||||
|
||||
const draftContent = `# Improving User Retention
|
||||
|
||||
User retention is key. You need to keep users engaged.
|
||||
Offer them value and they will stay.
|
||||
If they have questions, they should contact support.`;
|
||||
|
||||
const availableComponents: ComponentDefinition[] = [
|
||||
{
|
||||
name: "InfoCard",
|
||||
description: "A colored box to highlight important tips or warnings.",
|
||||
usageExample:
|
||||
'<InfoCard variant="warning" title="Pro Tip">Always measure retention.</InfoCard>',
|
||||
},
|
||||
{
|
||||
name: "CallToAction",
|
||||
description: "A prominent button for conversion.",
|
||||
usageExample: '<CallToAction href="/contact">Get in Touch</CallToAction>',
|
||||
},
|
||||
];
|
||||
|
||||
console.log("📄 Original Content:");
|
||||
console.log(draftContent);
|
||||
console.log("\n🚀 Optimizing content with components...\n");
|
||||
|
||||
try {
|
||||
const post = await generator.optimizePost(draftContent, {
|
||||
enhanceFacts: true,
|
||||
addDiagrams: false, // Skip diagrams for this test to focus on components
|
||||
addMemes: false,
|
||||
availableComponents,
|
||||
});
|
||||
|
||||
console.log("\n\n✅ OPTIMIZATION COMPLETE");
|
||||
console.log("--------------------------------------------------");
|
||||
console.log(post.content);
|
||||
console.log("--------------------------------------------------");
|
||||
|
||||
// Save to file
|
||||
const outputPath = path.join(__dirname, "optimized-components.md");
|
||||
fs.writeFileSync(outputPath, post.content);
|
||||
console.log(`📄 Saved output to: ${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error("❌ Optimization failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user