servibot
Version:
This is the official API for ServiBot, an advanced AI chatbot which provides enhanced customer service to businesses.
816 lines (785 loc) • 27.8 kB
JavaScript
"use client";
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
import "firebase/compat/storage";
import {
arrayUnion,
arrayRemove,
serverTimestamp,
increment,
} from "firebase/firestore";
import {
Button,
Flex,
Image,
Text,
Input,
InputGroup,
InputRightElement,
Spinner,
ChakraProvider,
useToast,
} from "@chakra-ui/react";
import { useEffect, useState, useReducer, useRef } from "react";
import OpenAI from "openai";
import { ChevronDownIcon } from "@chakra-ui/icons";
const ServiBot = (props) => {
const toast = useToast();
const bottomRef = useRef(null);
const [color, setColor] = useState("");
const [display, setDisplay] = useState(false);
const [label, setLabel] = useState([true, "Label"]);
const [companyName, setCompanyName] = useState("");
const [messages, setMessages] = useState([
`Welcome to our chatbot, how can I help you today?`,
]);
const [animationTrigger, setAnimationTrigger] = useState(false);
const [img, setImg] = useState("");
const [img2, setImg2] = useState("one");
const [txt, setTxt] = useState("");
const [position, setPosition] = useState("");
const [prompts, setPrompts] = useState([]);
const [show, setShow] = useState(false);
const [toxt, setToxt] = useState("");
const [resload, setResload] = useState(false);
const [ready, setReady] = useState(false);
const [chatImg, setChatImg] = useState("");
const [xImg, setXImg] = useState("");
const [avatarImg, setAvatarImg] = useState("");
const [logoImg, setLogoImg] = useState("");
const [sendImg, setSendImg] = useState("");
const firebaseConfig = {
apiKey: "AIzaSyANzBgpkTRm4wWVTXvOGN06_4moH30yYW0",
authDomain: "servibot-35220.firebaseapp.com",
projectId: "servibot-35220",
storageBucket: "servibot-35220.appspot.com",
messagingSenderId: "568351336305",
appId: "1:568351336305:web:a1026f44a414a51b3938d0",
measurementId: "G-CV36XS4YHD",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
// Use these for db & auth
const db = firebaseApp.firestore();
const auth = firebase.auth();
const storage = firebase.storage();
useEffect(() => {
if (props.id != "") {
db.collection("companies")
.doc(props.id)
.get()
.then((val) => {
if (val.exists) {
if (val.get("respondersImage") != "") {
storage
.ref(val.get("respondersImage"))
.getDownloadURL()
.then((url) => {
setImg2(url);
});
} else {
setImg2("");
}
// split up storage stuff in case what and change chatimg stuff as well
storage
.ref("/logo.png")
.getDownloadURL()
.then((url) => {
setLogoImg(url);
storage
.ref("/avatar.png")
.getDownloadURL()
.then((url) => {
setAvatarImg(url);
storage
.ref("/x.png")
.getDownloadURL()
.then((url) => {
setXImg(url);
storage
.ref("/send.png")
.getDownloadURL()
.then((url) => {
setSendImg(url);
storage
.ref("/chat.png")
.getDownloadURL()
.then((url) => {
setChatImg(url);
setReady(true);
});
});
});
});
});
setPrompts(val.get("prompts"));
setColor(val.get("color"));
setDisplay(val.get("display"));
setLabel(val.get("label"));
setCompanyName(val.get("companyName"));
setPosition(val.get("position"));
} else {
console.error("This is an invalid API");
console.log(
"Please try again or contact us if it continually doesn't work"
);
}
});
} else {
console.error("This is an invalid id");
}
}, []);
useEffect(() => {}, [messages]);
useEffect(() => {}, [ready]);
useEffect(() => {}, [show]);
// useEffect(() => {}, [img]);
useEffect(() => {}, [img2]);
useEffect(() => {}, [chatImg]);
useEffect(() => {}, [xImg]);
useEffect(() => {}, [avatarImg]);
useEffect(() => {}, [logoImg]);
useEffect(() => {}, [sendImg]);
useEffect(() => {}, [resload]);
const openAIOutput = async (e) => {
e.preventDefault();
setMessages((prevMessages) => [...prevMessages, n]);
let n = toxt;
setToxt("");
setResload(true);
let maxTokens = 15000;
db.collection("OpenAI")
.doc("API")
.get()
.then(async (val) => {
const apiK = val.get("Key");
let openai = new OpenAI({
apiKey: apiK,
dangerouslyAllowBrowser: true,
});
let model = "gpt-3.5-turbo-16k";
let temp = 0.85;
try {
// Send a request to the OpenAI API to generate text
const response = await openai.chat.completions.create({
model: model,
// prompt: prompt,
messages: [
{
role: "user",
content: `Answer the text message: ${n} with another text message (presumably shorter) as a welcoming employee of a company. \n\nAnswer the message based on the information about the company:\n${
[...prompts][0]
}. Answer the questions like a normal person would. Try to connect with others and be the most attractive employee you can be for a company. If a question is personal, feel free to answer in a personal way. If possible try to keep text messages shorter.`,
},
],
max_tokens: maxTokens,
temperature: temp,
});
// console.log([...prompts][0]);
// console.log(`request cost: ${response.usage.total_tokens} tokens`);
// console.log(response.choices[0].message.content);
setResload(false);
setMessages((prevMessages) => [
...prevMessages,
response.choices[0].message.content,
]);
setToxt("");
return;
} catch (err) {
console.log("This is an error");
toast({
title: "Cannot generate more code",
duration: 3000,
isClosable: true,
status: "error",
});
setResload(false);
throw err;
}
})
.catch((err) => {
toast({
title: "There has been an error",
duration: 3000,
isClosable: true,
status: "error",
});
console.log(err.message);
});
};
const scrollToBottom = () => {
if (bottomRef.current) {
bottomRef.current.scrollTop = bottomRef.current.scrollHeight;
}
};
useEffect(scrollToBottom, [messages]);
if (ready) {
return (
<ChakraProvider>
{position == "left" ? (
<Flex
position={"fixed"}
left={0}
top={"calc(100vh - 490px)"}
direction={"column"}
width={330}
height={450}
zIndex={2000}
gap={3}
margin={5}
>
{show ? (
<Flex
direction={"column"}
width={"100%"}
height={"82.5%"}
// boxShadow={"0 0 5px 2px #bcbcbc"}
boxShadow={"0 0 3px 1px #bcbcbc"}
borderRadius={5}
// zIndex={2000}
position={"relative"}
>
<Flex
w={"full"}
height={10}
justifyContent={"flex-end"}
alignItems={"center"}
backgroundColor={
color == "blue"
? "#3D96EE"
: color == "green"
? "#37D35D"
: color == "red"
? "#F44B4B"
: color == "orange"
? "#E37500"
: color == "purple"
? "#913AD6"
: color == "yellow"
? "#C1C545"
: "#3D96EE"
}
borderTopRadius={5}
>
<Button
colorScheme={"transparent"}
_hover={{
opacity: 0.8,
}}
onClick={() => setShow(false)}
>
<ChevronDownIcon color={"white"} />
</Button>
</Flex>
<Flex
direction={"column"}
width={"100%"}
padding={2}
overflowY={"scroll"}
backgroundColor={"#ffffff"}
gap={2}
ref={bottomRef}
>
{messages.map((message, index) => (
<Flex
width={"100%"}
justifyContent={"left"}
alignItems={"center"}
gap={2}
>
<Image
// src={img == "" ? "/avatar.png" : img}
alt={"Avatar image"}
src={
index % 2 == 0
? img2 != ""
? img2
: logoImg
: // : img != ""
// ? img
avatarImg
}
boxShadow={"0 0 3px 1px #dfdfdf"}
w={30}
h={30}
borderRadius={"50%"}
/>
<Flex
alignItems={"center"}
justifyContent={"center"}
backgroundColor={index % 2 == 0 ? "#dfdfdf" : "#37C34E"}
borderRadius={15}
pl={3}
pr={3}
pt={1}
pb={1}
>
<Text
textAlign={"left"}
color={index % 2 == 0 ? "#000000" : "#ffffff"}
fontSize={"11pt"}
>
{message}
</Text>
</Flex>
</Flex>
/* Waiting for AI notification thing */
/* <Flex
direction={"column"}
alignItems={"center"}
justifyContent={"center"}
width={"100%"}
>
<Text
textAlign={"center"}
fontSize={"10pt"}
fontWeight={700}
>
It may take a few seconds, please wait...
</Text>
</Flex> */
))}
</Flex>
<Flex flex="1" backgroundColor={"#ffffff"} />
<InputGroup
size="md"
w="100%"
h="40px"
backgroundColor={"#ffffff"}
borderBottomRadius={5}
borderTop={"1px solid #efefef"}
borderRadius={0}
>
<Flex
alignItems={"center"}
justifyContent={"center"}
width={"100%"}
as={"form"}
onSubmit={(e) => openAIOutput(e)}
>
<Input
type="text"
placeholder="Type here"
readOnly={resload}
value={toxt}
onChange={(e) => setToxt(e.target.value)}
borderTopRadius={0}
pr={8}
required
// value={inputValue}
// onChange={handleInputChange}
/>
<InputRightElement>
<Button
h="100%"
size="sm"
type={"submit"}
colorScheme={"transparent"}
w={20}
_hover={{
cursor: "pointer",
opacity: 0.8,
}}
>
{resload == false ? (
<Image src={sendImg} alt={"Send it here"} />
) : (
<Spinner color="black" size={"sm"} />
)}
</Button>
</InputRightElement>
</Flex>
</InputGroup>
</Flex>
) : (
<Flex flex="1" />
)}
{display && (
<Flex
gap={3}
alignItems={"center"}
justifyContent={position == "right" ? "right" : "left"}
>
{[...label][0] && txt != "" && position == "right" && (
<Flex
backgroundColor={"white"}
paddingLeft={3}
paddingRight={3}
boxShadow={"0 0 5px 2px #bcbcbc"}
borderRadius={5}
as={Button}
colorScheme={"transparent"}
color={"black"}
fontWeight={400}
onClick={() => setShow(!show)}
// zIndex={2000}
// _hover={{
// opacity: 0.8,
// boxShadow: "0 0 3px 1px #bcbcbc",
// }}
>
<Text>{txt}</Text>
</Flex>
)}
<Button
colorScheme={"transparent"}
// _hover={{
// opacity: 0.8,
// boxShadow: "none",
// }}
borderRadius={"50%"}
padding={4}
width={65}
height={65}
// Uncomment later line below
// boxShadow={"0 0 5px 2px #bcbcbc"}
// zIndex={2000}
backgroundColor={
color == "blue"
? "#3D96EE"
: color == "green"
? "#37D35D"
: color == "red"
? "#F44B4B"
: color == "orange"
? "#E37500"
: color == "purple"
? "#913AD6"
: color == "yellow"
? "#C1C545"
: "#3D96EE"
}
_hover={{
opacity: 0.95,
}}
onClick={() => {
setAnimationTrigger(false);
// Trigger the animation
setTimeout(() => setAnimationTrigger(true), 10);
setShow(!show);
}}
sx={{
animation: animationTrigger ? "bounce 0.3s ease" : "none",
"@keyframes bounce": {
"0%": { transform: "scale(1)" },
"50%": { transform: "scale(1.1)" },
"100%": { transform: "scale(1)" },
},
}}
>
{chatImg != "" && (
<Image src={!show ? chatImg : xImg} alt={"Chat icon"} />
)}
</Button>
{[...label][0] && txt != "" && position == "left" && (
<Flex
backgroundColor={"white"}
paddingLeft={3}
paddingRight={3}
boxShadow={"0 0 5px 2px #bcbcbc"}
borderRadius={5}
as={Button}
colorScheme={"transparent"}
color={"black"}
_hover={{
opacity: 0.95,
}}
fontWeight={400}
// zIndex={2000}
// _hover={{
// opacity: 0.8,
// boxShadow: "0 0 3px 1px #bcbcbc",
// }}
>
<Text>{txt}</Text>
</Flex>
)}
</Flex>
)}
</Flex>
) : (
<Flex
position={"fixed"}
left={"calc(100vw - 370px)"}
top={"calc(100vh - 490px)"}
direction={"column"}
width={330}
height={450}
gap={3}
margin={5}
zIndex={2000}
>
{show ? (
<Flex
direction={"column"}
width={"100%"}
height={"82.5%"}
position={"relative"}
// boxShadow={"0 0 5px 2px #bcbcbc"}
boxShadow={"0 0 3px 1px #bcbcbc"}
borderRadius={5}
// zIndex={2000}
>
<Flex
w={"full"}
height={10}
justifyContent={"flex-end"}
alignItems={"center"}
backgroundColor={
color == "blue"
? "#3D96EE"
: color == "green"
? "#37D35D"
: color == "red"
? "#F44B4B"
: color == "orange"
? "#E37500"
: color == "purple"
? "#913AD6"
: color == "yellow"
? "#C1C545"
: "#3D96EE"
}
borderTopRadius={5}
>
<Button
colorScheme={"transparent"}
_hover={{
opacity: 0.8,
}}
onClick={() => setShow(false)}
>
<ChevronDownIcon color={"white"} />
</Button>
</Flex>
<Flex
direction={"column"}
width={"100%"}
padding={2}
overflowY={"scroll"}
gap={2}
backgroundColor={"#ffffff"}
ref={bottomRef}
>
{messages.map((message, index) => (
<Flex
width={"100%"}
justifyContent={"left"}
alignItems={"center"}
gap={2}
>
<Image
// src={img == "" ? "/avatar.png" : img}
src={
index % 2 == 0
? img2 != ""
? img2
: logoImg
: img != ""
? img
: avatarImg
}
boxShadow={"0 0 3px 1px #dfdfdf"}
w={30}
h={30}
borderRadius={"50%"}
alt={"Profile Image"}
/>
<Flex
alignItems={"center"}
justifyContent={"center"}
backgroundColor={index % 2 == 0 ? "#dfdfdf" : "#37C34E"}
borderRadius={15}
pl={3}
pr={3}
pt={1}
pb={1}
>
<Text
textAlign={"left"}
color={index % 2 == 0 ? "#000000" : "#ffffff"}
fontSize={"11pt"}
>
{message}
</Text>
</Flex>
</Flex>
/* Waiting for AI notification thing */
/* <Flex
direction={"column"}
alignItems={"center"}
justifyContent={"center"}
width={"100%"}
>
<Text
textAlign={"center"}
fontSize={"10pt"}
fontWeight={700}
>
It may take a few seconds, please wait...
</Text>
</Flex> */
))}
</Flex>
<Flex flex="1" backgroundColor={"#ffffff"} />
<InputGroup
size="md"
w="100%"
h="40px"
borderTop={"1px solid #efefef"}
borderRadius={0}
backgroundColor={"#ffffff"}
borderBottomRadius={5}
>
<Flex
alignItems={"center"}
justifyContent={"center"}
width={"100%"}
as={"form"}
onSubmit={(e) => openAIOutput(e)}
>
<Input
type="text"
placeholder="Type here"
readOnly={resload}
value={toxt}
onChange={(e) => setToxt(e.target.value)}
borderTopRadius={0}
pr={8}
required
// value={inputValue}
// onChange={handleInputChange}
/>
<InputRightElement>
<Button
h="100%"
size="sm"
type={"submit"}
colorScheme={"transparent"}
w={20}
_hover={{
cursor: "pointer",
opacity: 0.8,
}}
>
{resload == false ? (
<Image src={sendImg} alt={"Send it here"} />
) : (
<Spinner color="black" size={"sm"} />
)}
</Button>
</InputRightElement>
</Flex>
</InputGroup>
</Flex>
) : (
<Flex flex="1" />
)}
{display && (
<Flex
gap={3}
alignItems={"center"}
justifyContent={position == "right" ? "right" : "left"}
>
{[...label][0] && txt != "" && position == "right" && (
<Flex
backgroundColor={"white"}
paddingLeft={3}
paddingRight={3}
boxShadow={"0 0 5px 2px #bcbcbc"}
borderRadius={5}
as={Button}
colorScheme={"transparent"}
color={"black"}
fontWeight={400}
_hover={{
opacity: 0.95,
}}
onClick={() => setShow(!show)}
// zIndex={2000}
// _hover={{
// opacity: 0.8,
// boxShadow: "0 0 3px 1px #bcbcbc",
// }}
>
<Text>{txt}</Text>
</Flex>
)}
<Button
colorScheme={"transparent"}
// _hover={{
// opacity: 0.8,
// boxShadow: "none",
// }}
borderRadius={"50%"}
padding={4}
width={65}
height={65}
// Uncomment later line below
// boxShadow={"0 0 5px 2px #bcbcbc"}
// zIndex={2000}
backgroundColor={
color == "blue"
? "#3D96EE"
: color == "green"
? "#37D35D"
: color == "red"
? "#F44B4B"
: color == "orange"
? "#E37500"
: color == "purple"
? "#913AD6"
: color == "yellow"
? "#C1C545"
: "#3D96EE"
}
_hover={{
opacity: 0.95,
}}
onClick={() => {
setAnimationTrigger(false);
// Trigger the animation
setTimeout(() => setAnimationTrigger(true), 10);
setShow(!show);
}}
sx={{
animation: animationTrigger ? "bounce 0.3s ease" : "none",
"@keyframes bounce": {
"0%": { transform: "scale(1)" },
"50%": { transform: "scale(1.1)" },
"100%": { transform: "scale(1)" },
},
}}
>
{chatImg != "" && (
<Image src={!show ? chatImg : xImg} alt={"Chat icon"} />
)}
</Button>
{[...label][0] && txt != "" && position == "left" && (
<Flex
backgroundColor={"white"}
paddingLeft={3}
paddingRight={3}
boxShadow={"0 0 5px 2px #bcbcbc"}
borderRadius={5}
as={Button}
// zIndex={2000}
colorScheme={"transparent"}
color={"black"}
fontWeight={400}
// _hover={{
// opacity: 0.8,
// boxShadow: "0 0 3px 1px #bcbcbc",
// }}
>
<Text>{txt}</Text>
</Flex>
)}
</Flex>
)}
</Flex>
)}
</ChakraProvider>
);
}
};
export default ServiBot;