smart-ai-chatbot
Version:
A customizable AI chatbot component for React and web applications.
93 lines (92 loc) • 5.59 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect, useCallback } from "react";
import * as use from "@tensorflow-models/universal-sentence-encoder";
import * as tf from "@tensorflow/tfjs";
import { FaRobot, FaTimes, FaPaperPlane } from "react-icons/fa";
const Chatbot = ({ dataset, title = "AI Chatbot", theme = "dark", }) => {
const [message, setMessage] = useState("");
const [reply, setReply] = useState("");
const [model, setModel] = useState(null);
const [isOpen, setIsOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (isOpen && !model) {
use.load().then(setModel);
}
}, [isOpen, model]);
const handleSubmit = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
if (!model || !message.trim())
return;
setIsLoading(true);
setReply("");
try {
const inputEmbedding = yield model.embed([message]);
const questionEmbeddings = yield model.embed(dataset.map((q) => q.question));
const similarities = tf.matMul(tf.tensor2d(inputEmbedding.arraySync(), inputEmbedding.shape), tf.tensor(questionEmbeddings.arraySync(), questionEmbeddings.shape), false, true);
const bestMatchIndex = similarities.argMax(1).dataSync()[0];
setReply(dataset[bestMatchIndex].answer);
}
catch (error) {
console.error(error);
setReply("Sorry, something went wrong. Please try again.");
}
finally {
setMessage("");
setIsLoading(false);
}
}), [model, message, dataset]);
const handleKeyDown = (e) => {
if (e.key === "Enter") {
e.preventDefault(); // Prevent default form submission
handleSubmit();
}
};
const handleClose = () => {
setIsOpen(false);
setMessage("");
setReply("");
};
const themes = {
dark: {
backgroundColor: "#1A1A1A",
buttonColor: "#4CAF50",
textColor: "#FFFFFF",
inputBackgroundColor: "#121212",
borderColor: "#4CAF50",
},
light: {
backgroundColor: "#FFFFFF",
buttonColor: "#2196F3",
textColor: "#000000",
inputBackgroundColor: "#F5F5F5",
borderColor: "#2196F3",
},
};
const selectedTheme = themes[theme];
return (_jsx("section", { className: "fixed bottom-6 right-6 z-50", children: isOpen ? (_jsxs("div", { className: "p-6 rounded-lg shadow-2xl w-96 max-w-[90vw] border", style: {
backgroundColor: selectedTheme.backgroundColor,
color: selectedTheme.textColor,
borderColor: selectedTheme.borderColor,
}, children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsxs("h3", { className: "text-lg font-bold flex items-center space-x-2", children: [_jsx(FaRobot, {}), _jsx("span", { children: title })] }), _jsx("button", { onClick: handleClose, className: "text-gray-400 hover:text-white", children: _jsx(FaTimes, { size: 20 }) })] }), _jsxs("div", { className: "mb-4 flex space-x-2", children: [_jsx("input", { type: "text", value: message, onChange: (e) => setMessage(e.target.value), onKeyDown: handleKeyDown, placeholder: "Ask me anything...", className: "w-full p-3 rounded-lg border focus:ring focus:ring-blue-500", style: {
backgroundColor: selectedTheme.inputBackgroundColor,
color: selectedTheme.textColor,
borderColor: selectedTheme.borderColor,
}, required: true }), _jsx("button", { type: "button" // Keep as type="button"
, onClick: handleSubmit, disabled: isLoading, className: "p-3 rounded-lg hover:bg-opacity-80 disabled:bg-gray-500 flex items-center justify-center", style: { backgroundColor: selectedTheme.buttonColor }, children: _jsx(FaPaperPlane, { size: 18 }) })] }), !reply && !isLoading ? null : (_jsx("div", { className: "p-4 rounded-lg border min-h-[50px]", style: {
backgroundColor: selectedTheme.inputBackgroundColor,
borderColor: selectedTheme.borderColor,
}, children: isLoading ? (_jsx("p", { className: "animate-pulse", children: "\u23F3 Typing..." })) : (_jsx("p", { children: reply })) }))] })) : (_jsxs("button", { onClick: () => setIsOpen(true), className: "p-4 rounded-full shadow-lg flex items-center space-x-2", style: {
backgroundColor: selectedTheme.backgroundColor,
color: selectedTheme.textColor,
}, children: [_jsx(FaRobot, { size: 20 }), _jsx("span", { children: "Chat" })] })) }));
};
export default Chatbot;