replit-clone / components /ai-agent.js
creative888's picture
add a chat with ai option in this, so the user can use the ai to write codes
0f0f876 verified
class AIAgent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.isOpen = false;
this.conversation = [
{
role: 'assistant',
content: 'πŸ‘‹ Hello! I\'m your AI coding assistant.\n\nI can help you with:\n\nπŸ’» Writing and debugging code\nπŸ“š Explaining programming concepts\nπŸš€ Setting up new projects\n⚑ Optimizing your existing code\n\nJust tell me what you need help with! For example:\n\n- "Write a Python function to calculate factorial"\n- "Explain how React hooks work"\n- "Help me debug this Node.js error"\n- "Create a React component for a login form"'
}
];
this.projectContext = {
currentFile: null,
projectType: null,
language: null
};
}
connectedCallback() {
this.render();
this.setupEventListeners();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
font-family: 'Inter', sans-serif;
}
.chat-container {
position: absolute;
bottom: 70px;
right: 0;
width: 400px;
height: 500px;
background: white;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
overflow: hidden;
transform: translateY(20px);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.chat-container.open {
transform: translateY(0);
opacity: 1;
visibility: visible;
}
.chat-header {
background: #0088CC;
color: white;
padding: 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-title {
font-weight: 600;
font-size: 16px;
}
.close-btn {
background: none;
border: none;
color: white;
cursor: pointer;
font-size: 20px;
}
.chat-messages {
flex: 1;
padding: 16px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 12px;
}
.message {
max-width: 80%;
padding: 12px 16px;
border-radius: 18px;
font-size: 14px;
line-height: 1.4;
}
.user-message {
align-self: flex-end;
background: #0088CC;
color: white;
border-bottom-right-radius: 4px;
}
.assistant-message {
align-self: flex-start;
background: #f1f5f9;
color: #334155;
border-bottom-left-radius: 4px;
}
.chat-input {
display: flex;
padding: 16px;
border-top: 1px solid #e2e8f0;
background: white;
}
.chat-input input {
flex: 1;
padding: 12px 16px;
border: 1px solid #cbd5e1;
border-radius: 24px;
outline: none;
font-size: 14px;
}
.chat-input input:focus {
border-color: #0088CC;
}
.send-btn {
background: #0088CC;
color: white;
border: none;
width: 40px;
height: 40px;
border-radius: 50%;
margin-left: 10px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.send-btn:hover {
background: #0077b3;
}
.agent-button {
width: 60px;
height: 60px;
border-radius: 50%;
background: #0088CC;
color: white;
border: none;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 136, 204, 0.3);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
transition: all 0.2s ease;
}
.agent-button:hover {
transform: scale(1.05);
box-shadow: 0 6px 16px rgba(0, 136, 204, 0.4);
}
.typing-indicator {
align-self: flex-start;
background: #f1f5f9;
padding: 12px 16px;
border-radius: 18px;
display: none;
}
.typing-indicator span {
height: 8px;
width: 8px;
background: #94a3b8;
border-radius: 50%;
display: inline-block;
margin: 0 2px;
animation: bounce 1.3s linear infinite;
}
.typing-indicator span:nth-child(2) {
animation-delay: 0.15s;
}
.typing-indicator span:nth-child(3) {
animation-delay: 0.3s;
}
@keyframes bounce {
0%, 60%, 100% {
transform: translateY(0);
}
30% {
transform: translateY(-5px);
}
}
@media (max-width: 480px) {
.chat-container {
width: calc(100vw - 40px);
height: 70vh;
}
}
</style>
<div class="chat-container" id="chatContainer">
<div class="chat-header">
<div class="chat-title">AI Coding Assistant</div>
<button class="close-btn" id="closeBtn">Γ—</button>
</div>
<div class="chat-messages" id="chatMessages">
${this.renderMessages()}
<div class="typing-indicator" id="typingIndicator">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="chat-input">
<input type="text" id="messageInput" placeholder="Ask me to create projects, write code, or explain concepts..." />
<button class="send-btn" id="sendBtn">
<i data-feather="send"></i>
</button>
</div>
</div>
<button class="agent-button" id="agentButton">
<i data-feather="message-square"></i>
</button>
`;
// Initialize feather icons
import('https://unpkg.com/feather-icons').then(() => {
feather.replace();
});
}
renderMessages() {
return this.conversation.map(msg => `
<div class="message ${msg.role}-message">
${msg.content}
</div>
`).join('');
}
setupEventListeners() {
const agentButton = this.shadowRoot.getElementById('agentButton');
const closeBtn = this.shadowRoot.getElementById('closeBtn');
const chatContainer = this.shadowRoot.getElementById('chatContainer');
const messageInput = this.shadowRoot.getElementById('messageInput');
const sendBtn = this.shadowRoot.getElementById('sendBtn');
const chatMessages = this.shadowRoot.getElementById('chatMessages');
const typingIndicator = this.shadowRoot.getElementById('typingIndicator');
agentButton.addEventListener('click', () => {
this.isOpen = !this.isOpen;
chatContainer.classList.toggle('open', this.isOpen);
});
closeBtn.addEventListener('click', () => {
this.isOpen = false;
chatContainer.classList.remove('open');
});
sendBtn.addEventListener('click', () => this.sendMessage());
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.sendMessage();
}
});
// Auto-scroll to bottom of messages
const observer = new MutationObserver(() => {
chatMessages.scrollTop = chatMessages.scrollHeight;
});
observer.observe(chatMessages, { childList: true, subtree: true });
}
async sendMessage() {
const messageInput = this.shadowRoot.getElementById('messageInput');
const chatMessages = this.shadowRoot.getElementById('chatMessages');
const typingIndicator = this.shadowRoot.getElementById('typingIndicator');
const message = messageInput.value.trim();
if (!message) return;
// Add user message to conversation
this.conversation.push({
role: 'user',
content: message
});
// Clear input
messageInput.value = '';
// Re-render messages
const messagesContainer = this.shadowRoot.getElementById('chatMessages');
messagesContainer.innerHTML = this.renderMessages() + `
<div class="typing-indicator" id="typingIndicator">
<span></span>
<span></span>
<span></span>
</div>
`;
// Show typing indicator
typingIndicator.style.display = 'block';
chatMessages.scrollTop = chatMessages.scrollHeight;
try {
// Call Grok API
const response = await this.callGrokAPI(message);
// Hide typing indicator
typingIndicator.style.display = 'none';
// Add assistant response to conversation
this.conversation.push({
role: 'assistant',
content: response
});
// Re-render messages
messagesContainer.innerHTML = this.renderMessages() + `
<div class="typing-indicator" id="typingIndicator">
<span></span>
<span></span>
<span></span>
</div>
`;
} catch (error) {
// Hide typing indicator
typingIndicator.style.display = 'none';
// Show error message
this.conversation.push({
role: 'assistant',
content: 'Sorry, I encountered an error. Please try again.'
});
// Re-render messages
messagesContainer.innerHTML = this.renderMessages() + `
<div class="typing-indicator" id="typingIndicator">
<span></span>
<span></span>
<span></span>
</div>
`;
}
chatMessages.scrollTop = chatMessages.scrollHeight;
}
async callGrokAPI(message) {
// Simulated API call - replace with actual API in production
try {
// Check for special commands
if (message.toLowerCase().includes('create project')) {
return this.handleProjectCreation(message);
} else if (message.toLowerCase().includes('write code')) {
return this.handleCodeRequest(message);
} else if (message.toLowerCase().includes('explain')) {
return this.handleExplanationRequest(message);
} else if (message.toLowerCase().includes('debug')) {
return this.handleDebugRequest(message);
}
// Default response
return `I can help you with coding tasks. Try asking me to:
- "Create a new React project"
- "Write a Python function to calculate factorial"
- "Explain how promises work in JavaScript"
- "Debug this code: [paste your code]"`;
} catch (error) {
console.error('Error:', error);
return 'Sorry, I encountered an error. Please try again.';
}
}
handleProjectCreation(message) {
// Extract project type from message
const projectType = message.match(/create (.*?) project/i)?.[1] || 'web';
this.projectContext.projectType = projectType;
let response = `I'll help you create a ${projectType} project. `;
switch(projectType.toLowerCase()) {
case 'react':
response += `Here's how to set up a basic React project:\n\n1. Create these files:\n- index.html\n- app.js\n- styles.css\n\n2. Add this to index.html:\n\`\`\`html\n<!DOCTYPE html>\n<html>\n<head>\n <title>React App</title>\n <link rel="stylesheet" href="styles.css">\n</head>\n<body>\n <div id="root"></div>\n <script src="app.js"></script>\n</body>\n</html>\n\`\`\`\n\n3. Add this to app.js:\n\`\`\`javascript\nimport React from 'react';\nimport ReactDOM from 'react-dom';\n\nfunction App() {\n return (\n <div>\n <h1>Hello React!</h1>\n </div>\n );\n}\n\nReactDOM.render(<App />, document.getElementById('root'));\n\`\`\``;
this.projectContext.language = 'javascript';
break;
case 'python':
response += `Here's a basic Python project structure:\n\n1. Create main.py:\n\`\`\`python\ndef main():\n print("Hello Python!")\n\nif __name__ == "__main__":\n main()\n\`\`\`\n\n2. Create requirements.txt for dependencies`;
this.projectContext.language = 'python';
break;
default:
response += `Here's a basic web project structure:\n\n1. Create index.html:\n\`\`\`html\n<!DOCTYPE html>\n<html>\n<head>\n <title>My Project</title>\n <link rel="stylesheet" href="styles.css">\n</head>\n<body>\n <h1>Hello World!</h1>\n <script src="script.js"></script>\n</body>\n</html>\n\`\`\`\n\n2. Create styles.css for styling\n3. Create script.js for JavaScript`;
this.projectContext.language = 'javascript';
}
return response;
}
handleCodeRequest(message) {
if (!this.projectContext.language) {
return "First tell me what kind of project you're working on (e.g., 'Create a React project') so I can provide language-specific help.";
}
const codeType = message.match(/write (.*?) code/i)?.[1] || 'function';
let codeExample = '';
switch(this.projectContext.language) {
case 'javascript':
if (codeType.includes('function')) {
codeExample = `\`\`\`javascript\n// Function example\nfunction ${this.getFunctionName(message)}(${this.getFunctionParams(message)}) {\n // ${this.getFunctionDescription(message)}\n return result;\n}\n\`\`\``;
} else if (codeType.includes('component')) {
codeExample = `\`\`\`javascript\n// React component example\nfunction ${this.getComponentName(message)}() {\n return (\n <div>\n <h1>${this.getComponentTitle(message)}</h1>\n </div>\n );\n}\n\`\`\``;
}
break;
case 'python':
codeExample = `\`\`\`python\ndef ${this.getFunctionName(message)}(${this.getFunctionParams(message)}):\n """\n ${this.getFunctionDescription(message)}\n """\n return result\n\`\`\``;
break;
default:
codeExample = `Here's a generic code example for your request:\n\`\`\`\n// Implement your ${codeType} here\n\`\`\``;
}
return `Here's ${this.projectContext.language} code for ${codeType}:\n\n${codeExample}\n\nWould you like me to explain any part of this?`;
}
handleExplanationRequest(message) {
const concept = message.match(/explain (.*)/i)?.[1] || 'this concept';
return `Here's an explanation of ${concept}:\n\n${this.getConceptExplanation(concept)}\n\nLet me know if you'd like more details or examples.`;
}
handleDebugRequest(message) {
const codeBlock = message.match(/```[\s\S]*?```/)?.[0] || 'your code';
return `Looking at ${codeBlock.includes('```') ? 'the code' : 'your code'}, here are potential issues to check:\n\n1. Syntax errors\n2. Variable scope issues\n3. Type mismatches\n4. Async/await problems\n\nFor more specific help, please share the exact error message you're getting.`;
}
// Helper methods
getFunctionName(message) {
return message.match(/function named (.*?)[\s,.]/i)?.[1] || 'exampleFunction';
}
getFunctionParams(message) {
return message.match(/parameters? (.*?)[\s,.]/i)?.[1] || 'param1, param2';
}
getFunctionDescription(message) {
return message.match(/that (.*?)[\s,.]/i)?.[1] || 'Does something useful';
}
getComponentName(message) {
return message.match(/component named (.*?)[\s,.]/i)?.[1] || 'ExampleComponent';
}
getComponentTitle(message) {
return message.match(/title (.*?)[\s,.]/i)?.[1] || 'My Component';
}
getConceptExplanation(concept) {
const explanations = {
'react': 'React is a JavaScript library for building user interfaces. It lets you create reusable UI components and efficiently update the DOM when data changes.',
'python': 'Python is a high-level, interpreted programming language known for its readability and versatility. It\'s great for web development, data analysis, AI, and more.',
'javascript': 'JavaScript is the programming language of the web. It runs in browsers and can manipulate HTML/CSS, handle user interactions, and make network requests.',
'promises': 'Promises in JavaScript represent the eventual completion (or failure) of an asynchronous operation and its resulting value. They help avoid callback hell.'
};
return explanations[concept.toLowerCase()] ||
`I'll explain ${concept} in simple terms...`;
}
}
customElements.define('ai-agent', AIAgent);