Hardik Singh commited on
Commit
2bb7aec
·
1 Parent(s): cf368fd

feat: implemented ongoing/historical separation and frontline detection

Browse files
api/intel_engine.py CHANGED
@@ -96,3 +96,25 @@ async def get_priority_monitor():
96
  async with db.pool.acquire() as conn:
97
  rows = await conn.fetch(query)
98
  return [dict(r) for r in rows]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  async with db.pool.acquire() as conn:
97
  rows = await conn.fetch(query)
98
  return [dict(r) for r in rows]
99
+
100
+ async def get_active_frontlines():
101
+ """Identifies active frontline clusters based on intensity and recency."""
102
+ query = """
103
+ SELECT
104
+ ST_X(ST_Centroid(ST_Collect(geom::geometry))) as lon,
105
+ ST_Y(ST_Centroid(ST_Collect(geom::geometry))) as lat,
106
+ COUNT(*) as event_count,
107
+ country,
108
+ country_iso3,
109
+ MAX(severity_score) as highest_severity,
110
+ mode() WITHIN GROUP (ORDER BY event_type) as primary_engagement
111
+ FROM conflict_events
112
+ WHERE event_time >= NOW() - INTERVAL '48 hours'
113
+ AND category IN ('MILITARY', 'MILITANT')
114
+ GROUP BY country, country_iso3, ST_SnapToGrid(geom::geometry, 1.5)
115
+ HAVING COUNT(*) >= 2
116
+ ORDER BY event_count DESC
117
+ """
118
+ async with db.pool.acquire() as conn:
119
+ rows = await conn.fetch(query)
120
+ return [dict(r) for r in rows]
api/routes/conflicts.py CHANGED
@@ -125,6 +125,57 @@ async def get_recent_conflicts(request: Request, days: int = 7, limit: int = 100
125
  }
126
  await set_cache(cache_key, response, ttl=300)
127
  return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  @router.get("/near")
130
  async def get_conflicts_near(
 
125
  }
126
  await set_cache(cache_key, response, ttl=300)
127
  return response
128
+ @router.get("/ongoing")
129
+ async def get_ongoing_conflicts(request: Request, limit: int = 50):
130
+ """Returns only MILITARY/MILITANT events from the last 48 hours."""
131
+ cache_key = f"conflicts:ongoing:{limit}"
132
+ cached = await check_cache(request, cache_key)
133
+ if cached: return cached
134
+
135
+ query = """
136
+ SELECT * FROM conflict_events
137
+ WHERE event_time >= NOW() - INTERVAL '48 hours'
138
+ AND category IN ('MILITARY', 'MILITANT', 'TERRORIST')
139
+ ORDER BY event_time DESC LIMIT $1
140
+ """
141
+ async with db.pool.acquire() as conn:
142
+ records = await conn.fetch(query, limit)
143
+
144
+ data = [dict(r) for r in records]
145
+ for d in data:
146
+ if d.get("geom"): del d["geom"]
147
+ d["event_time"] = d["event_time"].isoformat() + "Z" if d["event_time"] else None
148
+
149
+ res = {"status": 200, "success": True, "count": len(data), "data": data}
150
+ await set_cache(cache_key, res, ttl=60) # Short TTL for live data
151
+ return res
152
+
153
+ @router.get("/historical")
154
+ async def get_historical_conflicts(request: Request, days_ago: int = 2, limit: int = 100):
155
+ """Returns military events older than the specified timeframe (default 2 days)."""
156
+ cache_key = f"conflicts:historical:{days_ago}:{limit}"
157
+ cached = await check_cache(request, cache_key)
158
+ if cached: return cached
159
+
160
+ query = """
161
+ SELECT * FROM conflict_events
162
+ WHERE event_time < NOW() - INTERVAL '$1 days'
163
+ AND category IN ('MILITARY', 'MILITANT', 'TERRORIST')
164
+ ORDER BY event_time DESC LIMIT $2
165
+ """
166
+ # Note: Using parameterized interval is tricky in asyncpg, so we simplify
167
+ query = query.replace("$1", str(days_ago))
168
+ async with db.pool.acquire() as conn:
169
+ records = await conn.fetch(query, limit)
170
+
171
+ data = [dict(r) for r in records]
172
+ for d in data:
173
+ if d.get("geom"): del d["geom"]
174
+ d["event_time"] = d["event_time"].isoformat() + "Z" if d["event_time"] else None
175
+
176
+ res = {"status": 200, "success": True, "count": len(data), "data": data}
177
+ await set_cache(cache_key, res, ttl=3600) # Long TTL for history
178
+ return res
179
 
180
  @router.get("/near")
181
  async def get_conflicts_near(
api/routes/intel.py CHANGED
@@ -1,6 +1,6 @@
1
  from fastapi import APIRouter, HTTPException
2
  from api.intel_engine import (
3
- get_daily_sitrep, get_conflict_trends, get_world_hotspots, get_priority_monitor
4
  )
5
 
6
  router = APIRouter(prefix="/intel", tags=["Intelligence"])
@@ -36,3 +36,11 @@ async def monitor():
36
  return await get_priority_monitor()
37
  except Exception as e:
38
  raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
 
 
 
1
  from fastapi import APIRouter, HTTPException
2
  from api.intel_engine import (
3
+ get_daily_sitrep, get_conflict_trends, get_world_hotspots, get_priority_monitor, get_active_frontlines
4
  )
5
 
6
  router = APIRouter(prefix="/intel", tags=["Intelligence"])
 
36
  return await get_priority_monitor()
37
  except Exception as e:
38
  raise HTTPException(status_code=500, detail=str(e))
39
+
40
+ @router.get("/frontlines")
41
+ async def frontlines():
42
+ """Get active frontline clusters (Ongoing high-intensity conflict zones)."""
43
+ try:
44
+ return await get_active_frontlines()
45
+ except Exception as e:
46
+ raise HTTPException(status_code=500, detail=str(e))