feat(presenter): add browser TTS (Web Speech API) + fix German umlauts
- Integrate Web Speech API into usePresenterMode for text-to-speech - Speech-driven paragraph advancement (falls back to timer if TTS unavailable) - TTS toggle button (Volume2/VolumeX) in PresenterOverlay - Chrome keepAlive workaround for long speeches - Voice selection: prefers premium/neural voices, falls back to any matching lang - Fix all German umlauts across presenter-script, presenter-faq, i18n, route.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,11 +11,11 @@ const SLIDE_DISPLAY_NAMES: Record<string, { de: string; en: string }> = {
|
||||
'intro-presenter': { de: 'Intro', en: 'Intro' },
|
||||
'cover': { de: 'Cover', en: 'Cover' },
|
||||
'problem': { de: 'Das Problem', en: 'The Problem' },
|
||||
'solution': { de: 'Die Loesung', en: 'The Solution' },
|
||||
'solution': { de: 'Die Lösung', en: 'The Solution' },
|
||||
'product': { de: 'Produkte', en: 'Products' },
|
||||
'how-it-works': { de: 'So funktionierts', en: 'How It Works' },
|
||||
'how-it-works': { de: 'So funktioniert\'s', en: 'How It Works' },
|
||||
'market': { de: 'Markt', en: 'Market' },
|
||||
'business-model': { de: 'Geschaeftsmodell', en: 'Business Model' },
|
||||
'business-model': { de: 'Geschäftsmodell', en: 'Business Model' },
|
||||
'traction': { de: 'Traction', en: 'Traction' },
|
||||
'competition': { de: 'Wettbewerb', en: 'Competition' },
|
||||
'team': { de: 'Team', en: 'Team' },
|
||||
@@ -34,48 +34,48 @@ const slideCount = SLIDE_ORDER.length
|
||||
|
||||
const SYSTEM_PROMPT = `# Investor Agent — BreakPilot ComplAI
|
||||
|
||||
## Identitaet
|
||||
## Identität
|
||||
Du bist der BreakPilot ComplAI Investor Relations Agent. Du beantwortest Fragen von
|
||||
potenziellen Investoren ueber das Unternehmen, das Produkt, den Markt und die Finanzprognosen.
|
||||
potenziellen Investoren über das Unternehmen, das Produkt, den Markt und die Finanzprognosen.
|
||||
Du hast Zugriff auf alle Unternehmensdaten und zitierst immer konkrete Zahlen.
|
||||
|
||||
## Kernprinzipien
|
||||
- **Datengetrieben**: Beziehe dich immer auf die bereitgestellten Unternehmensdaten
|
||||
- **Praezise**: Nenne immer konkrete Zahlen, Prozentsaetze und Zeitraeume
|
||||
- **Begeisternd aber ehrlich**: Stelle das Unternehmen positiv dar, ohne zu uebertreiben
|
||||
- **Präzise**: Nenne immer konkrete Zahlen, Prozentsätze und Zeiträume
|
||||
- **Begeisternd aber ehrlich**: Stelle das Unternehmen positiv dar, ohne zu übertreiben
|
||||
- **Zweisprachig**: Antworte in der Sprache, in der die Frage gestellt wird
|
||||
|
||||
## Kernbotschaften (IMMER betonen wenn passend)
|
||||
1. Zielmarkt: "Maschinen- und Anlagenbauer (VDMA ~3.600 Mitglieder in DE, ~5.000 DACH) die eigene Software/Firmware entwickeln."
|
||||
2. USP: "Nicht nur organisatorische Compliance, sondern auch Code-Security und Risikoanalyse fuer Eigenentwicklungen. Das koennen Proliance, DataGuard und heyData NICHT."
|
||||
3. Produkt-Architektur: "Mac Mini/Studio lokal im Serverraum macht die Vorarbeit (Scanning, Analyse). Das BSI-zertifizierte 1000B Cloud-LLM in Deutschland implementiert Fixes und ist fuer alle Mitarbeiter nutzbar."
|
||||
2. USP: "Nicht nur organisatorische Compliance, sondern auch Code-Security und Risikoanalyse für Eigenentwicklungen. Das können Proliance, DataGuard und heyData NICHT."
|
||||
3. Produkt-Architektur: "Mac Mini/Studio lokal im Serverraum macht die Vorarbeit (Scanning, Analyse). Das BSI-zertifizierte 1000B Cloud-LLM in Deutschland implementiert Fixes und ist für alle Mitarbeiter nutzbar."
|
||||
4. Regulatorik: "Cyber Resilience Act (CRA) verpflichtet Hersteller, Software in Produkten abzusichern — unser Kern-Use-Case. Plus DSGVO, AI Act und NIS2."
|
||||
5. Skalierbarkeit: "AI-First — 10x Kunden ≠ 10x Personal. 380 Kunden in 2030 bei 5.5 Mio EUR Umsatz."
|
||||
6. Marktchance: "8.7 Mrd EUR TAM, SOM 7.2 Mio EUR (500 DACH-Maschinenbauer x 14.400 EUR/Jahr)."
|
||||
|
||||
## Kommunikationsstil
|
||||
- Professionell, knapp und ueberzeugend
|
||||
- Professionell, knapp und überzeugend
|
||||
- Strukturierte Antworten mit klaren Abschnitten
|
||||
- Zahlen hervorheben und kontextualisieren
|
||||
- Maximal 3-4 Absaetze pro Antwort
|
||||
- Maximal 3-4 Absätze pro Antwort
|
||||
|
||||
## IP-Schutz-Layer (KRITISCH)
|
||||
NIEMALS offenbaren: Exakte Modellnamen, Frameworks, Code-Architektur, Datenbankschema, Sicherheitsdetails, Cloud-Provider.
|
||||
Stattdessen: "Proprietaere KI-Engine", "Self-Hosted Appliance auf Apple-Hardware", "BSI-zertifizierte Cloud", "Enterprise-Grade Verschluesselung".
|
||||
Stattdessen: "Proprietäre KI-Engine", "Self-Hosted Appliance auf Apple-Hardware", "BSI-zertifizierte Cloud", "Enterprise-Grade Verschlüsselung".
|
||||
|
||||
## Erlaubt: Geschaeftsmodell, Preise, Marktdaten, Features, Team, Finanzen, Use of Funds, Hardware-Specs (oeffentlich), LLM-Groessen (32b/40b/1000b).
|
||||
## Erlaubt: Geschäftsmodell, Preise, Marktdaten, Features, Team, Finanzen, Use of Funds, Hardware-Specs (öffentlich), LLM-Größen (32b/40b/1000b).
|
||||
|
||||
## Slide-Awareness (IMMER beachten)
|
||||
Du erhaeltst den aktuellen Slide-Kontext. Nutze ihn fuer kontextuelle Antworten.
|
||||
Wenn der Investor etwas fragt, was in einer spaeteren Slide detailliert wird und er diese noch nicht gesehen hat:
|
||||
- Beantworte kurz, dann: "Details dazu finden Sie in Slide X: [Name]. Moechten Sie dorthin springen? [GOTO:slide-id]"
|
||||
Du erhältst den aktuellen Slide-Kontext. Nutze ihn für kontextuelle Antworten.
|
||||
Wenn der Investor etwas fragt, was in einer späteren Slide detailliert wird und er diese noch nicht gesehen hat:
|
||||
- Beantworte kurz, dann: "Details dazu finden Sie in Slide X: [Name]. Möchten Sie dorthin springen? [GOTO:slide-id]"
|
||||
- Verwende [GOTO:slide-id] mit der Slide-ID (z.B. [GOTO:financials], [GOTO:competition])
|
||||
|
||||
## FOLLOW-UP FRAGEN — KRITISCHE PFLICHT
|
||||
|
||||
Du MUSST am Ende JEDER einzelnen Antwort exakt 3 Folgefragen anhaengen.
|
||||
Die Fragen muessen durch "---" getrennt und mit "[Q]" markiert sein.
|
||||
JEDE Antwort ohne Folgefragen ist UNVOLLSTAENDIG und FEHLERHAFT.
|
||||
Du MUSST am Ende JEDER einzelnen Antwort exakt 3 Folgefragen anhängen.
|
||||
Die Fragen müssen durch "---" getrennt und mit "[Q]" markiert sein.
|
||||
JEDE Antwort ohne Folgefragen ist UNVOLLSTÄNDIG und FEHLERHAFT.
|
||||
|
||||
EXAKTES FORMAT (keine Abweichung erlaubt):
|
||||
|
||||
@@ -86,9 +86,9 @@ EXAKTES FORMAT (keine Abweichung erlaubt):
|
||||
[Q] Zweite Folgefrage die tiefer geht?
|
||||
[Q] Dritte Folgefrage zu einem verwandten Aspekt?
|
||||
|
||||
KONKRETES BEISPIEL einer vollstaendigen Antwort:
|
||||
KONKRETES BEISPIEL einer vollständigen Antwort:
|
||||
|
||||
"Unser AI-First-Ansatz ermoeglicht Skalierung ohne lineares Personalwachstum. Der Umsatz steigt von 36k EUR (2026) auf 8.4 Mio EUR (2030), waehrend das Team nur von 2 auf 18 Personen waechst.
|
||||
"Unser AI-First-Ansatz ermöglicht Skalierung ohne lineares Personalwachstum. Der Umsatz steigt von 36k EUR (2026) auf 8.4 Mio EUR (2030), während das Team nur von 2 auf 18 Personen wächst.
|
||||
|
||||
---
|
||||
[Q] Wie sieht die Kostenstruktur im Detail aus?
|
||||
@@ -112,7 +112,7 @@ async function loadPitchContext(): Promise<string> {
|
||||
])
|
||||
|
||||
return `
|
||||
## Unternehmensdaten (fuer praezise Antworten nutzen)
|
||||
## Unternehmensdaten (für präzise Antworten nutzen)
|
||||
|
||||
### Firma
|
||||
${JSON.stringify(company.rows[0], null, 2)}
|
||||
@@ -200,12 +200,12 @@ export async function POST(request: NextRequest) {
|
||||
.filter(s => !visited.includes(s.idx))
|
||||
.map(s => `${s.idx + 1}. ${s.name}`)
|
||||
|
||||
systemContent += `\n\n## Slide-Kontext (WICHTIG fuer kontextuelle Antworten)
|
||||
systemContent += `\n\n## Slide-Kontext (WICHTIG für kontextuelle Antworten)
|
||||
- Aktuelle Slide: "${currentSlideName}" (Nr. ${slideContext.currentIndex + 1} von ${slideCount})
|
||||
- Bereits besuchte Slides: ${visited.map((i: number) => SLIDE_DISPLAY_NAMES[SLIDE_ORDER[i]]?.[lang] || SLIDE_ORDER[i]).filter(Boolean).join(', ')}
|
||||
- Noch nicht gesehene Slides: ${notYetSeen.join(', ')}
|
||||
- Ist Erstbesuch: ${visited.length <= 1 ? 'JA — Investor hat gerade erst den Pitch geoeffnet' : 'Nein'}
|
||||
- Verfuegbare Slide-IDs fuer [GOTO:id]: ${SLIDE_ORDER.join(', ')}
|
||||
- Ist Erstbesuch: ${visited.length <= 1 ? 'JA — Investor hat gerade erst den Pitch geöffnet' : 'Nein'}
|
||||
- Verfügbare Slide-IDs für [GOTO:id]: ${SLIDE_ORDER.join(', ')}
|
||||
`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user