Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>🚁 DroneAgent Chatbot</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| height: 100vh; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .chat-container { | |
| width: 90%; | |
| max-width: 800px; | |
| height: 80vh; | |
| background: white; | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0,0,0,0.1); | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .chat-header { | |
| background: linear-gradient(135deg, #4CAF50, #45a049); | |
| color: white; | |
| padding: 20px; | |
| text-align: center; | |
| font-size: 1.2em; | |
| font-weight: bold; | |
| } | |
| .chat-messages { | |
| flex: 1; | |
| padding: 20px; | |
| overflow-y: auto; | |
| background: #f8f9fa; | |
| } | |
| .message { | |
| margin-bottom: 15px; | |
| padding: 12px 16px; | |
| border-radius: 18px; | |
| max-width: 80%; | |
| word-wrap: break-word; | |
| white-space: pre-wrap; | |
| } | |
| .user-message { | |
| background: #007bff; | |
| color: white; | |
| margin-left: auto; | |
| text-align: right; | |
| } | |
| .bot-message { | |
| background: #e9ecef; | |
| color: #333; | |
| margin-right: auto; | |
| } | |
| .chat-input-container { | |
| padding: 20px; | |
| background: white; | |
| border-top: 1px solid #dee2e6; | |
| display: flex; | |
| gap: 10px; | |
| } | |
| .chat-input { | |
| flex: 1; | |
| padding: 12px 16px; | |
| border: 2px solid #dee2e6; | |
| border-radius: 25px; | |
| outline: none; | |
| font-size: 14px; | |
| transition: border-color 0.3s; | |
| } | |
| .chat-input:focus { | |
| border-color: #007bff; | |
| } | |
| .send-button { | |
| padding: 12px 24px; | |
| background: #007bff; | |
| color: white; | |
| border: none; | |
| border-radius: 25px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| transition: background 0.3s; | |
| } | |
| .send-button:hover { | |
| background: #0056b3; | |
| } | |
| .send-button:disabled { | |
| background: #6c757d; | |
| cursor: not-allowed; | |
| } | |
| .examples { | |
| margin-bottom: 20px; | |
| padding: 15px; | |
| background: #fff3cd; | |
| border-radius: 10px; | |
| border-left: 4px solid #ffc107; | |
| } | |
| .examples h3 { | |
| margin-bottom: 10px; | |
| color: #856404; | |
| } | |
| .example-button { | |
| display: inline-block; | |
| margin: 5px; | |
| padding: 8px 12px; | |
| background: #fff; | |
| border: 1px solid #ffc107; | |
| border-radius: 15px; | |
| cursor: pointer; | |
| font-size: 12px; | |
| transition: all 0.3s; | |
| } | |
| .example-button:hover { | |
| background: #ffc107; | |
| color: white; | |
| } | |
| .loading { | |
| text-align: center; | |
| color: #6c757d; | |
| font-style: italic; | |
| padding: 10px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="chat-container"> | |
| <div class="chat-header"> | |
| 🚁 DroneAgent - AI Mission Planner | |
| </div> | |
| <div class="chat-messages" id="chatMessages"> | |
| <div class="examples"> | |
| <h3>🎯 Try these examples:</h3> | |
| <div class="example-button" onclick="sendExample('Go straight 100m from 16.047, 108.206')"> | |
| Go straight 100m from 16.047, 108.206 | |
| </div> | |
| <div class="example-button" onclick="sendExample('Survey mission at 16.047, 108.206')"> | |
| Survey mission at 16.047, 108.206 | |
| </div> | |
| <div class="example-button" onclick="sendExample('Patrol route at 16.047, 108.206 at 80m altitude')"> | |
| Patrol route at 16.047, 108.206 at 80m altitude | |
| </div> | |
| <div class="example-button" onclick="sendExample('Photography flight at 16.047, 108.206')"> | |
| Photography flight at 16.047, 108.206 | |
| </div> | |
| <div class="example-button" onclick="sendExample('Hi, I want to take photos of my building')"> | |
| Hi, I want to take photos of my building | |
| </div> | |
| </div> | |
| </div> | |
| <div class="chat-input-container"> | |
| <input type="text" class="chat-input" id="chatInput" placeholder="Type your message... (e.g., 'Survey mission at 16.047, 108.206')" onkeypress="handleKeyPress(event)"> | |
| <button class="send-button" id="sendButton" onclick="sendMessage()">Send</button> | |
| <button class="send-button" style="background: #28a745;" onclick="getLatestMission()">📁 Latest</button> | |
| <button class="send-button" style="background: #17a2b8;" onclick="getDroneStatus()">🚁 Drone</button> | |
| </div> | |
| </div> | |
| <script> | |
| const chatMessages = document.getElementById('chatMessages'); | |
| const chatInput = document.getElementById('chatInput'); | |
| const sendButton = document.getElementById('sendButton'); | |
| // Add welcome message | |
| addBotMessage("👋 Hi! I'm DroneBot, your friendly AI assistant for drone mission planning!\n\n🚁 I can help you create professional drone missions. Try one of the examples above or ask me anything about drone missions!"); | |
| function handleKeyPress(event) { | |
| if (event.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| } | |
| function sendExample(text) { | |
| chatInput.value = text; | |
| sendMessage(); | |
| } | |
| async function sendMessage() { | |
| const message = chatInput.value.trim(); | |
| if (!message) return; | |
| // Add user message | |
| addUserMessage(message); | |
| chatInput.value = ''; | |
| // Disable input | |
| sendButton.disabled = true; | |
| chatInput.disabled = true; | |
| // Add loading message | |
| const loadingElement = addLoadingMessage(); | |
| try { | |
| const response = await fetch('http://localhost:8000/chat', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ message: message }) | |
| }); | |
| const data = await response.json(); | |
| // Remove loading message | |
| loadingElement.remove(); | |
| // Add bot response | |
| let botResponse = data.ai_response || 'Sorry, I had trouble processing that request.'; | |
| // Add comprehensive status information | |
| if (data.mission_file) { | |
| botResponse += `\n\n📁 Mission file: ${data.mission_file}`; | |
| } | |
| addBotMessage(botResponse); | |
| } catch (error) { | |
| loadingElement.remove(); | |
| addBotMessage('❌ Error: Could not connect to DroneAgent server. Make sure the server is running on http://localhost:8000'); | |
| } | |
| // Re-enable input | |
| sendButton.disabled = false; | |
| chatInput.disabled = false; | |
| chatInput.focus(); | |
| } | |
| function addUserMessage(message) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message user-message'; | |
| messageDiv.textContent = message; | |
| chatMessages.appendChild(messageDiv); | |
| scrollToBottom(); | |
| } | |
| function addBotMessage(message) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message bot-message'; | |
| messageDiv.textContent = message; | |
| chatMessages.appendChild(messageDiv); | |
| scrollToBottom(); | |
| } | |
| function addLoadingMessage() { | |
| const loadingDiv = document.createElement('div'); | |
| loadingDiv.className = 'loading'; | |
| loadingDiv.textContent = '🤖 DroneBot is thinking...'; | |
| chatMessages.appendChild(loadingDiv); | |
| scrollToBottom(); | |
| return loadingDiv; | |
| } | |
| async function getLatestMission() { | |
| try { | |
| const loadingElement = addLoadingMessage(); | |
| const response = await fetch('http://localhost:8000/api/latest-mission'); | |
| const data = await response.json(); | |
| loadingElement.remove(); | |
| if (data.status === 'success') { | |
| let message = `📁 **Latest Mission Retrieved**\n\n`; | |
| message += `**File:** ${data.filename}\n`; | |
| message += `**Created:** ${new Date(data.created_at).toLocaleString()}\n`; | |
| message += `**Size:** ${data.file_size} bytes\n\n`; | |
| message += `✅ Mission plan ready for QGroundControl!`; | |
| addBotMessage(message); | |
| } else { | |
| addBotMessage(`📁 ${data.message}`); | |
| } | |
| } catch (error) { | |
| addBotMessage('❌ Error retrieving latest mission. Make sure the server is running.'); | |
| } | |
| } | |
| async function getDroneStatus() { | |
| try { | |
| const loadingElement = addLoadingMessage(); | |
| const response = await fetch('http://localhost:8000/drone/status'); | |
| const data = await response.json(); | |
| loadingElement.remove(); | |
| if (data.status === 'success') { | |
| const status = data.drone_status; | |
| const rec = data.mission_recommendations; | |
| let message = `🚁 **Drone Status**\n\n`; | |
| message += `🔋 Battery: ${status.batteryRemaining}% (${status.voltage.toFixed(1)}V)\n`; | |
| message += `📡 GPS: ${status.satelite} satellites\n`; | |
| message += `📍 Location: ${status.latitude.toFixed(4)}, ${status.longitude.toFixed(4)}\n`; | |
| message += `🛩️ Mode: ${status.mode} | Altitude: ${status.altitude.toFixed(0)}m\n\n`; | |
| message += `**Mission Recommendations:**\n`; | |
| message += `• Optimal Altitude: ${rec.optimal_altitude}\n`; | |
| message += `• Max Distance: ${rec.max_mission_distance}\n`; | |
| message += `• Flight Time: ${rec.estimated_flight_time}\n`; | |
| message += `• Ready: ${rec.ready_for_mission ? '✅ Yes' : '❌ No'}`; | |
| addBotMessage(message); | |
| } else { | |
| addBotMessage('❌ Could not retrieve drone status.'); | |
| } | |
| } catch (error) { | |
| addBotMessage('❌ Error retrieving drone status. Make sure the server is running.'); | |
| } | |
| } | |
| function scrollToBottom() { | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| // Focus input on load | |
| chatInput.focus(); | |
| </script> | |
| </body> | |
| </html> | |