Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaser-123 authored Jul 2, 2024
1 parent f5f9ea6 commit cff0b27
Showing 1 changed file with 280 additions and 0 deletions.
280 changes: 280 additions & 0 deletions chatbot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
<!-- Author (C) @theSmartBisnu -->

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generative AI Multimodal Chat App</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/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>


<div class="chat-container">
<div id="output-field">How can I help you today?</div>
<div id="output-container" class="mb-3"></div>
<div class="input-group mb-3">
<!-- Image Preview Inside Input -->
<div id="image-preview-container" class="input-group-prepend" style="margin-right: -1px;">
<span id="image-preview" style="display: none;">
<img src="" alt="Image preview" style="height: 38px; margin-right: 5px;">
<button type="button" id="clear-image" class="close" aria-label="Close" style="font-size: 30px; line-height: 18px; color: red;">&times;</button>
</span>
</div>
<input type="text" id="prompt-input" class="form-control" placeholder="Type your prompt here..." aria-label="Message input">
<button class="input-group-text" 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/*">
<button id="generate-btn" class="btn btn-primary">Send</button>
</div>
</div>

<style>
body, html {
height: 100%;
margin: 0;
display: block;
padding-top: 20px;
width: 100%;
padding-left: 10px;
padding-right: 10px;
justify-content: center;
align-items: center;
background-color: brown; /* 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 = 'YOUR_API_KEY'; // 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>
</body>
</html>

0 comments on commit cff0b27

Please sign in to comment.