Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Static/Styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,53 @@ button {
button:hover {
background-color: #45a049;
}

.settings-link {
position: absolute;
top: 10px;
right: 10px;
color: white;
cursor: pointer;
}

#settings-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}

#settings-modal .modal-content {
background: white;
padding: 20px;
border-radius: 8px;
}

.scrape-container {
display: flex;
padding: 10px;
border-top: 1px solid #f0f0f0;
}

.scrape-container input[type="text"] {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}

.scrape-container button {
margin-left: 5px;
}

#geojson-list {
padding: 10px;
border-top: 1px solid #f0f0f0;
max-height: 150px;
overflow-y: auto;
}
65 changes: 64 additions & 1 deletion Templates/Index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MapsPeople Customer Service Chatbot</title>
<title>Airport Map Scraper</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
Expand All @@ -13,6 +13,7 @@
<div class="chat-container">
<div class="header">
<h1>At your Service</h1>
<span id="settings-link" class="settings-link" title="Settings">⚙</span>
</div>
<div class="chat-box" id="chat-box">
<div class="message bot">Hello! I can help you with troubleshooting MapsPeople SDK. What is your query?</div>
Expand All @@ -25,6 +26,20 @@ <h1>At your Service</h1>
<button id="live-support-btn">Talk to an Agent</button>
<button id="email-response-btn">Create Ticket</button>
</div>
<div class="scrape-container">
<input type="text" id="map-link" placeholder="Airport map URL">
<button id="scrape-btn" title="Scrape">🔍</button>
<button id="recheck-btn" style="display:none" title="Recheck">♻</button>
</div>
<div id="geojson-list"></div>
</div>

<div id="settings-modal">
<div class="modal-content">
<label for="api-key">ChatGPT API Key:</label>
<input type="text" id="api-key" placeholder="sk-...">
<button id="save-key">Save</button>
</div>
</div>

<script>
Expand Down Expand Up @@ -82,6 +97,54 @@ <h1>At your Service</h1>
document.getElementById('chat-box').appendChild(messageDiv);
document.getElementById('chat-box').scrollTop = document.getElementById('chat-box').scrollHeight;
}

// Settings modal logic
document.getElementById('settings-link').addEventListener('click', function() {
document.getElementById('settings-modal').style.display = 'flex';
});
document.getElementById('save-key').addEventListener('click', function() {
const key = document.getElementById('api-key').value;
localStorage.setItem('api_key', key);
document.getElementById('settings-modal').style.display = 'none';
});

// Scrape functionality
document.getElementById('scrape-btn').addEventListener('click', runScrape);
document.getElementById('recheck-btn').addEventListener('click', recheck);

function runScrape() {
const url = document.getElementById('map-link').value;
if (!url) return;
const apiKey = localStorage.getItem('api_key') || '';
fetch('/scrape', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({url: url, api_key: apiKey})
}).then(r => r.json()).then(data => {
if (!data.success) {
alert('No GeoJSON files found. Please use the chat for assistance.');
return;
}
document.getElementById('geojson-list').innerHTML = data.files.map(f => `<div>${f.description || 'GeoJSON'}: <a href="${f.url}" target="_blank">${f.url}</a></div>`).join('');
alert(`Web Scraping Successful - Created ${data.files.length} geojson files`);
document.getElementById('recheck-btn').style.display = 'inline-block';
});
}

function recheck() {
const url = document.getElementById('map-link').value;
const apiKey = localStorage.getItem('api_key') || '';
const files = Array.from(document.querySelectorAll('#geojson-list a')).map(a => ({url: a.href}));
fetch('/recheck', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({url: url, files: files, api_key: apiKey})
}).then(r => r.json()).then(data => {
alert(data.critique);
});
}
</script>
</body>
</html>
78 changes: 71 additions & 7 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from flask import Flask, render_template, request, jsonify
import openai
import os
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

app = Flask(__name__)

# Configure OpenAI API key
openai.api_key = 'YOUR_OPENAI_API_KEY'
# Configure OpenAI API key. Can be overridden from the settings dialog
openai.api_key = os.environ.get("OPENAI_API_KEY", "")

@app.route('/')
def index():
Expand All @@ -17,16 +20,77 @@ def chat():

# Call OpenAI API to get a response
try:
response = openai.Completion.create(
engine="davinci-codex",
prompt=user_message,
max_tokens=150
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": user_message}],
max_tokens=150,
)
response_text = response.choices[0].text.strip()
response_text = response.choices[0].message["content"].strip()
except Exception as e:
response_text = "Sorry, I'm having trouble responding right now. Please try again later."

return jsonify({"response": response_text})


def scrape_geojson(url):
"""Return a list of GeoJSON links and descriptions from the provided URL."""
try:
resp = requests.get(url, timeout=10)
resp.raise_for_status()
except Exception:
return []

soup = BeautifulSoup(resp.text, "html.parser")
results = []
for tag in soup.find_all(["a", "script", "link"]):
for attr in ["href", "src", "data-src"]:
link = tag.get(attr)
if not link:
continue
if link.lower().endswith(".geojson") or link.lower().endswith(".json"):
full_url = urljoin(url, link)
desc = tag.get("title") or tag.get("alt") or tag.get("aria-label") or tag.text.strip()
results.append({"url": full_url, "description": desc})
return results


@app.route("/scrape", methods=["POST"])
def scrape():
data = request.get_json()
target_url = data.get("url")
api_key = data.get("api_key")
if api_key:
openai.api_key = api_key
files = scrape_geojson(target_url)
if not files:
return jsonify({"success": False, "files": []})
return jsonify({"success": True, "files": files})


@app.route("/recheck", methods=["POST"])
def recheck():
data = request.get_json()
files = data.get("files", [])
target_url = data.get("url")
api_key = data.get("api_key")
if api_key:
openai.api_key = api_key
prompt = (
"We scraped the following GeoJSON links from {url}:\n{files}\n"
"Did we capture all geospatial data? Provide a short critique.".format(
url=target_url, files="\n".join(f["url"] for f in files)
)
)
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
max_tokens=150,
)
critique = response.choices[0].message["content"].strip()
except Exception:
critique = "Unable to verify with ChatGPT at this time."
return jsonify({"critique": critique})

if __name__ == '__main__':
app.run(debug=True)