🚀 LOCALSCOPE

At this year’s hackathon, we’re thrilled to unveil LOCALSCOPE — your all-in-one platform to better understand the world around you. Built by four passionate CEGEP students, our mission is to turn raw local data into actionable insights that spark awareness and drive positive change.


👥 Meet the Team

  • Elie Mathis Mbemba
  • Samuel Gauthier
  • Ali Farhat
  • Arav Sahni

🔍 What LOCALSCOPE Does

  1. Real-Time Social & Environmental Data

    • 📊 Crime rates
    • 🌬️ Daily air quality
    • ☔ Precipitation levels
  2. Cultural & Community Events

    • 🎵 Concerts
    • 🏟️ Sports games
    • 🎨 Local festivals & more
  3. AI-Powered Chatbot

    • 🤖 Always on-duty to answer your questions
    • 🔎 Dive deep into any dataset

🎯 Our Goal

By bringing diverse datasets into one intuitive interface, LOCALSCOPE makes it effortless for individuals, researchers, and community leaders to:

  • Stay informed about key issues
  • Uncover patterns and trends
  • Take meaningful action in their neighborhoods

“Empowering local communities with data-driven insights — that’s the LOCALSCOPE promise.”

Built With

  • asyncio
  • cartopy
  • css3
  • dompurify
  • eventbrite
  • flask
  • flask-cors
  • google-gemini-ai
  • html5
  • javascript-es6+
  • marked.js
  • matplotlib
  • mysql
  • newsapi
  • openmeteo-api
  • openstreetmap/nominatim-api
  • openweather-api
  • python
  • sha-256
  • ticketmaster-api
Share this project:

Updates

posted an update

!DOCTYPE html> LocalScope

<header>
  <div id="logo-div">
    <h1 class="logo-text" id="logo-text">
      Local<span id="scope">Scope</span>
    </h1>
  </div>
  <heading class="page1">
    <button onclick="window.location.href='./public/about.html'" class="aboutButton" id="abtBtn">
      About
    </button>


  </heading>
  <br />
  <br />
  <div class="card">
    <div class="card-content">
      <p class="card-text">
        Discover what's happening<br />
        <span id="wherever">wherever you go</span>
      </p>
    </div>
  </div>
  <br />
  <p>
    LocalScope uses AI powered tools to look at nearby databases to provide
    you with important information surrounding the areas you may want to
    visit!
  </p>
</header>
<div id="space"></div>

<main>
  <p>
    To start with, enter your town or postal code, or allow us to directly
    take your location:
  </p>
  <div class="input-container">
    <img
      id="location-icon"
      src="./assets/location-icon.png"
      alt="Location Icon"
    />
    <input
      type="text"
      class="location-input"
      placeholder="Enter a place or postal code..."
    />
  </div>
  <br />
  <div class="use-location">
    <p>or</p>
    <button onclick="getLocation()" id="location-button">
      use my location
    </button>
  </div>


</main>

<script>
  let userInput;

  // get lat & lon from chrome
  function getLocation() {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function (position) {
        const lat = position.coords.latitude;
        const lon = position.coords.longitude;
        var rawPosition = "latitude=" + lat + "&longitude=" + lon;
        getTown(lat, lon);
      });
    } else {
      alert("Geolocation is not supported by this browser.");
    }
  }
  // using openstreetmap to change the coords given by native js into a town name
  async function getTown(latitude, longitude) {
    const response = await fetch(
      `https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}`
    );
    const data = await response.json();
    userInput =
      data.address.city || data.address.town || data.address.village;
    sendToResults();
  }

  // grab the input location
  const locationInput = document.querySelector(".location-input");
  locationInput.addEventListener("keydown", function (event) {
    if (event.key === "Enter") {
      userInput = encodeURIComponent(locationInput.value);
      sendToResults();
    }
  });
  function sendToResults() {
    window.location.href = `./public/results.html?text=${userInput}`;
  }

  // show the sign up form
  const showForm = document.getElementById("showForm");
  const formOverlay = document.getElementById("formOverlay");

  // Show form with transition
  showForm.addEventListener("click", () => {
    formOverlay.style.display = "flex";
    setTimeout(() => {
      formOverlay.classList.add("active");
    }, 10);
  });

  // Close form with transition
  function closeForm() {
    formOverlay.classList.remove("active");
    setTimeout(() => {
      formOverlay.style.display = "none";
    }, 300);
  }
  // Form submission and validation
  document
    .querySelector(".form")
    .addEventListener("submit", async function (e) {
      e.preventDefault();

      try {
        // check if passwords are... actually the same
        const password = this.querySelector('input[name="password"]').value;
        const confirmPassword = this.querySelector(
          'input[name="confirm_password"]'
        ).value;

        if (password !== confirmPassword) {
          throw new Error("Passwords do not match");
        }

        // loading
        const submitBtn = this.querySelector(".submit");
        submitBtn.disabled = true;
        submitBtn.textContent = "Signing up...";

        // grab registration data
        const formData = new FormData(this);
        const data = Object.fromEntries(formData.entries());

        console.log("Sending data:", data); // debug log

        const res = await fetch("http://localhost:5001/signup", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Accept: "application/json",
          },
          body: JSON.stringify(data),
        });

        if (!res.ok) {
          const result = await res.json().catch(() => ({})); // handle non-JSON response?
          throw new Error(result.message || "Signup failed");
        }

        alert("Signup successful!");
        closeForm();
      } catch (error) {
        console.error("Error:", error); // debug log
        if (error.name === "TypeError") {
          alert("Network error: Failed to connect to the server.");
        } else {
          alert(error.message);
        }
      } finally {
        // reset button state
        const submitBtn = this.querySelector(".submit");
        submitBtn.disabled = false;
        submitBtn.textContent = "Submit";
      }
    });

  // Close form when clicking outside
  formOverlay.addEventListener("click", (e) => {
    if (e.target === formOverlay) {
      closeForm();
    }
  });




  const showSignIn = document.getElementById("showSignIn");
  const signInOverlay = document.getElementById("signInOverlay");
  const switchToSignUp = document.getElementById("switchToSignUp");

  showSignIn.addEventListener("click", (e) => {
    e.preventDefault();
    closeForm(); 
    signInOverlay.style.display = "flex";
    setTimeout(() => {
        signInOverlay.classList.add("active");
    }, 10);
  });


  function closeSignIn() {
      signInOverlay.classList.remove("active");
      setTimeout(() => {
          signInOverlay.style.display = "none";
      }, 300);
  }


  switchToSignUp.addEventListener("click", (e) => {
      e.preventDefault();
      closeSignIn();
      formOverlay.style.display = "flex";
      setTimeout(() => {
          formOverlay.classList.add("active");
      }, 10);
  });


  document.getElementById("signInForm").addEventListener("submit", async function(e) {
      e.preventDefault();

      try {
          const submitBtn = this.querySelector(".submit");
          submitBtn.disabled = true;
          submitBtn.textContent = "Signing in...";

          const formData = new FormData(this);
          const data = Object.fromEntries(formData.entries());

          const res = await fetch("http://localhost:5001/signin", {
              method: "POST",
              headers: {
                  "Content-Type": "application/json",
                  "Accept": "application/json"
              },
              body: JSON.stringify(data)
          });

          if (!res.ok) {
              const result = await res.json().catch(() => ({}));
              throw new Error(result.message || "Sign in failed");
          }

          alert("Sign in successful!");
          closeSignIn();
      } catch (error) {
          console.error("Error:", error);
          if (error.name === "TypeError") {
              alert("Network error: Failed to connect to the server.");
          } else {
              alert(error.message);
          }
      } finally {
          const submitBtn = this.querySelector(".submit");
          submitBtn.disabled = false;
          submitBtn.textContent = "Sign In";
      }
  });

  // Close sign in form when clicking outside
  signInOverlay.addEventListener("click", (e) => {
      if (e.target === signInOverlay) {
          closeSignIn();
      }
  });

</script>
<script src="./script.js"></script>

Log in or sign up for Devpost to join the conversation.