From 9f0fc6805ca649ce367c0cecaacb7f60173e01b4 Mon Sep 17 00:00:00 2001 From: Floke Date: Mon, 22 Dec 2025 19:59:17 +0000 Subject: [PATCH] Dateien nach "b2b-marketing-assistant" hochladen --- b2b-marketing-assistant/.gitignore | 24 ++ b2b-marketing-assistant/App.tsx | 388 +++++++++++++++++++++++++++ b2b-marketing-assistant/constants.ts | 365 +++++++++++++++++++++++++ b2b-marketing-assistant/index.html | 59 ++++ b2b-marketing-assistant/index.tsx | 16 ++ 5 files changed, 852 insertions(+) create mode 100644 b2b-marketing-assistant/.gitignore create mode 100644 b2b-marketing-assistant/App.tsx create mode 100644 b2b-marketing-assistant/constants.ts create mode 100644 b2b-marketing-assistant/index.html create mode 100644 b2b-marketing-assistant/index.tsx diff --git a/b2b-marketing-assistant/.gitignore b/b2b-marketing-assistant/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/b2b-marketing-assistant/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/b2b-marketing-assistant/App.tsx b/b2b-marketing-assistant/App.tsx new file mode 100644 index 00000000..797322ec --- /dev/null +++ b/b2b-marketing-assistant/App.tsx @@ -0,0 +1,388 @@ + +import React, { useState, useCallback, useRef } from 'react'; +import { GoogleGenAI, Chat } from "@google/genai"; +import { InputForm } from './components/InputForm'; +import { StepDisplay } from './components/StepDisplay'; +import { LoadingSpinner, BotIcon, SparklesIcon, MarkdownIcon, PrintIcon } from './components/Icons'; +import { ExportMenu } from './components/ExportMenu'; +import { PROMPTS, translations } from './constants'; +import type { AnalysisStep, AnalysisData, InputData } from './types'; +import { parseGeminiStepResponse } from './services/parser'; +import { generateMarkdown, downloadFile, tableToMarkdown } from './services/export'; + +const App: React.FC = () => { + const [inputData, setInputData] = useState({ + companyUrl: '', + language: 'de', + regions: '', + focus: '', + channels: ['LinkedIn', 'Kaltmail', 'Landingpage'] + }); + const [analysisData, setAnalysisData] = useState>({}); + const [isLoading, setIsLoading] = useState(false); + const [isEnriching, setIsEnriching] = useState(false); + const [error, setError] = useState(null); + const [generationStep, setGenerationStep] = useState(0); // 0: idle, 1-6: step X is complete + const chatRef = useRef(null); + + const t = translations[inputData.language]; + const STEP_TITLES = t.stepTitles; + const STEP_KEYS: (keyof AnalysisData)[] = ['offer', 'targetGroups', 'personas', 'painPoints', 'gains', 'messages']; + + + const handleStartGeneration = useCallback(async () => { + if (!inputData.companyUrl) { + setError('Bitte geben Sie eine Unternehmens-URL ein.'); + return; + } + setIsLoading(true); + setError(null); + setAnalysisData({}); + setGenerationStep(0); + + try { + const ai = new GoogleGenAI({ apiKey: process.env.API_KEY }); + const currentPrompts = PROMPTS[inputData.language]; + + const newChat = ai.chats.create({ + model: 'gemini-2.5-pro', + config: { + systemInstruction: currentPrompts.SYSTEM_PROMPT.replace('{{language}}', inputData.language) + } + }); + chatRef.current = newChat; + + let prompt = currentPrompts.STEP_PROMPTS[0]; + prompt = prompt.replace('{{company_url}}', inputData.companyUrl); + prompt = prompt.replace('{{language}}', inputData.language); + prompt = prompt.replace('{{regions}}', inputData.regions); + prompt = prompt.replace('{{focus}}', inputData.focus); + + const response = await newChat.sendMessage({ message: prompt }); + + const parsedData = parseGeminiStepResponse(response.text); + setAnalysisData(parsedData); + setGenerationStep(1); + + } catch (e) { + console.error(e); + setError(e instanceof Error ? `Ein Fehler ist aufgetreten: ${e.message}` : 'Ein unbekannter Fehler ist aufgetreten.'); + } finally { + setIsLoading(false); + } + }, [inputData]); + + const handleGenerateNextStep = useCallback(async () => { + if (!chatRef.current || generationStep >= 6) return; + + setIsLoading(true); + setError(null); + const nextStepIndex = generationStep; + + try { + let context = ''; + for (let i = 0; i < generationStep; i++) { + const stepKey = STEP_KEYS[i]; + const stepObject = analysisData[stepKey]; + if (stepObject) { + context += `\n\n## ${STEP_TITLES[stepKey]}\n\n`; + const summary = stepObject.summary && stepObject.summary.length > 0 ? `**${t.summaryTitle}**\n${stepObject.summary.map(s => `* ${s}`).join('\n')}\n\n` : ''; + const table = tableToMarkdown(stepObject); + context += `${summary}${table}`; + } + } + + const currentPrompts = PROMPTS[inputData.language]; + let prompt = currentPrompts.STEP_PROMPTS[nextStepIndex]; + prompt = prompt.replace('{{previous_steps_data}}', context); + + if (nextStepIndex === 5) { // Step 6 is index 5 + prompt = prompt.replace('{{channels}}', inputData.channels.join(', ')); + } + + const response = await chatRef.current.sendMessage({ message: prompt }); + const parsedData = parseGeminiStepResponse(response.text); + + setAnalysisData(prev => ({ ...prev, ...parsedData })); + setGenerationStep(prev => prev + 1); + + } catch (e) { + console.error(e); + setError(e instanceof Error ? `Ein Fehler ist aufgetreten: ${e.message}` : 'Ein unbekannter Fehler ist aufgetreten.'); + setGenerationStep(prev => prev); // Stay on the current step if error + } finally { + setIsLoading(false); + } + }, [analysisData, generationStep, inputData.channels, inputData.language, STEP_KEYS, STEP_TITLES, t.summaryTitle]); + + const handleDataChange = (step: K, newData: AnalysisData[K]) => { + if (analysisData[step]) { + setAnalysisData(prev => prev ? { ...prev, [step]: newData } : { [step]: newData }); + } + }; + + const getEnrichPrompt = (lang: 'de' | 'en', url: string, productName: string) => { + if (lang === 'en') { + return `# Task +Fill in the information for the following product/solution based on the website ${url}. Respond ONLY with the content for the remaining 4 columns, separated by '|||'. + +# Product/Solution +${productName} + +# Column Order +1. Description (1–2 sentences) +2. Core Features +3. Differentiation +4. Primary Source (URL) + +# Important +Respond *only* with the text for the 4 columns, separated by '|||'. Do not output any headers or explanations.`; + } + // German (original) + return `# Aufgabe +Fülle die Informationen für das folgende Produkt/Lösung basierend auf der Webseite ${url} aus. Antworte NUR mit dem Inhalt für die restlichen 4 Spalten, getrennt durch '|||'. + +# Produkt/Lösung +${productName} + +# Spalten-Reihenfolge +1. Beschreibung (1–2 Sätze) +2. Kernfunktionen +3. Differenzierung +4. Primäre Quelle (URL) + +# Wichtig +Antworte *nur* mit dem Text für die 4 Spalten, getrennt durch '|||'. Gib keine Überschriften oder Erklärungen aus.`; + }; + + + const handleEnrichOfferRow = useCallback(async (productName: string, productUrl?: string) => { + if (!analysisData.offer) return; + + setIsEnriching(true); + setError(null); + + const loadingText = t.loadingButton.replace('...', ''); + const placeholderRow = [productName, loadingText, loadingText, loadingText, loadingText]; + + setAnalysisData(prev => { + if (!prev.offer) return prev; + const currentOffer = prev.offer; + const updatedRows = [...currentOffer.rows, placeholderRow]; + return { + ...prev, + offer: { + ...currentOffer, + rows: updatedRows, + } + }; + }); + + try { + const ai = new GoogleGenAI({ apiKey: process.env.API_KEY }); + // Use the specific product URL if provided, otherwise fallback to the main company URL + const targetUrl = productUrl && productUrl.trim() !== '' ? productUrl.trim() : inputData.companyUrl; + + const enrichPrompt = getEnrichPrompt(inputData.language, targetUrl, productName); + + const response = await ai.models.generateContent({ + model: 'gemini-2.5-flash', + contents: enrichPrompt + }); + const text = response.text || ''; + const enrichedParts = text.split('|||').map(s => s.trim()); + + const finalEnrichedData = Array(4).fill(''); + for (let i = 0; i < 4; i++) { + if (enrichedParts[i]) { + finalEnrichedData[i] = enrichedParts[i]; + } + } + + const newRow = [productName, ...finalEnrichedData]; + + setAnalysisData(prev => { + const offerData = prev.offer; + if (!offerData) return prev; + const finalRows = offerData.rows.map(row => + row[0] === productName && row[1] === loadingText ? newRow : row + ); + return { ...prev, offer: { ...offerData, rows: finalRows } }; + }); + + } catch (e) { + console.error(e); + // On error, clear loading text so user can edit manually + setAnalysisData(prev => { + const offerData = prev.offer; + if (!offerData) return prev; + const emptyRow = [productName, '', '', '', '']; + const finalRows = offerData.rows.map(row => + row[0] === productName && row[1] === loadingText ? emptyRow : row + ); + return { ...prev, offer: { ...offerData, rows: finalRows } }; + }); + } finally { + setIsEnriching(false); + } + }, [analysisData.offer, inputData.companyUrl, inputData.language, t.loadingButton]); + + const handleDownloadMarkdown = () => { + if (!analysisData) return; + const markdownContent = generateMarkdown(analysisData as AnalysisData, STEP_TITLES, t.summaryTitle); + downloadFile(markdownContent, 'b2b-marketing-analysis.md', 'text/markdown;charset=utf-8'); + }; + + const handlePrint = () => { + window.print(); + }; + + const renderStep = (stepKey: keyof AnalysisData, title: string) => { + const step = analysisData[stepKey] as AnalysisStep | undefined; + if (!step) return null; + + const canDelete = ['offer', 'targetGroups', 'personas'].includes(stepKey); + + return ( + handleDataChange(stepKey, { ...step, rows: newRows })} + canAddRows={stepKey === 'offer'} + onEnrichRow={stepKey === 'offer' ? handleEnrichOfferRow : undefined} + isEnriching={isEnriching} + canDeleteRows={canDelete} + t={t} + /> + ); + }; + + const renderContinueButton = (stepNumber: number) => { + if (isLoading || generationStep !== stepNumber - 1) return null; + return ( +
+ +
+ ); + } + + return ( +
+
+
+

+ {t.appTitle} +

+

+ {t.appSubtitle} +

+
+ +
+ +
+ + {error && ( +
+ {t.errorTitle} + {error} +
+ )} + +
+ {isLoading && ( +
+ +

+ {t.generatingStep.replace('{{stepTitle}}', STEP_TITLES[STEP_KEYS[generationStep]])} +

+
+ )} + + {!isLoading && generationStep === 0 && !error && ( +
+ +

{t.readyTitle}

+

{t.readyText}

+
+ )} + + {generationStep > 0 && ( + <> + {generationStep >= 6 && ( +
+ +
+ )} + + {renderStep('offer', STEP_TITLES.offer)} + {renderContinueButton(2)} + {generationStep >= 2 && renderStep('targetGroups', STEP_TITLES.targetGroups)} + {renderContinueButton(3)} + {generationStep >= 3 && renderStep('personas', STEP_TITLES.personas)} + {renderContinueButton(4)} + {generationStep >= 4 && renderStep('painPoints', STEP_TITLES.painPoints)} + {renderContinueButton(5)} + {generationStep >= 5 && renderStep('gains', STEP_TITLES.gains)} + {renderContinueButton(6)} + {generationStep >= 6 && renderStep('messages', STEP_TITLES.messages)} + + + {generationStep === 6 && !isLoading && ( +
+
+ +
+

+ {t.analysisCompleteTitle} +

+

+ {t.analysisCompleteText.replace('{{otherLanguage}}', t.otherLanguage)} +

+ +
+ + +
+
+ )} + + )} +
+
+
+ ); +}; + +export default App; diff --git a/b2b-marketing-assistant/constants.ts b/b2b-marketing-assistant/constants.ts new file mode 100644 index 00000000..bbc480f6 --- /dev/null +++ b/b2b-marketing-assistant/constants.ts @@ -0,0 +1,365 @@ + +export const LANGUAGE_OPTIONS = [ + { value: 'de', label: 'Deutsch' }, + { value: 'en', label: 'English' }, +]; + +export const CHANNEL_OPTIONS = ['LinkedIn', 'Kaltmail', 'Landingpage']; + +export const translations = { + de: { + appTitle: 'B2B Marketing Assistant', + appSubtitle: 'Analysiere eine URL, um gezielte Marketingstrategien zu erstellen.', + companyUrlLabel: 'Unternehmens-URL', + companyUrlPlaceholder: 'https://beispiel-unternehmen.de', + targetLanguageLabel: 'Zielsprache', + productFocusLabel: 'Produkt-/Lösungsfokus', + productFocusOptional: '(optional)', + productFocusPlaceholder: 'z.B. Cloud-Services', + regionsLabel: 'Region(en) / Märkte', + regionsOptional: '(optional)', + regionsPlaceholder: 'z.B. DACH, Nordamerika', + channelsLabel: 'Gewünschte Kanäle', + channelsOptional: '(optional)', + generateButton: 'Analyse generieren', + analyzingButton: 'Analysiere...', + errorTitle: 'Fehler:', + generatingStep: 'Generiere {{stepTitle}}... Dies kann einen Moment dauern.', + readyTitle: 'Bereit zur Analyse', + readyText: 'Geben Sie oben eine URL ein, um mit der Generierung Ihrer B2B-Marketingstrategie zu beginnen.', + continueButton: 'Ergebnisse für Schritt {{step}} korrekt. Weiter zu Schritt {{nextStep}}.', + analysisCompleteTitle: 'Analyse abgeschlossen. Nächste Schritte:', + analysisCompleteText: 'Möchtest du, dass ich eine Rolle/Branche priorisiere, die Botschaften nach Kanal verfeinere oder Beispiele in {{otherLanguage}} ausformuliere? Nenne optional Metriken (z.B. Zeit-zu-Einsatz, First-Contact-Resolution, Fehlerrate), die besonders wichtig sind.', + otherLanguage: 'Englisch', + exportButton: 'Exportieren', + exportAsMarkdown: 'Als Markdown (.md)', + exportAsPdf: 'Drucken / Als PDF', + summaryTitle: 'Kurzresümee:', + filterPlaceholder: 'Tabelle filtern...', + copyTableButton: 'Tabelle kopieren', + copySuccess: 'Gefilterte Tabelle kopiert!', + copyFailure: 'Kopieren fehlgeschlagen.', + addRowButton: '+ Zeile hinzufügen', + loadingButton: 'Lade...', + deleteRowAria: 'Zeile löschen', + copyToClipboardAria: 'In die Zwischenablage kopieren', + newProductPrompt: 'Name des Produkts/der Lösung', + productUrlPlaceholder: 'URL für dieses Produkt (optional)', + noFilterResults: 'Keine Ergebnisse für "{{query}}" gefunden.', + stepTitles: { + offer: 'Schritt 1: Angebot (WAS)', + targetGroups: 'Schritt 2: Zielgruppen (WER - Unternehmen)', + personas: 'Schritt 3: Zielpersonen/Rollen (WER - Personen)', + painPoints: 'Schritt 4: Painpoints je Rolle (WARUM)', + gains: 'Schritt 5: Gains & Nutzen je Rolle (WARUM wechseln)', + messages: 'Schritt 6: Marketingbotschaften je Segment & Rolle (WIE sprechen)', + } + }, + en: { + appTitle: 'B2B Marketing Assistant', + appSubtitle: 'Analyze a URL to create targeted B2B marketing strategies.', + companyUrlLabel: 'Company URL', + companyUrlPlaceholder: 'https://example-company.com', + targetLanguageLabel: 'Target Language', + productFocusLabel: 'Product/Solution Focus', + productFocusOptional: '(optional)', + productFocusPlaceholder: 'e.g., Cloud Services', + regionsLabel: 'Region(s) / Markets', + regionsOptional: '(optional)', + regionsPlaceholder: 'e.g., EMEA, North America', + channelsLabel: 'Desired Channels', + channelsOptional: '(optional)', + generateButton: 'Generate Analysis', + analyzingButton: 'Analyzing...', + errorTitle: 'Error:', + generatingStep: 'Generating {{stepTitle}}... This may take a moment.', + readyTitle: 'Ready to Analyze', + readyText: 'Enter a URL above to start generating your B2B marketing strategy.', + continueButton: 'Results for step {{step}} are correct. Continue to step {{nextStep}}.', + analysisCompleteTitle: 'Analysis complete. Next steps:', + analysisCompleteText: 'Would you like me to prioritize a role/industry, refine messages by channel, or write examples in {{otherLanguage}}? Optionally, mention metrics (e.g., time-to-value, first-contact resolution, error rate) that are particularly important.', + otherLanguage: 'German', + exportButton: 'Export', + exportAsMarkdown: 'As Markdown (.md)', + exportAsPdf: 'Print / As PDF', + summaryTitle: 'Summary:', + filterPlaceholder: 'Filter table...', + copyTableButton: 'Copy Table', + copySuccess: 'Filtered table copied!', + copyFailure: 'Copy failed.', + addRowButton: '+ Add Row', + loadingButton: 'Loading...', + deleteRowAria: 'Delete row', + copyToClipboardAria: 'Copy to clipboard', + newProductPrompt: 'Product/Solution Name', + productUrlPlaceholder: 'URL for this product (optional)', + noFilterResults: 'No results found for "{{query}}".', + stepTitles: { + offer: 'Step 1: Offer (WHAT)', + targetGroups: 'Step 2: Target Groups (WHO - Companies)', + personas: 'Step 3: Personas/Roles (WHO - People)', + painPoints: 'Step 4: Pain Points per Role (WHY)', + gains: 'Step 5: Gains & Benefits per Role (WHY switch)', + messages: 'Step 6: Marketing Messages per Segment & Role (HOW to speak)', + } + } +}; + + +const SYSTEM_PROMPT_DE = ` +# Systemrolle + +Du bist ein **B2B-Marketing-Researcher & Copywriter**. Du analysierst eine Unternehmens-URL, identifizierst Angebot, Zielgruppen, konkrete Zielrollen, deren Painpoints sowie Gains und formulierst darauf basierend eine wertschätzende, fachkundige Marketingbotschaft. **Antworte nur mit Ergebnissen, keine Gedankengänge.** Belege jede Aussage mit einer konkreten Seiten-URL der analysierten Domain. Kennzeichne Unsicherheiten explizit. Deine Antwort muss immer in der Zielsprache {{language}} sein. + +# Arbeitsprinzipien + +1. **Quellenpriorisierung:** Produktseite → Lösungsseite → Branchen/Industrien/Referenzen → Unternehmens-/Über-uns-Seite → Blog/News (nur zur Verifikation). +2. **Faktenpolicy:** Nur aus der Domain der bereitgestellten URL ableiten; bei Vermutungen: als *Hypothese* kennzeichnen. +3. **B2B-Ton:** sachkundig, respektvoll, nicht marktschreierisch. +4. **Klarheit & Struktur:** Jede Stufe als Markdown-Tabelle + optionales Kurzresümee dokumentieren. +5. **Mindestens 4 spezifische Rollen** je Zielgruppe (nicht generisch). +6. **Kompakt & nützlich:** Präzise Formulierungen; keine Floskeln. +`; + +const STEP_PROMPTS_DE = [ + // Step 1: Offer + `# Aufgabe +Führe **Schritt 1 – Angebot verstehen (WAS)** für das folgende Unternehmen durch. + +# Eingaben +* **Unternehmens-URL:** \`{{company_url}}\` +* **Zielsprache der Ausgabe:** \`{{language}}\` +* **Region(en) / Märkte (optional):** \`{{regions}}\` +* **Produkt-/Lösungsfokus (optional):** \`{{focus}}\` + +# Anweisungen für Schritt 1 +* Extrahiere Produkt(e)/Leistung(en), Kernfunktionen, Differenzierung, relevante Werteversprechen. +* Erstelle ein kurzes Resümee (max. 4 Bulletpoints) der wichtigsten Erkenntnisse. +* **Output:** Tabelle mit Spalten: *Produkt/Lösung | Beschreibung (1–2 Sätze) | Kernfunktionen | Differenzierung | Primäre Quelle (URL)*. +* **Format-Anforderung:** Antworte NUR mit den Ergebnissen für diesen einen Schritt. Deine Antwort muss mit der Überschrift "## Schritt 1: Angebot (WAS)" beginnen und das Kurzresümee sowie die Markdown-Tabelle enthalten. Gib keine weiteren Erklärungen ab.`, + + // Step 2: Target Groups + `# Aufgabe +Führe nun **Schritt 2 – Zielgruppen (WER – Unternehmen)** durch. + +# Kontext: Validierte Ergebnisse aus vorherigen Schritten +{{previous_steps_data}} + +# Anweisungen für Schritt 2 +* Identifiziere B2B-Zielsegmente (Branchen/Unternehmensarten/Größen/Regionen) basierend auf dem gegebenen Angebot. +* **Output:** Tabelle: *Zielbranche/Segment | Typische Unternehmensmerkmale | Region(en) | Relevanzbeleg (URL)*. +* **Format-Anforderung:** Antworte NUR mit den Ergebnissen für diesen einen Schritt. Deine Antwort muss mit der Überschrift "## Schritt 2: Zielgruppen (Unternehmen)" beginnen und die Markdown-Tabelle enthalten.`, + + // Step 3: Personas + `# Aufgabe +Führe nun **Schritt 3 – Zielpersonen/Rollen (WER – Personen)** durch. + +# Kontext: Validierte Ergebnisse aus vorherigen Schritten +{{previous_steps_data}} + +# Anweisungen für Schritt 3 +* Für jede Zielbranche: mind. 4 **spezifische** Rollen mit Verantwortungsbereich und Kaufbeteiligung (E, I, D, U nach RACI-Logik). Erfinde **keine** Personen; leite Rollen logisch aus Problem-/Prozessbezug ab. +* **Output:** Tabelle: *Rolle (präzise) | Verantwortungsbereich | Warum relevant für Produkt | Kaufbeteiligung (E/I/D/U) | Quelle/Indiz (URL oder Referenz)*. +* **Format-Anforderung:** Antworte NUR mit den Ergebnissen für diesen einen Schritt. Deine Antwort muss mit der Überschrift "## Schritt 3: Zielpersonen (Rollen)" beginnen.`, + + // Step 4: Pain Points + `# Aufgabe +Führe nun **Schritt 4 – Painpoints je Rolle (WARUM)** durch. + +# Kontext: Validierte Ergebnisse aus vorherigen Schritten +{{previous_steps_data}} + +# Anweisungen für Schritt 4 +* Formuliere pro Rolle 3–5 konkrete Painpoints (Beobachtungen, keine Features). +* Tagge jeden Painpoint mit einer Kategorie: **Kosten | Zeit | Risiko | Compliance | Qualität | Mitarbeiterbindung.** +* Füge eine **Impact-Schätzung (€, h, %)** als Hypothese hinzu. +* **Output:** Tabelle: *Rolle | Painpoint (konkret, messbar/operativ) | Kategorie | Auswirkung (Kosten, Risiko, Zeit) | Impact-Schätzung (€, h, %) | Dringlichkeit (hoch/mittel/niedrig) | Quelle/Indiz (URL)*. +* **Format-Anforderung:** Antworte NUR mit den Ergebnissen für diesen einen Schritt. Deine Antwort muss mit der Überschrift "## Schritt 4: Painpoints je Rolle" beginnen.`, + + // Step 5: Gains + `# Aufgabe +Führe nun **Schritt 5 – Gains & Nutzen je Rolle (WARUM wechseln)** durch. + +# Kontext: Validierte Ergebnisse aus vorherigen Schritten +{{previous_steps_data}} + +# Anweisungen für Schritt 5 +* Basierend auf den identifizierten Painpoints, formuliere pro Rolle 2-3 konkrete Gains (Vorteile/Nutzen). +* Quantifiziere den Nutzen als Hypothese (z.B. Einsparung in €, Zeitgewinn in h, Effizienzsteigerung in %). +* **Output:** Tabelle: *Rolle | Gain (konkreter Nutzen) | Quantifizierung (Hypothese in €, h, %) | Quelle/Indiz (URL)*. +* **Format-Anforderung:** Antworte NUR mit den Ergebnissen für diesen einen Schritt. Deine Antwort muss mit der Überschrift "## Schritt 5: Gains & Nutzen je Rolle" beginnen.`, + + // Step 6: Messages + `# Aufgabe +Führe nun **Schritt 6 – Marketingbotschaft (WIE sprechen)** durch. + +# Kontext: Validierte Ergebnisse aus vorherigen Schritten +{{previous_steps_data}} + +# Eingaben für diesen Schritt +* **Gewünschte Kanäle für die Botschaft:** \`{{channels}}\` + +# Anweisungen für Schritt 6: Chain-of-Thought-Analyse & Texterstellung + +**Dein Ziel ist es, für JEDE Zielbranche aus Schritt 2 eine EIGENE, spezifische Botschaft für JEDE Rolle aus Schritt 3 zu erstellen. Das Ergebnis MUSS eine vollständige Matrix sein (z.B. 3 Zielbranchen x 4 Rollen = 12 einzigartige Botschaften).** + +Führe für jede Kombination aus **[Zielbranche/Segment]** und **[Rolle]** den folgenden Denkprozess durch, bevor du die finale Botschaft formulierst: + +1. **Schritt 6.1 (Analyse): Produkt-Rollen-Fit.** + * Welches Produkt/welche Lösung aus der "Angebot"-Tabelle (Schritt 1) ist für die **[Rolle]** am relevantesten? + * *Beispiel-Gedanke:* "Für den Einsatzleiter im Kundenservice ist die Software zur Einsatzplanung relevanter als die mobile App, da er für die Disposition zuständig ist." + +2. **Schritt 6.2 (Analyse): Branchen-Use-Case.** + * Was sind 1-2 typische Anwendungsfälle für das ausgewählte Produkt in der **[Zielbranche/Segment]**? Was macht die **[Rolle]** damit konkret? + * *Beispiel-Gedanke:* "Ein Servicetechniker im Maschinenbau nutzt die mobile App typischerweise, um auf Wartungsprotokolle zuzugreifen und digitale Serviceberichte direkt beim Kunden zu erstellen." + +3. **Schritt 6.3 (Analyse): Nutzen-Quantifizierung.** + * Betrachte die Painpoints (Schritt 4) und Gains (Schritt 5) für die **[Rolle]**. Welcher Painpoint ist am dringendsten, welcher Gain am überzeugendsten? + * Leite daraus einen konkreten, für die **[Rolle]** relevanten KPI ab (z.B. First-Contact-Resolution-Rate, Zeit-bis-zur-Lösung, Anlagenausfallzeit). + * Formuliere den quantifizierbaren Nutzen aus Schritt 5 in Bezug auf diesen KPI. + * *Beispiel-Gedanke:* "Der Painpoint des Leiters Instandhaltung ist 'ungeplante Anlagenausfälle'. Der Gain ist 'Reduzierung der Ausfallzeiten um 15%'. Der relevante KPI ist die 'Overall Equipment Effectiveness (OEE)'. Der Nutzen ist die Steigerung der OEE durch vorausschauende Wartungsplanung." + +4. **Schritt 6.4 (Synthese): Botschaft formulieren.** + * Synthetisiere die Erkenntnisse aus 6.1-6.3 zu einer prägnanten Kernbotschaft (2-3 Sätze) nach der Struktur: **Beobachtung (Problem) → Niedrigschwellige Lösungsidee → Produkt-Brücke → Quantifizierter Nutzen.** + * Erstelle Varianten dieser Botschaft für die Kanäle: {{channels}}. + +# Output-Format +Erstelle NUR die finale Markdown-Tabelle. Der Denkprozess (6.1-6.3) ist eine interne Anweisung an dich und soll NICHT im Output erscheinen. +* **Tabelle-Spalten:** *Zielbranche/Segment | Rolle | Kernbotschaft (2–3 Sätze) | {{channels}}*. +* **Anforderung:** Deine Antwort muss mit der Überschrift "## Schritt 6: Botschaften" beginnen und NUR die vollständige Markdown-Tabelle enthalten.`, +]; + + +const SYSTEM_PROMPT_EN = ` +# System Role + +You are a **B2B Marketing Researcher & Copywriter**. You analyze a company URL, identify the offer, target groups, specific target roles, their pain points and gains, and based on this, you formulate an appreciative, expert marketing message. **Answer only with results, no thought processes.** Support every statement with a specific page URL from the analyzed domain. Explicitly mark uncertainties. Your response must always be in the target language {{language}}. + +# Working Principles + +1. **Source Prioritization:** Product Page → Solutions Page → Industries/References → Company/About Us Page → Blog/News (for verification only). +2. **Fact Policy:** Only derive from the domain of the provided URL; for assumptions, mark them as a *hypothesis*. +3. **B2B Tone:** Knowledgeable, respectful, not salesy. +4. **Clarity & Structure:** Document each stage as a Markdown table + an optional short summary. +5. **At least 4 specific roles** per target group (not generic). +6. **Concise & Useful:** Precise wording; no clichés. +`; + +const STEP_PROMPTS_EN = [ + // Step 1: Offer + `# Task +Perform **Step 1 – Understand the Offer (WHAT)** for the following company. + +# Inputs +* **Company URL:** \`{{company_url}}\` +* **Target Language of Output:** \`{{language}}\` +* **Region(s) / Markets (optional):** \`{{regions}}\` +* **Product/Solution Focus (optional):** \`{{focus}}\` + +# Instructions for Step 1 +* Extract product(s)/service(s), core features, differentiation, and relevant value propositions. +* Create a short summary (max. 4 bullet points) of the key findings. +* **Output:** Table with columns: *Product/Solution | Description (1–2 sentences) | Core Features | Differentiation | Primary Source (URL)*. +* **Format Requirement:** Respond ONLY with the results for this single step. Your response must start with the heading "## Step 1: Offer (WHAT)" and include the short summary and the Markdown table. Do not provide any other explanations.`, + + // Step 2: Target Groups + `# Task +Now perform **Step 2 – Target Groups (WHO – Companies)**. + +# Context: Validated results from previous steps +{{previous_steps_data}} + +# Instructions for Step 2 +* Identify B2B target segments (industries/company types/sizes/regions) based on the given offer. +* **Output:** Table: *Target Industry/Segment | Typical Company Characteristics | Region(s) | Proof of Relevance (URL)*. +* **Format Requirement:** Respond ONLY with the results for this single step. Your response must start with the heading "## Step 2: Target Groups (Companies)" and include the Markdown table.`, + + // Step 3: Personas + `# Task +Now perform **Step 3 – Personas/Roles (WHO – People)**. + +# Context: Validated results from previous steps +{{previous_steps_data}} + +# Instructions for Step 3 +* For each target industry: at least 4 **specific** roles with their area of responsibility and involvement in purchasing (E, I, D, U based on RACI logic). Do **not** invent people; logically derive roles from problem/process context. +* **Output:** Table: *Role (precise) | Area of Responsibility | Why relevant for the product | Buying Involvement (E/I/D/U) | Source/Indication (URL or reference)*. +* **Format Requirement:** Respond ONLY with the results for this single step. Your response must start with the heading "## Step 3: Personas (Roles)".`, + + // Step 4: Pain Points + `# Task +Now perform **Step 4 – Pain Points per Role (WHY)**. + +# Context: Validated results from previous steps +{{previous_steps_data}} + +# Instructions for Step 4 +* For each role, formulate 3–5 specific pain points (observations, not features). +* Tag each pain point with a category: **Cost | Time | Risk | Compliance | Quality | Employee Retention.** +* Add an **Impact Estimate (€, h, %)** as a hypothesis. +* **Output:** Table: *Role | Pain Point (specific, measurable/operational) | Category | Impact (Cost, Risk, Time) | Impact Estimate (€, h, %) | Urgency (high/medium/low) | Source/Indication (URL)*. +* **Format Requirement:** Respond ONLY with the results for this single step. Your response must start with the heading "## Step 4: Pain Points per Role".`, + + // Step 5: Gains + `# Task +Now perform **Step 5 – Gains & Benefits per Role (WHY switch)**. + +# Context: Validated results from previous steps +{{previous_steps_data}} + +# Instructions for Step 5 +* Based on the identified pain points, formulate 2-3 concrete gains (advantages/benefits) for each role. +* Quantify the benefit as a hypothesis (e.g., savings in €, time gained in h, efficiency increase in %). +* **Output:** Table: *Role | Gain (specific benefit) | Quantification (Hypothesis in €, h, %) | Source/Indication (URL)*. +* **Format Requirement:** Respond ONLY with the results for this single step. Your response must start with the heading "## Step 5: Gains & Benefits per Role".`, + + // Step 6: Messages + `# Task +Now perform **Step 6 – Marketing Message (HOW to speak)**. + +# Context: Validated results from previous steps +{{previous_steps_data}} + +# Inputs for this step +* **Desired channels for the message:** \`{{channels}}\` + +# Instructions for Step 6: Chain-of-Thought Analysis & Copywriting + +**Your goal is to create a SEPARATE, specific message for EACH role from Step 3 within EACH target industry from Step 2. The result MUST be a complete matrix (e.g., 3 target industries x 4 roles = 12 unique messages).** + +For each combination of **[Target Industry/Segment]** and **[Role]**, perform the following thought process before writing the final message: + +1. **Step 6.1 (Analysis): Product-Role Fit.** + * Which product/solution from the "Offer" table (Step 1) is most relevant to the **[Role]**? + * *Example thought:* "For the Customer Service Manager, the scheduling software is more relevant than the mobile app because they are responsible for dispatching." + +2. **Step 6.2 (Analysis): Industry Use Case.** + * What are 1-2 typical use cases for the selected product in the **[Target Industry/Segment]**? What does the **[Role]** specifically do with it? + * *Example thought:* "A service technician in mechanical engineering typically uses the mobile app to access maintenance logs and create digital service reports directly on-site with the customer." + +3. **Step 6.3 (Analysis): Benefit Quantification.** + * Look at the pain points (Step 4) and gains (Step 5) for the **[Role]**. Which pain point is most urgent, which gain most convincing? + * Derive a concrete KPI relevant to the **[Role]** (e.g., First-Contact Resolution Rate, Time-to-Resolution, plant downtime). + * Formulate the quantifiable benefit from Step 5 in relation to this KPI. + * *Example thought:* "The Maintenance Manager's pain point is 'unplanned plant downtime'. The gain is 'reducing downtime by 15%'. The relevant KPI is 'Overall Equipment Effectiveness (OEE)'. The benefit is increasing OEE through predictive maintenance planning." + +4. **Step 6.4 (Synthesis): Formulate Message.** + * Synthesize the findings from 6.1-6.3 into a concise core message (2-3 sentences) following the structure: **Observation (Problem) → Low-threshold solution idea → Product bridge → Quantified benefit.** + * Create variations of this message for the channels: {{channels}}. + +# Output Format +Create ONLY the final Markdown table. The thought process (6.1-6.3) is an internal instruction for you and should NOT appear in the output. +* **Table Columns:** *Target Industry/Segment | Role | Core Message (2–3 sentences) | {{channels}}*. +* **Requirement:** Your response must start with the heading "## Step 6: Messages" and contain ONLY the complete Markdown table.`, +]; + +export const PROMPTS = { + de: { + SYSTEM_PROMPT: SYSTEM_PROMPT_DE, + STEP_PROMPTS: STEP_PROMPTS_DE, + }, + en: { + SYSTEM_PROMPT: SYSTEM_PROMPT_EN, + STEP_PROMPTS: STEP_PROMPTS_EN, + } +}; diff --git a/b2b-marketing-assistant/index.html b/b2b-marketing-assistant/index.html new file mode 100644 index 00000000..8760dbfa --- /dev/null +++ b/b2b-marketing-assistant/index.html @@ -0,0 +1,59 @@ + + + + + + + B2B Marketing Assistant powered by Gemini + + + + + + +
+ + + \ No newline at end of file diff --git a/b2b-marketing-assistant/index.tsx b/b2b-marketing-assistant/index.tsx new file mode 100644 index 00000000..aaa0c6e4 --- /dev/null +++ b/b2b-marketing-assistant/index.tsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +const rootElement = document.getElementById('root'); +if (!rootElement) { + throw new Error("Could not find root element to mount to"); +} + +const root = ReactDOM.createRoot(rootElement); +root.render( + + + +);