# Project export: In The Know: Flipping the narrative on school shootings

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: In The Know uses real-time spatial audio data from cell-phones to pinpoint shooter location, providing critical information to students and faculty on the front lines.
- Devpost: https://devpost.com/software/in-the-know-flipping-the-narrative-on-school-shootings
- GitHub: https://github.com/justinleong22/In-The-Know
- Demo: https://youtu.be/_AKKyGO1nPg
- Video: https://www.youtube.com/embed/_AKKyGO1nPg?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — csun365 (9 commits), Justin Leong (3 commits), abisatish (1 commits)

## Devpost submission (written by the team)

### Overview

Motivation Growing up in Parkland, Florida, one of our hackers experienced firsthand the effects of the Marjory Stoneman Douglas school shooting. Surveys have shown that over 60% of Americans worry that they or a loved one will die in a mass shooting (Brennan 2017). The most harrowing reality of school shootings is the lack of real-time information––students and faculty cannot make informed decisions without knowing where the active shooter is. What It Does In The Know flips the narrative on school shootings by providing critical data of the shooter’s location to students and faculty on the front lines. In The Know predicts location of active shooter in real-time to allow students and faculty to make more informed decisions during critical situations. Using an intuitive and streamlined UI, users are only a single button-press away from calling 911 in case of emergencies, facilitating faster response. During the event of an emergency, all phones begin recording from every student in the school. After an anomaly is detected in the audio, the data is sent to our proprietary algorithm, updating the shooter location on the easy-to-read map on your screen. A single point representing shooter location is displayed on an intuitive, easy-to-use map, giving the user information where they are relative to the shooter. With this information, it allows them to make a decision of the best course of action, filling the gap in knowledge during this critical event. How We Built It Our app is built with React Native on the frontend, with a FastAPI RESTful API with an Uvicorn ASGI server implementation. We designed an end-to-end data acquisition, processing, and inference framework powered by mathematical modeling and spatial audio features. After an emergency is triggered, the app’s frontend enters anomaly-detection mode, listening for gunshots in real-time. After a statistically significant anomaly is detected using local maxima and neighborhood region analysis, we forward anomalous audio clips to the backend, marking the first step in our data pipeline. This is how we detect the shooter’s location: our model first segments students in different spatial groups, then considers the inputted audio data from each individual phone. We account for real life situations where phones may be in different conditions such as in pockets, backpacks, out in the open, or with loud background noise. Then, our model filters through this noisy data to detect anomalies, and identifies audio samples with the highest signals. We then generate a probability density function using a spatial mathematical approach to pinpoint the location of the shooter. We’ve experimented with different weightings and scaling factors, and generated over 250 simulations to optimize our model. Challenges In our workflow, it was challenging to ensure that asynchronous functions were called at proper moments and data was received correctly. Another barrier we experienced is a lack of data on gunshot audio; in particular, an ideal scenario involves multi-perspective data from random points within a ~300 meter radius of a gunshot. We decided to simulate realistic data, pulling from mathematical insights on sound decay rates with respect to relative distance, while accounting for background noise and phone placement. Finally, we encountered errors when integrating the predictive model into the backend infrastructure. Accomplishments We engineered a real-time data tracking system to identify the location of a live shooter with extreme precision (radius of error consistently less than 3-5 meters relative to a ~300 meter long school). We optimized the model with over 250 simulated events, and created algorithm for audio anomaly detection and distance calculation with signal processing

### What we learned

Throughout the course of this project, we learned to navigate constraints, such as limited data sourcing and computational resources for signal processing, and develop a system capable of effectively responding to reported incidents. We sharpened our research and experimentation skills, reinforcing important functionalities such as data privacy, algorithm accuracy, and noticing along the way the many interdisciplinary connections in software. Finally, our findings motivated a deep societal connection, underscoring the necessity of ethical considerations and ongoing refinement to In The Know in future use cases. Whats next We’ll onboard schools in the Parkland, Florida area from March to June 2024. This will help us establish and strengthen partnerships with select schools at a premium rate. We hope to provide protection and safety to communities scarred from the Stoneman Douglas massacre. Afterwards, we intend to scale and expand to other districts. With our local schools and expanded ones, we’ll continue to build a network of protection against gun violence. Finally, we hope to establish government partnerships and create national programs to help maximize impact. Ethics Every student deserves the right to a safe education. In the United States, gun violence has made this nearly impossible, with more than 360,000 students having experienced gun violence at school since Columbine (Cox et al. 2024). In The Know is designed to return power to students and teachers, helping them finally feel safe again at school. One of our hackers, having grown up in Parkland, has directly felt the negative impact and intergenerational trauma that gun violence can cause, reverberating across communities. We believe that safety should always come first in the face of an active shooter situation, even before incredibly important principles like privacy. We prioritized creating a user experience that would help save the most lives, which used advanced computational analysis based off of audio recordings to triangulate the location of the active shooter. We did not take this decision lightly, and considered many ethical concerns throughout development. Ethical considerations that we evaluated include: Privacy Concerns. Recording audio from student phones, even if they have given prior consent, can infringe on student privacy. We evaluated the potential benefit of finding the active shooter’s location to outweigh privacy concerns in emergencies. As such, recordings will only begin during a confirmed emergency/active shooter risk. There are also likely legal risks in specific states or localities, based on recording laws. Before our public release, we will ensure compliance with local laws based on user/school location. Ensuring Informed Consent. Students may not fully realize that the app will record all audio. We want to ensure that students fully understand the data they agree to give during an emergency, and that students have the option to refuse to provide audio data without fear of punishment. We believe that due to the potential benefit of lives saved, most students would agree to provide data during school shooting emergencies. Although the current app includes a pop-up upon installation that asks for access to the user’s phone microphone, students may click through this notification without reading. In the future, we would consider creating clear recording consent forms for students. Data Security. As we handle large amounts of sensitive and private information, data security is a major priority. We do not store any audio files, and will never EVER sell ANY user information for ANY reason. We think that as the majority of our users would be children, this is extremely unethical and would go against our core ethical priorities. We will do our utmost to prevent ANY human from EVER listening to audio data taken from the app. Emergencies should not be abused for profit. Bias and Discrimination. Many mainstream narratives assume that white people are most impacted by school shootings. Although the deadliest school shooting perpetrators were mostly white (creating the misperception that school shootings mostly harm white children), children of color are the most likely to be targeted and negatively impacted by gun violence. (“School Shooting Toll…” 2023). We recognize the disproportionate impact that re-activating intergenerational trauma causes to the most marginalized groups in the United States. In the face of rampant racism (seen in police brutality and discrimination), we hope that In The Know provides meaningful information that helps communities of color survive in a bigoted and violent world. We also evaluated potential risks from deploying our app, negatively impacting students and faculty. These included: Inaccurate Information about Shooter Movements. Ethically, the worst case scenario is providing inaccurate information to students. If students make choices using this inaccurate information, they could face great harm from wrong decisions (such as running when the shooter is nearby). As such, accuracy is the highest priority of our models. We generated over 250+ computational simulations at Marjory Stoneman Douglas High School, and we’re able to successfully predict shooter movements. This is fantastic news! In the future, we want to scale this through a larger number of schools onboarded. Government or School Administration Misuse. Government surveillance agencies could attempt to misuse the app to gain information on students. School administrators may also be tempted to try to abuse the app to always listen to student conversations. However, we have put clear safeguards in our app to minimize misuse. To begin, as data is not stored, bad actors wouldn’t be able to infringe upon student privacy for no reason. No human will listen to any audio data taken from our app. Furthermore, organizations that frequently misuse the app will no longer have access to administrative privileges. False alarms. These can cause panic, emotional harm, and harm mental health of students through creating fear. Some students may also misuse the app for “pranks”, and misclicks may occur. In addition to laws preventing false 911 calls or prank emergencies, we think students should be given the benefit of the doubt. Further, trying to curtail the ability to report emergencies would be unethical, and the risks of reacting to a non-emergency are smaller than the risks of not reacting to an actual emergency. We recognize the undue stress false emergencies could present, which is why we shall do our best to ensure only real emergencies are reported. After evaluating the ethical considerations and different risks across many stakeholders, In The Know can mitigate risks while maximizing benefits. To students, knowing the location of the active shooter is a life-and-death situation. Let’s help save lives together. Bibliography Brennan, W. (2017, January) Bulletproofing America. The Atlantic. https://www.theatlantic.com/magazine/archive/2017/01/bulletproofing/508754/ NCJA. (2023, February 14). School shooting toll rises rapidly, with major impact on minorities. NCJA. https://www.ncja.org/crimeandjusticenews/school-shooting-toll-rises-rapidly-with-major-impact-on-minorities There have been 394 school shootings since Columbine - Washington Post. (2024). https://www.washingtonpost.com/education/interactive/school-shootings-database/

## README (from the GitHub repository)

# In The Know - Treehacks 2024

## Motivation
Growing up in Parkland, Florida, one of our hackers experienced firsthand the effects of the Marjory Stoneman Douglas school shooting. Surveys have shown that over 60% of Americans worry that they or a loved one will die in a mass shooting (Brennan 2017). The most harrowing reality of school shootings is the lack of real-time information––students and faculty cannot make informed decisions without knowing where the active shooter is. 

## What It Does
In The Know flips the narrative on school shootings by providing critical data of the shooter’s location to students and faculty on the front lines. In The Know predicts location of active shooter in real-time to allow students and faculty to make more informed decisions during critical situations. Using an intuitive and streamlined UI, users are only a single button-press away from calling 911 in case of emergencies, facilitating faster response.

During the event of an emergency, all phones begin recording from every student in the school. After an anomaly is detected in the audio, the data is sent to our proprietary algorithm, updating the shooter location on the easy-to-read map on your screen.

A single point representing shooter location is displayed on an intuitive, easy-to-use map, giving the user information where they are relative to the shooter. With this information, it allows them to make a decision of the best course of action, filling the gap in knowledge during this critical event.

## How We Built It
Our app is built with React Native on the frontend, with a FastAPI RESTful API with an Uvicorn ASGI server implementation. We designed an end-to-end data acquisition, processing, and inference framework powered by mathematical modeling and spatial audio features.

After an emergency is triggered, the app’s frontend enters anomaly-detection mode, listening for gunshots in real-time. After a statistically significant anomaly is detected using local maxima and neighborhood region analysis, we forward anomalous audio clips to the backend, marking the first step in our data pipeline.

This is how we detect the shooter’s location: our model first segments students in different spatial groups, then considers the inputted audio data from each individual phone. We account for real life situations where phones may be in different conditions such as in pockets, backpacks, out in the open, or with loud background noise. Then, our model filters through this noisy data to detect anomalies, and identifies audio samples with the highest signals. We then generate a probability density function using a spatial mathematical approach to pinpoint the location of the shooter.  We’ve experimented with different weightings and scaling factors, and generated over 250 simulations to optimize our model. 

## Challenges
In our workflow, it was challenging to ensure that asynchronous functions were called at proper moments and data was received correctly. Another barrier we experienced is a lack of data on gunshot audio; in particular, an ideal scenario involves multi-perspective data from random points within a ~300 meter radius of a gunshot. We decided to simulate realistic data, pulling from mathematical insights on sound decay rates with respect to relative distance, while accounting for background noise and phone placement. Finally, we encountered errors when integrating the predictive model into the backend infrastructure.

## Accomplishments
We engineered a real-time data tracking system to identify the location of a live shooter with extreme precision (radius of error consistently less than 3-5 meters relative to a ~300 meter long school). We optimized the model with over 250 simulated events, and created algorithm for audio anomaly detection and distance calculation with signal processing

## What we learned
Throughout the course of this project, we learned to navigate constraints, such as limited data sourcing and computational resources for signal processing, and develop a system capable of effectively responding to reported incidents. We sharpened our research and experimentation skills, reinforcing important functionalities such as data privacy, algorithm accuracy, and noticing along the way the many interdisciplinary connections in software. Finally, our findings motivated a deep societal connection, underscoring the necessity of ethical considerations and ongoing refinement to In The Know in future use cases.

## Whats next
We’ll onboard schools in the Parkland, Florida area from March to June 2024. This will help us establish and strengthen partnerships with select schools at a premium rate. We hope to provide protection and safety to communities scarred from the Stoneman Douglas massacre. Afterwards, we intend to scale and expand to other districts. With our local schools and expanded ones, we’ll continue to build a network of protection against gun violence. Finally, we hope to establish government partnerships and create national programs to help maximize impact.

## Ethics
Every student deserves the right to a safe education. In the United States, gun violence has made this nearly impossible, with more than 360,000 students having experienced gun violence at school since Columbine (Cox et al. 2024). In The Know is designed to return power to students and teachers, helping them finally feel safe again at school. 

One of our hackers, having grown up in Parkland, has directly felt the negative impact and intergenerational trauma that gun violence can cause, reverberating across communities. We believe that safety should always come first in the face of an active shooter situation, even before incredibly important principles like privacy. We prioritized creating a user experience that would help save the most lives, which used advanced computational analysis based off of audio recordings to triangulate the location of the active shooter. 

We did not take this decision lightly, and considered many ethical concerns throughout development.

Ethical considerations that we evaluated include:
Privacy Concerns. Recording audio from student phones, even if they have given prior consent, can infringe on student privacy. We evaluated the potential benefit of finding the active shooter’s location to outweigh privacy concerns in emergencies. As such, recordings will only begin during a confirmed emergency/active shooter risk. There are also likely legal risks in specific states or localities, based on recording laws. Before our public release, we will ensure compliance with local laws based on user/school location.

Ensuring Informed Consent. Students may not fully realize that the app will record all audio. We want to ensure that students fully understand the data they agree to give during an emergency, and that students have the option to refuse to provide audio data without fear of punishment. We believe that due to the potential benefit of lives saved, most students would agree to provide data during school shooting emergencies.

Although the current app includes a pop-up upon installation that asks for access to the user’s phone microphone, students may click through this notification without reading. In the future, we would consider creating clear recording consent forms for students. 

Data Security. As we handle large amounts of sensitive and private information, data security is a major priority. We do not store any audio files, and will never EVER sell ANY user information for ANY reason. We think that as the majority of our users would be children, this is extremely unethical and would go against our core ethical priorities. We will do our utmost to prevent ANY human from EVER listening to audio data taken from the app. Emergencies should not be abused for profit. 

Bias and Discrimination. Many mainstream narratives assume that white people are most impacted by school shootings. Although the deadliest school shooting perpetrators were mostly white (creat

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 24 recognized source files, 84 KB.
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- TensorFlow (technology) — detected in the code
- Express (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (31 of 31)

```
.gitignore
all.py
App.js
app.json
audio.py
babel.config.js
backend/__init__.py
backend/all.py
backend/audio.py
backend/detect.py
backend/inference.py
backend/integration.py
backend/main.py
backend/model.py
backend/msd_coords.npy
backend/msd_driver.py
backend/README.md
backend/requirements.txt
backend/school.py
backend/test.py
backend/trial.py
data/data.js
inference.py
integration.py
LICENSE
msd_coords.npy
msd_driver.py
package.json
README.md
school.py
trial.py
```

### Dependencies

- backend/requirements.txt: absl-py@==2.1.0, annotated-types@==0.6.0, anyio@==4.2.0, astunparse@==1.6.3, audioread@==3.0.1, cachetools@==5.3.2, certifi@==2024.2.2, cffi@==1.16.0, charset-normalizer@==3.3.2, click@==8.1.7, decorator@==5.1.1, fastapi@==0.109.2, flatbuffers@==23.5.26, gast@==0.5.4, google-auth@==2.28.0, google-auth-oauthlib@==1.2.0, google-pasta@==0.2.0, grpcio@==1.60.1, h11@==0.14.0, h5py@==3.10.0, idna@==3.6, joblib@==1.3.2, keras@==2.15.0, lazy_loader@==0.3, libclang@==16.0.6, librosa@==0.10.1, llvmlite@==0.42.0, Markdown@==3.5.2, MarkupSafe@==2.1.5, ml-dtypes@==0.2.0, msgpack@==1.0.7, numba@==0.59.0, numpy@==1.26.4, oauthlib@==3.2.2, opt-einsum@==3.3.0, packaging@==23.2, pandas@==2.2.0, platformdirs@==4.2.0, plotly@==5.19.0, pooch@==1.8.0, protobuf@==4.25.3, pyarrow@==15.0.0, pyasn1@==0.5.1, pyasn1-modules@==0.3.0, pycparser@==2.21, pydantic@==2.6.1, pydantic_core@==2.16.2, python-dateutil@==2.8.2, pytz@==2024.1, requests@==2.31.0, requests-oauthlib@==1.3.1, rsa@==4.9, scikit-learn@==1.4.1.post1, scipy@==1.12.0, six@==1.16.0, sniffio@==1.3.0, soundfile@==0.12.1, soxr@==0.3.7, starlette@==0.36.3, tenacity@==8.2.3, tensorboard@==2.15.2, tensorboard-data-server@==0.7.2, tensorflow@==2.15.0, tensorflow-estimator@==2.15.0, tensorflow-io-gcs-filesystem@==0.36.0, tensorflow-macos@==2.15.0, termcolor@==2.4.0, threadpoolctl@==3.3.0, typing_extensions@==4.9.0, tzdata@==2024.1, urllib3@==2.2.0, uvicorn@==0.27.1, Werkzeug@==3.0.1, wrapt@==1.14.1
- package.json: @babel/core@^7.20.0, @gorhom/bottom-sheet@^4.6.0, @react-native-mapbox-gl/maps@^8.6.0-beta.0, expo@~50.0.6, expo-av@~13.10.5, expo-font@^11.10.3, expo-location@~16.5.3, expo-status-bar@~1.11.1, react@18.2.0, react-native@0.73.4, react-native-gesture-handler@~2.14.0, react-native-maps@^1.10.2, react-native-reanimated@~3.6.2

### Recent commits (newest first)

- Delete backend/gunshot.csv
- Delete backend/gunshot.wav
- readme
- final
- Add files via upload
- Added coords
- add.py
- edited prediction function
- massive file dump
- added model
- added generated data
- added school class
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "mapapp",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@gorhom/bottom-sheet": "^4.6.0",
    "@react-native-mapbox-gl/maps": "^8.6.0-beta.0",
    "expo": "~50.0.6",
    "expo-av": "~13.10.5",
    "expo-font": "^11.10.3",
    "expo-location": "~16.5.3",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-native": "0.73.4",
    "react-native-gesture-handler": "~2.14.0",
    "react-native-maps": "^1.10.2",
    "react-native-reanimated": "~3.6.2"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

```

### backend/requirements.txt

```
absl-py==2.1.0
annotated-types==0.6.0
anyio==4.2.0
astunparse==1.6.3
audioread==3.0.1
cachetools==5.3.2
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
decorator==5.1.1
fastapi==0.109.2
flatbuffers==23.5.26
gast==0.5.4
google-auth==2.28.0
google-auth-oauthlib==1.2.0
google-pasta==0.2.0
grpcio==1.60.1
h11==0.14.0
h5py==3.10.0
idna==3.6
joblib==1.3.2
keras==2.15.0
lazy_loader==0.3
libclang==16.0.6
librosa==0.10.1
llvmlite==0.42.0
Markdown==3.5.2
MarkupSafe==2.1.5
ml-dtypes==0.2.0
msgpack==1.0.7
numba==0.59.0
numpy==1.26.4
oauthlib==3.2.2
opt-einsum==3.3.0
packaging==23.2
pandas==2.2.0
platformdirs==4.2.0
plotly==5.19.0
pooch==1.8.0
protobuf==4.25.3
pyarrow==15.0.0
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycparser==2.21
pydantic==2.6.1
pydantic_core==2.16.2
python-dateutil==2.8.2
pytz==2024.1
requests==2.31.0
requests-oauthlib==1.3.1
rsa==4.9
scikit-learn==1.4.1.post1
scipy==1.12.0
six==1.16.0
sniffio==1.3.0
soundfile==0.12.1
soxr==0.3.7
starlette==0.36.3
tenacity==8.2.3
tensorboard==2.15.2
tensorboard-data-server==0.7.2
tensorflow==2.15.0
tensorflow-estimator==2.15.0
tensorflow-io-gcs-filesystem==0.36.0
tensorflow-macos==2.15.0
termcolor==2.4.0
threadpoolctl==3.3.0
typing_extensions==4.9.0
tzdata==2024.1
urllib3==2.2.0
uvicorn==0.27.1
Werkzeug==3.0.1
wrapt==1.14.1
```

### App.js

```javascript
import React, { useMemo, useState, useEffect, useRef } from 'react';
import { StyleSheet, View, Text, SafeAreaView, Button, TextInput, ImageBackground, Image} from 'react-native';
import MapView, { Heatmap, Marker, PROVIDER_GOOGLE, Polygon } from 'react-native-maps';
//import { locations } from './data/data';
import * as Location from 'expo-location';
import { Platform } from 'react-native';
import { Audio } from 'expo-av';
import { Linking } from 'react-native';
import { Switch } from 'react-native';
import { TouchableOpacity } from 'react-native';

const schoolImage = require('./assets/school.png')
const profilePic = require('./assets/profilepic.png')
const shieldImage = require('./assets/shield.png')
//const gifImage = re


export default function App() {
  const [lat, setLat] = useState();
  const [long, setLong] = useState();
  const [distanceFrom, setDistanceFrom] = useState();
  const [locations, setLocations] = useState([]);
  
  const [threatExists, setThreatExists] = useState(false);
  const [currentCoordinate, setCurrentCoordinate] = useState({
    latitude: 26.3043,
    longitude: -80.26764,
  });
  const [shooterLocation, setShooterLocation] = useState({
    latitude: 26.3043,
    longitude: -80.26764
  });
  const [recording, setRecording] = React.useState();
  const [recordings, setRecordings] = React.useState([]);
  const [reportText, setReportText] = useState("")
  const [showGif, setShowGif] = useState(false)


  const calculateDistance = (lat1, lon1, lat2, lon2) => {
    const R = 6371e3; // Earth radius in meters
    const φ1 = (lat1 * Math.PI) / 180;
    const φ2 = (lat2 * Math.PI) / 180;
    const Δφ = ((lat2 - lat1) * Math.PI) / 180;
    const Δλ = ((lon2 - lon1) * Math.PI) / 180;
    const a =
        Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
        Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    const d = R * c; // Distance in meters
    return d;
};


  const handleCall = () => {
    const phoneNumber = '9544595315'; 
    Linking.openURL(`tel:${phoneNumber}`);
  }; 

    const fetchData = async () => {
      //console.log("fetchData call recieved")
      try{
      //console.log("Sending Get Request")
      const response = await fetch('http://0.0.0.0:8000/api/shooter_location');

      const data = await response.json()
      const [latitude, longitude] = data;
      
      
      //console.log(data)
      //console.log(latitude)
      //console.log(longitude)
      await setLat(latitude);
      await setLong(longitude);
      // await setShooterLocation({
      //   latitude: latitude,
      //   longitude: longitude
      // })

      await setDistanceFrom(calculateDistance(
        currentCoordinate.latitude,
        currentCoordinate.longitude,
        latitude,
        longitude
        ));

      // await setLocations(prevLocations => [
      //   {
      //     latitude,
      //     longitude,
      //     weight: 2
      //   },
      //    ...prevLocations])

      // console.log("all locations", locations)
      
      // const newLocationInstance = {
      //   latitude: latitude,
      //   longitude: longitude,
      //   weight: 2
      // };
      
      //setLocations([...locations, newLocationInstance])
       } catch(error)
      {
        console.log(error)
      }
    }



    useEffect(() => {
      if (lat !== undefined && long !== undefined) {
        // Create new location instance
        const newLocationInstance = {
          latitude: lat,
          longitude: long,
          weight: 2
        };
        //console.log("New instance: ", newLocationInstance)
    
        // Update locations state
        setLocations(prevLocations => [newLocationInstance, ...prevLocations]);
      }
    }, [lat, long]);

    


    const sendUserData = async () => {
      //getUserLocation();
      const response = await fetch(
        `http://0.0.0.0:8000/api/update`,
        {
          method: 'post',
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            //files: recordings.map(recording => recording.file), // Assuming recording.file contains the file data
            files: [],
            latitude: currentCoordinate.latitude,
            longitude: currentCoordinate.longitude,
            res: 300
          })  
        })
    }


    
  async function startRecording() {
    //console.log("Starting recording")
    try {
      const perm = await Audio.requestPermissionsAsync();
      if (perm.status === "granted") {
        await Audio.setAudioModeAsync({
          allowsRecordingIOS: true,
          playsInSilentModeIOS: true
        });
        const { recording } = await Audio.Recording.createAsync(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY);
        setRecording(recording);
      }
    } catch (err) {}
  }

  async function stopRecording() {
    //console.log("Stopping Recording")
    setRecording(undefined);

    await recording.stopAndUnloadAsync();
    let allRecordings = [...recordings];
    const { sound, status } = await recording.createNewLoadedSoundAsync();
    allRecordings.push({
      sound: sound,
      duration: getDurationFormatted(status.durationMillis),
      file: recording.getURI(),
    });

    setRecordings(allRecordings);
    //console.log(recordings);
  }
  

  function getDurationFormatted(milliseconds) {
    const minutes = milliseconds / 1000 / 60;
    const seconds = Math.round((minutes - Math.floor(minutes)) * 60);
    return seconds < 10 ? `${Math.floor(minutes)}:0${seconds}` : `${Math.floor(minutes)}:${seconds}`
  }

  function getRecordingLines() {
    //console.log(recordings)
    return recordings.map((recordingLine, index) => {
      return (
        <View key={index} style={styles.row}>
          <Text style={styles.fill}>
            Recording #{index + 1} | {recordingLine.duration}
          </Text>
          <Button onPress={() => recordingLine.sound.rep
[truncated — 6950 more characters]
```

### backend/main.py

```python
from fastapi import FastAPI, File, UploadFile, Response
import uvicorn

from detect import *
from model import *
from all import predict_location

app = FastAPI()

@app.get("/api")
def server_test() -> dict[str, list[str]]:
    return {"messages": ["Server healthy."]}

@app.post("/api/update")
def update_user_info(files: list[UploadFile], latitude: list[float], longitude: list[float], res: Response):
    send_files = []
    send_lat = []
    send_long = []
    for i in range(len(files)):
        # safety check for file type
        if not files[i].content_type.startswith("audio/"):
            return {"error": "Invalid file type"}
        # safety check for lat. long. format
        if(len(latitude) != len(longitude)):
            return {"error": "Invalid coordinates"}
        
        else:
            # if there is an anomaly in the audio
            if(detect_gunshots(files[i])):
                # send to model along with lat and long
                send_files.append(files[i])
                send_lat.append(latitude[i])
                send_long.append(longitude[i])

    if(len(send_files) == 0):
        res.status_code = 500
        return "No detected anomalies"
    else:
        res.status_code = 200
        send(send_files, send_lat, send_long)
        return "Detected anomalies"
    
@app.get("/api/shooter_location")
def get_shooter_location():
    return predict_location()


if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8000)
```

### babel.config.js

```javascript
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      'react-native-reanimated/plugin'
    ]
  };
};

```

### integration.py

```python
import numpy as np
import pickle
from trial import *

from school import *
from audio import *
from inference import *

path = sys.argv[1]

grid_locs_sound_data = pickle.load(open(path, "rb"))
coords_gen = np.array(list(grid_locs_sound_data.keys()))

locis = sample_random_path()
random_walk = [(locis[0][i], locis[1][i]) for i in range(100,150)]

count = 0
def predict():
    gunshot_loc = random_walk[count]
    dists_x_y = coords_gen - gunshot_loc
    closest_loc = np.argmin(np.square(dists_x_y[:,0]) + np.square(dists_x_y[:,1]) ** 0.5)
    response = LocIdentification(stoneman_douglas.coords, 
                                 stoneman_douglas.cluster_labels, 
                                 grid_locs_sound_data[(coords_gen[closest_loc][0], coords_gen[closest_loc][1])])
    prediction = response.predicted_loc
    count += 1
    return (prediction[0], prediction[1])


```

### school.py

```python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

class School():
  def __init__(self, school_boundary, blocked_out_areas, num_students):
    self.boundary = school_boundary
    self.blocked_out = blocked_out_areas
    self.coords = self.sample_lat_long(num_students)
    self.cluster_labels = self.cluster_students()

  def in_bounds(self, coord, lat1, long1, lat2, long2):
    if np.random.binomial(1, 0.02):
      return False
    return coord[0] >= lat1 and coord[0] <= lat2 and coord[1] >= long1 and coord[1] <= long2

  def plot_coords(self, coords):
    coords = np.array(coords)
    plt.scatter(coords[:,1], coords[:,0], s=1)
    plt.show()

  def sample_lat_long(self, num_students):
    lat_rand = np.random.uniform(school_boundary[0][0], school_boundary[1][0], size=int(num_students / 0.7))
    long_rand = np.random.uniform(school_boundary[0][1], school_boundary[1][1], size=int(num_students / 0.7))
    coords_rand = np.vstack((lat_rand, long_rand)).T
    coords_rand = coords_rand.tolist()
    for block in self.blocked_out:
      lat1 = block[0][0]
      lat2 = block[1][0]
      long1 = block[0][1]
      long2 = block[1][1]
      coords_rand = [coord for coord in coords_rand if not self.in_bounds(coord, lat1, long1, lat2, long2)]
    return np.array(coords_rand)

  def cluster_students(self, num_clusters=10):
    kmeans = KMeans(n_clusters=num_clusters, n_init="auto")
    kmeans.fit(self.coords)
    # plt.scatter(coords_rand[:,1], coords_rand[:,0], s=1, c=kmeans.labels_)
    # plt.scatter(kmeans.cluster_centers_[:,1], kmeans.cluster_centers_[:,0], c="r")
    # plt.show()
    return kmeans.labels_

```

### audio.py

```python
import numpy as np
import os
import scipy
from scipy.io import wavfile

class StudentRecordings():
  def __init__(self, coords, gunshot_loc, path=None):
    self.root = "/content/drive/MyDrive/Treehacks Empower Project/" + path
    self.decibel_gunshot = 150
    self.radius_of_max_decibel = 1 # meter
    self.all_data = self.collect_student_audio(coords, gunshot_loc)

  def distance(self, lat1, long1, lat2, long2):
    return ((lat1 - lat2) ** 2 + (long1 - long2) ** 2) ** 0.5 * 111139

  def acquire_data(self):
    idx = np.random.randint(len(os.listdir(self.root)))
    path = os.listdir(self.root)[idx]
    _, gunshot = wavfile.read(self.root + "/" + path)
    gunshot = gunshot[np.arange(0, gunshot.shape[0], 100)]
    return gunshot

  def sound_decay(self, sound_data, distance):
    decibel_decay = np.log2(distance / self.radius_of_max_decibel) * 6
    ratio = 1 - decibel_decay / self.decibel_gunshot
    return sound_data * ratio

  def distort_sound(self, sound_data):
    # distortion accounts for phones in pocket, phones in backpack, poor audio quality, etc.
    p_distortion = 0.6
    if np.random.binomial(1, p_distortion):
      sound_data = sound_data * np.clip(np.random.normal(loc=0.2, scale=0.2), a_min=0, a_max=None)
    for i in range(sound_data.shape[0]):
      sound_data[i] -= np.random.uniform(0, sound_data[i] * 0.2)
    return sound_data

  def collect_student_audio(self, coords, gunshot_loc):
    gunshot = self.acquire_data()
    all_sound_data = []
    for coord in coords:
      dist = self.distance(coord[0], coord[1], gunshot_loc[0], gunshot_loc[1])
      dist_adjusted_sound = self.sound_decay(gunshot, dist)
      distorted_sound = self.distort_sound(dist_adjusted_sound)
      all_sound_data.append(distorted_sound)
    return np.array(all_sound_data)

```

### inference.py

```python
import numpy as np
import scipy
import matplotlib.pyplot as plt
import pickle

class LocIdentification():
  def __init__(self, coords, cluster_labels, all_data):
    self.scaling_factor = 1e4
    self.locations = []
    self.absolute_peaks = []
    self.predicted_loc = self.calculate(coords, cluster_labels, all_data)

  def filter_from_cluster(self, coords, cluster_data):
    top_n = 5
    idxs = np.argsort(np.max(cluster_data, axis=1))[-1 * top_n:]
    locations = coords[idxs]
    absolute_peaks = np.max(cluster_data, axis=1)[idxs]
    self.locations.append(locations)
    self.absolute_peaks.append(absolute_peaks)
    return locations, absolute_peaks
  
  def location_inference(self, coords_subset, peak_data):
    loc_delegates = []
    peak_delegates = []
    for i in range(peak_data.shape[0]):
      subweights = scipy.special.softmax(self.scaling_factor * (peak_data[i] - np.min(peak_data[i])))
      loc_delegate = np.sum(np.multiply(coords_subset[i], subweights.reshape(-1,1)), axis=0)
      peak_delegate = np.sum(np.multiply(peak_data[i], subweights))
      loc_delegates.append(loc_delegate)
      peak_delegates.append(peak_delegate)
      
    weights = scipy.special.softmax(self.scaling_factor * (peak_delegates - np.min(peak_delegates)))
    computed_loc = np.sum(np.multiply(loc_delegates, weights.reshape(-1,1)), axis=0)
    return computed_loc
  
  def calculate(self, coords, cluster_labels, all_data):
    candidate_coords = []
    absolute_peaks = []
    for cluster in range(np.max(cluster_labels) + 1):
      locs, peaks = self.filter_from_cluster(coords[cluster_labels == cluster], all_data[cluster_labels == cluster])
      candidate_coords.append(locs)
      absolute_peaks.append(peaks)
    candidate_coords = np.array(candidate_coords)
    absolute_peaks = np.array(absolute_peaks)
    return self.location_inference(candidate_coords, absolute_peaks)

```

### msd_driver.py

```python
from school import *
from audio import *
from inference import *
from skimage.io import imread

blocked_out_areas = [[(26.30519670082991, -80.2696934486984), (26.30552456843113, -80.26946004753805)],
                     [(26.30505198614237, -80.2696934486984), (26.305172487141704, -80.26750267960053)],
                     [(26.30424262326676, -80.2696934486984), (26.304385226697374, -80.26897105198778)],
                     [(26.304160444938894, -80.26930268328718), (26.304232955231214, -80.26891443200984)],
                     [(26.304375558673733, -80.26759599538046), (26.305028148460227, -80.26750432493998)],
                     [(26.303653, -80.26761014375148), (26.304248003454635, -80.26750432493998)],
                     [(26.304221729826835, -80.26856872033741), (26.304692348071782, -80.26804374157416)],
                     [(26.303624226860236, -80.26930672012321), (26.303892050342267, -80.26889396286808)],
                     [(26.304810957510572, -80.26883965065957), (26.304946120422322, -80.26864852620692)],
                     [(26.303975472509677, -80.2688456230644), (26.304131751948994, -80.26862691756197)],
                     [(26.30494156021424, -80.26883928377447), (26.305137618206654, -80.26798664927954)],
                     [(26.303687408626995, -80.26755336516939), (26.305135501619723, -80.26731600801872)]
                    ]

school_boundary = [(26.303653, -80.2696934486984), (26.305085, -80.267475)] # bottom left to top right (lat, long) or (y, x)

stoneman_douglas = School(school_boundary, blocked_out_areas, 2500)

interval = 12
all_lats = np.linspace(school_boundary[0][0], school_boundary[1][0], num=interval)
all_longs = np.linspace(school_boundary[0][1], school_boundary[1][1], num=interval)
all_lats = np.tile(all_lats, interval)
all_longs = np.array([np.repeat(i, interval) for i in all_longs]).flatten()
grid_locs = np.vstack((all_lats, all_longs)).T

grid_locs_sound_data = {}

for loc in grid_locs_2:
  data = StudentRecordings(stoneman_douglas.coords, (loc[0], loc[1]), "glock_17_9mm_caliber")
  grid_locs_sound_data[(loc[0], loc[1])] = data.all_data
  
```

[13 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]