Spaces:
Running
Running
Update main.js
Browse files
main.js
CHANGED
@@ -29,8 +29,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
29 |
const settingsBtn = document.getElementById('settingsBtn');
|
30 |
const settingsModal = document.getElementById('settingsModal');
|
31 |
const closeSettingsModal = document.getElementById('closeSettingsModal');
|
|
|
|
|
32 |
|
33 |
-
// --- FUNCTIONS ---
|
34 |
|
35 |
function toggleARView(showAR) {
|
36 |
arActive = showAR;
|
@@ -54,7 +56,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
54 |
.then(pois => {
|
55 |
poisData = pois;
|
56 |
const scene = document.querySelector('a-scene');
|
57 |
-
if (!scene) return
|
58 |
pois.forEach(poi => {
|
59 |
const entity = document.createElement('a-entity');
|
60 |
entity.setAttribute('gps-new-entity-place', { latitude: poi.latitude, longitude: poi.longitude });
|
@@ -79,30 +81,125 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
79 |
toggleARView(false);
|
80 |
});
|
81 |
}
|
82 |
-
|
83 |
-
// THIS IS A SIMPLE, PLACEHOLDER FUNCTION FOR NOW
|
84 |
function showObjectInfo(poiId) {
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
}
|
92 |
|
93 |
-
function addUserMessage(message) {
|
94 |
-
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
// --- EVENT LISTENERS ---
|
98 |
|
99 |
arToggle.addEventListener('click', () => toggleARView(!arActive));
|
100 |
-
document.querySelector('a-scene')
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
106 |
closeObjectModal.addEventListener('click', () => objectModal.classList.add('hidden'));
|
107 |
sendBtn.addEventListener('click', handleSearch);
|
108 |
userInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') handleSearch(); });
|
@@ -122,5 +219,4 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
122 |
|
123 |
// --- INITIALIZATION ---
|
124 |
fetchPoisAndCreateAREntities();
|
125 |
-
});
|
126 |
-
// NOTE: I have omitted the full code for addUserMessage, addAIMessage, and handleSearch for brevity, but they should be included in your file from the previous correct version. The key is that this version uses a very simple showObjectInfo function.
|
|
|
29 |
const settingsBtn = document.getElementById('settingsBtn');
|
30 |
const settingsModal = document.getElementById('settingsModal');
|
31 |
const closeSettingsModal = document.getElementById('closeSettingsModal');
|
32 |
+
const aerodeckSection = document.getElementById('aerodeckSection');
|
33 |
+
const aerodeckList = document.getElementById('aerodeckList');
|
34 |
|
35 |
+
// --- CORE & UI FUNCTIONS ---
|
36 |
|
37 |
function toggleARView(showAR) {
|
38 |
arActive = showAR;
|
|
|
56 |
.then(pois => {
|
57 |
poisData = pois;
|
58 |
const scene = document.querySelector('a-scene');
|
59 |
+
if (!scene) return;
|
60 |
pois.forEach(poi => {
|
61 |
const entity = document.createElement('a-entity');
|
62 |
entity.setAttribute('gps-new-entity-place', { latitude: poi.latitude, longitude: poi.longitude });
|
|
|
81 |
toggleARView(false);
|
82 |
});
|
83 |
}
|
84 |
+
|
|
|
85 |
function showObjectInfo(poiId) {
|
86 |
+
objectTitle.textContent = 'Loading...';
|
87 |
+
objectDescription.textContent = '';
|
88 |
+
aerodeckSection.classList.add('hidden');
|
89 |
+
|
90 |
+
fetch(`${config.backendUrl}/api/pois/${poiId}`)
|
91 |
+
.then(response => { if (!response.ok) throw new Error('POI not found'); return response.json(); })
|
92 |
+
.then(data => {
|
93 |
+
objectTitle.textContent = data.name;
|
94 |
+
objectDescription.textContent = data.description || "No description available.";
|
95 |
+
objectImage.src = `https://via.placeholder.com/300x200?text=${encodeURIComponent(data.name)}`;
|
96 |
+
if (data.aerodecks && data.aerodecks.length > 0) {
|
97 |
+
aerodeckList.innerHTML = '';
|
98 |
+
data.aerodecks.forEach(deck => {
|
99 |
+
const itemElement = document.createElement('div');
|
100 |
+
itemElement.className = 'flex justify-between items-center p-2 bg-gray-100 rounded';
|
101 |
+
const statusColor = deck.status === 'Operational' ? 'text-green-500' : 'text-orange-500';
|
102 |
+
itemElement.innerHTML = `
|
103 |
+
<div>
|
104 |
+
<div class="font-medium">${deck.deck_name}</div>
|
105 |
+
<div class="text-sm text-gray-600">Size: ${deck.size_meters}m | Charging: ${deck.is_charging_available ? 'Yes' : 'No'}</div>
|
106 |
+
</div>
|
107 |
+
<div class="font-bold text-sm ${statusColor}">${deck.status}</div>
|
108 |
+
`;
|
109 |
+
aerodeckList.appendChild(itemElement);
|
110 |
+
});
|
111 |
+
aerodeckSection.classList.remove('hidden');
|
112 |
+
}
|
113 |
+
objectModal.classList.remove('hidden');
|
114 |
+
})
|
115 |
+
.catch(error => {
|
116 |
+
console.error("Error fetching POI details:", error);
|
117 |
+
alert("Could not load details for this location.");
|
118 |
+
});
|
119 |
}
|
120 |
|
121 |
+
function addUserMessage(message) {
|
122 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
123 |
+
const msg = `<div class="ai-message user-message"><p>${message}</p></div>`;
|
124 |
+
chatContainer.insertAdjacentHTML('beforeend', msg);
|
125 |
+
aiAssistant.scrollTop = aiAssistant.scrollHeight;
|
126 |
+
}
|
127 |
+
|
128 |
+
function addAIMessage(message) {
|
129 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
130 |
+
const msg = `<div class="ai-message assistant-message"><div class="font-bold text-indigo-800 mb-1">AR Guide</div><p>${message}</p></div>`;
|
131 |
+
chatContainer.insertAdjacentHTML('beforeend', msg);
|
132 |
+
aiAssistant.scrollTop = aiAssistant.scrollHeight;
|
133 |
+
}
|
134 |
+
|
135 |
+
function handleSearch() {
|
136 |
+
const searchTerm = userInput.value.trim();
|
137 |
+
if (!searchTerm) return;
|
138 |
+
addUserMessage(searchTerm);
|
139 |
+
userInput.value = '';
|
140 |
+
const searchKeywords = ['search', 'find', 'show', 'where is', 'landmark', 'park', 'beach', 'hollywood', 'map', 'navigate'];
|
141 |
+
const isLocalSearch = searchKeywords.some(keyword => searchTerm.toLowerCase().includes(keyword));
|
142 |
+
if (isLocalSearch) {
|
143 |
+
const stopWords = ['show', 'me', 'find', 'is', 'a', 'the', 'for', 'where', 'search', 'of', 'at'];
|
144 |
+
const searchTokens = searchTerm.toLowerCase().split(' ').filter(word => !stopWords.includes(word) && word.length > 2);
|
145 |
+
if (searchTokens.length === 0) return addAIMessage("Please be more specific in your local search.");
|
146 |
+
const results = poisData.filter(poi => {
|
147 |
+
const poiText = (poi.name + ' ' + (poi.description || '')).toLowerCase();
|
148 |
+
return searchTokens.some(token => {
|
149 |
+
if (poiText.includes(token)) return true;
|
150 |
+
if (token.endsWith('s')) return poiText.includes(token.slice(0, -1));
|
151 |
+
return false;
|
152 |
+
});
|
153 |
+
});
|
154 |
+
if (results.length > 0) {
|
155 |
+
let responseMessage = `I found ${results.length} local result(s):<ul>`;
|
156 |
+
results.forEach(poi => { responseMessage += `<li class="mt-2 list-disc list-inside">${poi.name}</li>`; });
|
157 |
+
responseMessage += "</ul>";
|
158 |
+
addAIMessage(responseMessage);
|
159 |
+
} else {
|
160 |
+
addAIMessage(`Sorry, I couldn't find any local places matching "${searchTerm}".`);
|
161 |
+
}
|
162 |
+
} else {
|
163 |
+
addAIMessage("AI is thinking...");
|
164 |
+
fetch(`${config.backendUrl}/api/ask`, {
|
165 |
+
method: 'POST',
|
166 |
+
headers: { 'Content-Type': 'application/json' },
|
167 |
+
body: JSON.stringify({ prompt: searchTerm })
|
168 |
+
})
|
169 |
+
.then(response => { if (!response.ok) throw new Error('Network error'); return response.json(); })
|
170 |
+
.then(data => {
|
171 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
172 |
+
const thinkingMessage = Array.from(chatContainer.querySelectorAll('.assistant-message')).pop();
|
173 |
+
if (thinkingMessage && thinkingMessage.textContent.includes("AI is thinking...")) {
|
174 |
+
thinkingMessage.querySelector('p').innerHTML = data.response.replace(/\n/g, '<br>');
|
175 |
+
} else {
|
176 |
+
addAIMessage(data.response.replace(/\n/g, '<br>'));
|
177 |
+
}
|
178 |
+
})
|
179 |
+
.catch(error => {
|
180 |
+
console.error('Error asking AI:', error);
|
181 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
182 |
+
const thinkingMessage = Array.from(chatContainer.querySelectorAll('.assistant-message')).pop();
|
183 |
+
if (thinkingMessage && thinkingMessage.textContent.includes("AI is thinking...")) {
|
184 |
+
thinkingMessage.querySelector('p').innerHTML = "Sorry, I had trouble connecting to the AI.";
|
185 |
+
} else {
|
186 |
+
addAIMessage("Sorry, I had trouble connecting to the AI.");
|
187 |
+
}
|
188 |
+
});
|
189 |
+
}
|
190 |
+
}
|
191 |
|
192 |
// --- EVENT LISTENERS ---
|
193 |
|
194 |
arToggle.addEventListener('click', () => toggleARView(!arActive));
|
195 |
+
if (document.querySelector('a-scene')) {
|
196 |
+
document.querySelector('a-scene').addEventListener('click', (event) => {
|
197 |
+
if (event.target.hasAttribute('data-poi-id')) {
|
198 |
+
const poiId = parseInt(event.target.getAttribute('data-poi-id'), 10);
|
199 |
+
showObjectInfo(poiId);
|
200 |
+
}
|
201 |
+
});
|
202 |
+
}
|
203 |
closeObjectModal.addEventListener('click', () => objectModal.classList.add('hidden'));
|
204 |
sendBtn.addEventListener('click', handleSearch);
|
205 |
userInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') handleSearch(); });
|
|
|
219 |
|
220 |
// --- INITIALIZATION ---
|
221 |
fetchPoisAndCreateAREntities();
|
222 |
+
});
|
|