Spaces:
Running
Running
Update main.js
Browse files
main.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
document.addEventListener('DOMContentLoaded', () => {
|
2 |
// --- CONFIGURATION ---
|
3 |
const config = {
|
4 |
-
backendUrl: 'https://ar-city-explorer-backend.aiagents.workers.dev'
|
5 |
};
|
6 |
|
7 |
// --- GLOBAL STATE ---
|
@@ -29,10 +29,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
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 |
-
// ---
|
36 |
|
37 |
function toggleARView(showAR) {
|
38 |
arActive = showAR;
|
@@ -52,10 +50,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
52 |
|
53 |
function fetchPoisAndCreateAREntities() {
|
54 |
fetch(`${config.backendUrl}/api/pois`)
|
55 |
-
.then(response => {
|
56 |
-
if (!response.ok) throw new Error(`Network error: ${response.statusText}`);
|
57 |
-
return response.json();
|
58 |
-
})
|
59 |
.then(pois => {
|
60 |
poisData = pois;
|
61 |
const scene = document.querySelector('a-scene');
|
@@ -84,155 +79,40 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
84 |
toggleARView(false);
|
85 |
});
|
86 |
}
|
87 |
-
|
88 |
-
function showObjectInfo(poiId) {
|
89 |
-
objectTitle.textContent = 'Loading...';
|
90 |
-
objectDescription.textContent = '';
|
91 |
-
aerodeckSection.classList.add('hidden');
|
92 |
-
|
93 |
-
fetch(`${config.backendUrl}/api/pois/${poiId}`)
|
94 |
-
.then(response => {
|
95 |
-
if (!response.ok) throw new Error('POI not found');
|
96 |
-
return response.json();
|
97 |
-
})
|
98 |
-
.then(data => {
|
99 |
-
objectTitle.textContent = data.name;
|
100 |
-
objectDescription.textContent = data.description || "No description available.";
|
101 |
-
objectImage.src = `https://via.placeholder.com/300x200?text=${encodeURIComponent(data.name)}`;
|
102 |
-
|
103 |
-
if (data.aerodecks && data.aerodecks.length > 0) {
|
104 |
-
aerodeckList.innerHTML = '';
|
105 |
-
data.aerodecks.forEach(deck => {
|
106 |
-
const itemElement = document.createElement('div');
|
107 |
-
itemElement.className = 'flex justify-between items-center p-2 bg-gray-100 rounded';
|
108 |
-
const statusColor = deck.status === 'Operational' ? 'text-green-500' : 'text-orange-500';
|
109 |
-
itemElement.innerHTML = `
|
110 |
-
<div>
|
111 |
-
<div class="font-medium">${deck.deck_name}</div>
|
112 |
-
<div class="text-sm text-gray-600">Size: ${deck.size_meters}m | Charging: ${deck.is_charging_available ? 'Yes' : 'No'}</div>
|
113 |
-
</div>
|
114 |
-
<div class="font-bold text-sm ${statusColor}">${deck.status}</div>
|
115 |
-
`;
|
116 |
-
aerodeckList.appendChild(itemElement);
|
117 |
-
});
|
118 |
-
aerodeckSection.classList.remove('hidden');
|
119 |
-
}
|
120 |
-
objectModal.classList.remove('hidden');
|
121 |
-
})
|
122 |
-
.catch(error => {
|
123 |
-
console.error("Error fetching POI details:", error);
|
124 |
-
alert("Could not load details for this location.");
|
125 |
-
});
|
126 |
-
}
|
127 |
|
128 |
-
|
129 |
-
|
130 |
-
const
|
131 |
-
|
132 |
-
|
|
|
|
|
|
|
133 |
}
|
134 |
|
135 |
-
function
|
136 |
-
|
137 |
-
|
138 |
-
chatContainer.insertAdjacentHTML('beforeend', msg);
|
139 |
-
aiAssistant.scrollTop = aiAssistant.scrollHeight;
|
140 |
-
}
|
141 |
-
|
142 |
-
function handleSearch() {
|
143 |
-
// This is the latest, most forgiving search function
|
144 |
-
const searchTerm = userInput.value.trim();
|
145 |
-
if (!searchTerm) return;
|
146 |
-
addUserMessage(searchTerm);
|
147 |
-
userInput.value = '';
|
148 |
-
const searchKeywords = ['search', 'find', 'show', 'where is', 'landmark', 'park', 'beach', 'hollywood', 'map', 'navigate'];
|
149 |
-
const isLocalSearch = searchKeywords.some(keyword => searchTerm.toLowerCase().includes(keyword));
|
150 |
-
if (isLocalSearch) {
|
151 |
-
const stopWords = ['show', 'me', 'find', 'is', 'a', 'the', 'for', 'where', 'search', 'of', 'at'];
|
152 |
-
const searchTokens = searchTerm.toLowerCase().split(' ').filter(word => !stopWords.includes(word) && word.length > 2);
|
153 |
-
if (searchTokens.length === 0) return addAIMessage("Please be more specific in your local search.");
|
154 |
-
const results = poisData.filter(poi => {
|
155 |
-
const poiText = (poi.name + ' ' + (poi.description || '')).toLowerCase();
|
156 |
-
return searchTokens.some(token => {
|
157 |
-
if (poiText.includes(token)) return true;
|
158 |
-
if (token.endsWith('s')) return poiText.includes(token.slice(0, -1));
|
159 |
-
return false;
|
160 |
-
});
|
161 |
-
});
|
162 |
-
if (results.length > 0) {
|
163 |
-
let responseMessage = `I found ${results.length} local result(s):<ul>`;
|
164 |
-
results.forEach(poi => { responseMessage += `<li class="mt-2 list-disc list-inside">${poi.name}</li>`; });
|
165 |
-
responseMessage += "</ul>";
|
166 |
-
addAIMessage(responseMessage);
|
167 |
-
} else {
|
168 |
-
addAIMessage(`Sorry, I couldn't find any local places matching "${searchTerm}".`);
|
169 |
-
}
|
170 |
-
} else {
|
171 |
-
addAIMessage("AI is thinking...");
|
172 |
-
fetch(`${config.backendUrl}/api/ask`, {
|
173 |
-
method: 'POST',
|
174 |
-
headers: { 'Content-Type': 'application/json' },
|
175 |
-
body: JSON.stringify({ prompt: searchTerm })
|
176 |
-
})
|
177 |
-
.then(response => { if (!response.ok) throw new Error('Network error'); return response.json(); })
|
178 |
-
.then(data => {
|
179 |
-
const chatContainer = aiAssistant.querySelector('.flex-col');
|
180 |
-
const thinkingMessage = Array.from(chatContainer.querySelectorAll('.assistant-message')).pop();
|
181 |
-
if (thinkingMessage && thinkingMessage.textContent.includes("AI is thinking...")) {
|
182 |
-
thinkingMessage.querySelector('p').innerHTML = data.response.replace(/\n/g, '<br>');
|
183 |
-
} else {
|
184 |
-
addAIMessage(data.response.replace(/\n/g, '<br>'));
|
185 |
-
}
|
186 |
-
})
|
187 |
-
.catch(error => {
|
188 |
-
console.error('Error asking AI:', error);
|
189 |
-
const chatContainer = aiAssistant.querySelector('.flex-col');
|
190 |
-
const thinkingMessage = Array.from(chatContainer.querySelectorAll('.assistant-message')).pop();
|
191 |
-
if (thinkingMessage && thinkingMessage.textContent.includes("AI is thinking...")) {
|
192 |
-
thinkingMessage.querySelector('p').innerHTML = "Sorry, I had trouble connecting to the AI.";
|
193 |
-
} else {
|
194 |
-
addAIMessage("Sorry, I had trouble connecting to the AI.");
|
195 |
-
}
|
196 |
-
});
|
197 |
-
}
|
198 |
-
}
|
199 |
|
200 |
// --- EVENT LISTENERS ---
|
201 |
|
202 |
arToggle.addEventListener('click', () => toggleARView(!arActive));
|
203 |
-
|
204 |
document.querySelector('a-scene').addEventListener('click', (event) => {
|
205 |
if (event.target.hasAttribute('data-poi-id')) {
|
206 |
const poiId = parseInt(event.target.getAttribute('data-poi-id'), 10);
|
207 |
showObjectInfo(poiId);
|
208 |
}
|
209 |
});
|
210 |
-
|
211 |
closeObjectModal.addEventListener('click', () => objectModal.classList.add('hidden'));
|
212 |
-
|
213 |
sendBtn.addEventListener('click', handleSearch);
|
214 |
-
userInput.addEventListener('keypress', (e) => {
|
215 |
-
|
216 |
-
});
|
217 |
-
|
218 |
-
settingsBtn.addEventListener('click', () => {
|
219 |
-
settingsModal.classList.remove('hidden');
|
220 |
-
});
|
221 |
-
closeSettingsModal.addEventListener('click', () => {
|
222 |
-
settingsModal.classList.add('hidden');
|
223 |
-
});
|
224 |
-
settingsModal.addEventListener('click', (event) => {
|
225 |
-
if (event.target === settingsModal) {
|
226 |
-
settingsModal.classList.add('hidden');
|
227 |
-
}
|
228 |
-
});
|
229 |
-
|
230 |
const settingToggles = settingsModal.querySelectorAll('input[data-setting]');
|
231 |
settingToggles.forEach(toggle => {
|
232 |
const settingName = toggle.dataset.setting;
|
233 |
-
if (userSettings[settingName] !== undefined) {
|
234 |
-
toggle.checked = userSettings[settingName];
|
235 |
-
}
|
236 |
toggle.addEventListener('change', (event) => {
|
237 |
const changedSettingName = event.target.dataset.setting;
|
238 |
userSettings[changedSettingName] = event.target.checked;
|
@@ -242,4 +122,5 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
242 |
|
243 |
// --- INITIALIZATION ---
|
244 |
fetchPoisAndCreateAREntities();
|
245 |
-
});
|
|
|
|
1 |
document.addEventListener('DOMContentLoaded', () => {
|
2 |
// --- CONFIGURATION ---
|
3 |
const config = {
|
4 |
+
backendUrl: 'https://ar-city-explorer-backend.aiagents.workers.dev'
|
5 |
};
|
6 |
|
7 |
// --- GLOBAL STATE ---
|
|
|
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;
|
|
|
50 |
|
51 |
function fetchPoisAndCreateAREntities() {
|
52 |
fetch(`${config.backendUrl}/api/pois`)
|
53 |
+
.then(response => { if (!response.ok) throw new Error('Network error'); return response.json(); })
|
|
|
|
|
|
|
54 |
.then(pois => {
|
55 |
poisData = pois;
|
56 |
const scene = document.querySelector('a-scene');
|
|
|
79 |
toggleARView(false);
|
80 |
});
|
81 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
+
// THIS IS A SIMPLE, PLACEHOLDER FUNCTION FOR NOW
|
84 |
+
function showObjectInfo(poiId) {
|
85 |
+
const poi = poisData.find(p => p.id === poiId);
|
86 |
+
if (!poi) return;
|
87 |
+
objectTitle.textContent = poi.name;
|
88 |
+
objectDescription.textContent = poi.description || "No description available.";
|
89 |
+
objectImage.src = `https://via.placeholder.com/300x200?text=${encodeURIComponent(poi.name)}`;
|
90 |
+
objectModal.classList.remove('hidden');
|
91 |
}
|
92 |
|
93 |
+
function addUserMessage(message) { /* ... (rest of function) ... */ }
|
94 |
+
function addAIMessage(message) { /* ... (rest of function) ... */ }
|
95 |
+
function handleSearch() { /* ... (rest of function) ... */ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
// --- EVENT LISTENERS ---
|
98 |
|
99 |
arToggle.addEventListener('click', () => toggleARView(!arActive));
|
|
|
100 |
document.querySelector('a-scene').addEventListener('click', (event) => {
|
101 |
if (event.target.hasAttribute('data-poi-id')) {
|
102 |
const poiId = parseInt(event.target.getAttribute('data-poi-id'), 10);
|
103 |
showObjectInfo(poiId);
|
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(); });
|
109 |
+
settingsBtn.addEventListener('click', () => { settingsModal.classList.remove('hidden'); });
|
110 |
+
closeSettingsModal.addEventListener('click', () => { settingsModal.classList.add('hidden'); });
|
111 |
+
settingsModal.addEventListener('click', (event) => { if (event.target === settingsModal) { settingsModal.classList.add('hidden'); } });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
const settingToggles = settingsModal.querySelectorAll('input[data-setting]');
|
113 |
settingToggles.forEach(toggle => {
|
114 |
const settingName = toggle.dataset.setting;
|
115 |
+
if (userSettings[settingName] !== undefined) { toggle.checked = userSettings[settingName]; }
|
|
|
|
|
116 |
toggle.addEventListener('change', (event) => {
|
117 |
const changedSettingName = event.target.dataset.setting;
|
118 |
userSettings[changedSettingName] = event.target.checked;
|
|
|
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.
|