Spaces:
Running
Running
Update index.html
Browse files- index.html +188 -23
index.html
CHANGED
@@ -162,6 +162,42 @@
|
|
162 |
border-left: none;
|
163 |
border-top: none;
|
164 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
</style>
|
166 |
</head>
|
167 |
<body class="scanlines min-h-screen">
|
@@ -195,7 +231,7 @@
|
|
195 |
</div>
|
196 |
|
197 |
<!-- Terminal Content -->
|
198 |
-
<div class="p-4 h-96 overflow-y-auto terminal-font text-green-200">
|
199 |
<div class="mb-4">
|
200 |
<span class="neon-purple">user@vibecode:~$</span> <span class="neon-green">welcome to Vibecode</span>
|
201 |
</div>
|
@@ -285,7 +321,7 @@
|
|
285 |
<a href="#" class="mx-2 hover:text-neon-green transition-all">Discord</a>
|
286 |
<a href="#" class="mx-2 hover:text-neon-green transition-all">GitHub</a>
|
287 |
</div>
|
288 |
-
<p>Vibecode ©
|
289 |
</footer>
|
290 |
</div>
|
291 |
|
@@ -294,6 +330,11 @@
|
|
294 |
const userInput = document.getElementById('user-input');
|
295 |
const sendBtn = document.getElementById('send-btn');
|
296 |
const chatMessages = document.getElementById('chat-messages');
|
|
|
|
|
|
|
|
|
|
|
297 |
|
298 |
// Typing animation for the terminal prompt
|
299 |
const typingElement = document.querySelector('.typing');
|
@@ -340,14 +381,29 @@
|
|
340 |
// Add user message
|
341 |
addMessage(message, 'user');
|
342 |
|
343 |
-
//
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
351 |
|
352 |
// Clear input
|
353 |
userInput.value = '';
|
@@ -364,26 +420,135 @@
|
|
364 |
? 'bg-neon-green/10 border border-neon-green/30 text-neon-green'
|
365 |
: 'bg-gray-800/50 border border-neon-purple/30 text-gray-300'
|
366 |
}`;
|
367 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
368 |
|
369 |
messageDiv.appendChild(bubble);
|
370 |
chatMessages.appendChild(messageDiv);
|
371 |
|
372 |
// Scroll to bottom
|
373 |
-
|
374 |
}
|
375 |
|
376 |
-
function
|
377 |
-
|
378 |
-
const
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
|
386 |
-
return
|
387 |
}
|
388 |
|
389 |
// Event listeners
|
@@ -395,5 +560,5 @@
|
|
395 |
});
|
396 |
});
|
397 |
</script>
|
398 |
-
|
399 |
</html>
|
|
|
162 |
border-left: none;
|
163 |
border-top: none;
|
164 |
}
|
165 |
+
|
166 |
+
.loading-dots:after {
|
167 |
+
content: '...';
|
168 |
+
animation: dots 1.5s steps(5, end) infinite;
|
169 |
+
display: inline-block;
|
170 |
+
width: 0;
|
171 |
+
overflow: hidden;
|
172 |
+
vertical-align: bottom;
|
173 |
+
}
|
174 |
+
|
175 |
+
@keyframes dots {
|
176 |
+
0%, 20% { width: 0; }
|
177 |
+
40% { width: 0.2em; }
|
178 |
+
60% { width: 0.4em; }
|
179 |
+
80% { width: 0.6em; }
|
180 |
+
100% { width: 0; }
|
181 |
+
}
|
182 |
+
|
183 |
+
/* Code syntax highlighting */
|
184 |
+
.code-snippet {
|
185 |
+
background-color: rgba(0,0,0,0.4);
|
186 |
+
padding: 12px;
|
187 |
+
border-radius: 4px;
|
188 |
+
border-left: 3px solid var(--neon-green);
|
189 |
+
font-family: 'IBM Plex Mono', monospace;
|
190 |
+
font-size: 0.9em;
|
191 |
+
overflow-x: auto;
|
192 |
+
margin: 10px 0;
|
193 |
+
}
|
194 |
+
|
195 |
+
.code-keyword { color: #ff79c6; }
|
196 |
+
.code-string { color: #f1fa8c; }
|
197 |
+
.code-comment { color: #6272a4; }
|
198 |
+
.code-function { color: #50fa7b; }
|
199 |
+
.code-variable { color: #8be9fd; }
|
200 |
+
.code-number { color: #bd93f9; }
|
201 |
</style>
|
202 |
</head>
|
203 |
<body class="scanlines min-h-screen">
|
|
|
231 |
</div>
|
232 |
|
233 |
<!-- Terminal Content -->
|
234 |
+
<div class="p-4 h-96 overflow-y-auto terminal-font text-green-200" id="terminal-content">
|
235 |
<div class="mb-4">
|
236 |
<span class="neon-purple">user@vibecode:~$</span> <span class="neon-green">welcome to Vibecode</span>
|
237 |
</div>
|
|
|
321 |
<a href="#" class="mx-2 hover:text-neon-green transition-all">Discord</a>
|
322 |
<a href="#" class="mx-2 hover:text-neon-green transition-all">GitHub</a>
|
323 |
</div>
|
324 |
+
<p>Vibecode © 2025 | Onchain Replit with Vibes</p>
|
325 |
</footer>
|
326 |
</div>
|
327 |
|
|
|
330 |
const userInput = document.getElementById('user-input');
|
331 |
const sendBtn = document.getElementById('send-btn');
|
332 |
const chatMessages = document.getElementById('chat-messages');
|
333 |
+
const terminalContent = document.getElementById('terminal-content');
|
334 |
+
|
335 |
+
// Gemini API Key
|
336 |
+
const GEMINI_API_KEY = "AIzaSyAX_-SVl0NpZ8Iv8mlkJ3olLbgxs_fTyGw";
|
337 |
+
const GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent";
|
338 |
|
339 |
// Typing animation for the terminal prompt
|
340 |
const typingElement = document.querySelector('.typing');
|
|
|
381 |
// Add user message
|
382 |
addMessage(message, 'user');
|
383 |
|
384 |
+
// Add loading indicator
|
385 |
+
const loadingId = addLoadingIndicator();
|
386 |
+
|
387 |
+
// Call Gemini API
|
388 |
+
callGeminiAPI(message)
|
389 |
+
.then(response => {
|
390 |
+
// Remove loading indicator
|
391 |
+
removeLoadingIndicator(loadingId);
|
392 |
+
|
393 |
+
// Add AI response
|
394 |
+
addMessage(formatResponse(response, message), 'ai');
|
395 |
+
|
396 |
+
// Scroll to bottom
|
397 |
+
terminalContent.scrollTop = terminalContent.scrollHeight;
|
398 |
+
})
|
399 |
+
.catch(error => {
|
400 |
+
// Remove loading indicator
|
401 |
+
removeLoadingIndicator(loadingId);
|
402 |
+
|
403 |
+
// Add error message
|
404 |
+
addMessage("Error processing your request. Please try again.", 'ai');
|
405 |
+
console.error("Gemini API Error:", error);
|
406 |
+
});
|
407 |
|
408 |
// Clear input
|
409 |
userInput.value = '';
|
|
|
420 |
? 'bg-neon-green/10 border border-neon-green/30 text-neon-green'
|
421 |
: 'bg-gray-800/50 border border-neon-purple/30 text-gray-300'
|
422 |
}`;
|
423 |
+
|
424 |
+
// Format the response with code highlighting if it contains code
|
425 |
+
if (sender === 'ai' && text.includes('```')) {
|
426 |
+
const formattedText = formatCodeBlocks(text);
|
427 |
+
bubble.innerHTML = formattedText;
|
428 |
+
} else {
|
429 |
+
bubble.textContent = text;
|
430 |
+
}
|
431 |
|
432 |
messageDiv.appendChild(bubble);
|
433 |
chatMessages.appendChild(messageDiv);
|
434 |
|
435 |
// Scroll to bottom
|
436 |
+
terminalContent.scrollTop = terminalContent.scrollHeight;
|
437 |
}
|
438 |
|
439 |
+
function addLoadingIndicator() {
|
440 |
+
const loadingId = 'loading-' + Date.now();
|
441 |
+
const loadingDiv = document.createElement('div');
|
442 |
+
loadingDiv.id = loadingId;
|
443 |
+
loadingDiv.className = 'flex justify-start';
|
444 |
+
|
445 |
+
const loadingBubble = document.createElement('div');
|
446 |
+
loadingBubble.className = 'terminal-font rounded px-4 py-2 bg-gray-800/50 border border-neon-purple/30 text-gray-300';
|
447 |
+
|
448 |
+
const loadingText = document.createElement('span');
|
449 |
+
loadingText.className = 'loading-dots';
|
450 |
+
loadingText.textContent = 'Generating smart contract';
|
451 |
+
|
452 |
+
loadingBubble.appendChild(loadingText);
|
453 |
+
loadingDiv.appendChild(loadingBubble);
|
454 |
+
chatMessages.appendChild(loadingDiv);
|
455 |
+
|
456 |
+
// Scroll to bottom
|
457 |
+
terminalContent.scrollTop = terminalContent.scrollHeight;
|
458 |
+
|
459 |
+
return loadingId;
|
460 |
+
}
|
461 |
+
|
462 |
+
function removeLoadingIndicator(loadingId) {
|
463 |
+
const loadingElement = document.getElementById(loadingId);
|
464 |
+
if (loadingElement) {
|
465 |
+
loadingElement.remove();
|
466 |
+
}
|
467 |
+
}
|
468 |
+
|
469 |
+
async function callGeminiAPI(message) {
|
470 |
+
// Construct prompt for blockchain context
|
471 |
+
const blockchainPrompt = `You are Vibecode AI, an expert in blockchain development and smart contract creation.
|
472 |
+
The user will give you a request related to creating tokens, NFTs, DAOs, or other blockchain applications.
|
473 |
+
|
474 |
+
Please respond with:
|
475 |
+
1. An explanation of what you'll create based on their request
|
476 |
+
2. The appropriate smart contract code (Solidity) to implement their request
|
477 |
+
3. Clear deployment instructions
|
478 |
+
|
479 |
+
Current user request: "${message}"`;
|
480 |
+
|
481 |
+
try {
|
482 |
+
const response = await fetch(`${GEMINI_API_URL}?key=${GEMINI_API_KEY}`, {
|
483 |
+
method: 'POST',
|
484 |
+
headers: {
|
485 |
+
'Content-Type': 'application/json'
|
486 |
+
},
|
487 |
+
body: JSON.stringify({
|
488 |
+
contents: [{
|
489 |
+
parts: [{
|
490 |
+
text: blockchainPrompt
|
491 |
+
}]
|
492 |
+
}]
|
493 |
+
})
|
494 |
+
});
|
495 |
+
|
496 |
+
if (!response.ok) {
|
497 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
498 |
+
}
|
499 |
+
|
500 |
+
const data = await response.json();
|
501 |
+
|
502 |
+
// Extract the text from the response
|
503 |
+
if (data.candidates &&
|
504 |
+
data.candidates[0] &&
|
505 |
+
data.candidates[0].content &&
|
506 |
+
data.candidates[0].content.parts &&
|
507 |
+
data.candidates[0].content.parts[0]) {
|
508 |
+
return data.candidates[0].content.parts[0].text;
|
509 |
+
} else {
|
510 |
+
throw new Error("Unexpected response format from Gemini API");
|
511 |
+
}
|
512 |
+
} catch (error) {
|
513 |
+
console.error("Error calling Gemini API:", error);
|
514 |
+
throw error;
|
515 |
+
}
|
516 |
+
}
|
517 |
+
|
518 |
+
function formatResponse(response, userRequest) {
|
519 |
+
// You can customize the formatting of the AI response here
|
520 |
+
return response;
|
521 |
+
}
|
522 |
+
|
523 |
+
function formatCodeBlocks(text) {
|
524 |
+
// Split the text by code blocks
|
525 |
+
const parts = text.split('```');
|
526 |
+
let result = '';
|
527 |
+
|
528 |
+
for (let i = 0; i < parts.length; i++) {
|
529 |
+
if (i % 2 === 0) {
|
530 |
+
// Regular text
|
531 |
+
result += parts[i];
|
532 |
+
} else {
|
533 |
+
// Code block
|
534 |
+
const codeLines = parts[i].split('\n');
|
535 |
+
const language = codeLines[0] || '';
|
536 |
+
const code = codeLines.slice(1).join('\n');
|
537 |
+
|
538 |
+
// Basic syntax highlighting for Solidity
|
539 |
+
let highlightedCode = code
|
540 |
+
.replace(/\b(contract|function|address|uint|string|bytes|mapping|struct|enum|bool|public|private|internal|external|view|pure|returns|memory|storage|calldata)\b/g, '<span class="code-keyword">$1</span>')
|
541 |
+
.replace(/(\/\/.*)/g, '<span class="code-comment">$1</span>')
|
542 |
+
.replace(/"([^"]*)"/g, '<span class="code-string">"$1"</span>')
|
543 |
+
.replace(/\b(\d+)\b/g, '<span class="code-number">$1</span>')
|
544 |
+
.replace(/\b(constructor|require|assert|emit)\b/g, '<span class="code-function">$1</span>')
|
545 |
+
.replace(/\b(msg|block|tx|address)\b/g, '<span class="code-variable">$1</span>');
|
546 |
+
|
547 |
+
result += `<div class="code-snippet">${highlightedCode}</div>`;
|
548 |
+
}
|
549 |
+
}
|
550 |
|
551 |
+
return result;
|
552 |
}
|
553 |
|
554 |
// Event listeners
|
|
|
560 |
});
|
561 |
});
|
562 |
</script>
|
563 |
+
</body>
|
564 |
</html>
|