Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AI Code Chat</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .code-block { | |
| font-family: 'Courier New', monospace; | |
| background-color: #f3f4f6; | |
| padding: 1rem; | |
| border-radius: 0.5rem; | |
| overflow-x: auto; | |
| white-space: pre; | |
| margin-bottom: 1rem; | |
| border-left: 4px solid #3b82f6; | |
| } | |
| .chat-message.user { | |
| background-color: #eef2ff; | |
| border-radius: 1rem 1rem 0 1rem; | |
| } | |
| .chat-message.ai { | |
| background-color: #f8fafc; | |
| border-radius: 1rem 1rem 1rem 0; | |
| } | |
| .loader { | |
| border: 3px solid #f3f3f3; | |
| border-top: 3px solid #3b82f6; | |
| border-radius: 50%; | |
| width: 20px; | |
| height: 20px; | |
| animation: spin 1s linear infinite; | |
| display: inline-block; | |
| vertical-align: middle; | |
| margin-left: 8px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .file-tree-item { | |
| transition: all 0.2s; | |
| } | |
| .file-tree-item:hover { | |
| background-color: #f1f5f9; | |
| cursor: pointer; | |
| } | |
| .repo-info-card { | |
| transition: all 0.3s; | |
| } | |
| .repo-info-card:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <header class="text-center mb-10"> | |
| <h1 class="text-4xl font-bold text-blue-600 mb-2"> | |
| <i class="fas fa-robot mr-2"></i> AI Code Chat | |
| </h1> | |
| <p class="text-gray-600 max-w-2xl mx-auto"> | |
| Analyze any GitHub repository with AI. Ask questions about the codebase and get insightful answers. | |
| </p> | |
| </header> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
| <!-- Configuration Panel --> | |
| <div class="bg-white p-6 rounded-xl shadow-md lg:col-span-1"> | |
| <h2 class="text-xl font-semibold mb-4 text-blue-600"> | |
| <i class="fas fa-cog mr-2"></i>Settings | |
| </h2> | |
| <div class="mb-4"> | |
| <label for="apiKey" class="block text-sm font-medium text-gray-700 mb-1"> | |
| <i class="fas fa-key mr-1"></i>OpenAI API Key | |
| </label> | |
| <div class="relative"> | |
| <input | |
| type="password" | |
| id="apiKey" | |
| placeholder="sk-..." | |
| class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" | |
| > | |
| <button class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 focus:outline-none" id="toggleKey"> | |
| <i class="fas fa-eye"></i> | |
| </button> | |
| </div> | |
| <p class="text-xs text-gray-500 mt-1"> | |
| Your API key is stored locally and never sent to our servers. | |
| </p> | |
| </div> | |
| <div class="mb-6"> | |
| <label for="githubRepo" class="block text-sm font-medium text-gray-700 mb-1"> | |
| <i class="fab fa-github mr-1"></i>GitHub Repository URL | |
| </label> | |
| <input | |
| type="text" | |
| id="githubRepo" | |
| placeholder="https://github.com/username/repo" | |
| class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" | |
| > | |
| <button | |
| id="loadRepoBtn" | |
| class="mt-3 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-md flex items-center justify-center transition duration-200" | |
| > | |
| <i class="fas fa-download mr-2"></i>Load & Index Code | |
| </button> | |
| </div> | |
| <div id="repoInfo" class="hidden bg-gray-50 p-4 rounded-lg repo-info-card"> | |
| <div class="flex justify-between items-start mb-2"> | |
| <div> | |
| <h3 id="repoName" class="font-semibold text-blue-600"></h3> | |
| <p id="repoDescription" class="text-sm text-gray-600"></p> | |
| </div> | |
| <span id="repoLang" class="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full"></span> | |
| </div> | |
| <div class="flex justify-between text-xs text-gray-500 mt-3"> | |
| <span id="repoStars"><i class="fas fa-star mr-1"></i></span> | |
| <span id="repoIssues"><i class="fas fa-exclamation-circle mr-1"></i></span> | |
| <span id="repoSize"><i class="fas fa-code mr-1"></i></span> | |
| </div> | |
| </div> | |
| <div id="processingStatus" class="hidden mt-4"> | |
| <div class="flex flex-col space-y-3"> | |
| <div class="flex items-center"> | |
| <span class="w-4 h-4 rounded-full bg-blue-600 mr-2 flex-shrink-0"></span> | |
| <span class="text-sm font-medium text-gray-700">Processing files...</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="w-4 h-4 rounded-full bg-blue-600 mr-2 flex-shrink-0"></span> | |
| <span class="text-sm font-medium text-gray-700">Building code index...</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="w-4 h-4 rounded-full bg-blue-600 mr-2 flex-shrink-0"></span> | |
| <span class="text-sm font-medium text-gray-700">Ready for questions!</span> | |
| </div> | |
| </div> | |
| <div class="mt-3 relative pt-1"> | |
| <div class="flex mb-2 items-center justify-between"> | |
| <div> | |
| <span class="text-xs font-semibold inline-block text-blue-600"> | |
| Progress | |
| </span> | |
| </div> | |
| <div class="text-right"> | |
| <span class="text-xs font-semibold inline-block text-blue-600" id="progressPercent"> | |
| 0% | |
| </span> | |
| </div> | |
| </div> | |
| <div class="overflow-hidden h-2 mb-4 text-xs flex rounded bg-blue-200"> | |
| <div id="progressBar" style="width:0%" class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-blue-500"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="fileTree" class="hidden max-h-96 overflow-y-auto mt-4 border border-gray-200 rounded-lg p-3"> | |
| <h4 class="font-medium text-gray-700 mb-2"> | |
| <i class="fas fa-folder-open mr-1"></i>Repository Structure | |
| </h4> | |
| <div id="treeContent" class="space-y-1"></div> | |
| </div> | |
| </div> | |
| <!-- Chat Interface --> | |
| <div class="bg-white p-6 rounded-xl shadow-md lg:col-span-2 flex flex-col"> | |
| <h2 class="text-xl font-semibold mb-4 text-blue-600"> | |
| <i class="fas fa-comments mr-2"></i>Code Chat | |
| </h2> | |
| <div id="chatContainer" class="flex-grow mb-4 overflow-y-auto max-h-[500px] space-y-3"> | |
| <div class="text-center text-gray-500 py-10 hidden" id="noRepoMessage"> | |
| <i class="fas fa-code-branch text-4xl mb-4 text-blue-200"></i> | |
| <p class="text-lg">Load a GitHub repository to start chatting about its code</p> | |
| </div> | |
| <div id="chatMessages"></div> | |
| </div> | |
| <div class="mt-auto"> | |
| <form id="chatForm" class="flex"> | |
| <input | |
| type="text" | |
| id="userInput" | |
| placeholder="Ask about the code..." | |
| class="flex-grow px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50" | |
| disabled | |
| > | |
| <button | |
| type="submit" | |
| id="sendBtn" | |
| class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-r-md transition duration-200 disabled:opacity-50" | |
| disabled | |
| > | |
| <i class="fas fa-paper-plane"></i> | |
| </button> | |
| </form> | |
| <div class="flex items-center mt-2 text-xs text-gray-500"> | |
| <span>Model: <span id="modelName">gpt-4o-mini</span></span> | |
| <span class="mx-2">|</span> | |
| <span>Built with <i class="fas fa-heart text-red-400 ml-1"></i></span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // State management | |
| const state = { | |
| apiKey: '', | |
| githubRepo: '', | |
| indexedFiles: [], | |
| chatHistory: [] | |
| }; | |
| // DOM elements | |
| const elements = { | |
| apiKey: document.getElementById('apiKey'), | |
| githubRepo: document.getElementById('githubRepo'), | |
| loadRepoBtn: document.getElementById('loadRepoBtn'), | |
| repoInfo: document.getElementById('repoInfo'), | |
| repoName: document.getElementById('repoName'), | |
| repoDescription: document.getElementById('repoDescription'), | |
| repoLang: document.getElementById('repoLang'), | |
| repoStars: document.getElementById('repoStars'), | |
| repoIssues: document.getElementById('repoIssues'), | |
| repoSize: document.getElementById('repoSize'), | |
| processingStatus: document.getElementById('processingStatus'), | |
| progressBar: document.getElementById('progressBar'), | |
| progressPercent: document.getElementById('progressPercent'), | |
| fileTree: document.getElementById('fileTree'), | |
| treeContent: document.getElementById('treeContent'), | |
| chatContainer: document.getElementById('chatContainer'), | |
| noRepoMessage: document.getElementById('noRepoMessage'), | |
| chatMessages: document.getElementById('chatMessages'), | |
| chatForm: document.getElementById('chatForm'), | |
| userInput: document.getElementById('userInput'), | |
| sendBtn: document.getElementById('sendBtn'), | |
| toggleKey: document.getElementById('toggleKey') | |
| }; | |
| // Initialize the application | |
| function init() { | |
| // Load saved API key if exists | |
| const savedKey = localStorage.getItem('openai_api_key'); | |
| if (savedKey) { | |
| state.apiKey = savedKey; | |
| elements.apiKey.value = savedKey; | |
| toggleKeyVisibility(true); | |
| } | |
| // Load saved repo if exists | |
| const savedRepo = localStorage.getItem('github_repo'); | |
| if (savedRepo) { | |
| state.githubRepo = savedRepo; | |
| elements.githubRepo.value = savedRepo; | |
| } | |
| // Event listeners | |
| elements.apiKey.addEventListener('change', handleApiKeyChange); | |
| elements.githubRepo.addEventListener('change', handleGithubRepoChange); | |
| elements.loadRepoBtn.addEventListener('click', handleLoadRepo); | |
| elements.chatForm.addEventListener('submit', handleChatSubmit); | |
| elements.toggleKey.addEventListener('click', toggleKeyVisibility); | |
| // Show initial state | |
| toggleNoRepoMessage(true); | |
| } | |
| // Toggle API key visibility | |
| let keyVisible = false; | |
| function toggleKeyVisibility(forceShow = false) { | |
| if (forceShow) { | |
| elements.apiKey.type = 'text'; | |
| elements.toggleKey.innerHTML = '<i class="fas fa-eye-slash"></i>'; | |
| keyVisible = true; | |
| return; | |
| } | |
| keyVisible = !keyVisible; | |
| elements.apiKey.type = keyVisible ? 'text' : 'password'; | |
| elements.toggleKey.innerHTML = keyVisible ? '<i class="fas fa-eye-slash"></i>' : '<i class="fas fa-eye"></i>'; | |
| } | |
| // Handle API key change | |
| function handleApiKeyChange(e) { | |
| state.apiKey = e.target.value.trim(); | |
| localStorage.setItem('openai_api_key', state.apiKey); | |
| } | |
| // Handle GitHub repo URL change | |
| function handleGithubRepoChange(e) { | |
| state.githubRepo = e.target.value.trim(); | |
| localStorage.setItem('github_repo', state.githubRepo); | |
| } | |
| // Toggle "no repo" message visibility | |
| function toggleNoRepoMessage(show) { | |
| if (show) { | |
| elements.noRepoMessage.classList.remove('hidden'); | |
| elements.userInput.disabled = true; | |
| elements.sendBtn.disabled = true; | |
| } else { | |
| elements.noRepoMessage.classList.add('hidden'); | |
| elements.userInput.disabled = false; | |
| elements.sendBtn.disabled = false; | |
| } | |
| } | |
| // Handle load repository button click | |
| async function handleLoadRepo() { | |
| if (!state.apiKey) { | |
| showAlert('Please enter your OpenAI API key', 'error'); | |
| return; | |
| } | |
| if (!state.githubRepo) { | |
| showAlert('Please enter a GitHub repository URL', 'error'); | |
| return; | |
| } | |
| // Validate GitHub URL | |
| const repoParts = state.githubRepo.match(/github\.com\/([^\/]+)\/([^\/]+)/); | |
| if (!repoParts) { | |
| showAlert('Invalid GitHub repository URL. Format should be: https://github.com/username/repo', 'error'); | |
| return; | |
| } | |
| const [_, owner, repo] = repoParts; | |
| try { | |
| // Update UI for loading | |
| elements.loadRepoBtn.disabled = true; | |
| elements.loadRepoBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Loading...'; | |
| // Get repository info | |
| const repoInfo = await fetchRepoInfo(owner, repo); | |
| displayRepoInfo(repoInfo); | |
| // Show processing UI | |
| elements.processingStatus.classList.remove('hidden'); | |
| // Simulate processing (in a real app, this would be the actual indexing process) | |
| simulateProcessing(); | |
| // Display file tree (simulated - in a real app, this would come from actual indexing) | |
| displayFileTree(simulateFileTree()); | |
| // Enable chat | |
| toggleNoRepoMessage(false); | |
| } catch (error) { | |
| console.error('Error loading repository:', error); | |
| showAlert(`Failed to load repository: ${error.message}`, 'error'); | |
| } finally { | |
| // Reset the button | |
| elements.loadRepoBtn.disabled = false; | |
| elements.loadRepoBtn.innerHTML = '<i class="fas fa-download mr-2"></i>Load & Index Code'; | |
| } | |
| } | |
| // Simulate processing (in a real app, this would be replaced with actual processing) | |
| function simulateProcessing() { | |
| let progress = 0; | |
| const interval = setInterval(() => { | |
| progress += Math.random() * 10; | |
| if (progress >= 100) { | |
| progress = 100; | |
| clearInterval(interval); | |
| } | |
| updateProgress(progress); | |
| }, 300); | |
| } | |
| // Update progress bar | |
| function updateProgress(percent) { | |
| elements.progressBar.style.width = `${percent}%`; | |
| elements.progressPercent.textContent = `${Math.round(percent)}%`; | |
| } | |
| // Display repository information | |
| function displayRepoInfo(repoInfo) { | |
| elements.repoName.textContent = repoInfo.full_name; | |
| elements.repoDescription.textContent = repoInfo.description || 'No description provided'; | |
| elements.repoLang.textContent = repoInfo.language || 'Unknown'; | |
| elements.repoStars.innerHTML = `${repoInfo.stargazers_count.toLocaleString()} stars`; | |
| elements.repoIssues.innerHTML = `${repoInfo.open_issues.toLocaleString()} open issues`; | |
| elements.repoSize.innerHTML = `${(repoInfo.size / 1024).toFixed(1)} MB`; | |
| // Set language color | |
| const langColor = getLanguageColor(repoInfo.language); | |
| elements.repoLang.style.backgroundColor = `${langColor}20`; | |
| elements.repoLang.style.color = langColor; | |
| elements.repoInfo.classList.remove('hidden'); | |
| } | |
| // Get color for programming language | |
| function getLanguageColor(lang) { | |
| if (!lang) return '#64748b'; | |
| const colors = { | |
| 'JavaScript': '#f1e05a', | |
| 'TypeScript': '#3178c6', | |
| 'Python': '#3572A5', | |
| 'Java': '#b07219', | |
| 'C++': '#f34b7d', | |
| 'C#': '#178600', | |
| 'Ruby': '#701516', | |
| 'Go': '#00ADD8', | |
| 'PHP': '#4F5D95', | |
| 'Swift': '#F05138' | |
| }; | |
| return colors[lang] || '#64748b'; | |
| } | |
| // Simulate file tree (in a real app, this would come from actual repository) | |
| function simulateFileTree() { | |
| return { | |
| name: 'root', | |
| type: 'dir', | |
| children: [ | |
| { | |
| name: 'src', | |
| type: 'dir', | |
| children: [ | |
| { | |
| name: 'components', | |
| type: 'dir', | |
| children: [ | |
| { name: 'Header.js', type: 'file', lang: 'JavaScript', size: '4.2 KB' }, | |
| { name: 'Footer.js', type: 'file', lang: 'JavaScript', size: '3.1 KB' }, | |
| ] | |
| }, | |
| { | |
| name: 'pages', | |
| type: 'dir', | |
| children: [ | |
| { name: 'Home.js', type: 'file', lang: 'JavaScript', size: '7.5 KB' }, | |
| { name: 'About.js', type: 'file', lang: 'JavaScript', size: '5.2 KB' }, | |
| ] | |
| }, | |
| { name: 'App.js', type: 'file', lang: 'JavaScript', size: '8.7 KB' }, | |
| ] | |
| }, | |
| { | |
| name: 'public', | |
| type: 'dir', | |
| children: [ | |
| { name: 'index.html', type: 'file', lang: 'HTML', size: '1.8 KB' }, | |
| { name: 'styles.css', type: 'file', lang: 'CSS', size: '3.4 KB' }, | |
| ] | |
| }, | |
| { name: 'package.json', type: 'file', lang: 'JSON', size: '1.2 KB' }, | |
| { name: 'README.md', type: 'file', lang: 'Markdown', size: '2.5 KB' }, | |
| ] | |
| }; | |
| } | |
| // Display file tree | |
| function displayFileTree(tree) { | |
| elements.treeContent.innerHTML = ''; | |
| renderTreeItem(tree, elements.treeContent); | |
| elements.fileTree.classList.remove('hidden'); | |
| } | |
| // Render a tree item recursively | |
| function renderTreeItem(item, parentEl, level = 0) { | |
| const itemEl = document.createElement('div'); | |
| itemEl.className = `file-tree-item pl-${level * 4}`; | |
| itemEl.style.marginLeft = `${level * 12}px`; | |
| const icon = item.type === 'dir' ? 'fa-folder text-blue-400' : `fa-file text-gray-400`; | |
| const size = item.type === 'file' ? `<span class="text-xs text-gray-500 ml-2">${item.size}</span>` : ''; | |
| itemEl.innerHTML = ` | |
| <div class="flex items-center py-1 px-2 rounded"> | |
| <i class="fas ${icon} mr-2 text-sm"></i> | |
| <span class="text-sm">${item.name}</span> | |
| ${size} | |
| </div> | |
| `; | |
| parentEl.appendChild(itemEl); | |
| if (item.children) { | |
| item.children.forEach(child => { | |
| renderTreeItem(child, parentEl, level + 1); | |
| }); | |
| } | |
| } | |
| // Handle chat form submission | |
| async function handleChatSubmit(e) { | |
| e.preventDefault(); | |
| const userMessage = elements.userInput.value.trim(); | |
| if (!userMessage) return; | |
| // Add user message to chat | |
| addMessage('user', userMessage); | |
| elements.userInput.value = ''; | |
| // Create a placeholder for the AI response | |
| const aiMessageId = addMessage('ai', '<div class="loader"></div>', true); | |
| try { | |
| // Simulate API call (in a real app, this would call the OpenAI API) | |
| elements.sendBtn.disabled = true; | |
| // Simulate processing delay | |
| await new Promise(resolve => setTimeout(resolve, 1500)); | |
| // Generate a mock response (in a real app, this would come from OpenAI) | |
| const mockResponse = generateMockResponse(userMessage); | |
| // Update the AI message | |
| updateMessage(aiMessageId, mockResponse); | |
| } catch (error) { | |
| console.error('Error getting AI response:', error); | |
| updateMessage(aiMessageId, 'Sorry, I encountered an error processing your request.'); | |
| } finally { | |
| elements.sendBtn.disabled = false; | |
| } | |
| } | |
| // Add a message to the chat | |
| function addMessage(role, content, isPending = false) { | |
| const messageId = `msg-${Date.now()}`; | |
| const messageEl = document.createElement('div'); | |
| messageEl.id = messageId; | |
| messageEl.className = `chat-message ${role} p-4`; | |
| if (typeof content === 'string') { | |
| messageEl.innerHTML = content; | |
| } else { | |
| messageEl.appendChild(content); | |
| } | |
| elements.chatMessages.appendChild(messageEl); | |
| elements.chatContainer.scrollTop = elements.chatContainer.scrollHeight; | |
| return isPending ? messageId : null; | |
| } | |
| // Update an existing message | |
| function updateMessage(messageId, newContent) { | |
| const messageEl = document.getElementById(messageId); | |
| if (messageEl) { | |
| if (typeof newContent === 'string') { | |
| messageEl.innerHTML = newContent; | |
| } else { | |
| messageEl.innerHTML = ''; | |
| messageEl.appendChild(newContent); | |
| } | |
| elements.chatContainer.scrollTop = elements.chatContainer.scrollHeight; | |
| } | |
| } | |
| // Show an alert message | |
| function showAlert(message, type = 'info') { | |
| const alertEl = document.createElement('div'); | |
| alertEl.className = `fixed top-4 right-4 px-6 py-3 rounded-md shadow-md text-white ${ | |
| type === 'error' ? 'bg-red-500' : 'bg-blue-500' | |
| } animate-fade-in`; | |
| alertEl.textContent = message; | |
| document.body.appendChild(alertEl); | |
| // Remove after 4 seconds | |
| setTimeout(() => { | |
| alertEl.classList.add('animate-fade-out'); | |
| setTimeout(() => alertEl.remove(), 300); | |
| }, 4000); | |
| } | |
| // Generate a mock response (in a real app, this would come from OpenAI API) | |
| function generateMockResponse(userMessage) { | |
| const lowerMsg = userMessage.toLowerCase(); | |
| if (lowerMsg.includes('component') || lowerMsg.includes('file') || lowerMsg.includes('code')) { | |
| return ` | |
| <div> | |
| <p>Based on the repository structure, I found these relevant components:</p> | |
| <div class="mt-2 mb-4"> | |
| <ul class="list-disc pl-5 space-y-1"> | |
| <li><span class="font-medium">App.js</span> - Main application entry point</li> | |
| <li><span class="font-medium">Header.js</span> - Navigation component</li> | |
| <li><span class="font-medium">Footer.js</span> - Page footer component</li> | |
| </ul> | |
| </div> | |
| <p>Would you like me to show you the code for any specific file?</p> | |
| </div> | |
| `; | |
| } else if (lowerMsg.includes('html') || lowerMsg.includes('markup')) { | |
| return ` | |
| <div> | |
| <p>The public/index.html file contains the base HTML structure:</p> | |
| <pre class="code-block mt-2"> | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>React App</title> | |
| <link rel="stylesheet" href="styles.css"> | |
| </head> | |
| <body> | |
| <div id="root"></div> | |
| <script src="../src/App.js"></script> | |
| </body> | |
| </html></pre> | |
| <p class="mt-2">This is a standard HTML5 template with a root div where the React application mounts.</p> | |
| </div> | |
| `; | |
| } else if (lowerMsg.includes('function') || lowerMsg.includes('method')) { | |
| return ` | |
| <div> | |
| <p>Here's an example function from one of the components:</p> | |
| <pre class="code-block mt-2"> | |
| // Example function from Header.js | |
| function handleNavigation(route) { | |
| // Check if route is valid | |
| if (!routes.includes(route)) { | |
| console.error('Invalid navigation route:', route); | |
| return; | |
| } | |
| // Update state and navigate | |
| setCurrentRoute(route); | |
| window.history.pushState({}, route, \`/\${route}\`); | |
| }</pre> | |
| <p class="mt-2">This function handles navigation between different routes in the application.</p> | |
| </div> | |
| `; | |
| } else if (lowerMsg.includes('dependencies') || lowerMsg.includes('package.json')) { | |
| return ` | |
| <div> | |
| <p>The package.json shows these main dependencies:</p> | |
| <div class="mt-2 mb-4"> | |
| <ul class="list-disc pl-5 space-y-1"> | |
| <li><span class="font-medium">react</span> (^18.2.0) - Core library</li> | |
| <li><span class="font-medium">react-dom</span> (^18.2.0) - DOM rendering</li> | |
| <li><span class="font-medium">react-router-dom</span> (^6.4.3) - Routing</li> | |
| </ul> | |
| </div> | |
| <p>The project is built with React and uses functional components with hooks.</p> | |
| </div> | |
| `; | |
| } else { | |
| return ` | |
| <div> | |
| <p>I'm analyzing the repository and can help you understand:</p> | |
| <ul class="list-disc pl-5 space-y-1 mt-2"> | |
| <li>The code structure and architecture</li> | |
| <li>Specific components or functions</li> | |
| <li>Dependencies and configuration</li> | |
| </ul> | |
| <p class="mt-3">Could you be more specific about what you'd like to know?</p> | |
| </div> | |
| `; | |
| } | |
| } | |
| // Simulate fetching repository info (in a real app, this would call GitHub API) | |
| function fetchRepoInfo(owner, repo) { | |
| return new Promise((resolve) => { | |
| setTimeout(() => { | |
| resolve({ | |
| full_name: `${owner}/${repo}`, | |
| description: "A sample repository for the AI Code Chat application.", | |
| language: "JavaScript", | |
| stargazers_count: 1284, | |
| open_issues: 23, | |
| size: 5042 | |
| }); | |
| }, 800); | |
| }); | |
| } | |
| // Initialize the app | |
| init(); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=fredthehack/ai-code-chat" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
| </html> |