KI Chat Bubble
This commit is contained in:
68
Profice WebSite/scripts/add/flowise-proxy.php
Normal file
68
Profice WebSite/scripts/add/flowise-proxy.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Flowise Chat Proxy — credentials hidden server-side
|
||||
* Called via .htaccess rewrite: /api/v1/prediction/* → this file
|
||||
*/
|
||||
|
||||
// SENSITIVE — never expose these in client-side JS
|
||||
$FLOWISE_HOST = 'https://flowise.profice.de';
|
||||
$FLOWISE_CHATFLOW = 'd63d3d02-b5fa-482c-9161-c21c615fb625';
|
||||
|
||||
// CORS — restrict to your domain in production
|
||||
$allowedOrigins = [
|
||||
'https://profice.de',
|
||||
'https://www.profice.de',
|
||||
'http://localhost',
|
||||
'http://127.0.0.1',
|
||||
'https://staging.profice.de'
|
||||
];
|
||||
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||
header('Content-Type: application/json');
|
||||
if (in_array($origin, $allowedOrigins)) {
|
||||
header("Access-Control-Allow-Origin: $origin");
|
||||
} else {
|
||||
header('Access-Control-Allow-Origin: https://profice.de');
|
||||
}
|
||||
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$input = file_get_contents('php://input');
|
||||
$target = "$FLOWISE_HOST/api/v1/prediction/$FLOWISE_CHATFLOW";
|
||||
|
||||
$ch = curl_init($target);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $input,
|
||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Accept: application/json'],
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 60,
|
||||
CURLOPT_CONNECTTIMEOUT => 10,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
http_response_code(502);
|
||||
echo json_encode(['error' => 'Proxy error', 'detail' => $error]);
|
||||
exit();
|
||||
}
|
||||
|
||||
http_response_code($httpCode);
|
||||
echo $response;
|
||||
?>
|
||||
94
Profice WebSite/scripts/ki-chat-bubble.js
Normal file
94
Profice WebSite/scripts/ki-chat-bubble.js
Normal file
@@ -0,0 +1,94 @@
|
||||
// KI Chat Bubble — Flowise embed
|
||||
// To remove: delete this file and the <script> tag in index.html that loads it.
|
||||
|
||||
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js";
|
||||
|
||||
// On production the PHP proxy is used so credentials never appear in client JS.
|
||||
// On localhost the embed talks directly to Flowise (dev only).
|
||||
const isLocal = ['localhost', '127.0.0.1'].includes(window.location.hostname);
|
||||
|
||||
Chatbot.init({
|
||||
chatflowid: isLocal ? "d63d3d02-b5fa-482c-9161-c21c615fb625" : "chat",
|
||||
apiHost: isLocal ? "https://flowise.profice.de" : window.location.origin,
|
||||
theme: {
|
||||
button: {
|
||||
backgroundColor: "#5a5252",
|
||||
right: 24,
|
||||
bottom: 24,
|
||||
size: "medium",
|
||||
iconColor: "#EBEBDE"
|
||||
},
|
||||
chatWindow: {
|
||||
showTitle: true,
|
||||
title: "Profice Assistent",
|
||||
titleBackgroundColor: "#5a5252",
|
||||
titleTextColor: "#EBEBDE",
|
||||
welcomeMessage: "Hallo! Ich bin der KI-Assistent von Profice. Wie kann ich Ihnen helfen?\n\nIch berate Sie gerne zu unseren Lösungen für Automatisierung, KI-Systeme und digitale Prozesse.",
|
||||
backgroundColor: "#ffffff",
|
||||
fontSize: 15,
|
||||
showAgentMessages: true,
|
||||
poweredByTextColor: "#ffffff",
|
||||
botMessage: {
|
||||
backgroundColor: "#f5f4ef",
|
||||
textColor: "#5a5252",
|
||||
showAvatar: true,
|
||||
avatarSrc: "/images/icons/KI.png"
|
||||
},
|
||||
userMessage: {
|
||||
backgroundColor: "#5a5252",
|
||||
textColor: "#EBEBDE",
|
||||
showAvatar: false
|
||||
},
|
||||
textInput: {
|
||||
placeholder: "Ihre Nachricht...",
|
||||
backgroundColor: "#ffffff",
|
||||
textColor: "#5a5252",
|
||||
sendButtonColor: "#d4864a"
|
||||
},
|
||||
footer: {
|
||||
textColor: "#ffffff",
|
||||
text: " ",
|
||||
company: " ",
|
||||
companyLink: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inject orange border around just the header.
|
||||
// ::part(header) is not exported by Flowise so we inject into the shadow root directly.
|
||||
// The header is identified as the element that has the dark titleBackgroundColor AND
|
||||
// contains the chat title — this avoids matching user message bubbles.
|
||||
function injectHeaderStyle() {
|
||||
const flowise = document.querySelector('flowise-chatbot');
|
||||
if (!flowise?.shadowRoot) return false;
|
||||
|
||||
const shadow = flowise.shadowRoot;
|
||||
if (shadow.querySelector('#profice-header-applied')) return true;
|
||||
|
||||
const all = [...shadow.querySelectorAll('*')];
|
||||
|
||||
const header = all.find(el => {
|
||||
const bg = getComputedStyle(el).backgroundColor;
|
||||
return bg === 'rgb(90, 82, 82)' && el.textContent.includes('Profice Assistent');
|
||||
});
|
||||
|
||||
if (!header) return false;
|
||||
|
||||
header.style.border = '3px solid #d4864a';
|
||||
header.style.boxSizing = 'border-box';
|
||||
// No border-radius here — the parent chatwindow's overflow:hidden clips corners naturally
|
||||
|
||||
const marker = document.createElement('span');
|
||||
marker.id = 'profice-header-applied';
|
||||
marker.style.display = 'none';
|
||||
shadow.appendChild(marker);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retry until shadow DOM is populated (widget loads async)
|
||||
let attempts = 0;
|
||||
const interval = setInterval(() => {
|
||||
if (injectHeaderStyle() || ++attempts > 20) clearInterval(interval);
|
||||
}, 300);
|
||||
Reference in New Issue
Block a user