Skip to content

Commit

Permalink
issue fixed mini chatbot (#370)
Browse files Browse the repository at this point in the history
#360 Add mini chattbot issue fixed , This chatbot gives quike response
to the users questions and runs smoothly , @GarimaSingh0109 Add
gssoc-ext, Hactoberfest-accepted and level 3 to this PR ,

Screenrecording


https://github.com/user-attachments/assets/bca37898-58ab-4c8a-b418-fcbb76c31819



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
	- Introduced a web-based chat interface for waste management chatbot.
- Added a chatbot button linking to the new chat interface on the main
page.

- **Enhancements**
- Improved user interface with new styles for the chatbot button and
tooltip.
	- Adjusted the position and appearance of the scroll-to-top button.

These changes enhance user interaction and accessibility within the
waste management application.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
GarimaSingh0109 authored Oct 20, 2024
2 parents 388d133 + 3c50081 commit 8d89c31
Show file tree
Hide file tree
Showing 4 changed files with 419 additions and 2 deletions.
Binary file added bot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added chatbot.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
366 changes: 366 additions & 0 deletions chatbot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Waste Management-Chat Bot</title>
<link
href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
rel="stylesheet"
/>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="Style.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/a11y-dark.min.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
</head>
<body class="bg-[#1B63AC] flex items-center justify-center min-h-screen">
<div id="Loader"></div>
<div
class="flex flex-col items-center justify-center w-full max-w-xl space-y-4"
>
<div class="w-full flex justify-center">
<img
src="bot.jpg"
alt="Chat Bot"
class="h-42 w-42 object-cover"
/>
</div>

<div class="chat-container w-full bg-white p-4 rounded-lg shadow-md">
<div id="output-field" class="text-center text-lg font-semibold mb-3">
How can I help you today?
</div>
<div
id="output-container"
class="mb-3 overflow-auto"
style="max-height: 300px"
></div>
<div class="input-group mb-3">
<div id="image-preview-container" class="input-group-prepend mr-1">
<span
id="image-preview"
class="flex items-center"
style="display: none"
>
<img src="" alt="Image preview" class="h-10 mr-2" />
<button
type="button"
id="clear-image"
class="close text-red-600 text-2xl leading-none"
aria-label="Close"
>
&times;
</button>
</span>
</div>
<input
type="text"
id="prompt-input"
class="form-control flex-1"
placeholder="Type your prompt here..."
aria-label="Message input"
/>
<button
class="input-group-text bg-gray-200"
id="inputGroupFileAddon"
onclick="document.getElementById('image-input').click();"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="25"
height="25"
fill="currentColor"
class="bi bi-image"
viewBox="0 0 16 16"
>
<path d="M6.002 5.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0" />
<path
d="M2.002 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm12 1a1 1 0 0 1 1 1v6.5l-3.777-1.947a.5.5 0 0 0-.577.093l-3.71 3.71-2.66-1.772a.5.5 0 0 0-.63.062L1.002 12V3a1 1 0 0 1 1-1z"
/>
</svg>
</button>
<input type="file" id="image-input" accept="image/*" class="hidden" />
<button id="generate-btn" class="btn btn-primary">Send</button>
</div>
</div>
</div>

<style>
.chat-container {
width: 100%;
max-width: 500px;
}

body,
html {
margin: 0;
padding: 0;
background-color: #42c553; /* Optional: to visualize the centering */
}
</style>

<script type="importmap">
{
"imports": {
"@google/generative-ai": "https://esm.run/@google/generative-ai"
}
}
</script>

<script type="module">
import {
GoogleGenerativeAI,
HarmBlockThreshold,
HarmCategory,
} from "@google/generative-ai";

const API_KEY = "AIzaSyBF265bY6o63VuPypal-5w0-b7sr0N_O3A"; // Replace with your gemini-api actual API key
const genAI = new GoogleGenerativeAI(API_KEY);
let chat;

const safetySettings = [
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
},
];

async function fileToGenerativePart(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => {
const base64Data = reader.result.split(",")[1];
resolve({ inlineData: { data: base64Data, mimeType: file.type } });
};
reader.readAsDataURL(file);
});
}

async function sendMessage(prompt, imageParts = []) {
let model;
let result;
clearGreeting(); // Clear the greeting after sending the message

if (imageParts.length > 0) {
model = genAI.getGenerativeModel({
model: "gemini-pro-vision",
safetySettings,
});
} else {
if (!chat) {
chat = await genAI
.getGenerativeModel({ model: "gemini-pro", safetySettings })
.startChat({
history: [],
generationConfig: {
maxOutputTokens: 4000, // maxOutputTokens Limit around 4096
},
});
}
model = chat;
}

try {
if (imageParts.length > 0) {
result = await model.generateContent([prompt, ...imageParts]);
} else {
result = await model.sendMessage(prompt);
}

const response = await result.response;
if (response) {
const text = await response.text();
displayMessage(text, "ai");
} else {
// This block handles a null response, suggesting blocked content
displayMessage(
"This content is not safe for display based on current settings.",
"ai"
);
}
} catch (error) {
console.error("Error during message generation:", error);
displayMessage(
"This content is not safe for display based on current settings. or an internal error.",
"ai"
);
}
clearInputs();
}

function displayMessage(message, sender) {
const outputContainer = document.getElementById("output-container");
const msgDiv = document.createElement("div");
msgDiv.classList.add(
"chat-message",
sender === "user" ? "user-message" : "ai-message"
);

if (sender === "ai") {
// Show loading animation for AI messages
msgDiv.innerHTML =
'<div class="loading">' +
'<div class="loading-dot"></div>' +
'<div class="loading-dot"></div>' +
'<div class="loading-dot"></div>' +
"</div>";
outputContainer.appendChild(msgDiv);

// Simulate processing delay
setTimeout(() => {
// Clear loading animation
msgDiv.innerHTML = "";

if (message.startsWith("```") && message.endsWith("```")) {
// Code block handling
const codeContent = message.substring(3, message.length - 3);
const escapedCode = codeContent
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
msgDiv.innerHTML = `<pre><code class="hljs">${escapedCode}</code></pre>`;
window.hljs.highlightBlock(msgDiv.querySelector("code"));

// Add Copy button
const copyButton = document.createElement("button");
copyButton.innerText = "Copy code";
copyButton.onclick = function () {
navigator.clipboard.writeText(codeContent).then(
() => {
// Change text to show confirmation instead of using alert
copyButton.innerText = "Copied!";
// Optional: revert the button text back to "Copy code" after 2 seconds
setTimeout(() => {
copyButton.innerText = "Copy code";
}, 2000);
},
(err) => {
console.error("Failed to copy text: ", err);
}
);
};

msgDiv.appendChild(copyButton);
} else {
// For regular messages
msgDiv.innerHTML = marked.parse(message);
}

// Scroll the output container to the bottom to ensure the latest message is visible
outputContainer.scrollTop = outputContainer.scrollHeight;
}, 1500); // Adjust the delay as needed
} else {
// User messages are displayed immediately without the loading animation
msgDiv.innerHTML =
message.startsWith("```") && message.endsWith("```")
? `<pre><code class="hljs">${message.substring(
3,
message.length - 3
)}</code></pre>`
: marked.parse(message);

// If it's a code block, enable syntax highlighting and add a copy button
if (message.startsWith("```") && message.endsWith("```")) {
const codeBlock = msgDiv.querySelector("pre code");
window.hljs.highlightBlock(codeBlock);
const copyButton = document.createElement("button");
copyButton.innerText = "Copy code";
copyButton.onclick = function () {
navigator.clipboard.writeText(codeBlock.textContent).then(
() => {
alert("Code copied to clipboard!");
},
(err) => {
alert("Failed to copy text: ", err);
}
);
};
msgDiv.appendChild(copyButton);
}

outputContainer.appendChild(msgDiv);
}

// Ensure the latest message is visible
outputContainer.scrollTop = outputContainer.scrollHeight;
}

function clearInputs() {
document.getElementById("prompt-input").value = "";
document.getElementById("image-input").value = "";
clearImagePreview();
}

document
.getElementById("generate-btn")
.addEventListener("click", async () => {
const prompt = document.getElementById("prompt-input").value;
const files = document.getElementById("image-input").files;
const imageParts = await Promise.all(
[...files].map(fileToGenerativePart)
);
if (prompt.trim() !== "") {
displayMessage(prompt, "user");
await sendMessage(prompt, imageParts);
}
});

function clearGreeting() {
const outputField = document.getElementById("output-field");
if (outputField) {
outputField.style.display = "none"; // Hide the field completely
}
}

document
.getElementById("image-input")
.addEventListener("change", function (event) {
const [file] = event.target.files;
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
const previewContainer = document.getElementById("image-preview");
const previewImage =
previewContainer.getElementsByTagName("img")[0];
previewImage.src = e.target.result;
previewContainer.style.display = "flex";
};
reader.readAsDataURL(file);
}
});

document
.getElementById("clear-image")
.addEventListener("click", function () {
// Clear the preview
const previewContainer = document.getElementById("image-preview");
const previewImage = previewContainer.getElementsByTagName("img")[0];
previewImage.src = "";
previewContainer.style.display = "none";
// Clear the file input
document.getElementById("image-input").value = "";
});

function clearImagePreview() {
const previewContainer = document.getElementById("image-preview");
if (previewContainer) {
const previewImage = previewContainer.getElementsByTagName("img")[0];
previewImage.src = "";
previewContainer.style.display = "none";
}
}
</script>
<script>
var loader = document.getElementById("Loader");
window.addEventListener("load", function () {
loader.style.display = "none";
});
</script>
</body>
</html>
Loading

0 comments on commit 8d89c31

Please sign in to comment.