Merge pull request 'intelligence: a plate read on a patrol channel is a traffic stop' (#181) from feat/plate-read-stops into main
This commit was merged in pull request #181.
This commit is contained in:
@@ -517,12 +517,33 @@ _NO_BACKSTOP_TG = re.compile(r"\b(mta|rail|railroad|train|transit|bridges? and t
|
||||
r"rescue|ambulance|dpw|public works)\b", re.IGNORECASE)
|
||||
|
||||
|
||||
# A plate read aloud — two or more phonetic letters then 3-7 digits:
|
||||
# "Frank David Boy, 4514", "Lincoln, Charlie, Robert, 7-4-0-7". On a patrol
|
||||
# channel that is a unit running a car it has stopped. Held-out replay of
|
||||
# 09-21 (server-26#170): Ossining's Post 4 stops were read out only as plates
|
||||
# and never became incidents.
|
||||
_PHONETIC = (r"(?:adam|alpha|baker|boy|bravo|charlie|charles|david|delta|eddie|edward|echo|frank|"
|
||||
r"george|golf|henry|hotel|ida|india|john|juliet|king|kilo|lincoln|lima|larry|mary|"
|
||||
r"michael|mike|nora|nancy|november|ocean|oscar|peter|paul|papa|queen|robert|romeo|"
|
||||
r"sam|sierra|tom|tango|union|uniform|victor|william|whiskey|x-ray|xray|young|yankee|zebra|zulu)")
|
||||
_PLATE_READ = re.compile(rf"\b{_PHONETIC}(?:[,\s]+{_PHONETIC}){{1,3}}[,\s]+\d(?:[\s-]?\d){{2,6}}\b",
|
||||
re.IGNORECASE)
|
||||
|
||||
|
||||
def _self_initiated_backstop(
|
||||
text: str, tags: list, incident_type: Optional[str], severity: str,
|
||||
talkgroup_name: Optional[str] = None,
|
||||
) -> tuple[list, Optional[str], str]:
|
||||
if talkgroup_name and _NO_BACKSTOP_TG.search(talkgroup_name):
|
||||
return tags, incident_type, severity
|
||||
# A plate read only stands for a stop when extraction found no other
|
||||
# event in the call: the plate on an MVA, a tow or a parked-car complaint
|
||||
# belongs to that event, not to a new stop.
|
||||
if not tags and _PLATE_READ.search(text or ""):
|
||||
tags = ["traffic-stop"]
|
||||
incident_type = incident_type or "police"
|
||||
if severity == "routine":
|
||||
severity = "minor"
|
||||
for pattern, tag in _SELF_INITIATED:
|
||||
m = pattern.search(text or "")
|
||||
if not m or _NEGATED.search(text[: m.start()]):
|
||||
|
||||
@@ -140,3 +140,17 @@ def test_short_stop_report_opens_a_scene():
|
||||
return await intelligence.extract_scenes("c1", "Adam 3 on a stop.", "Ch 1 (Patched with 155.310)")
|
||||
scenes = asyncio.run(run())
|
||||
assert len(scenes) == 1 and scenes[0]["tags"] == ["traffic-stop"] and scenes[0]["incident_type"] == "police"
|
||||
|
||||
|
||||
def test_plate_read_on_a_patrol_channel_is_a_stop():
|
||||
from app.internal.intelligence import _self_initiated_backstop as b
|
||||
ch = "Ossining - Police Dispatch"
|
||||
for t in ("Post 4. 52-62, 3-3. Hemlock Circle. Frank David Boy, 4514. 10-8.",
|
||||
"4, Ossining. 52-22, Ramapo, New York. Lincoln, Charlie, Robert, 7-4-0-7 on a Chevy.",
|
||||
"New York, Mary, Charlie, Nora, 5-8-6-7."):
|
||||
assert b(t, [], None, "routine", ch) == (["traffic-stop"], "police", "minor"), t
|
||||
# a plate on a call that is already about something else stays with it
|
||||
assert b("MVA, plate Mary George Sam 2740", ["mva"], "accident", "moderate", ch) == (["mva"], "accident", "moderate")
|
||||
# not on rail/bridge channels, and not without digits
|
||||
assert b("Frank David Boy 4514", [], None, "routine", "MTA Bridges and Tunnels - Whitestone") == ([], None, "routine")
|
||||
assert b("Charlie, David, go ahead.", [], None, "routine", ch) == ([], None, "routine")
|
||||
|
||||
Reference in New Issue
Block a user