google_takeout: add semantic location history (#278)

* google_takeout: add semantic location history
This commit is contained in:
seanbreckenridge 2023-03-04 10:36:10 -08:00 committed by GitHub
parent a4c713664e
commit 9d231a8ea9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 0 deletions

View file

@ -89,6 +89,14 @@ class location:
export_path: Paths = ''
accuracy: float
class google_takeout_semantic:
# a value between 0 and 100, 100 being the most confident
# set to 0 to include all locations
# https://locationhistoryformat.com/reference/semantic/#/$defs/placeVisit/properties/locationConfidence
require_confidence: float = 40
# default accuracy for semantic locations
accuracy: float = 100
from my.core.compat import Literal
class time:

View file

@ -16,6 +16,7 @@ logger = LazyLogger(__name__, level="warning")
def locations() -> Iterator[Location]:
# can add/comment out sources here to disable them, or use core.disabled_modules
yield from _takeout_locations()
yield from _takeout_semantic_locations()
yield from _gpslogger_locations()
yield from _ip_locations()
@ -26,6 +27,17 @@ def _takeout_locations() -> Iterator[Location]:
yield from google_takeout.locations()
@import_source(module_name="my.location.google_takeout_semantic")
def _takeout_semantic_locations() -> Iterator[Location]:
from . import google_takeout_semantic
for event in google_takeout_semantic.locations():
if isinstance(event, Exception):
logger.error(f"google_takeout_semantic: {event}")
continue
yield event
@import_source(module_name="my.location.gpslogger")
def _gpslogger_locations() -> Iterator[Location]:
from . import gpslogger

View file

@ -0,0 +1,76 @@
"""
Extracts semantic location history using google_takeout_parser
"""
# This is a separate module to prevent ImportError and a new config block from breaking
# previously functional my.location.google_takeout locations
REQUIRES = ["git+https://github.com/seanbreckenridge/google_takeout_parser"]
from typing import Iterator, List
from my.google.takeout.parser import events, _cachew_depends_on as _parser_cachew_depends_on
from google_takeout_parser.models import PlaceVisit as SemanticLocation
from my.core import dataclass, make_config
from my.core.common import mcachew, LazyLogger, Stats
from my.core.error import Res
from .common import Location
logger = LazyLogger(__name__)
from my.config import location as user_config
@dataclass
class semantic_locations_config(user_config.google_takeout_semantic):
# a value between 0 and 100, 100 being the most confident
# set to 0 to include all locations
# https://locationhistoryformat.com/reference/semantic/#/$defs/placeVisit/properties/locationConfidence
require_confidence: int = 40
# default accuracy for semantic locations
accuracy: float = 100
config = make_config(semantic_locations_config)
# add config to cachew dependency so it recomputes on config changes
def _cachew_depends_on() -> List[str]:
dep = _parser_cachew_depends_on()
dep.insert(0, f"require_confidence={config.require_confidence} accuracy={config.accuracy}")
return dep
@mcachew(
depends_on=_cachew_depends_on,
logger=logger,
)
def locations() -> Iterator[Res[Location]]:
require_confidence = config.require_confidence
if require_confidence < 0 or require_confidence > 100:
yield ValueError("location.google_takeout.semantic_require_confidence must be between 0 and 100")
return
for g in events():
if isinstance(g, SemanticLocation):
if g.visitConfidence < require_confidence:
logger.debug(f"Skipping {g} due to low confidence ({g.visitConfidence}))")
continue
yield Location(
lon=g.lng,
lat=g.lat,
dt=g.dt,
# can accuracy be inferred from visitConfidence?
# there's no exact distance value in the data, its a 0-100% confidence value...
accuracy=config.accuracy,
elevation=None,
datasource="google_takeout_semantic",
)
def stats() -> Stats:
from my.core import stat
return {**stat(locations)}