# Project export: Threat Tracker

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: Cal Hacks 11.0
- Tagline: Introducing a real-time, AI-powered map that keeps you informed about threats and recent news in your area.
- Devpost: https://devpost.com/software/threat-tracker
- GitHub: https://github.com/veryyynice/Threat-Track
- Video: https://www.youtube.com/embed/KnXwWhtEW54?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Buyantogtokh Khurelbaatar (10 commits), TheB2D (5 commits), Tom Strzyz (4 commits)

## Devpost submission (written by the team)

### Inspiration

: The app was born from the need to respond to global crises like the ongoing wars in Palestine, Ukraine, and Myanmar. Which have made the importance of real-time, location-based threat awareness more critical than ever. While these conflicts are often headline news, people living far from the conflict zones may lack the immediate understanding of how quickly conditions change on the ground. Our inspiration came from a desire to bridge that gap by leveraging technology to provide a solution that could offer real-time updates about dangerous areas, not just in warzones but in urban centers and conflict-prone regions around the world.

### How we built it

: Our app was developed with scalability and responsiveness in mind, given the complexity of gathering real-time data from diverse sources. For the backend, we used Python to run a Reflex web app, which hosts our API endpoints and powers the data pipeline. Reflex was chosen for its ability to handle asynchronous tasks, crucial for integrating with a MongoDB database that stores a large volume of data gathered from news articles. This architecture allows us to scrape, store, and process incoming data efficiently without compromising performance. On the frontend, we leveraged React Native to ensure cross-platform compatibility, offering users a seamless experience on both iOS and Android devices. React Native's flexibility allowed us to build a responsive interface where users can interact with the heat map, see threat levels, and access detailed news summaries all within the same app. We also integrated Meta LLaMA, a hyperbolic transformer model, which processes the textual data we scrape from news articles. The model is designed to analyze and assess the threat level of each news piece, outputting both the geographical coordinates and a risk assessment score. This was a particularly complex part of the development process, as fine-tuning the model to provide reliable, context-aware predictions required significant iteration and testing. Challenges we faced: The most pressing challenge was data scraping, particularly the obstacles put in place by websites that actively work to prevent scraping. Many news websites have anti-scraping measures in place, making it difficult to gather comprehensive data. To address this, we had to get creative with our scraping methods, using dynamic techniques that could mimic human-like browsing to avoid detection. Another major challenge was iOS integration, particularly in working with location services. iOS tends to have stricter privacy controls, which required us to implement complex authentication mechanisms and permissions handling. Additionally, deploying the backend infrastructure presented challenges in ensuring that it scaled smoothly under heavy data loads, all while maintaining low-latency responses for real-time updates. We also faced hurdles in speech-to-text functionality, as we aim to make the app more accessible by allowing users to interact with it via voice commands. Integrating accurate, multi-language speech recognition that can handle diverse accents and conditions in real-world environments is a work in progress. Accomplishments we're proud of: Despite these challenges, we successfully built a dynamic heat map that allows users to visually grasp the intensity of threats in different geographical areas. The Meta LLaMA model was another major achievement, enabling us to not only scrape news articles but also analyze and assign a threat level in real time. This means that a user can look at the app, see a particular area highlighted as high risk, and read news reports with data-backed assessments. We've created something that helps people stay informed about their environment in a practical, visually intuitive way. Moreover, building a fully functional app with both backend and frontend integration, while using cutting-edge machine learning models for threat assessment, is something we're particularly proud of. The app is capable of processing large datasets and serving actionable insights with minimal delays, which is no small feat given the technical complexity involved.

### What we learned

: One of the biggest takeaways from this project was the importance of starting with the fundamentals and building a solid foundation before adding complex features. In the early stages, we focused on getting the core infrastructure right—ensuring the scraping, data pipeline, and database were robust enough to handle scaling before moving on to model integration and feature expansion. This allowed us to pivot more easily when challenges arose, such as working with real-time data or adjusting to API limitations. We also learned a great deal about the nuances of natural language processing and machine learning, especially when it comes to applying those technologies to dynamic, unstructured news data. It’s one thing to build an AI model that processes text in a controlled environment, but real-world data is messy, often incomplete, and constantly evolving. Understanding how to fine-tune models like Meta LLaMA to give reliable assessments on current events was both challenging and incredibly rewarding.

### What's next

: Looking ahead, we plan to expand the app’s capabilities further by integrating speech-to-text functionality. This will make the app more accessible, allowing users to dictate queries or receive voice-based updates on emerging threats without having to type or navigate through screens. This feature will be particularly valuable for users who may be on the move or in situations where typing isn’t practical. We’re also focusing on improving the accuracy and scope of our web scrapers, aiming to gather more diverse data from a broader range of news sources while adhering to ethical guidelines. This includes exploring ways to improve scraping from difficult sites and even partnering with news outlets to gain access to structured data. Beyond these immediate goals, we see potential in scaling the app to include predictive analytics, using historical data to forecast potential danger zones before they escalate. This would help users not only react to current events but also plan ahead based on emerging patterns in conflict areas. Another exciting direction is user-driven content, allowing people to report and share information about dangerous areas directly through the app, further enriching the data landscape.

## README (from the GitHub repository)

# Threat Tracker

Threat Tracker is an iOS app built with React Native that provides real-time threat intelligence by scraping the web for local news and analyzing data using Hyperbolic Labs' large language model (LLM). The app generates a danger level heat map based on geolocated threat data and allows users to manually input threat information by selecting a location and danger level. Users are notified when danger levels in their vicinity rise.

## Features

- **Real-time Threat Scraping**: Automatically scrapes the web for news articles related to potential threats in your area.
- **AI-driven Analysis**: Uses Hyperbolic Labs' LLM to extract coordinates and assess the danger level of incidents.
- **Danger Level Heat Map**: Displays a heat map that visually represents the current threat level in different areas.
- **User Input for Threats**: Users can contribute by manually adding threats, specifying the location and assigning a danger level.
- **Push Notifications**: Alerts users when there is a significant increase in danger levels around them.
  
<img title="screenshot" src="screenshot.png">

## Tech Stack

- **Frontend**: React Native
- **Backend**: MongoDB hosted on Reflex.dev
- **AI Integration**: Hyperbolic Labs LLM for location and danger level processing
- **Hosting**: Reflex.dev

## Reflex Hosted API
- Using FastAPI framework and adapted in Reflex
- Two endpoints connected to the MongoDB

```py
#get request
import requests

url = "https://rxh-prod-api-threattracker.fly.dev/locations"

response = requests.request("GET", url)
```
```py
#post information
import requests

url = "https://rxh-prod-api-threattracker.fly.dev/locations/"

payload = {
    "latitude": 1,
    "longitude": 1,
    "weight": 3,
    "summary": "summary goes here"
}
response = requests.request("POST", url, json=payload)
```

<img title="LLM scraped data" src="news.png">

- **LLM usage**: Extracted coordinates using Hyperbolic Labs' LLM from News articles scrabed from web. Also the danger level of incidents were assessed using LLM from the news.



## Detected evidence (automated analysis)

Indexed codebase: 8146 recognized source files, 22264 KB.
- C (language) — detected in the code
- C++ (language) — detected in the code
- JavaScript (language) — detected in the code
- Kotlin (language) — detected in the code
- Python (language) — detected in the code
- Swift (language) — detected in the code
- TypeScript (language) — detected in the code
- MongoDB (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 9138)

```
__tests__/App.test.tsx
.bundle/config
.DS_Store
.eslintrc.js
.gitignore
.prettierrc.js
.watchmanconfig
android/app/build.gradle
android/app/debug.keystore
android/app/proguard-rules.pro
android/app/src/debug/AndroidManifest.xml
android/app/src/main/AndroidManifest.xml
android/app/src/main/java/com/threattracker/MainActivity.kt
android/app/src/main/java/com/threattracker/MainApplication.kt
android/app/src/main/res/drawable/rn_edit_text_material.xml
android/app/src/main/res/values/strings.xml
android/app/src/main/res/values/styles.xml
android/build.gradle
android/gradle.properties
android/gradle/wrapper/gradle-wrapper.properties
android/gradlew
android/gradlew.bat
android/settings.gradle
api.py
App.js
app.json
babel.config.js
backend.py
devices.json
dummy.js
eslintrc.js
FinalApp.js
FirstUI
Gemfile
Gemfile.lock
gitignore
index.js
ios/.DS_Store
ios/.xcode.env
ios/.xcode.env.local
ios/Podfile
ios/Podfile.lock
ios/Pods/boost/boost/algorithm/string.hpp
ios/Pods/boost/boost/algorithm/string/case_conv.hpp
ios/Pods/boost/boost/algorithm/string/classification.hpp
ios/Pods/boost/boost/algorithm/string/compare.hpp
ios/Pods/boost/boost/algorithm/string/concept.hpp
ios/Pods/boost/boost/algorithm/string/config.hpp
ios/Pods/boost/boost/algorithm/string/constants.hpp
ios/Pods/boost/boost/algorithm/string/detail/case_conv.hpp
ios/Pods/boost/boost/algorithm/string/detail/classification.hpp
ios/Pods/boost/boost/algorithm/string/detail/find_format_all.hpp
ios/Pods/boost/boost/algorithm/string/detail/find_format_store.hpp
ios/Pods/boost/boost/algorithm/string/detail/find_format.hpp
ios/Pods/boost/boost/algorithm/string/detail/find_iterator.hpp
ios/Pods/boost/boost/algorithm/string/detail/finder.hpp
ios/Pods/boost/boost/algorithm/string/detail/formatter.hpp
ios/Pods/boost/boost/algorithm/string/detail/predicate.hpp
ios/Pods/boost/boost/algorithm/string/detail/replace_storage.hpp
ios/Pods/boost/boost/algorithm/string/detail/sequence.hpp
ios/Pods/boost/boost/algorithm/string/detail/trim.hpp
ios/Pods/boost/boost/algorithm/string/detail/util.hpp
ios/Pods/boost/boost/algorithm/string/erase.hpp
ios/Pods/boost/boost/algorithm/string/find_format.hpp
ios/Pods/boost/boost/algorithm/string/find_iterator.hpp
ios/Pods/boost/boost/algorithm/string/find.hpp
ios/Pods/boost/boost/algorithm/string/finder.hpp
ios/Pods/boost/boost/algorithm/string/formatter.hpp
ios/Pods/boost/boost/algorithm/string/iter_find.hpp
ios/Pods/boost/boost/algorithm/string/join.hpp
ios/Pods/boost/boost/algorithm/string/predicate_facade.hpp
ios/Pods/boost/boost/algorithm/string/predicate.hpp
ios/Pods/boost/boost/algorithm/string/replace.hpp
ios/Pods/boost/boost/algorithm/string/sequence_traits.hpp
ios/Pods/boost/boost/algorithm/string/split.hpp
ios/Pods/boost/boost/algorithm/string/std_containers_traits.hpp
ios/Pods/boost/boost/algorithm/string/std/list_traits.hpp
ios/Pods/boost/boost/algorithm/string/std/slist_traits.hpp
ios/Pods/boost/boost/algorithm/string/std/string_traits.hpp
ios/Pods/boost/boost/algorithm/string/trim.hpp
ios/Pods/boost/boost/algorithm/string/yes_no_type.hpp
ios/Pods/boost/boost/array.hpp
ios/Pods/boost/boost/assert.hpp
ios/Pods/boost/boost/assert/source_location.hpp
ios/Pods/boost/boost/bind/arg.hpp
ios/Pods/boost/boost/bind/bind_cc.hpp
ios/Pods/boost/boost/bind/bind_mf_cc.hpp
ios/Pods/boost/boost/bind/bind_mf2_cc.hpp
ios/Pods/boost/boost/bind/bind_template.hpp
ios/Pods/boost/boost/bind/bind.hpp
ios/Pods/boost/boost/bind/detail/is_same.hpp
ios/Pods/boost/boost/bind/detail/requires_cxx11.hpp
ios/Pods/boost/boost/bind/detail/result_traits.hpp
ios/Pods/boost/boost/bind/mem_fn_cc.hpp
ios/Pods/boost/boost/bind/mem_fn_template.hpp
ios/Pods/boost/boost/bind/mem_fn_vw.hpp
ios/Pods/boost/boost/bind/mem_fn.hpp
ios/Pods/boost/boost/bind/placeholders.hpp
ios/Pods/boost/boost/bind/std_placeholders.hpp
ios/Pods/boost/boost/bind/storage.hpp
ios/Pods/boost/boost/blank.hpp
ios/Pods/boost/boost/call_traits.hpp
ios/Pods/boost/boost/concept_check.hpp
ios/Pods/boost/boost/concept/assert.hpp
ios/Pods/boost/boost/concept/detail/backward_compatibility.hpp
ios/Pods/boost/boost/concept/detail/borland.hpp
ios/Pods/boost/boost/concept/detail/concept_def.hpp
ios/Pods/boost/boost/concept/detail/concept_undef.hpp
ios/Pods/boost/boost/concept/detail/general.hpp
ios/Pods/boost/boost/concept/detail/has_constraints.hpp
ios/Pods/boost/boost/concept/detail/msvc.hpp
ios/Pods/boost/boost/concept/usage.hpp
ios/Pods/boost/boost/config.hpp
ios/Pods/boost/boost/config/auto_link.hpp
ios/Pods/boost/boost/config/compiler/borland.hpp
ios/Pods/boost/boost/config/compiler/clang_version.hpp
ios/Pods/boost/boost/config/compiler/clang.hpp
ios/Pods/boost/boost/config/compiler/codegear.hpp
ios/Pods/boost/boost/config/compiler/comeau.hpp
ios/Pods/boost/boost/config/compiler/common_edg.hpp
[9018 more files omitted for size]
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Update README.md
- Delete pic1.png
- Add files via upload
- insert api info
- Update README.md
- deep gram api
- Added images for readme
- Update README.md
- more hidden files
- second major initial commit from dev laptop
- Add files via upload
- major upload from dev branch on local macbook
- Update FirstUI
- Create newsscraper.py
- Create api.py
- Add files via upload
- Create FirstUI
- Create Setting.js
- Update FinalApp.js
- Create FinalApp.js

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

### ios/Pods/GoogleMaps/CHANGELOG.md

```markdown
Please go to https://developers.google.com/maps/documentation/ios-sdk/releases
to view the Maps iOS release notes.

```

### Gemfile

```
source 'https://rubygems.org'

# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"

# Exclude problematic versions of cocoapods and activesupport that causes build failures.
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'

```

### index.js

```javascript
/**
 * @format
 */

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);

```

### App.js

```javascript
import React, { useEffect, useState } from 'react';
import { Image, View, StyleSheet, Modal, Text, TouchableOpacity, TextInput } from 'react-native';
import MapView, { Heatmap, PROVIDER_GOOGLE, Marker } from 'react-native-maps';
// import Voice from '@react-native-voice/voice';


function MapScreen() {
  const [threatLevel, setThreatLevel] = useState(1);
  const [modalVisible, setModalVisible] = useState(false);
  const [threatDetails, setThreatDetails] = useState('');
  const [settingsModalVisible, setSettingsModalVisible] = useState(false);
  const [radiusModalVisible, setRadiusModalVisible] = useState(false);
  const [radiusDetails, setRadiusDetails] = useState('');
  const [points, setPoints] = useState([]);


    useEffect(() => {
        // Define the async function inside useEffect
        const fetchData = async () => {
            try {
                const requestOptions = {
                    method: "GET",
                    redirect: "follow"
                };

                let response = await fetch("https://rxh-prod-api-threattracker.fly.dev/locations", requestOptions);
                let json = await response.json();

                // Assuming convertData is defined elsewhere in your code
                const convertedPoints = convertData(json);
                setPoints(convertedPoints);
            } catch (error) {
                console.error("Error fetching data:", error);
            }
        };

        fetchData(); // Call the async function

        // No cleanup needed, so we return nothing or undefined explicitly
        return undefined;
    }, []); // Empty dependency array to run only once

    useEffect(() => {
        console.log(points)
    },[points])

  const handleAddThreat = () => {
    setModalVisible(true);


  };

  const handleRadius = () => {
    setRadiusModalVisible(true)
  };

  const handleCancel = () => {
    setThreatDetails('');
    setModalVisible(false)
  }

  const radiusCancel = () => {
    setRadiusDetails('');
    setRadiusModalVisible(false);
  }

  function convertData(data) {
    return data.map(item => ({
        latitude: item.latitude,
        longitude: item.longitude,
        weight: item.weight
    }));
}

  const handleSaveThreat = () => {
    setModalVisible(false);
    console.log('Threat Details', threatDetails);
    setThreatDetails('');
  };

  const radiusSaveThreat = () => {
    setRadiusModalVisible(false);
    console.log('Radius Details', )
    setRadiusDetails('');
  }
  return (
    <View style={styles.container}>
      <MapView
        provider={PROVIDER_GOOGLE}
        style={styles.map}
        initialRegion={{
          latitude: 37.78225,
          longitude: -122.4124,
          latitudeDelta: 0.0922,
          longitudeDelta: 0.0421,
        }}
      >
        <Heatmap
          points={points}
          radius={50}
          opacity={1}
          gradient={{
            colors: ["black", "yellow", "red"],
            // startPoints: Platform.OS === 'ios' ? [0.01, 0.1] : [0.02, 0.66],
            startPoints: [0.01, 0.2, 1.0],
            colorMapSize: 256
          }}
        />
        <Marker
            coordinate = {{latitude: 37.782872,longitude: -122.401}}
            title="User Location"/>
      </MapView>

      <TouchableOpacity style={styles.parentIcon} onPress={handleRadius}>
        <Image style={styles.settingsIcon} source={require("./xd.png")}/>
      </TouchableOpacity>

      <TouchableOpacity style={styles.button} onPress={handleAddThreat}>
        <Text style={styles.buttonText}>Add a threat</Text>

      </TouchableOpacity>

      <Modal
        animationType="slide"
        transparent={true}
        visible={modalVisible}
        onRequestClose={() => setModalVisible(false)}
      >
        <View style={styles.modalContainer}>
          <View style={styles.modalView}>
            <Text style={styles.modalTitle}>Add Threat Details</Text>
            <TextInput
              style={styles.input}
              placeholder="Enter threat details"
              value={threatDetails}
              onChangeText={setThreatDetails}
            />

            <TouchableOpacity style={styles.button} onPress={handleSaveThreat}>
              <Text style={styles.buttonText}>Save</Text>
            </TouchableOpacity>

          </View>
        </View>
        <TouchableOpacity onPress={() => setModalVisible(false)}>
              <Text onPress={handleCancel} style={styles.cancelButton}>Cancel</Text>
            </TouchableOpacity>
      </Modal>

      <Modal
        animationType="slide"
        transparent={true}
        visible={radiusModalVisible}
        onRequestClose={() => setRadiusModalVisible(false)}
      >
        <View style={styles.modalContainer}>
          <View style={styles.modalView}>
            <Text style={styles.modalTitle}>Notification Radius</Text>
            <TextInput
              style={styles.input}
              placeholder="Whats the danger level?"
              value={radiusDetails}
              onChangeText={setRadiusDetails}
            />

            <TouchableOpacity style={styles.button} onPress={radiusSaveThreat}>
              <Text style={styles.buttonText}>Save</Text>
            </TouchableOpacity>

          </View>
        </View>
        <TouchableOpacity onPress={() => setRadiusModalVisible(false)}>
              <Text onPress={radiusCancel} style={styles.cancelButton}>Cancel</Text>
        </TouchableOpacity>
      </Modal>
    </View>
  );
}

// export function VoiceRecognition() {
//     const [isListening, setIsListening] = useState(false);
//     const [recognizedText, setRecognizedText] = useState('');
//     const [partialResults, setPartialResults] = useState([]);
  
//     useEffect(() => {
//       Voice.onSpeechStart = onSpeechStart;
//       Voice.onSpeechRecognized = onSpeechRecognized;
//       Voice.onSpeechEnd = onSpeechEnd;
//       Voice.onSpeechError = onSpeechError;
//       Voice.onSpeechPartialResults = onSpeech
[truncated — 5492 more characters]
```

### jest.config.js

```javascript
module.exports = {
  preset: 'react-native',
};

```

### .eslintrc.js

```javascript
module.exports = {
  root: true,
  extends: '@react-native',
};

```

### eslintrc.js

```javascript
module.exports = {
  root: true,
  extends: '@react-native',
};

```

### babel.config.js

```javascript
module.exports = {
  presets: ['module:@react-native/babel-preset'],
};

```

### .prettierrc.js

```javascript
module.exports = {
  arrowParens: 'avoid',
  bracketSameLine: true,
  bracketSpacing: false,
  singleQuote: true,
  trailingComma: 'all',
};

```

### metro.config.js

```javascript
const { getDefaultConfig } = require('expo/metro-config');
const { mergeConfig } = require('@react-native/metro-config');

/**
 * Metro configuration
 * https://reactnative.dev/docs/metro
 *
 * @type {import('metro-config').MetroConfig}
 */
const config = {};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

```

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