Spaces:
Running
Running
| <html lang="de" class="scroll-smooth"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Agentic Supply Chain Showcase | valantic & databricks</title> | |
| <!-- Tailwind CSS --> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <!-- Tailwind Configuration --> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| brand: { | |
| dark: '#1c1b3d', // valantic inspired dark blue | |
| light: '#2a2859', | |
| accent: '#ff3621', // databricks inspired red | |
| accentHover: '#e02814' | |
| } | |
| }, | |
| fontFamily: { | |
| sans: ['Inter', 'system-ui', 'sans-serif'], | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <!-- Lucide Icons --> | |
| <script src="https://unpkg.com/lucide@latest"></script> | |
| <style> | |
| /* Custom animations */ | |
| .fade-in-up { | |
| animation: fadeInUp 0.8s ease-out forwards; | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| @keyframes fadeInUp { | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .chat-message { | |
| animation: popIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; | |
| opacity: 0; | |
| transform: scale(0.95); | |
| transform-origin: top left; | |
| } | |
| @keyframes popIn { | |
| to { opacity: 1; transform: scale(1); } | |
| } | |
| .typing-indicator span { | |
| animation: blink 1.4s infinite both; | |
| height: 6px; | |
| width: 6px; | |
| background: #94a3b8; /* Slate-400 for light mode */ | |
| border-radius: 50%; | |
| display: inline-block; | |
| margin: 0 1px; | |
| } | |
| .typing-indicator span:nth-child(2) { animation-delay: 0.2s; } | |
| .typing-indicator span:nth-child(3) { animation-delay: 0.4s; } | |
| @keyframes blink { | |
| 0% { opacity: 0.2; transform: scale(0.8); } | |
| 20% { opacity: 1; transform: scale(1.2); } | |
| 100% { opacity: 0.2; transform: scale(0.8); } | |
| } | |
| /* Map Pin Animations */ | |
| .pin-active .ping { | |
| animation: ping 1.5s cubic-bezier(0, 0, 0.2, 1) infinite; | |
| } | |
| @keyframes ping { | |
| 75%, 100% { transform: scale(2.5); opacity: 0; } | |
| } | |
| .delay-100 { animation-delay: 100ms; } | |
| .delay-200 { animation-delay: 200ms; } | |
| .delay-300 { animation-delay: 300ms; } | |
| /* Scrollbar styling for chat */ | |
| .chat-scroll::-webkit-scrollbar { width: 6px; } | |
| .chat-scroll::-webkit-scrollbar-track { background: transparent; } | |
| .chat-scroll::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; } | |
| .chat-scroll::-webkit-scrollbar-thumb:hover { background: #94a3b8; } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 text-gray-800 font-sans antialiased"> | |
| <!-- Navigation --> | |
| <nav class="fixed w-full z-50 bg-white/90 backdrop-blur-md shadow-sm"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div class="flex justify-between h-20 items-center"> | |
| <div class="flex items-center gap-4"> | |
| <span class="text-2xl font-extrabold text-brand-dark tracking-tight">valantic</span> | |
| <span class="text-gray-300">|</span> | |
| <span class="text-xl font-bold text-brand-accent tracking-tight">databricks</span> | |
| </div> | |
| <div class="hidden md:flex space-x-8"> | |
| <a href="#problem-loesung" class="text-gray-600 hover:text-brand-accent font-medium transition-colors">Die Challenge</a> | |
| <a href="#showcase" class="text-gray-600 hover:text-brand-accent font-medium transition-colors">Interactive Demo</a> | |
| <a href="#architektur" class="text-gray-600 hover:text-brand-accent font-medium transition-colors">Architektur</a> | |
| </div> | |
| <div class="hidden md:flex"> | |
| <a href="#showcase" class="bg-brand-accent hover:bg-brand-accentHover text-white px-6 py-2.5 rounded-full font-semibold transition-all shadow-md hover:shadow-lg"> | |
| Zum Showcase | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <!-- Section 1: Hero Area --> | |
| <section class="relative pt-32 pb-20 lg:pt-48 lg:pb-32 overflow-hidden bg-brand-dark text-white"> | |
| <div class="absolute inset-0 z-0"> | |
| <div class="absolute inset-0 bg-gradient-to-r from-brand-dark via-brand-dark/90 to-brand-light/80 z-10"></div> | |
| <img src="https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?q=80&w=2070&auto=format&fit=crop" alt="Supply Chain Background" class="w-full h-full object-cover opacity-50 mix-blend-overlay" /> | |
| </div> | |
| <div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"> | |
| <div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 text-sm font-medium mb-8 fade-in-up"> | |
| <i data-lucide="sparkles" class="w-4 h-4 text-brand-accent"></i> | |
| IPAI KI-Festival 2026 | |
| </div> | |
| <h1 class="text-4xl md:text-6xl lg:text-7xl font-extrabold tracking-tight mb-6 fade-in-up delay-100"> | |
| Proaktives Supply-Chain <br class="hidden md:block" /> | |
| Management mit <span class="text-transparent bg-clip-text bg-gradient-to-r from-brand-accent to-orange-400">Agentic AI</span>. | |
| </h1> | |
| <p class="mt-4 text-xl md:text-2xl text-gray-300 max-w-3xl mx-auto mb-10 fade-in-up delay-200"> | |
| Erleben Sie die nächste Stufe der Automatisierung: Hybrid Intelligence auf der Databricks Data Intelligence Platform. | |
| </p> | |
| <div class="flex flex-col sm:flex-row justify-center gap-4 fade-in-up delay-300"> | |
| <button onclick="document.getElementById('showcase').scrollIntoView({behavior: 'smooth'})" class="bg-brand-accent hover:bg-brand-accentHover text-white px-8 py-4 rounded-full font-bold text-lg transition-all shadow-lg hover:shadow-brand-accent/30 flex items-center justify-center gap-2 cursor-pointer"> | |
| Interaktive Demo starten | |
| <i data-lucide="play" class="w-5 h-5"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Section 2: Problem vs. Lösung --> | |
| <section id="problem-loesung" class="py-24 bg-white"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div class="text-center mb-16"> | |
| <h2 class="text-3xl md:text-4xl font-bold text-brand-dark mb-4">Statische Regeln treffen auf eine chaotische Welt</h2> | |
| <div class="w-24 h-1 bg-brand-accent mx-auto rounded-full"></div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-12 lg:gap-24"> | |
| <div class="space-y-8"> | |
| <div class="flex items-center gap-3 mb-6"> | |
| <div class="w-12 h-12 rounded-full bg-red-100 flex items-center justify-center text-red-600"><i data-lucide="alert-triangle" class="w-6 h-6"></i></div> | |
| <h3 class="text-2xl font-bold text-gray-900">Die Challenge</h3> | |
| </div> | |
| <div class="bg-gray-50 p-6 rounded-2xl border border-gray-100"><div class="flex gap-4"><i data-lucide="database" class="w-6 h-6 text-gray-500 mt-1"></i><div><h4 class="font-bold text-gray-900 mb-2">Informations-Silos</h4><p class="text-gray-600">Supply Chain Manager müssen statische Vertragsdaten und dynamische Echtzeit-Ereignisse manuell abgleichen.</p></div></div></div> | |
| <div class="bg-gray-50 p-6 rounded-2xl border border-gray-100"><div class="flex gap-4"><i data-lucide="git-network" class="w-6 h-6 text-gray-500 mt-1"></i><div><h4 class="font-bold text-gray-900 mb-2">Hohe Komplexität</h4><p class="text-gray-600">Unterschiedliche Produkte haben unterschiedliche Toleranzgrenzen. Was für Produkt A kritisch ist, ist für B irrelevant.</p></div></div></div> | |
| <div class="bg-gray-50 p-6 rounded-2xl border border-gray-100"><div class="flex gap-4"><i data-lucide="clock" class="w-6 h-6 text-gray-500 mt-1"></i><div><h4 class="font-bold text-gray-900 mb-2">Reaktives Handeln</h4><p class="text-gray-600">Risiken werden oft erst erkannt, wenn der Schaden an sensiblen Gütern bereits eingetreten ist.</p></div></div></div> | |
| </div> | |
| <div class="space-y-8"> | |
| <div class="flex items-center gap-3 mb-6"> | |
| <div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center text-green-600"><i data-lucide="check-circle" class="w-6 h-6"></i></div> | |
| <h3 class="text-2xl font-bold text-gray-900">Der Customer Benefit</h3> | |
| </div> | |
| <div class="bg-blue-50/50 p-6 rounded-2xl border border-blue-100"><div class="flex gap-4"><i data-lucide="monitor" class="w-6 h-6 text-brand-accent mt-1"></i><div><h4 class="font-bold text-gray-900 mb-2">Single Pane of Glass</h4><p class="text-gray-600">Konsolidierung von unstrukturiertem Firmenwissen und weltweiten Live-Daten in einer einzigen Schnittstelle.</p></div></div></div> | |
| <div class="bg-blue-50/50 p-6 rounded-2xl border border-blue-100"><div class="flex gap-4"><i data-lucide="shield-check" class="w-6 h-6 text-brand-accent mt-1"></i><div><h4 class="font-bold text-gray-900 mb-2">Proaktives Risikomanagement</h4><p class="text-gray-600">Das System warnt, bevor ein Schaden entsteht ("Präventiver Alarm"), indem es Wettervorhersagen gegen Produkt-Toleranzen prüft.</p></div></div></div> | |
| <div class="bg-blue-50/50 p-6 rounded-2xl border border-blue-100"><div class="flex gap-4"><i data-lucide="bot" class="w-6 h-6 text-brand-accent mt-1"></i><div><h4 class="font-bold text-gray-900 mb-2">Automatisierte Entscheidungsfindung</h4><p class="text-gray-600">24/7 Überwachung globaler Lieferketten. Der Agent empfiehlt direkt die korrekte Maßnahme.</p></div></div></div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Section 3: Interactive Map & Showcase --> | |
| <section id="showcase" class="py-24 bg-brand-dark text-white overflow-hidden"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div class="mb-12 text-center"> | |
| <span class="text-brand-accent font-semibold tracking-wider uppercase text-sm">Interaktive Demo</span> | |
| <h2 class="text-3xl md:text-5xl font-bold mt-2 mb-4 text-white">Agentic Control Center</h2> | |
| <p class="text-xl text-gray-300 max-w-3xl mx-auto">Wählen Sie ein aktives Transportszenario auf der Weltkarte, um zu sehen, wie das Multi-Agent System die Route in Echtzeit überwacht und schützt.</p> | |
| </div> | |
| <div class="grid grid-cols-1 xl:grid-cols-12 gap-8 items-start"> | |
| <!-- LEFT: Interactive Map (Light Mode) --> | |
| <div class="xl:col-span-5 bg-white border border-gray-200 rounded-2xl p-6 shadow-2xl relative overflow-hidden flex flex-col h-[650px] text-gray-900"> | |
| <h3 class="font-bold text-xl mb-4 flex items-center gap-2"> | |
| <i data-lucide="globe" class="text-brand-accent"></i> Global Routes | |
| </h3> | |
| <!-- Map Container --> | |
| <div class="relative flex-1 bg-slate-50 rounded-xl border border-slate-200 overflow-hidden mb-6 shadow-inner"> | |
| <!-- Generic abstract map background (Dark SVG works well on light BG with low opacity) --> | |
| <img src="https://upload.wikimedia.org/wikipedia/commons/8/80/World_map_-_low_resolution.svg" class="absolute inset-0 w-full h-full object-contain opacity-30 p-4 pointer-events-none" alt="World Map"> | |
| <!-- Connecting Lines (SVG) --> | |
| <svg class="absolute inset-0 w-full h-full pointer-events-none" id="map-lines"> | |
| <!-- Default line color is now slate-400 (#94a3b8) for light mode --> | |
| <path d="M 50% 35% L 75% 65%" stroke="#94a3b8" stroke-width="2" stroke-dasharray="4" class="route-line transition-colors duration-300" id="line-singapur"></path> | |
| <path d="M 50% 35% L 52% 20%" stroke="#94a3b8" stroke-width="2" stroke-dasharray="4" class="route-line transition-colors duration-300" id="line-oslo"></path> | |
| <path d="M 50% 35% L 62% 48%" stroke="#94a3b8" stroke-width="2" stroke-dasharray="4" class="route-line transition-colors duration-300" id="line-dubai"></path> | |
| </svg> | |
| <!-- HQ Pin (Frankfurt) --> | |
| <div class="absolute w-4 h-4 rounded-full bg-brand-dark z-20 shadow-[0_0_15px_rgba(28,27,61,0.5)]" style="top: 35%; left: 50%; transform: translate(-50%, -50%);"> | |
| <span class="absolute top-5 left-1/2 -translate-x-1/2 text-xs font-bold bg-white text-brand-dark px-2 py-0.5 rounded shadow-md border border-gray-200 whitespace-nowrap">HQ (FRA)</span> | |
| </div> | |
| <!-- Target Pins --> | |
| <!-- 1. Singapur --> | |
| <button onclick="playScenario('singapur')" id="pin-singapur" class="absolute w-5 h-5 rounded-full bg-brand-accent z-20 cursor-pointer transition-transform hover:scale-125 focus:outline-none pin-active group" style="top: 65%; left: 75%; transform: translate(-50%, -50%);"> | |
| <span class="absolute inset-0 rounded-full bg-brand-accent ping opacity-75"></span> | |
| <span class="absolute top-6 left-1/2 -translate-x-1/2 text-xs font-bold bg-white text-gray-800 px-2 py-1 rounded shadow-md border border-gray-200 whitespace-nowrap transition-colors group-hover:text-brand-accent">Singapur</span> | |
| </button> | |
| <!-- 2. Oslo --> | |
| <button onclick="playScenario('oslo')" id="pin-oslo" class="absolute w-5 h-5 rounded-full bg-gray-400 z-20 cursor-pointer transition-transform hover:scale-125 focus:outline-none group" style="top: 20%; left: 52%; transform: translate(-50%, -50%);"> | |
| <span class="absolute inset-0 rounded-full bg-brand-accent ping opacity-0"></span> | |
| <span class="absolute top-6 left-1/2 -translate-x-1/2 text-xs font-bold bg-white text-gray-800 px-2 py-1 rounded shadow-md border border-gray-200 whitespace-nowrap transition-colors group-hover:text-brand-accent">Oslo</span> | |
| </button> | |
| <!-- 3. Dubai --> | |
| <button onclick="playScenario('dubai')" id="pin-dubai" class="absolute w-5 h-5 rounded-full bg-gray-400 z-20 cursor-pointer transition-transform hover:scale-125 focus:outline-none group" style="top: 48%; left: 62%; transform: translate(-50%, -50%);"> | |
| <span class="absolute inset-0 rounded-full bg-brand-accent ping opacity-0"></span> | |
| <span class="absolute top-6 left-1/2 -translate-x-1/2 text-xs font-bold bg-white text-gray-800 px-2 py-1 rounded shadow-md border border-gray-200 whitespace-nowrap transition-colors group-hover:text-brand-accent">Dubai</span> | |
| </button> | |
| </div> | |
| <!-- Selected Scenario Info --> | |
| <div class="bg-slate-50 rounded-xl p-5 border border-slate-200 min-h-[160px]"> | |
| <div class="flex justify-between items-start mb-2"> | |
| <h4 id="info-title" class="font-bold text-lg text-gray-900">Lade Szenario...</h4> | |
| <span id="info-badge" class="bg-yellow-100 text-yellow-800 text-xs px-2 py-1 rounded border border-yellow-200 font-medium">Class II</span> | |
| </div> | |
| <p id="info-desc" class="text-sm text-gray-600 leading-relaxed mb-4"> | |
| Bitte wählen Sie eine Route aus. | |
| </p> | |
| <button onclick="startSimulation()" id="btn-simulate" class="w-full bg-brand-dark hover:bg-brand-light transition-colors text-white py-2 rounded-lg text-sm font-semibold flex justify-center items-center gap-2 shadow-md"> | |
| <i data-lucide="refresh-cw" class="w-4 h-4"></i> Überwachung starten | |
| </button> | |
| </div> | |
| </div> | |
| <!-- RIGHT: Visuals / Databricks UI Mockup (Light Mode) --> | |
| <div class="xl:col-span-7 relative h-[650px]"> | |
| <!-- Outer subtle glow --> | |
| <div class="absolute -inset-1 bg-gradient-to-r from-brand-accent to-orange-400 rounded-2xl blur opacity-15"></div> | |
| <div class="relative bg-white rounded-2xl border border-gray-200 shadow-2xl overflow-hidden h-full flex flex-col"> | |
| <!-- Browser Header --> | |
| <div class="bg-slate-50 px-4 py-3 flex items-center justify-between border-b border-slate-200 z-10 shrink-0"> | |
| <div class="flex items-center gap-2"> | |
| <div class="flex gap-1.5 mr-4"> | |
| <div class="w-3 h-3 rounded-full bg-red-400"></div> | |
| <div class="w-3 h-3 rounded-full bg-yellow-400"></div> | |
| <div class="w-3 h-3 rounded-full bg-green-400"></div> | |
| </div> | |
| <div class="bg-white border border-gray-200 shadow-sm text-xs text-gray-600 px-3 py-1.5 rounded-md flex items-center gap-2 font-mono"> | |
| <i data-lucide="layers" class="w-3 h-3 text-brand-accent"></i> Databricks Agent Playground | |
| </div> | |
| </div> | |
| <div class="text-xs font-mono text-gray-500 flex items-center gap-2 bg-blue-50 text-blue-700 px-2 py-1 rounded-md border border-blue-100"> | |
| <i data-lucide="user-check" class="w-3 h-3"></i> Human-in-the-Loop Active | |
| </div> | |
| </div> | |
| <!-- Chat Area --> | |
| <div class="flex-1 overflow-y-auto p-6 space-y-6 chat-scroll bg-slate-50/50" id="chat-container"> | |
| <!-- Chat content will be injected here by JS --> | |
| </div> | |
| <!-- Typing Input Bar Mockup --> | |
| <div class="bg-white p-4 border-t border-slate-200 shrink-0"> | |
| <div class="bg-slate-50 rounded-lg p-3 flex items-center gap-3 border border-slate-200 text-gray-400"> | |
| <i data-lucide="terminal" class="w-5 h-5"></i> | |
| <span class="text-sm font-mono">Agentic Supervisor is standing by...</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Section 4: Architektur --> | |
| <section id="architektur" class="py-24 bg-gray-50"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div class="text-center mb-16"> | |
| <h2 class="text-3xl md:text-4xl font-bold text-brand-dark mb-4">Wie denkt das Multi-Agent System?</h2> | |
| <p class="text-xl text-gray-600 max-w-2xl mx-auto">Die Architektur orchestriert spezialisierte Agenten, um komplexe Probleme in Sekunden zu lösen.</p> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-8"> | |
| <div class="bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl transition-all hover:-translate-y-1 group"><div class="w-14 h-14 bg-brand-dark text-white rounded-xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform"><i data-lucide="brain-circuit" class="w-7 h-7"></i></div><h3 class="text-xl font-bold text-gray-900 mb-3">Supervisor Agent</h3><p class="text-sm text-brand-accent font-semibold mb-3">Orchestration Layer</p><p class="text-gray-600">Einsatz eines Databricks Supervisor Agent, der komplexe Anfragen zerlegt und logisch an spezialisierte Sub-Agenten delegiert.</p></div> | |
| <div class="bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl transition-all hover:-translate-y-1 group"><div class="w-14 h-14 bg-blue-100 text-blue-600 rounded-xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform"><i data-lucide="book-open-check" class="w-7 h-7"></i></div><h3 class="text-xl font-bold text-gray-900 mb-3">Knowledge Assistant</h3><p class="text-sm text-blue-600 font-semibold mb-3">"Der Anwalt" (RAG)</p><p class="text-gray-600">Zuständig für statische Daten und Compliance. Nutzt Databricks Vector Search auf dem Unity Catalog, um SLAs und Verträge zu prüfen.</p></div> | |
| <div class="bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl transition-all hover:-translate-y-1 group"><div class="w-14 h-14 bg-green-100 text-green-600 rounded-xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform"><i data-lucide="radar" class="w-7 h-7"></i></div><h3 class="text-xl font-bold text-gray-900 mb-3">MCP Client</h3><p class="text-sm text-green-600 font-semibold mb-3">"Der Scout" (Live Data)</p><p class="text-gray-600">Zuständig für dynamische Daten und Real World Context. Verbindet sich via Model Context Protocol (MCP) mit externen APIs für Live-Wetter.</p></div> | |
| <div class="bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl transition-all hover:-translate-y-1 group"><div class="w-14 h-14 bg-orange-100 text-orange-600 rounded-xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform"><i data-lucide="zap" class="w-7 h-7"></i></div><h3 class="text-xl font-bold text-gray-900 mb-3">Action & Execution</h3><p class="text-sm text-orange-600 font-semibold mb-3">"Der Macher" (Future Outlook)</p><p class="text-gray-600">Ausblick auf "Active Agents" mit schreibendem Zugriff auf Systeme wie SAP oder Jira, um Folgeprozesse autonom und sicher anzustoßen.</p></div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Section 5: Footer --> | |
| <section class="py-16 bg-white border-t border-gray-200"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"> | |
| <div class="flex flex-col md:flex-row items-center justify-center gap-8 md:gap-16 mb-10 opacity-80"> | |
| <h2 class="text-3xl font-extrabold text-brand-dark tracking-tight">valantic</h2> | |
| <div class="hidden md:block w-px h-12 bg-gray-300"></div> | |
| <h2 class="text-3xl font-extrabold text-gray-800 tracking-tight flex items-center gap-2"> | |
| <i data-lucide="layers" class="text-brand-accent"></i> databricks | |
| </h2> | |
| </div> | |
| <p class="text-gray-500 max-w-2xl mx-auto font-medium"> | |
| Die gesamte Architektur ist vollständig in die <strong class="text-gray-800">Databricks Data Intelligence Platform</strong> integriert, um höchste Sicherheit, Transparenz und Governance durch den Unity Catalog zu gewährleisten. | |
| </p> | |
| <div class="mt-12 text-sm text-gray-400"> | |
| © 2026 valantic GmbH. Showcase entwickelt für das IPAI KI-Festival. | |
| </div> | |
| </div> | |
| </section> | |
| <!-- JavaScript for Interactivity --> | |
| <script> | |
| // Initialize Icons | |
| lucide.createIcons(); | |
| // SCENARIOS DATA (Updated styling classes for Light Mode) | |
| const scenarios = { | |
| singapur: { | |
| id: 'singapur', | |
| title: 'Route: FRA → Singapur', | |
| badge: 'Class II (Insulin)', | |
| badgeClass: 'bg-yellow-100 text-yellow-800 border-yellow-200', | |
| desc: 'Eine Lieferung Insulin liegt am Hafen von Singapur. Prüfen Sie, ob Wetterbedingungen die Ware gefährden.', | |
| userPrompt: 'Wir erwarten heute eine Insulin Lieferung (Lieferung #402) in Singapur. Sind Komplikationen zu erwarten?', | |
| mcpInput: '"Singapur Wetter heute"', | |
| mcpOutput: '32°C, 79-88% Luftfeuchtigkeit', | |
| ragQuery: '"Insulin Lagerbedingungen Temperatur Transport"', | |
| ragOutput: 'Class II (Rx), 15°C - 25°C. Critical Breach > 25°C.', | |
| alertType: 'red', | |
| alertTitle: 'HOHES RISIKO - KOMPLIKATIONEN ZU ERWARTEN', | |
| alertText: 'Die Außentemperaturen in Singapur liegen heute bei <strong>32°C</strong> und damit <strong>7°C über dem maximal zulässigen Grenzwert</strong> von 25°C für Insulin.', | |
| alertActions: [ | |
| 'Ware gilt als "potenziell kompromittiert".', | |
| 'Sofortige Umlagerung in Cool House veranlassen.', | |
| 'Benachrichtigung Quality Manager (qm@logitrans-demo.com).' | |
| ] | |
| }, | |
| oslo: { | |
| id: 'oslo', | |
| title: 'Route: FRA → Oslo', | |
| badge: 'Class I (Bio)', | |
| badgeClass: 'bg-blue-100 text-blue-800 border-blue-200', | |
| desc: 'Blutplasma-Transport erreicht das Terminal in Oslo im Winter. Gefriergefahr muss ausgeschlossen werden.', | |
| userPrompt: 'Wie ist der Status für den Blutplasma-Transport (Lieferung #812) am Terminal in Oslo?', | |
| mcpInput: '"Oslo Wetter heute aktuell"', | |
| mcpOutput: '-12°C, Schneesturm, starke Winde', | |
| ragQuery: '"Blutplasma Class I Lagerbedingungen Minimum"', | |
| ragOutput: 'Class I (Bio), strikt 2°C - 8°C. Darf auf keinen Fall gefrieren. Sofortige Vernichtung bei Frost.', | |
| alertType: 'red', | |
| alertTitle: 'GEFRIERGEFAHR DETEKTIERT', | |
| alertText: 'Die Außentemperaturen in Oslo betragen <strong>-12°C</strong>. Das liegt <strong>14°C unter der Mindesttemperatur</strong> für Blutplasma (Class I).', | |
| alertActions: [ | |
| 'Standzeit auf dem Rollfeld strikt untersagt.', | |
| 'Direkte Verladung in beheizten Spezial-LKW (Heated Transit) erforderlich.', | |
| 'Logbuch-Eintrag für Temperatur-Audit erstellen.' | |
| ] | |
| }, | |
| dubai: { | |
| id: 'dubai', | |
| title: 'Route: FRA → Dubai', | |
| badge: 'Class III (MedTech)', | |
| badgeClass: 'bg-green-100 text-green-800 border-green-200', | |
| desc: 'Transport von medizinischen Implantaten nach Dubai. Prüfen Sie die Hitze-Toleranz.', | |
| userPrompt: 'Wir haben einen Stau am Zoll in Dubai für die Implantate-Lieferung (#109). Ist die Hitze ein Problem?', | |
| mcpInput: '"Dubai Zollhafen Temperatur"', | |
| mcpOutput: '39°C, sonnig', | |
| ragQuery: '"Implantate MedTech Class III Toleranz Hitze"', | |
| ragOutput: 'Class III (MedTech), 0°C bis 40°C. Keine aktive Kühlung zwingend erforderlich.', | |
| alertType: 'green', | |
| alertTitle: 'ROUTE STATUS: NORMAL', | |
| alertText: 'Die Temperaturen in Dubai (39°C) liegen <strong>innerhalb der Toleranzgrenze</strong> von max. 40°C für Class III Güter.', | |
| alertActions: [ | |
| 'Keine Notfallmaßnahmen erforderlich.', | |
| 'Logbuch-Eintrag (Log Entry only) für die Verzögerung erstellen.', | |
| 'Regulären Weitertransport genehmigen.' | |
| ] | |
| } | |
| }; | |
| let currentScenario = 'singapur'; | |
| let simulationInProgress = false; | |
| // Element References | |
| const chatContainer = document.getElementById('chat-container'); | |
| const infoTitle = document.getElementById('info-title'); | |
| const infoBadge = document.getElementById('info-badge'); | |
| const infoDesc = document.getElementById('info-desc'); | |
| const btnSimulate = document.getElementById('btn-simulate'); | |
| // Typing Indicator HTML (Light Mode) | |
| const typingIndicatorHTML = ` | |
| <div class="flex gap-4 chat-message" id="typing-indicator"> | |
| <div class="w-8 h-8 rounded-full bg-brand-accent flex items-center justify-center shrink-0"> | |
| <i data-lucide="bot" class="w-4 h-4 text-white"></i> | |
| </div> | |
| <div class="bg-white border border-gray-200 shadow-sm rounded-2xl rounded-tl-none p-4 w-24"> | |
| <div class="typing-indicator"><span></span><span></span><span></span></div> | |
| </div> | |
| </div> | |
| `; | |
| function playScenario(id) { | |
| if (simulationInProgress) return; | |
| currentScenario = id; | |
| // 1. Update Map UI (Pins & Lines) | |
| ['singapur', 'oslo', 'dubai'].forEach(loc => { | |
| const btn = document.getElementById(`pin-${loc}`); | |
| const line = document.getElementById(`line-${loc}`); | |
| const ping = btn.querySelector('.ping'); | |
| if(loc === id) { | |
| btn.classList.replace('bg-gray-400', 'bg-brand-accent'); | |
| btn.classList.add('pin-active'); | |
| ping.classList.replace('opacity-0', 'opacity-75'); | |
| line.setAttribute('stroke', '#ff3621'); // databricks red | |
| line.classList.add('animate-pulse'); | |
| } else { | |
| btn.classList.replace('bg-brand-accent', 'bg-gray-400'); | |
| btn.classList.remove('pin-active'); | |
| ping.classList.replace('opacity-75', 'opacity-0'); | |
| line.setAttribute('stroke', '#94a3b8'); // slate-400 | |
| line.classList.remove('animate-pulse'); | |
| } | |
| }); | |
| // 2. Update Info Panel | |
| const data = scenarios[id]; | |
| infoTitle.innerText = data.title; | |
| infoBadge.innerText = data.badge; | |
| infoBadge.className = `text-xs px-2 py-1 rounded border font-medium ${data.badgeClass}`; | |
| infoDesc.innerText = data.desc; | |
| // Reset Chat | |
| chatContainer.innerHTML = ''; | |
| // Start simulation directly or wait for button press | |
| btnSimulate.classList.remove('opacity-50', 'cursor-not-allowed'); | |
| btnSimulate.innerHTML = '<i data-lucide="play" class="w-4 h-4"></i> Simulation starten'; | |
| lucide.createIcons(); | |
| } | |
| async function startSimulation() { | |
| if(simulationInProgress) return; | |
| simulationInProgress = true; | |
| btnSimulate.classList.add('opacity-50', 'cursor-not-allowed'); | |
| btnSimulate.innerHTML = '<i data-lucide="loader" class="w-4 h-4 animate-spin"></i> Analysiere...'; | |
| lucide.createIcons(); | |
| chatContainer.innerHTML = ''; | |
| const data = scenarios[currentScenario]; | |
| // Helper to scroll | |
| const scrollToBottom = () => chatContainer.scrollTop = chatContainer.scrollHeight; | |
| // STEP 1: User Message (Light Mode) | |
| chatContainer.innerHTML += ` | |
| <div class="flex gap-4 chat-message"> | |
| <div class="w-8 h-8 rounded-full bg-slate-200 border border-slate-300 flex items-center justify-center shrink-0"> | |
| <i data-lucide="user" class="w-4 h-4 text-slate-600"></i> | |
| </div> | |
| <div class="bg-white border border-gray-200 rounded-2xl rounded-tl-none px-5 py-3 text-gray-800 shadow-sm"> | |
| ${data.userPrompt} | |
| </div> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // Insert Typing | |
| chatContainer.insertAdjacentHTML('beforeend', typingIndicatorHTML); | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // STEP 2: MCP Tool Call (Delay 1.5s) | |
| await new Promise(r => setTimeout(r, 1500)); | |
| document.getElementById('typing-indicator').remove(); | |
| chatContainer.innerHTML += ` | |
| <div class="flex gap-4 chat-message"> | |
| <div class="w-8 h-8 rounded-full bg-brand-accent flex items-center justify-center shrink-0 shadow-md"> | |
| <i data-lucide="bot" class="w-4 h-4 text-white"></i> | |
| </div> | |
| <div class="w-full"> | |
| <div class="bg-white border border-gray-200 shadow-sm rounded-2xl rounded-tl-none p-4 text-gray-700"> | |
| Ich sammle die aktuellen Kontextdaten für diesen Standort. | |
| <div class="mt-4 bg-slate-50 rounded-lg p-3 border border-slate-200 font-mono text-sm"> | |
| <div class="flex items-center gap-2 text-green-600 font-semibold mb-2"> | |
| <i data-lucide="check-circle-2" class="w-4 h-4"></i> | |
| Tool approved: tavily_search (MCP Live Data) | |
| </div> | |
| <div class="text-gray-600"> | |
| <span class="text-blue-600">Input:</span> ${data.mcpInput} <br/> | |
| <span class="text-orange-600">Output:</span> ${data.mcpOutput} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // Insert Typing | |
| chatContainer.insertAdjacentHTML('beforeend', typingIndicatorHTML); | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // STEP 3: RAG Tool Call (Delay 1.5s) | |
| await new Promise(r => setTimeout(r, 1500)); | |
| document.getElementById('typing-indicator').remove(); | |
| chatContainer.innerHTML += ` | |
| <div class="flex gap-4 chat-message"> | |
| <div class="w-8 h-8 rounded-full bg-brand-accent flex items-center justify-center shrink-0 opacity-0"></div> | |
| <div class="w-full"> | |
| <div class="bg-white border border-gray-200 shadow-sm rounded-2xl p-4 text-gray-700"> | |
| <div class="bg-slate-50 rounded-lg p-3 border border-slate-200 font-mono text-sm"> | |
| <div class="flex items-center gap-2 text-purple-600 font-semibold mb-2"> | |
| <i data-lucide="book-open" class="w-4 h-4"></i> | |
| Calling: sla-knowledge-assistant (RAG) | |
| </div> | |
| <div class="text-gray-600"> | |
| <span class="text-blue-600">Query:</span> ${data.ragQuery} <br/> | |
| <span class="text-orange-600">Result:</span> ${data.ragOutput} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // Insert Typing | |
| chatContainer.insertAdjacentHTML('beforeend', typingIndicatorHTML); | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // STEP 4: Final Syntheses (Delay 1.5s) | |
| await new Promise(r => setTimeout(r, 1500)); | |
| document.getElementById('typing-indicator').remove(); | |
| const isAlert = data.alertType === 'red'; | |
| const iconColor = 'text-white'; | |
| const iconBg = isAlert ? 'bg-brand-accent' : 'bg-green-500'; | |
| const iconName = isAlert ? 'shield-alert' : 'shield-check'; | |
| const borderColor = isAlert ? 'border-red-200' : 'border-green-200'; | |
| const titleColor = isAlert ? 'text-red-600' : 'text-green-600'; | |
| const boxBg = isAlert ? 'bg-red-50 border-red-100' : 'bg-green-50 border-green-100'; | |
| let actionsHTML = ''; | |
| data.alertActions.forEach(act => { | |
| actionsHTML += `<li>${act}</li>`; | |
| }); | |
| const humanLoopQuestion = isAlert ? | |
| 'Soll ich die Benachrichtigung an den Quality Manager vorbereiten und die Notfallmaßnahmen anstoßen?' : | |
| 'Soll ich das Logbuch aktualisieren und den Transport freigeben?'; | |
| chatContainer.innerHTML += ` | |
| <div class="flex gap-4 chat-message"> | |
| <div class="w-8 h-8 rounded-full ${iconBg} flex items-center justify-center shrink-0 shadow-md"> | |
| <i data-lucide="${iconName}" class="w-4 h-4 ${iconColor}"></i> | |
| </div> | |
| <div class="w-full"> | |
| <div class="bg-white border ${borderColor} rounded-2xl rounded-tl-none p-5 text-gray-800 shadow-lg"> | |
| <h4 class="${titleColor} font-bold flex items-center gap-2 mb-3"> | |
| <i data-lucide="activity" class="w-5 h-5"></i> | |
| ${data.alertTitle} | |
| </h4> | |
| <p class="mb-3">${data.alertText}</p> | |
| <div class="${boxBg} border rounded p-3 mb-3 text-sm"> | |
| <strong>Vorgeschlagene Eskalationsmatrix:</strong> | |
| <ol class="list-decimal list-inside mt-2 space-y-1 text-gray-700"> | |
| ${actionsHTML} | |
| </ol> | |
| </div> | |
| <!-- Human in the Loop Section --> | |
| <div class="mt-5 border-t border-gray-100 pt-4"> | |
| <p class="text-sm text-gray-600 font-medium mb-3"> | |
| <i data-lucide="user-check" class="w-4 h-4 inline mr-1 text-blue-500"></i> | |
| ${humanLoopQuestion} | |
| </p> | |
| <div id="human-loop-actions" class="flex flex-col sm:flex-row gap-3"> | |
| <button onclick="handleHumanDecision(true)" class="flex-1 bg-green-50 hover:bg-green-100 text-green-700 border border-green-200 px-4 py-2.5 rounded-lg text-sm font-semibold flex justify-center items-center gap-2 transition-all"> | |
| <i data-lucide="check" class="w-4 h-4"></i> Aktion freigeben | |
| </button> | |
| <button onclick="handleHumanDecision(false)" class="flex-1 bg-white hover:bg-gray-50 text-gray-600 border border-gray-200 px-4 py-2.5 rounded-lg text-sm font-semibold flex justify-center items-center gap-2 transition-all"> | |
| <i data-lucide="x" class="w-4 h-4"></i> Abbrechen | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // Notice that we DO NOT set simulationInProgress = false here. | |
| // We wait for the human decision! | |
| btnSimulate.innerHTML = '<i data-lucide="user-check" class="w-4 h-4"></i> Warte auf Freigabe...'; | |
| lucide.createIcons(); | |
| } | |
| async function handleHumanDecision(approved) { | |
| // Remove buttons so they can't be clicked twice | |
| const actionDiv = document.getElementById('human-loop-actions'); | |
| if(actionDiv) actionDiv.remove(); | |
| const data = scenarios[currentScenario]; | |
| const isAlert = data.alertType === 'red'; | |
| const scrollToBottom = () => chatContainer.scrollTop = chatContainer.scrollHeight; | |
| // 1. User Message (The Decision) | |
| const userActionText = approved ? 'Aktion freigeben und ausführen.' : 'Aktion abbrechen. Nur lokal protokollieren.'; | |
| const userBorderColor = approved ? 'border-green-300 bg-green-50 text-green-800' : 'border-gray-300 bg-gray-50 text-gray-700'; | |
| chatContainer.innerHTML += ` | |
| <div class="flex gap-4 chat-message mt-2"> | |
| <div class="w-8 h-8 rounded-full bg-slate-200 border border-slate-300 flex items-center justify-center shrink-0"> | |
| <i data-lucide="user" class="w-4 h-4 text-slate-600"></i> | |
| </div> | |
| <div class="rounded-2xl rounded-tl-none px-5 py-3 shadow-sm border ${userBorderColor} font-medium"> | |
| ${userActionText} | |
| </div> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // Insert Typing | |
| chatContainer.insertAdjacentHTML('beforeend', typingIndicatorHTML); | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // 2. Execute Action (Delay 1.5s) | |
| await new Promise(r => setTimeout(r, 1500)); | |
| document.getElementById('typing-indicator').remove(); | |
| let aiFinalText = ''; | |
| let toolName = ''; | |
| let toolAction = ''; | |
| if (approved) { | |
| if (isAlert) { | |
| aiFinalText = 'Notfallprotokoll wurde initiiert. Der Quality Manager wurde benachrichtigt und der Transport-Stopp im System hinterlegt.'; | |
| toolName = 'sap_erp_connector & outlook_mailer'; | |
| toolAction = 'Status: COMPROMISED, Mails verschickt.'; | |
| } else { | |
| aiFinalText = 'Transportfreigabe wurde erteilt. Logbuch ist aktualisiert.'; | |
| toolName = 'logistics_db_update'; | |
| toolAction = 'Status: CLEARED, Log hinzugefügt.'; | |
| } | |
| } else { | |
| aiFinalText = 'Aktion durch Supervisor abgebrochen. Es wurden keine externen Systeme kontaktiert. Ein Vermerk wurde im lokalen Audit-Log gespeichert.'; | |
| toolName = 'local_audit_log'; | |
| toolAction = 'Status: OVERRIDDEN_BY_HUMAN'; | |
| } | |
| chatContainer.innerHTML += ` | |
| <div class="flex gap-4 chat-message"> | |
| <div class="w-8 h-8 rounded-full bg-orange-500 flex items-center justify-center shrink-0 shadow-md"> | |
| <i data-lucide="zap" class="w-4 h-4 text-white"></i> | |
| </div> | |
| <div class="w-full"> | |
| <div class="bg-white border border-gray-200 rounded-2xl rounded-tl-none p-4 text-gray-800 shadow-sm"> | |
| ${aiFinalText} | |
| <div class="mt-4 bg-slate-50 rounded-lg p-3 border border-slate-200 font-mono text-sm"> | |
| <div class="flex items-center gap-2 text-orange-600 font-semibold mb-2"> | |
| <i data-lucide="terminal-square" class="w-4 h-4"></i> | |
| Tool execution: ${toolName} | |
| </div> | |
| <div class="text-gray-600"> | |
| <span>${toolAction}</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| scrollToBottom(); | |
| // End of Simulation - Ready for next | |
| simulationInProgress = false; | |
| btnSimulate.innerHTML = '<i data-lucide="refresh-cw" class="w-4 h-4"></i> Neues Szenario starten'; | |
| btnSimulate.classList.remove('opacity-50', 'cursor-not-allowed'); | |
| lucide.createIcons(); | |
| } | |
| // Init Default State | |
| playScenario('singapur'); | |
| </script> | |
| </body> | |
| </html> |