Skip to content

Commit 2f2bfd1

Browse files
authored
1 parent b382ff1 commit 2f2bfd1

File tree

1 file changed

+191
-0
lines changed

1 file changed

+191
-0
lines changed

gemini-chat.html

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Gemini Chat App</title>
7+
<script type="module">
8+
import { GoogleGenerativeAI } from "https://esm.run/@google/generative-ai";
9+
import { marked } from "https://esm.run/marked";
10+
11+
let chat;
12+
let currentModel = "gemini-1.5-pro";
13+
let chatHistory = [];
14+
15+
function getApiKey() {
16+
let apiKey = localStorage.getItem("GEMINI_API_KEY");
17+
if (!apiKey) {
18+
apiKey = prompt("Please enter your Gemini API key:");
19+
if (apiKey) {
20+
localStorage.setItem("GEMINI_API_KEY", apiKey);
21+
}
22+
}
23+
return apiKey;
24+
}
25+
26+
async function getGenerativeModel(params) {
27+
const API_KEY = getApiKey();
28+
const genAI = new GoogleGenerativeAI(API_KEY);
29+
return genAI.getGenerativeModel(params);
30+
}
31+
32+
async function initChat() {
33+
try {
34+
const model = await getGenerativeModel({ model: currentModel });
35+
chat = model.startChat({
36+
history: chatHistory,
37+
});
38+
displayMessage("System", `Chatting with ${currentModel}`);
39+
} catch (error) {
40+
displayError("Failed to initialize chat: " + error.message);
41+
}
42+
}
43+
44+
async function sendMessage() {
45+
const userInput = document.getElementById("user-input");
46+
const message = userInput.value.trim();
47+
if (message) {
48+
displayMessage("You", message);
49+
userInput.value = "";
50+
51+
try {
52+
chatHistory.push({ role: "user", parts: [{ text: message }] });
53+
const startTime = performance.now();
54+
const result = await chat.sendMessageStream(message);
55+
let fullResponse = "";
56+
for await (const chunk of result.stream) {
57+
const chunkText = chunk.text();
58+
fullResponse += chunkText;
59+
updateModelResponse(fullResponse);
60+
}
61+
const endTime = performance.now();
62+
const duration = ((endTime - startTime) / 1000).toFixed(2);
63+
chatHistory.push({ role: "model", parts: [{ text: fullResponse }] });
64+
let usage = (await result.response).usageMetadata;
65+
console.log("Full result:", result);
66+
updateUsageMetadata(usage);
67+
updateDuration(duration);
68+
} catch (error) {
69+
displayError("Error: " + error.message);
70+
}
71+
}
72+
}
73+
74+
function displayMessage(sender, message) {
75+
const chatMessages = document.getElementById("chat-messages");
76+
const messageElement = document.createElement("div");
77+
messageElement.innerHTML = `<strong>${sender}:</strong> ${marked.parse(message)}`;
78+
chatMessages.appendChild(messageElement);
79+
chatMessages.scrollTop = chatMessages.scrollHeight;
80+
}
81+
82+
function displayError(message) {
83+
const chatMessages = document.getElementById("chat-messages");
84+
const errorElement = document.createElement("div");
85+
errorElement.innerHTML = `<strong style="color: red;">Error:</strong> <span style="color: red;">${message}</span>`;
86+
chatMessages.appendChild(errorElement);
87+
chatMessages.scrollTop = chatMessages.scrollHeight;
88+
}
89+
90+
function updateModelResponse(response) {
91+
const chatMessages = document.getElementById("chat-messages");
92+
let modelResponse = chatMessages.lastElementChild;
93+
if (!modelResponse || !modelResponse.querySelector("strong")?.textContent.includes("Model")) {
94+
modelResponse = document.createElement("div");
95+
modelResponse.innerHTML = "<strong>Model:</strong> ";
96+
chatMessages.appendChild(modelResponse);
97+
}
98+
modelResponse.innerHTML = `<strong>Model:</strong> ${marked.parse(response)}`;
99+
chatMessages.scrollTop = chatMessages.scrollHeight;
100+
}
101+
102+
function updateUsageMetadata(metadata) {
103+
const usageMetadataElement = document.getElementById("usage-metadata");
104+
usageMetadataElement.textContent = JSON.stringify(metadata, null, 2);
105+
}
106+
107+
function updateDuration(duration) {
108+
const durationElement = document.getElementById("api-duration");
109+
durationElement.textContent = `Last API call duration: ${duration} seconds`;
110+
}
111+
112+
function changeModel() {
113+
const modelSelect = document.getElementById("model-select");
114+
currentModel = modelSelect.value;
115+
displayMessage("System", `Changing model to ${currentModel}. Reinitializing chat...`);
116+
chatHistory = []; // Clear history when changing models
117+
initChat();
118+
}
119+
120+
function clearChat() {
121+
chatHistory = [];
122+
document.getElementById("chat-messages").innerHTML = "";
123+
document.getElementById("usage-metadata").textContent = "";
124+
document.getElementById("api-duration").textContent = "";
125+
initChat();
126+
}
127+
128+
window.onload = () => {
129+
initChat();
130+
document.getElementById("send-button").addEventListener("click", sendMessage);
131+
document.getElementById("user-input").addEventListener("keypress", (e) => {
132+
if (e.key === "Enter") sendMessage();
133+
});
134+
document.getElementById("model-select").addEventListener("change", changeModel);
135+
document.getElementById("clear-button").addEventListener("click", clearChat);
136+
};
137+
</script>
138+
<style>
139+
body {
140+
font-family: Arial, sans-serif;
141+
max-width: 800px;
142+
margin: 0 auto;
143+
padding: 20px;
144+
}
145+
#chat-messages {
146+
height: 400px;
147+
overflow-y: auto;
148+
border: 1px solid #ccc;
149+
padding: 10px;
150+
margin-bottom: 10px;
151+
}
152+
#user-input {
153+
width: calc(100% - 140px);
154+
padding: 5px;
155+
}
156+
#send-button, #clear-button {
157+
width: 60px;
158+
padding: 5px;
159+
}
160+
#model-select {
161+
margin-bottom: 10px;
162+
}
163+
#usage-metadata {
164+
white-space: pre-wrap;
165+
font-family: monospace;
166+
background-color: #f0f0f0;
167+
padding: 10px;
168+
margin-top: 10px;
169+
}
170+
#api-duration {
171+
margin-top: 10px;
172+
font-weight: bold;
173+
}
174+
</style>
175+
</head>
176+
<body>
177+
<h1>Gemini Chat App</h1>
178+
<select id="model-select">
179+
<option value="gemini-1.5-pro">gemini-1.5-pro (default)</option>
180+
<option value="gemini-1.5-pro-exp-0827">gemini-1.5-pro-exp-0827</option>
181+
<option value="gemini-1.5-flash-exp-0827">gemini-1.5-flash-exp-0827</option>
182+
<option value="gemini-1.5-flash-8b-exp-0827">gemini-1.5-flash-8b-exp-0827</option>
183+
</select>
184+
<div id="chat-messages"></div>
185+
<input type="text" id="user-input" placeholder="Type your message...">
186+
<button id="send-button">Send</button>
187+
<button id="clear-button">Clear</button>
188+
<div id="api-duration"></div>
189+
<pre id="usage-metadata"></pre>
190+
</body>
191+
</html>

0 commit comments

Comments
 (0)