From 25ca7a36d9225d5340559a6087e8fd8c38f530b0 Mon Sep 17 00:00:00 2001 From: Floke Date: Fri, 2 Jan 2026 18:20:25 +0000 Subject: [PATCH] Dateien nach "gtm-architect/v2" hochladen --- gtm-architect/v2/.env.local | 1 + gtm-architect/v2/.gitignore | 24 + gtm-architect/v2/geminiService.ts | 845 ++++++++++++++++++++++++++++++ gtm-architect/v2/index.html | 91 ++++ gtm-architect/v2/index.tsx | 15 + 5 files changed, 976 insertions(+) create mode 100644 gtm-architect/v2/.env.local create mode 100644 gtm-architect/v2/.gitignore create mode 100644 gtm-architect/v2/geminiService.ts create mode 100644 gtm-architect/v2/index.html create mode 100644 gtm-architect/v2/index.tsx diff --git a/gtm-architect/v2/.env.local b/gtm-architect/v2/.env.local new file mode 100644 index 00000000..be86fc11 --- /dev/null +++ b/gtm-architect/v2/.env.local @@ -0,0 +1 @@ +GEMINI_API_KEY=PLACEHOLDER_API_KEY diff --git a/gtm-architect/v2/.gitignore b/gtm-architect/v2/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/gtm-architect/v2/.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/gtm-architect/v2/geminiService.ts b/gtm-architect/v2/geminiService.ts new file mode 100644 index 00000000..9613caf1 --- /dev/null +++ b/gtm-architect/v2/geminiService.ts @@ -0,0 +1,845 @@ +import { GoogleGenAI, Type } from "@google/genai"; +import { Phase1Data, Phase2Data, Phase3Data, Phase4Data, Phase6Data, Phase7Data, Phase8Data, Phase9Data, Language } from "./types"; + +const getSystemInstruction = (lang: Language) => { + if (lang === 'de') { + return ` +# IDENTITY & PURPOSE +Du bist die "GTM Architect Engine" für Roboplanet. Deine Aufgabe ist es, für neue technische Produkte (Roboter) eine präzise Go-to-Market-Strategie zu entwickeln. +Du handelst nicht als kreativer Werbetexter, sondern als strategischer Analyst. Dein oberstes Ziel ist Product-Market-Fit und operative Umsetzbarkeit. +Antworte IMMER auf DEUTSCH. + +# CONTEXT: THE PARENT COMPANY (WACKLER) +Wir sind Teil der Wackler Group, einem großen Facility-Management-Dienstleister. +Unsere Strategie ist NICHT "Roboter ersetzen Menschen", sondern "Hybrid-Reinigung": +- 80% der Arbeit (monotone Flächenleistung) = Roboter. +- 20% der Arbeit (Edge Cases, Winterdienst, Treppen, Grobschmutz) = Manuelle Reinigung durch Wackler. + +# STRICT ANALYSIS RULES (MUST FOLLOW): +1. TECHNICAL FACT-CHECK (Keine Halluzinationen): + - Analysiere technische Daten extrem konservativ. + - Vakuumsystem = Kein "Winterdienst" (Schnee) und keine "Schwerindustrie" (Metallspäne), außer explizit genannt. + - Erfinde keine Features, nur um eine Zielgruppe passend zu machen. + +2. REGULATORY LOGIC (StVO-Check): + - Wenn Vmax < 20 km/h: Schließe "Öffentliche Städte/Kommunen/Straßenreinigung" kategorisch aus (Verkehrshindernis). + - Fokusänderung: Konzentriere dich stattdessen ausschließlich auf "Große, zusammenhängende Privatflächen" (Gated Areas). + +3. STRATEGIC TARGETING (Use-Case-Logik): + - Priorisiere Cluster A (Efficiency): Logistikzentren & Industrie-Hubs (24/7 Betrieb, Sicherheit). + - Priorisiere Cluster B (Experience): Shopping Center, Outlets & Freizeitparks (Sauberkeit als Visitenkarte). + - Entferne reine E-Commerce-Händler ohne physische Kundenfläche. + +4. THE "HYBRID SERVICE" LOGIC (RULE 5): + Wann immer du ein "Hartes Constraint" oder eine technische Limitierung identifizierst (z.B. "Kein Winterdienst" oder "Kommt nicht in Ecken"), darfst du dies niemals als reines "Nein" stehen lassen. + Wende stattdessen die **"Yes, and..." Logik** an: + 1. **Identifiziere die Lücke:** (z.B. "Roboter kann bei Schnee nicht fahren"). + 2. **Fülle die Lücke mit Service:** Schlage explizit vor, diesen Teil durch "Wackler Human Manpower" abzudecken. + 3. **Formuliere den USP:** Positioniere das Gesamtpaket als "100% Coverage" (Roboter + Mensch aus einer Hand). + +# THE PRODUCT MATRIX (CONTEXT) +Behalte immer im Hinterkopf, dass wir bereits folgende Produkte im Portfolio haben: +1. "Indoor Scrubber 50": Innenreinigung, Hartboden, Fokus: Supermärkte. Message: "Sauberkeit im laufenden Betrieb." +2. "Service Bot Bella": Service/Gastro, Indoor. Fokus: Restaurants. Message: "Entlastung für Servicekräfte." +`; + } else { + return ` +# IDENTITY & PURPOSE +You are the "GTM Architect Engine" for Roboplanet. Your task is to develop a precise Go-to-Market strategy for new technical products (robots). +You do not act as a creative copywriter, but as a strategic analyst. Your top goal is product-market fit and operational feasibility. +ALWAYS respond in ENGLISH. + +# CONTEXT: THE PARENT COMPANY (WACKLER) +We are part of the Wackler Group, a major facility management service provider. +Our strategy is NOT "Robots replace humans", but "Hybrid Cleaning": +- 80% of work (monotonous area coverage) = Robots. +- 20% of work (Edge cases, winter service, stairs, heavy debris) = Manual cleaning by Wackler. + +# STRICT ANALYSIS RULES (MUST FOLLOW): +1. TECHNICAL FACT-CHECK (No Hallucinations): + - Analyze technical data extremely conservatively. + - Vacuum System = No "Winter Service" (snow) and no "Heavy Industry" (metal shavings), unless explicitly stated. + - Do not invent features just to fit a target audience. + +2. REGULATORY LOGIC (Traffic Regs): + - If Vmax < 20 km/h: Categorically exclude "Public Cities/Streets" (traffic obstruction). + - Change Focus: Concentrate exclusively on "Large, contiguous private areas" (Gated Areas). + +3. STRATEGIC TARGETING (Use Case Logic): + - Prioritize Cluster A (Efficiency): Logistics Centers & Industrial Hubs (24/7 ops, safety). + - Prioritize Cluster B (Experience): Shopping Centers, Outlets & Theme Parks (Cleanliness as a calling card). + - Remove pure E-commerce retailers without physical customer areas. + +4. THE "HYBRID SERVICE" LOGIC (RULE 5): + Whenever you identify a "Hard Constraint" or technical limitation (e.g., "No winter service" or "Cannot reach corners"), never let this stand as a simple "No". + Instead, apply the **"Yes, and..." logic**: + 1. **Identify the gap:** (e.g., "Robot cannot operate in snow"). + 2. **Fill the gap with service:** Explicitly suggest covering this part with "Wackler Human Manpower". + 3. **Formulate the USP:** Position the total package as "100% Coverage" (Robot + Human from a single source). + +# THE PRODUCT MATRIX (CONTEXT) +Always keep in mind that we already have the following products in our portfolio: +1. "Indoor Scrubber 50": Indoor cleaning, hard floor, supermarkets. +2. "Service Bot Bella": Service/Hospitality, indoor. Focus: restaurants. Message: "Relief for service staff." +`; + } +}; + +const getClient = () => { + const apiKey = process.env.API_KEY; + if (!apiKey) { + throw new Error("API_KEY not found in environment variables"); + } + return new GoogleGenAI({ apiKey }); +}; + +// Helper to safely parse JSON from AI response +const cleanAndParseJson = (text: string | undefined): T => { + if (!text) throw new Error("AI returned empty response"); + + let cleaned = text.trim(); + // Remove markdown formatting if present + if (cleaned.startsWith('```json')) { + cleaned = cleaned.replace(/^```json\n?/, '').replace(/\n?```$/, ''); + } else if (cleaned.startsWith('```')) { + cleaned = cleaned.replace(/^```\n?/, '').replace(/\n?```$/, ''); + } + + try { + return JSON.parse(cleaned); + } catch (e) { + console.error("JSON Parse Error. Raw text:", text); + throw new Error("Failed to parse AI response. The model output was likely malformed or truncated. Please try again with shorter input."); + } +}; + +// --- Phase 1: Product Analysis --- +export const analyzeProduct = async (input: string, lang: Language): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const extractionPrompt = lang === 'de' ? ` + PHASE 1-A: TECHNICAL EXTRACTION + Input Product Description: "${input.substring(0, 25000)}..." + + Aufgabe: + 1. Extrahiere technische Hauptmerkmale (Specs, Fähigkeiten). + 2. Leite "Harte Constraints" ab. WICHTIG: Prüfe Vmax (<20km/h = Privatgelände) und Reinigungstyp (Vakuum != Grobschmutz/Schnee). + 3. Erstelle eine kurze Rohanalyse-Zusammenfassung. + + Output JSON format ONLY. + ` : ` + PHASE 1-A: TECHNICAL EXTRACTION + Input Product Description: "${input.substring(0, 25000)}..." + + Task: + 1. Extract key technical features (specs, capabilities). + 2. Derive "Hard Constraints". IMPORTANT: Check Vmax (<20km/h = Private Grounds) and Cleaning Type (Vacuum != Heavy Debris/Snow). + 3. Create a short raw analysis summary. + + Output JSON format ONLY. + `; + + const extractionResponse = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: extractionPrompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + responseSchema: { + type: Type.OBJECT, + properties: { + features: { type: Type.ARRAY, items: { type: Type.STRING } }, + constraints: { type: Type.ARRAY, items: { type: Type.STRING } }, + rawAnalysis: { type: Type.STRING } + } + } + } + }); + + const extractionData = cleanAndParseJson<{ + features: string[]; + constraints: string[]; + rawAnalysis: string; + }>(extractionResponse.text); + + const conflictPrompt = lang === 'de' ? ` + PHASE 1-B: PORTFOLIO CONFLICT CHECK + + Neue Produkt-Features: ${JSON.stringify(extractionData.features)} + Neue Produkt-Constraints: ${JSON.stringify(extractionData.constraints)} + + Existierendes Portfolio: + 1. "Indoor Scrubber 50": Innenreinigung, Hartboden, Supermärkte. + 2. "Service Bot Bella": Service/Gastro, Indoor, Restaurants. + + Aufgabe: + Prüfe, ob das neue Produkt signifikant mit bestehenden Produkten überlappt (Ist es nur ein Klon?). + + Output JSON format ONLY. + ` : ` + PHASE 1-B: PORTFOLIO CONFLICT CHECK + + New Product Features: ${JSON.stringify(extractionData.features)} + New Product Constraints: ${JSON.stringify(extractionData.constraints)} + + Existing Portfolio: + 1. "Indoor Scrubber 50": Indoor cleaning, hard floor, supermarkets. + 2. "Service Bot Bella": Service/Gastro, indoor, restaurants. + + Task: + Check if the new product overlaps significantly with existing ones (is it just a clone?). + + Output JSON format ONLY. + `; + + const conflictResponse = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: conflictPrompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + responseSchema: { + type: Type.OBJECT, + properties: { + conflictCheck: { + type: Type.OBJECT, + properties: { + hasConflict: { type: Type.BOOLEAN }, + details: { type: Type.STRING }, + relatedProduct: { type: Type.STRING, nullable: true } + } + } + } + } + } + }); + + const conflictData = cleanAndParseJson<{ + conflictCheck: Phase1Data['conflictCheck']; + }>(conflictResponse.text); + + return { + ...extractionData, + ...conflictData + }; +}; + +// --- Phase 2: ICP Discovery --- +export const discoverICPs = async (phase1Data: Phase1Data, lang: Language): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 2: ICP DISCOVERY & DATA PROXIES + Basierend auf Features: ${JSON.stringify(phase1Data.features)} + Und Constraints: ${JSON.stringify(phase1Data.constraints)} + + Aufgabe: + 1. Negative Selektion: Welche Branchen sind unmöglich? (Denke an Vmax & Vakuum-Regeln!) + 2. High Pain: Identifiziere Cluster A (Logistik/Industrie) und Cluster B (Shopping/Outlets). + 3. Data Proxy Generierung: Wie finden wir diese digital (z.B. Satellit, Register)? + + Output JSON format ONLY: + { + "icps": [ + { "name": "Branchen Name", "rationale": "Warum das passt (max 1 Satz)" } + ], + "dataProxies": [ + { "target": "Spezifisches Kriterium", "method": "Wie zu finden (z.B. Scraping)" } + ] + } + ` : ` + PHASE 2: ICP DISCOVERY & DATA PROXIES + Based on the product features: ${JSON.stringify(phase1Data.features)} + And constraints: ${JSON.stringify(phase1Data.constraints)} + + Task: + 1. Negative Selection: Which industries are impossible? (Remember Vmax & Vacuum rules!) + 2. High Pain: Identify Cluster A (Logistics/Industry) and Cluster B (Shopping/Outlets). + 3. Data Proxy Generation: How to find them digitally via data traces (e.g. satellite, registries). + + Output JSON format ONLY: + { + "icps": [ + { "name": "Industry Name", "rationale": "Why this is a good fit (max 1 sentence)" } + ], + "dataProxies": [ + { "target": "Specific criteria", "method": "How to find (e.g. scraping, satellite)" } + ] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +// --- Phase 3: Whale Hunting --- +export const huntWhales = async (phase2Data: Phase2Data, lang: Language): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 3: WHALE HUNTING + Target ICPs (Branchen): ${JSON.stringify(phase2Data.icps)} + + Aufgabe: + 1. Gruppiere die "Whales" (Key Accounts) strikt nach den identifizierten ICP-Branchen. + 2. Identifiziere pro Branche 3-5 konkrete Top-Unternehmen im DACH Markt. + 3. Definiere die Buying Center Rollen. + + Output JSON format ONLY: + { + "whales": [ + { "industry": "Name der ICP Branche", "accounts": ["Firma A", "Firma B"] } + ], + "roles": ["Jobtitel 1", "Jobtitel 2"] + } + ` : ` + PHASE 3: WHALE HUNTING + Target ICPs (Industries): ${JSON.stringify(phase2Data.icps)} + + Task: + 1. Group "Whales" (Key Accounts) strictly by the identified ICP industries. + 2. Identify 3-5 concrete top companies in the DACH market per industry. + 3. Define Buying Center Roles. + + Output JSON format ONLY: + { + "whales": [ + { "industry": "Name of ICP Industry", "accounts": ["Company A", "Company B"] } + ], + "roles": ["Job Title 1", "Job Title 2"] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +// --- Phase 4: Strategy --- +export const developStrategy = async (phase3Data: Phase3Data, phase1Data: Phase1Data, lang: Language): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const allAccounts = phase3Data.whales.flatMap(w => w.accounts); + + const prompt = lang === 'de' ? ` + PHASE 4: STRATEGY & ANGLE DEVELOPMENT + Accounts: ${JSON.stringify(allAccounts)} + Target Industries: ${JSON.stringify(phase3Data.whales.map(w => w.industry))} + Features: ${JSON.stringify(phase1Data.features)} + + Aufgabe: + 1. Entwickle einen spezifischen "Angle" (Aufhänger) pro Zielgruppe/Industrie. + 2. Consistency Check gegen Product Matrix (Differenzierung zu Scrubber 50/Bella). + 3. **WICHTIG:** Wende die "Hybrid Service Logic" an, wenn technische Constraints existieren! (Wackler Manpower als Ergänzung). + + Output JSON format ONLY: + { + "strategyMatrix": [ + { + "segment": "Zielsegment", + "painPoint": "Spezifischer Schmerz (Kurz)", + "angle": "Unser Marketing Angle (Kurz)", + "differentiation": "Wie es sich unterscheidet (Kurz)" + } + ] + } + ` : ` + PHASE 4: STRATEGY & ANGLE DEVELOPMENT + Accounts: ${JSON.stringify(allAccounts)} + Target Industries: ${JSON.stringify(phase3Data.whales.map(w => w.industry))} + Product Features: ${JSON.stringify(phase1Data.features)} + + Task: + 1. Develop specific "Angle" per target/industry. + 2. Consistency Check against Product Matrix (ensure differentiation from Scrubber 50/Bella). + 3. **IMPORTANT:** Apply "Hybrid Service Logic" if technical constraints exist! (Wackler Manpower as supplement). + + Output JSON format ONLY: + { + "strategyMatrix": [ + { + "segment": "Target Segment", + "painPoint": "Specific Pain (Short)", + "angle": "Our Marketing Angle (Short)", + "differentiation": "How it differs (Short)" + } + ] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +// --- Phase 5: Assets & Report --- +export const generateAssets = async ( + phase4Data: Phase4Data, + phase3Data: Phase3Data, + phase2Data: Phase2Data, + phase1Data: Phase1Data, + lang: Language +): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 5: ASSET GENERATION & FINAL REPORT + + CONTEXT DATA: + - Technical: ${JSON.stringify(phase1Data)} + - ICPs: ${JSON.stringify(phase2Data)} + - Targets (Whales): ${JSON.stringify(phase3Data)} + - Strategy: ${JSON.stringify(phase4Data)} + + AUFGABE: + 1. Erstelle einen "GTM STRATEGY REPORT" in Markdown. + 2. Struktur des Reports: + - Executive Summary + - Produkt Analyse (Features & Constraints) + - Zielgruppen (ICPs & Data Proxies) + - Target Accounts (Whales) & Buying Center + - Strategie-Matrix (Pains & Angles) + - Assets (LinkedIn, Email, Landing Page Headline) + 3. Self-Correction: Entferne "Marketing Bla-Bla". Nutze Fakten, TCO, ROI. + 4. Hybrid-Check: Stelle sicher, dass die "Hybrid Service Logic" (Wackler Manpower) in der Strategie und den Assets sichtbar ist, falls Constraints vorliegen. + + Output: + Gib striktes MARKDOWN zurück. Beginne mit "# GTM STRATEGY REPORT". + ` : ` + PHASE 5: ASSET GENERATION & FINAL REPORT + + CONTEXT DATA: + - Technical: ${JSON.stringify(phase1Data)} + - ICPs: ${JSON.stringify(phase2Data)} + - Targets (Whales): ${JSON.stringify(phase3Data)} + - Strategy: ${JSON.stringify(phase4Data)} + + TASK: + 1. Create a "GTM STRATEGY REPORT" in Markdown. + 2. Report Structure: + - Executive Summary + - Product Analysis (Features & Constraints) + - Target Audience (ICPs & Data Proxies) + - Target Accounts (Whales) & Buying Center + - Strategy Matrix (Pains & Angles) + - Assets (LinkedIn, Email, Landing Page Headline) + 3. Self-Correction: Remove "Marketing Fluff". Use Facts, TCO, ROI. + 4. Hybrid-Check: Ensure "Hybrid Service Logic" (Wackler Manpower) is visible in strategy and assets if constraints exist. + + Output: + Return strictly MARKDOWN formatted text. Start with "# GTM STRATEGY REPORT". + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + } + }); + + return response.text || "Error generating assets."; +}; + +// --- Phase 6: Sales Enablement & Visuals --- +export const generateSalesEnablement = async ( + phase4Data: Phase4Data, + phase3Data: Phase3Data, + phase1Data: Phase1Data, + lang: Language +): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 6: SALES ENABLEMENT & VISUALS + + CONTEXT: + - Produkt Features: ${JSON.stringify(phase1Data.features)} + - Accounts (Personas): ${JSON.stringify(phase3Data.roles)} + - Strategie: ${JSON.stringify(phase4Data.strategyMatrix)} + + AUFGABE: + 1. **Anticipate Friction:** Versetze dich in die Lage der identifizierten Personas. Was ist deren härtester Einwand? + 2. **Deflect & Solve:** Formuliere eine präzise, faktenbasierte Antwort für den Vertriebler (Battlecard). + 3. **Visual Context:** Erstelle präzise "Text-to-Image Prompts" (für Midjourney/DALL-E). + + Output JSON format ONLY: + { + "battlecards": [ + { + "persona": "Rolle", + "objection": "Einwand", + "responseScript": "Antwort" + } + ], + "visualPrompts": [ + { + "title": "Titel", + "context": "Kontext", + "prompt": "Prompt..." + } + ] + } + ` : ` + PHASE 6: SALES ENABLEMENT & VISUALS + + CONTEXT: + - Product Features: ${JSON.stringify(phase1Data.features)} + - Accounts (Personas): ${JSON.stringify(phase3Data.roles)} + - Strategy: ${JSON.stringify(phase4Data.strategyMatrix)} + + TASK: + 1. **Anticipate Friction:** Identify hardest objections. + 2. **Deflect & Solve:** Formulate response script (Battlecard). + 3. **Visual Context:** Create "Text-to-Image Prompts". + + Output JSON format ONLY: + { + "battlecards": [ + { + "persona": "Role", + "objection": "Objection", + "responseScript": "Response" + } + ], + "visualPrompts": [ + { + "title": "Title", + "context": "Context", + "prompt": "Prompt..." + } + ] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +// --- Phase 7: Vertical Landing Page Copy --- +export const generateLandingPageCopy = async ( + phase4Data: Phase4Data, + phase2Data: Phase2Data, + lang: Language +): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 7: VERTICAL LANDING PAGE COPY (Conversion Optimization) + + ICPs: ${JSON.stringify(phase2Data.icps)} + Strategy: ${JSON.stringify(phase4Data.strategyMatrix)} + + AUFGABE: + 1. Identifiziere generische Aussagen und transformiere sie in spezifische Nutzenargumente für die Top 2 ICPs. + 2. Wende die "Wackler-Symbiose" an: Erwähne Service/Hygiene als Trust-Element. + + Erstelle für die Top 2 ICPs jeweils einen Landingpage-Entwurf (Hero Section). + + Output JSON format ONLY: + { + "landingPages": [ + { + "industry": "Zielbranche", + "headline": "Nutzenorientierte Headline (Kein Produktname)", + "subline": "Tech Enabler + Wackler Service Garantie", + "bullets": ["Vorteil 1", "Vorteil 2", "Vorteil 3"], + "cta": "Branchen-spezifischer CTA" + } + ] + } + ` : ` + PHASE 7: VERTICAL LANDING PAGE COPY (Conversion Optimization) + + ICPs: ${JSON.stringify(phase2Data.icps)} + Strategy: ${JSON.stringify(phase4Data.strategyMatrix)} + + TASK: + 1. Transform generic features into specific benefits for the Top 2 ICPs. + 2. Apply "Wackler Symbiosis": Mention service/hygiene as trust element. + + Create Landing Page Drafts (Hero Section) for Top 2 ICPs. + + Output JSON format ONLY: + { + "landingPages": [ + { + "industry": "Target Industry", + "headline": "Benefit-oriented Headline", + "subline": "Tech Enabler + Wackler Service Guarantee", + "bullets": ["Benefit 1", "Benefit 2", "Benefit 3"], + "cta": "Industry-specific CTA" + } + ] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +// --- Phase 8: Business Case Builder --- +export const buildBusinessCase = async ( + phase2Data: Phase2Data, + phase1Data: Phase1Data, + lang: Language +): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 8: BUSINESS CASE BUILDER (The CFO Pitch) + + Input: + ICPs: ${JSON.stringify(phase2Data.icps)} + Features: ${JSON.stringify(phase1Data.features)} + + AUFGABE: + 1. Schätze Lohnkosten/Probleme der Zielgruppe (Personalmangel, Krankheitsstand). + 2. Setze den Roboter (Leasing ca. 330-600€/Monat) dagegen. + 3. Entwickle eine ROI-Logik. + + Erstelle für jeden ICP einen "Financial Argumentation Guide". + + Output JSON format ONLY: + { + "businessCases": [ + { + "industry": "Branche", + "costDriver": "Was kostet der Status Quo? (z.B. Laufwege)", + "efficiencyGain": "Wie amortisiert sich der Roboter?", + "riskArgument": "Warum Miete + Wackler Service sicherer ist als Kauf" + } + ] + } + ` : ` + PHASE 8: BUSINESS CASE BUILDER (The CFO Pitch) + + Input: + ICPs: ${JSON.stringify(phase2Data.icps)} + Features: ${JSON.stringify(phase1Data.features)} + + TASK: + 1. Estimate labor costs/pain points (shortage, sick leave). + 2. Compare against Robot Leasing (approx 330-600€/month). + 3. Develop ROI logic. + + Create a "Financial Argumentation Guide" for each ICP. + + Output JSON format ONLY: + { + "businessCases": [ + { + "industry": "Industry", + "costDriver": "Status Quo Cost", + "efficiencyGain": "Amortization Logic", + "riskArgument": "Why Lease + Service is safer than buying" + } + ] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +// --- Phase 9: Feature-to-Value Translator --- +export const translateTech = async ( + phase1Data: Phase1Data, + phase4Data: Phase4Data, + lang: Language +): Promise => { + const ai = getClient(); + const sysInstr = getSystemInstruction(lang); + + const prompt = lang === 'de' ? ` + PHASE 9: THE "FEATURE-TO-VALUE" TRANSLATOR + + Input Features: ${JSON.stringify(phase1Data.features)} + Strategy Pains: ${JSON.stringify(phase4Data.strategyMatrix.map(s => s.painPoint))} + + AUFGABE: + 1. Nimm ein technisches Feature (z.B. "LiDAR"). + 2. Frage: "So what?" (Was bringt das im Alltag?). + 3. Frage nochmal: "So what?" (Was ist der emotionale oder finanzielle Vorteil?). + * Kette: LiDAR -> Erkennt Hindernisse -> Stößt nicht an -> Keine Unfälle/Haftung -> **Sicherheit & Ruhe**. + 4. Formuliere den Benefit **ohne** Fachchinesisch. Nutze emotionale Trigger. + + Erstelle eine Tabelle für die Website-Kommunikation: + * **feature:** (Klein gedruckt für Techies) + * **story:** (Die Story) Der emotionale/wirtschaftliche Nutzen in der Sprache der Zielgruppe. + * **headline:** (Die Headline) Ein knackiger Slogan für dieses Feature. + + Output JSON format ONLY: + { + "techTranslations": [ + { + "feature": "Technisches Feature", + "story": "Benefit Story (So what chain)", + "headline": "Knackiger Slogan" + } + ] + } + ` : ` + PHASE 9: THE "FEATURE-TO-VALUE" TRANSLATOR + + Input Features: ${JSON.stringify(phase1Data.features)} + Strategy Pains: ${JSON.stringify(phase4Data.strategyMatrix.map(s => s.painPoint))} + + TASK: + 1. Take a technical feature (e.g. "LiDAR"). + 2. Ask: "So what?" (What does it do in daily life?). + 3. Ask again: "So what?" (What is the emotional or financial benefit?). + * Chain: LiDAR -> See obstacles -> No collision -> No accidents/liability -> **Safety & Peace of Mind**. + 4. Formulate the benefit **without** jargon. Use emotional triggers. + + Create a table for website communication: + * **feature:** (Small print for techies) + * **story:** (The Story) The emotional/economic benefit in target language. + * **headline:** (The Headline) A punchy slogan for this feature. + + Output JSON format ONLY: + { + "techTranslations": [ + { + "feature": "Tech Feature", + "story": "Benefit Story (So what chain)", + "headline": "Punchy Slogan" + } + ] + } + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt, + config: { + systemInstruction: sysInstr, + responseMimeType: "application/json", + } + }); + + return cleanAndParseJson(response.text); +}; + +export const translateReportToEnglish = async (reportMarkdown: string): Promise => { + const ai = getClient(); + const prompt = ` + TASK: Translate the following GTM Strategy Report into professional Business English. + CONTEXT: It is a B2B robotic strategy document. + CONSTRAINT: Keep the Markdown structure (#, ##, -, | tables) EXACTLY as is. Only translate the content. + + INPUT: + ${reportMarkdown} + `; + + const response = await ai.models.generateContent({ + model: 'gemini-3-flash-preview', + contents: prompt + }); + + return response.text || reportMarkdown; +}; + +export const generateConceptImage = async (prompt: string, referenceImagesBase64?: string[]): Promise => { + const ai = getClient(); + try { + const parts: any[] = []; + + // If reference images are provided, add them to parts + if (referenceImagesBase64 && referenceImagesBase64.length > 0) { + referenceImagesBase64.forEach(img => { + const cleanBase64 = img.split(',')[1] || img; + const match = img.match(/data:(.*?);base64/); + const mimeType = match ? match[1] : 'image/png'; + + parts.push({ + inlineData: { + mimeType: mimeType, + data: cleanBase64 + } + }); + }); + + parts.push({ + text: "Show the product in these reference images in the following context. Keep the product appearance consistent. " + prompt + }); + } else { + // Text-only prompt + parts.push({ text: prompt }); + } + + const response = await ai.models.generateContent({ + model: 'gemini-2.5-flash-image', + contents: { parts }, + config: { + imageConfig: { + aspectRatio: "16:9", + } + } + }); + + for (const part of response.candidates?.[0]?.content?.parts || []) { + if (part.inlineData) { + return `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`; + } + } + throw new Error("No image generated"); + } catch (e: any) { + console.error("Image generation failed", e); + throw new Error(e.message || "Failed to generate image"); + } +}; \ No newline at end of file diff --git a/gtm-architect/v2/index.html b/gtm-architect/v2/index.html new file mode 100644 index 00000000..f4c09d44 --- /dev/null +++ b/gtm-architect/v2/index.html @@ -0,0 +1,91 @@ + + + + + + Roboplanet GTM Architect + + + + + + + + +
+ + + \ No newline at end of file diff --git a/gtm-architect/v2/index.tsx b/gtm-architect/v2/index.tsx new file mode 100644 index 00000000..6ca5361e --- /dev/null +++ b/gtm-architect/v2/index.tsx @@ -0,0 +1,15 @@ +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( + + + +); \ No newline at end of file