diff --git a/competitor-analysis/translations.ts b/competitor-analysis/translations.ts new file mode 100644 index 00000000..44d92596 --- /dev/null +++ b/competitor-analysis/translations.ts @@ -0,0 +1,286 @@ +export const translations = { + de: { + appTitle: "B2B Competitor Analysis Agent", + restartAnalysis: "Analyse neustarten", + nextStepButton: "Bestätigen & Nächster Schritt", + companyCard: { + title: "Ausgangsunternehmen", + }, + inputForm: { + title: "Wettbewerbsanalyse starten", + subtitle: "Geben Sie die Website eines Unternehmens ein, um die Analyse zu beginnen.", + startUrlLabel: "Start-URL des Unternehmens", + maxCompetitorsLabel: "Max. Wettbewerber", + marketScopeLabel: "Marktfokus", + marketScopePlaceholder: "z.B. DACH, EU, global", + languageLabel: "Sprache", + submitButton: "Analyse starten", + }, + loadingSpinner: { + message: "AI analysiert, bitte warten...", + }, + errors: { + title: "Fehler:", + step1: "Fehler bei der Analyse der Start-URL. Bitte überprüfen Sie die URL und versuchen Sie es erneut.", + generic: (step: number) => `Ein Fehler ist in Schritt ${step} aufgetreten. Bitte versuchen Sie es erneut.`, + }, + stepIndicator: { + title: "Fortschritt", + steps: ["Extraktion", "Keywords", "Wettbewerber", "Analyse", "Silver Bullets", "Fazit", "Battlecards", "Referenzen"], + }, + step1: { + title: "Schritt 1: Extraktion der Unternehmensinformationen", + subtitle: "Überprüfen, bearbeiten oder ergänzen Sie die vom AI-Agenten extrahierten Produkte und Zielbranchen.", + addProductTitle: "Neues Produkt per URL hinzufügen", + productNameLabel: "Produktname", + productUrlLabel: "Produkt-URL", + productNamePlaceholder: "z.B. mobileX-Dispatch", + addProductError: "Produkt konnte nicht recherchiert werden. Bitte URL überprüfen.", + addButton: "Produkt hinzufügen", + addingButton: "Recherchiere...", + productsTitle: "Produkte / Lösungen", + purposeLabel: "Zweckbeschreibung", + industriesTitle: "Zielmärkte / Branchen", + industryNameLabel: "Branchenname", + editableCard: { add: "Hinzufügen", cancel: "Abbrechen", save: "Speichern" } + }, + step2: { + title: "Schritt 2: Abgeleitete Keywords", + subtitle: "Überprüfen Sie die für die Wettbewerbssuche generierten Keywords und passen Sie sie bei Bedarf an.", + cardTitle: "Keyword-Set", + termLabel: "Keyword / Phrase", + rationaleLabel: "Begründung", + editableCard: { add: "Hinzufügen", cancel: "Abbrechen", save: "Speichern" } + }, + step3: { + title: "Schritt 3: Wettbewerber finden", + subtitle: (max: number) => `Hier ist die Longlist potenzieller Wettbewerber. Entfernen oder ergänzen Sie Einträge. Die Top ${max} nach Konfidenz werden für die Detailanalyse in die Shortlist übernommen.`, + cardTitle: "Wettbewerber-Kandidaten", + nameLabel: "Name", + whyLabel: "Begründung", + visitButton: "Besuchen", + shortlistBoundary: "SHORTLIST-GRENZE", + editableCard: { add: "Hinzufügen", cancel: "Abbrechen", save: "Speichern" } + }, + step4: { + title: "Schritt 4: Portfolio- & Positionierungsanalyse", + subtitle: "Detailanalyse der Shortlist-Wettbewerber. Die relevantesten (höchster Overlap) stehen oben.", + downloadJson_title: "Analyse herunterladen", + portfolio: "Produktportfolio", + differentiators: "Alleinstellungsmerkmale", + targetIndustries: "Zielbranchen & Modell", + overlapScore: "Overlap Score", + }, + step5: { + title: "Schritt 5: Silver Bullets", + generating: "Positionierungsaussagen werden generiert...", + subtitle: "Dies sind prägnante Positionierungsaussagen, um Ihr Unternehmen im direkten Gespräch vom jeweiligen Wettbewerber abzugrenzen.", + cardTitle: "Gegenüber", + }, + step6: { + title: "Schritt 6: Vergleich & Fazit", + generating: "Fazit wird generiert...", + subtitle: "Zusammenfassende Analyse und strategische Einordnung.", + downloadButton: "Gesamtbericht laden", + downloadJson: "JSON herunterladen", + downloadMd: "Markdown (MD) herunterladen", + downloadPdf: "PDF herunterladen", + productMatrix: "Produkt-Matrix", + industryMatrix: "Branchen-Matrix", + summary: "Zusammenfassung & Positionierung", + opportunities: (name: string) => `Chancen & Lücken für ${name}`, + nextQuestions: "Nächste Fragen & Unsicherheiten", + markdown: { + title: "B2B Wettbewerbsanalyse", + startUrl: "Start-URL", + marketScope: "Marktfokus", + step1_title: "Schritt 1: Extraktion", + step1_products: "Produkte / Lösungen", + step1_industries: "Zielbranchen", + step4_title: "Schritt 4: Detaillierte Analyse", + portfolio: "Portfolio", + targetIndustries: "Zielbranchen", + differentiators: "Alleinstellungsmerkmale", + step5_title: "Schritt 5: Silver Bullets", + against: "Gegen", + step7_title: "Schritt 7: Sales Battlecards", + profile: "Profil", + focus: "Fokus", + positioning: "Positionierung", + strengthsVsWeaknesses: "Unsere Stärken vs. Ihre Schwächen", + landmineQuestions: '"Landminen"-Fragen', + silverBullet: "Silver Bullet", + step8_title: "Schritt 8: Referenzkunden-Analyse", + caseStudyLink: "Case Study Link", + noReferencesFound: "Keine Referenzen gefunden.", + sources: "Quellen für Referenz-Analyse", + step6_title: "Schritt 6: Fazit", + productMatrix: "Produkt-Matrix", + industryMatrix: "Branchen-Matrix", + summary: "Zusammenfassung & Positionierung", + opportunities: "Chancen & Lücken", + nextQuestions: "Nächste Fragen", + } + }, + step7: { + title: "Schritt 7: Sales Battlecards", + generating: "Battlecards werden generiert...", + subtitle: "Nutzen Sie diese \"Battlecards\" zur Vorbereitung auf Vertriebsgespräche. Jede Karte fasst die wichtigsten Argumente gegen einen spezifischen Wettbewerber zusammen.", + card: { + profile: "Competitor Profile", + strengths: "Our Strengths vs. Their Weaknesses", + landmines: "\"Landmine\" Questions to Ask", + silverBullet: "Silver Bullet", + } + }, + step8: { + title: "Schritt 8: Referenzkunden-Analyse", + subtitle: "Analyse der Testimonials und Case Studies der Wettbewerber, um deren Marktpräsenz und Erfolgsgeschichten zu verstehen. Die Ergebnisse basieren auf einer Google-Suche.", + noReferencesFound: "Keine öffentlichen Referenzkunden auf der offiziellen Website gefunden.", + caseStudyLink: "Case Study", + sourcesTitle: "Recherche-Quellen", + } + }, + en: { + appTitle: "B2B Competitor Analysis Agent", + restartAnalysis: "Restart Analysis", + nextStepButton: "Confirm & Next Step", + companyCard: { + title: "Initial Company", + }, + inputForm: { + title: "Start Competitor Analysis", + subtitle: "Enter a company's website to begin the analysis.", + startUrlLabel: "Company Start URL", + maxCompetitorsLabel: "Max Competitors", + marketScopeLabel: "Market Focus", + marketScopePlaceholder: "e.g., DACH, EU, global", + languageLabel: "Language", + submitButton: "Start Analysis", + }, + loadingSpinner: { + message: "AI is analyzing, please wait...", + }, + errors: { + title: "Error:", + step1: "Error analyzing the start URL. Please check the URL and try again.", + generic: (step: number) => `An error occurred in step ${step}. Please try again.`, + }, + stepIndicator: { + title: "Progress", + steps: ["Extraction", "Keywords", "Competitors", "Analysis", "Silver Bullets", "Conclusion", "Battlecards", "References"], + }, + step1: { + title: "Step 1: Company Information Extraction", + subtitle: "Review, edit, or add to the products and target industries extracted by the AI agent.", + addProductTitle: "Add New Product by URL", + productNameLabel: "Product Name", + productUrlLabel: "Product URL", + productNamePlaceholder: "e.g., mobileX-Dispatch", + addProductError: "Could not research product. Please check the URL.", + addButton: "Add Product", + addingButton: "Researching...", + productsTitle: "Products / Solutions", + purposeLabel: "Purpose Description", + industriesTitle: "Target Markets / Industries", + industryNameLabel: "Industry Name", + editableCard: { add: "Add", cancel: "Cancel", save: "Save" } + }, + step2: { + title: "Step 2: Derived Keywords", + subtitle: "Review and adjust the keywords generated for the competitor search if necessary.", + cardTitle: "Keyword Set", + termLabel: "Keyword / Phrase", + rationaleLabel: "Rationale", + editableCard: { add: "Add", cancel: "Cancel", save: "Save" } + }, + step3: { + title: "Step 3: Find Competitors", + subtitle: (max: number) => `Here is the longlist of potential competitors. Remove or add entries. The top ${max} by confidence will be shortlisted for detailed analysis.`, + cardTitle: "Competitor Candidates", + nameLabel: "Name", + whyLabel: "Justification", + visitButton: "Visit", + shortlistBoundary: "SHORTLIST BOUNDARY", + editableCard: { add: "Add", cancel: "Cancel", save: "Save" } + }, + step4: { + title: "Step 4: Portfolio & Positioning Analysis", + subtitle: "Detailed analysis of the shortlisted competitors. The most relevant (highest overlap) are at the top.", + downloadJson_title: "Download Analysis", + portfolio: "Product Portfolio", + differentiators: "Differentiators", + targetIndustries: "Target Industries & Model", + overlapScore: "Overlap Score", + }, + step5: { + title: "Step 5: Silver Bullets", + generating: "Generating positioning statements...", + subtitle: "These are concise positioning statements to differentiate your company from each competitor in direct conversation.", + cardTitle: "Against", + }, + step6: { + title: "Step 6: Comparison & Conclusion", + generating: "Generating conclusion...", + subtitle: "Summary analysis and strategic classification.", + downloadButton: "Download Full Report", + downloadJson: "Download JSON", + downloadMd: "Download Markdown (MD)", + downloadPdf: "Download PDF", + productMatrix: "Product Matrix", + industryMatrix: "Industry Matrix", + summary: "Summary & Positioning", + opportunities: (name: string) => `Opportunities & Gaps for ${name}`, + nextQuestions: "Next Questions & Uncertainties", + markdown: { + title: "B2B Competitor Analysis", + startUrl: "Start URL", + marketScope: "Market Focus", + step1_title: "Step 1: Extraction", + step1_products: "Products / Solutions", + step1_industries: "Target Industries", + step4_title: "Step 4: Detailed Analysis", + portfolio: "Portfolio", + targetIndustries: "Target Industries", + differentiators: "Differentiators", + step5_title: "Step 5: Silver Bullets", + against: "Against", + step7_title: "Step 7: Sales Battlecards", + profile: "Profile", + focus: "Focus", + positioning: "Positioning", + strengthsVsWeaknesses: "Our Strengths vs. Their Weaknesses", + landmineQuestions: '"Landmine" Questions', + silverBullet: "Silver Bullet", + step8_title: "Step 8: Reference Customer Analysis", + caseStudyLink: "Case Study Link", + noReferencesFound: "No references found.", + sources: "Sources for Reference Analysis", + step6_title: "Step 6: Conclusion", + productMatrix: "Product Matrix", + industryMatrix: "Industry Matrix", + summary: "Summary & Positioning", + opportunities: "Opportunities & Gaps", + nextQuestions: "Next Questions", + } + }, + step7: { + title: "Step 7: Sales Battlecards", + generating: "Generating battlecards...", + subtitle: "Use these \"Battlecards\" to prepare for sales conversations. Each card summarizes the key arguments against a specific competitor.", + card: { + profile: "Competitor Profile", + strengths: "Our Strengths vs. Their Weaknesses", + landmines: "\"Landmine\" Questions to Ask", + silverBullet: "Silver Bullet", + } + }, + step8: { + title: "Step 8: Reference Customer Analysis", + subtitle: "Analysis of competitor testimonials and case studies to understand their market presence and success stories. The results are based on a Google search.", + noReferencesFound: "No public reference customers found on the official website.", + caseStudyLink: "Case Study", + sourcesTitle: "Research Sources", + } + } +}; \ No newline at end of file diff --git a/competitor-analysis/tsconfig.json b/competitor-analysis/tsconfig.json new file mode 100644 index 00000000..2c6eed55 --- /dev/null +++ b/competitor-analysis/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "skipLibCheck": true, + "types": [ + "node" + ], + "moduleResolution": "bundler", + "isolatedModules": true, + "moduleDetection": "force", + "allowJs": true, + "jsx": "react-jsx", + "paths": { + "@/*": [ + "./*" + ] + }, + "allowImportingTsExtensions": true, + "noEmit": true + } +} \ No newline at end of file diff --git a/competitor-analysis/types.ts b/competitor-analysis/types.ts new file mode 100644 index 00000000..4ce6109d --- /dev/null +++ b/competitor-analysis/types.ts @@ -0,0 +1,120 @@ + + +export interface Evidence { + url: string; + snippet: string; +} + +export interface Product { + name: string; + purpose: string; + evidence: Evidence[]; +} + +export interface TargetIndustry { + name: string; + evidence: Evidence[]; +} + +export interface Keyword { + term: string; + rationale: string; +} + +export interface CompetitorCandidate { + name: string; + url: string; + confidence: number; + why: string; + evidence: Evidence[]; +} + +export interface ShortlistedCompetitor { + name: string; + url: string; +} + +export interface Analysis { + competitor: { + name: string; + url: string; + }; + portfolio: { + product: string; + purpose: string; + }[]; + target_industries: string[]; + delivery_model: string; + overlap_score: number; + differentiators: string[]; + evidence: Evidence[]; +} + +export interface SilverBullet { + competitor_name: string; + statement: string; +} + +export interface Conclusion { + product_matrix: { + product: string; + availability: { competitor: string; has_offering: boolean; }[]; + }[]; + industry_matrix: { + industry: string; + availability: { competitor: string; has_offering: boolean; }[]; + }[]; + overlap_scores: { competitor: string; score: number }[]; + summary: string; + opportunities: string; + next_questions: string[]; +} + +export interface Battlecard { + competitor_name: string; + competitor_profile: { + focus: string; + positioning: string; + }; + strengths_vs_weaknesses: string[]; + landmine_questions: string[]; + silver_bullet: string; +} + +export interface ReferenceCustomer { + name: string; + industry: string; + testimonial_snippet: string; + case_study_url: string; +} + +export interface ReferenceAnalysis { + competitor_name: string; + references: ReferenceCustomer[]; +} + + +export interface AppState { + step: number; + initial_params: { + start_url: string; + max_competitors: number; + market_scope: string; + language: 'de' | 'en'; + }; + company: { + name: string; + start_url: string; + }; + products: Product[]; + target_industries: TargetIndustry[]; + keywords: Keyword[]; + competitor_candidates: CompetitorCandidate[]; + competitors_shortlist: ShortlistedCompetitor[]; + analyses: Analysis[]; + silver_bullets: SilverBullet[]; + conclusion: Conclusion | null; + battlecards: Battlecard[]; + reference_analysis: ReferenceAnalysis[]; + reference_analysis_grounding: any[]; +} \ No newline at end of file diff --git a/competitor-analysis/vite.config.ts b/competitor-analysis/vite.config.ts new file mode 100644 index 00000000..ee5fb8d2 --- /dev/null +++ b/competitor-analysis/vite.config.ts @@ -0,0 +1,23 @@ +import path from 'path'; +import { defineConfig, loadEnv } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, '.', ''); + return { + server: { + port: 3000, + host: '0.0.0.0', + }, + plugins: [react()], + define: { + 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY), + 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY) + }, + resolve: { + alias: { + '@': path.resolve(__dirname, '.'), + } + } + }; +});