Spaces:
Running
Running
Update main.js
Browse files
main.js
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
document.addEventListener('DOMContentLoaded', () => {
|
2 |
// --- CONFIGURATION ---
|
3 |
const config = {
|
@@ -29,55 +30,180 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
29 |
const aerodeckSection = document.getElementById('aerodeckSection');
|
30 |
const aerodeckList = document.getElementById('aerodeckList');
|
31 |
|
32 |
-
|
33 |
-
/* --- START OF TEMPORARILY DISABLED CODE ---
|
34 |
-
|
35 |
-
// --- CORE & UI FUNCTIONS ---
|
36 |
|
37 |
function toggleARView(showAR) {
|
38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
|
41 |
function fetchPoisAndCreateAREntities() {
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
|
45 |
function showObjectInfo(poiId) {
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
}
|
48 |
|
49 |
function addUserMessage(message) {
|
50 |
-
|
|
|
|
|
|
|
51 |
}
|
52 |
|
53 |
function addAIMessage(message) {
|
54 |
-
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
function handleSearch() {
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
|
61 |
// --- EVENT LISTENERS ---
|
62 |
|
63 |
arToggle.addEventListener('click', () => toggleARView(!arActive));
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
if (debugLog) {
|
73 |
-
let debugMessage = "--- DIAGNOSTIC TEST ---\n\n";
|
74 |
-
debugMessage += "✅ The script is running and the debug tool works.\n";
|
75 |
-
debugMessage += "This means the syntax error is inside the 'temporarily disabled' code block."
|
76 |
-
debugLog.textContent = debugMessage;
|
77 |
-
debugLog.style.display = 'block';
|
78 |
-
debugLog.style.borderColor = 'blue';
|
79 |
-
debugLog.style.color = 'blue';
|
80 |
-
debugLog.style.backgroundColor = '#eef';
|
81 |
}
|
82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
});
|
|
|
1 |
+
// Final Corrected Version: June 13, 2025
|
2 |
document.addEventListener('DOMContentLoaded', () => {
|
3 |
// --- CONFIGURATION ---
|
4 |
const config = {
|
|
|
30 |
const aerodeckSection = document.getElementById('aerodeckSection');
|
31 |
const aerodeckList = document.getElementById('aerodeckList');
|
32 |
|
33 |
+
// --- FUNCTIONS ---
|
|
|
|
|
|
|
34 |
|
35 |
function toggleARView(showAR) {
|
36 |
+
arActive = showAR;
|
37 |
+
if (arActive) {
|
38 |
+
normalView.classList.add('hidden');
|
39 |
+
arViewport.classList.remove('hidden');
|
40 |
+
arToggle.innerHTML = '<i class="fas fa-times mr-1"></i> Exit AR';
|
41 |
+
if (poisData.length === 0) fetchPoisAndCreateAREntities();
|
42 |
+
} else {
|
43 |
+
arViewport.classList.add('hidden');
|
44 |
+
normalView.classList.remove('hidden');
|
45 |
+
arToggle.innerHTML = '<i class="fas fa-vr-cardboard mr-1"></i> AR Mode';
|
46 |
+
}
|
47 |
}
|
48 |
|
49 |
function fetchPoisAndCreateAREntities() {
|
50 |
+
fetch(`${config.backendUrl}/api/pois`)
|
51 |
+
.then(response => { if (!response.ok) throw new Error('Network error'); return response.json(); })
|
52 |
+
.then(pois => {
|
53 |
+
poisData = pois;
|
54 |
+
const scene = document.querySelector('a-scene');
|
55 |
+
if (!scene) return;
|
56 |
+
pois.forEach(poi => {
|
57 |
+
const entity = document.createElement('a-entity');
|
58 |
+
entity.setAttribute('gps-new-entity-place', { latitude: poi.latitude, longitude: poi.longitude });
|
59 |
+
const box = document.createElement('a-box');
|
60 |
+
box.setAttribute('material', 'color: red; opacity: 0.7;');
|
61 |
+
box.setAttribute('scale', '10 10 10');
|
62 |
+
box.setAttribute('position', '0 5 0');
|
63 |
+
box.setAttribute('data-poi-id', poi.id);
|
64 |
+
entity.appendChild(box);
|
65 |
+
const text = document.createElement('a-text');
|
66 |
+
text.setAttribute('value', poi.name);
|
67 |
+
text.setAttribute('look-at', '[gps-new-camera]');
|
68 |
+
text.setAttribute('scale', '50 50 50');
|
69 |
+
text.setAttribute('position', '0 15 0');
|
70 |
+
entity.appendChild(text);
|
71 |
+
scene.appendChild(entity);
|
72 |
+
});
|
73 |
+
})
|
74 |
+
.catch(error => {
|
75 |
+
console.error('Failed to load POIs:', error);
|
76 |
+
alert('Could not load city data. Check connection and backend URL.');
|
77 |
+
toggleARView(false);
|
78 |
+
});
|
79 |
}
|
80 |
|
81 |
function showObjectInfo(poiId) {
|
82 |
+
objectTitle.textContent = 'Loading...';
|
83 |
+
objectDescription.textContent = '';
|
84 |
+
if (aerodeckSection) aerodeckSection.classList.add('hidden');
|
85 |
+
fetch(`${config.backendUrl}/api/pois/${poiId}`)
|
86 |
+
.then(response => { if (!response.ok) throw new Error('POI not found'); return response.json(); })
|
87 |
+
.then(data => {
|
88 |
+
objectTitle.textContent = data.name;
|
89 |
+
objectDescription.textContent = data.description || "No description available.";
|
90 |
+
objectImage.src = `https://via.placeholder.com/300x200?text=${encodeURIComponent(data.name)}`;
|
91 |
+
if (data.aerodecks && data.aerodecks.length > 0) {
|
92 |
+
aerodeckList.innerHTML = '';
|
93 |
+
data.aerodecks.forEach(deck => {
|
94 |
+
const itemElement = document.createElement('div');
|
95 |
+
itemElement.className = 'flex justify-between items-center p-2 bg-gray-100 rounded';
|
96 |
+
const statusColor = deck.status === 'Operational' ? 'text-green-500' : 'text-orange-500';
|
97 |
+
itemElement.innerHTML = `<div><div class="font-medium">${deck.deck_name}</div><div class="text-sm text-gray-600">Size: ${deck.size_meters}m | Charging: ${deck.is_charging_available ? 'Yes' : 'No'}</div></div><div class="font-bold text-sm ${statusColor}">${deck.status}</div>`;
|
98 |
+
aerodeckList.appendChild(itemElement);
|
99 |
+
});
|
100 |
+
if (aerodeckSection) aerodeckSection.classList.remove('hidden');
|
101 |
+
}
|
102 |
+
if (objectModal) objectModal.classList.remove('hidden');
|
103 |
+
})
|
104 |
+
.catch(error => { console.error("Error fetching POI details:", error); alert("Could not load details for this location."); });
|
105 |
}
|
106 |
|
107 |
function addUserMessage(message) {
|
108 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
109 |
+
const msg = `<div class="ai-message user-message"><p>${message}</p></div>`;
|
110 |
+
chatContainer.insertAdjacentHTML('beforeend', msg);
|
111 |
+
aiAssistant.scrollTop = aiAssistant.scrollHeight;
|
112 |
}
|
113 |
|
114 |
function addAIMessage(message) {
|
115 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
116 |
+
const msg = `<div class="ai-message assistant-message"><div class="font-bold text-indigo-800 mb-1">AR Guide</div><p>${message}</p></div>`;
|
117 |
+
chatContainer.insertAdjacentHTML('beforeend', msg);
|
118 |
+
aiAssistant.scrollTop = aiAssistant.scrollHeight;
|
119 |
}
|
120 |
|
121 |
function handleSearch() {
|
122 |
+
const searchTerm = userInput.value.trim();
|
123 |
+
if (!searchTerm) return;
|
124 |
+
addUserMessage(searchTerm);
|
125 |
+
userInput.value = '';
|
126 |
+
const searchKeywords = ['search', 'find', 'show', 'where is', 'landmark', 'park', 'beach', 'hollywood', 'map', 'navigate'];
|
127 |
+
const isLocalSearch = searchKeywords.some(keyword => searchTerm.toLowerCase().includes(keyword));
|
128 |
+
if (isLocalSearch) {
|
129 |
+
const stopWords = ['show', 'me', 'find', 'is', 'a', 'the', 'for', 'where', 'search', 'of', 'at'];
|
130 |
+
const searchTokens = searchTerm.toLowerCase().split(' ').filter(word => !stopWords.includes(word) && word.length > 2);
|
131 |
+
if (searchTokens.length === 0) return addAIMessage("Please be more specific in your local search.");
|
132 |
+
const results = poisData.filter(poi => {
|
133 |
+
const poiText = (poi.name + ' ' + (poi.description || '')).toLowerCase();
|
134 |
+
return searchTokens.some(token => {
|
135 |
+
if (poiText.includes(token)) return true;
|
136 |
+
if (token.endsWith('s')) return poiText.includes(token.slice(0, -1));
|
137 |
+
return false;
|
138 |
+
});
|
139 |
+
});
|
140 |
+
if (results.length > 0) {
|
141 |
+
let responseMessage = `I found ${results.length} local result(s):<ul>`;
|
142 |
+
results.forEach(poi => { responseMessage += `<li class="mt-2 list-disc list-inside">${poi.name}</li>`; });
|
143 |
+
responseMessage += "</ul>";
|
144 |
+
addAIMessage(responseMessage);
|
145 |
+
} else {
|
146 |
+
addAIMessage(`Sorry, I couldn't find any local places matching "${searchTerm}".`);
|
147 |
+
}
|
148 |
+
} else {
|
149 |
+
addAIMessage("AI is thinking...");
|
150 |
+
fetch(`${config.backendUrl}/api/ask`, {
|
151 |
+
method: 'POST',
|
152 |
+
headers: { 'Content-Type': 'application/json' },
|
153 |
+
body: JSON.stringify({ prompt: searchTerm })
|
154 |
+
})
|
155 |
+
.then(response => { if (!response.ok) throw new Error('Network error'); return response.json(); })
|
156 |
+
.then(data => {
|
157 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
158 |
+
const thinkingMessage = Array.from(chatContainer.querySelectorAll('.assistant-message')).pop();
|
159 |
+
if (thinkingMessage && thinkingMessage.textContent.includes("AI is thinking...")) {
|
160 |
+
thinkingMessage.querySelector('p').innerHTML = data.response.replace(/\n/g, '<br>');
|
161 |
+
} else {
|
162 |
+
addAIMessage(data.response.replace(/\n/g, '<br>'));
|
163 |
+
}
|
164 |
+
})
|
165 |
+
.catch(error => {
|
166 |
+
console.error('Error asking AI:', error);
|
167 |
+
const chatContainer = aiAssistant.querySelector('.flex-col');
|
168 |
+
const thinkingMessage = Array.from(chatContainer.querySelectorAll('.assistant-message')).pop();
|
169 |
+
if (thinkingMessage && thinkingMessage.textContent.includes("AI is thinking...")) {
|
170 |
+
thinkingMessage.querySelector('p').innerHTML = "Sorry, I had trouble connecting to the AI.";
|
171 |
+
} else {
|
172 |
+
addAIMessage("Sorry, I had trouble connecting to the AI.");
|
173 |
+
}
|
174 |
+
});
|
175 |
+
}
|
176 |
}
|
177 |
|
178 |
// --- EVENT LISTENERS ---
|
179 |
|
180 |
arToggle.addEventListener('click', () => toggleARView(!arActive));
|
181 |
+
const sceneEl = document.querySelector('a-scene');
|
182 |
+
if (sceneEl) {
|
183 |
+
sceneEl.addEventListener('click', (event) => {
|
184 |
+
if (event.target.hasAttribute('data-poi-id')) {
|
185 |
+
const poiId = parseInt(event.target.getAttribute('data-poi-id'), 10);
|
186 |
+
showObjectInfo(poiId);
|
187 |
+
}
|
188 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
}
|
190 |
+
if(closeObjectModal) closeObjectModal.addEventListener('click', () => objectModal.classList.add('hidden'));
|
191 |
+
if(sendBtn) sendBtn.addEventListener('click', handleSearch);
|
192 |
+
if(userInput) userInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') handleSearch(); });
|
193 |
+
if(settingsBtn) settingsBtn.addEventListener('click', () => { settingsModal.classList.remove('hidden'); });
|
194 |
+
if(closeSettingsModal) closeSettingsModal.addEventListener('click', () => { settingsModal.classList.add('hidden'); });
|
195 |
+
if(settingsModal) settingsModal.addEventListener('click', (event) => { if (event.target === settingsModal) { settingsModal.classList.add('hidden'); } });
|
196 |
+
const settingToggles = settingsModal ? settingsModal.querySelectorAll('input[data-setting]') : [];
|
197 |
+
settingToggles.forEach(toggle => {
|
198 |
+
const settingName = toggle.dataset.setting;
|
199 |
+
if (userSettings[settingName] !== undefined) { toggle.checked = userSettings[settingName]; }
|
200 |
+
toggle.addEventListener('change', (event) => {
|
201 |
+
const changedSettingName = event.target.dataset.setting;
|
202 |
+
userSettings[changedSettingName] = event.target.checked;
|
203 |
+
// console.log('Settings updated:', userSettings); // You can re-enable this for testing
|
204 |
+
});
|
205 |
+
});
|
206 |
+
|
207 |
+
// --- INITIALIZATION ---
|
208 |
+
fetchPoisAndCreateAREntities();
|
209 |
});
|