pulse-ai-utils
Version:
Utility functions and helpers for AI-powered applications
278 lines • 9.61 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocationService = void 0;
const area_coordinates_1 = require("../constants/area-coordinates");
const geo_search_1 = require("./geo-search");
const geohash = __importStar(require("ngeohash"));
class LocationService {
constructor() {
this.areaCache = new Map();
}
/**
* Get location coordinates from area ID
*/
async getLocationFromArea(areaInput) {
// Normalize area name
const normalizedArea = this.normalizeAreaName(areaInput);
// Check cache
if (this.areaCache.has(normalizedArea)) {
return this.areaCache.get(normalizedArea);
}
// Look up in coordinates
const coords = area_coordinates_1.AREA_COORDINATES[normalizedArea];
if (coords) {
const location = {
lat: coords.lat,
lng: coords.lng,
area_id: normalizedArea
};
this.areaCache.set(normalizedArea, location);
return location;
}
// Try variations
for (const [areaId, coords] of Object.entries(area_coordinates_1.AREA_COORDINATES)) {
if (this.areaNamesMatch(areaInput, areaId)) {
const location = {
lat: coords.lat,
lng: coords.lng,
area_id: areaId
};
this.areaCache.set(normalizedArea, location);
return location;
}
}
return null;
}
/**
* Extract locations from content text and metadata
*/
async extractLocationsFromContent(content) {
const locations = [];
const foundAreas = new Map(); // area_id -> first position
// Always include primary area first
if (content.primary_area) {
const primaryLoc = await this.getLocationFromArea(content.primary_area);
if (primaryLoc) {
locations.push({
...primaryLoc,
area_id: content.primary_area,
relevance: 1.0
});
foundAreas.set(content.primary_area, 0);
}
}
// Search for area mentions in text
const searchText = `${content.title} ${content.description || ''}`.toLowerCase();
for (const [areaId, coords] of Object.entries(area_coordinates_1.AREA_COORDINATES)) {
if (foundAreas.has(areaId))
continue;
const areaName = areaId.replace(/-/g, ' ');
const variations = this.getAreaVariations(areaId);
for (const variation of variations) {
const regex = new RegExp(`\\b${variation}\\b`, 'i');
const match = searchText.match(regex);
if (match && match.index !== undefined) {
foundAreas.set(areaId, match.index);
break;
}
}
}
// Sort by position in text and add with decreasing relevance
const sortedAreas = Array.from(foundAreas.entries())
.filter(([areaId]) => areaId !== content.primary_area)
.sort(([, posA], [, posB]) => posA - posB);
for (let i = 0; i < sortedAreas.length; i++) {
const [areaId] = sortedAreas[i];
const coords = area_coordinates_1.AREA_COORDINATES[areaId];
locations.push({
lat: coords.lat,
lng: coords.lng,
area_id: areaId,
relevance: 0.8 - (i * 0.1)
});
}
return locations;
}
/**
* Get user location from IP address
*/
async getUserLocationFromIP(ip) {
// In production, this would call an IP geolocation service
// For now, return a mock response
// Services to consider: ipapi.co, ip-api.com, ipgeolocation.io
// Mock implementation
if (ip.startsWith('72.') || ip.startsWith('73.')) {
// Florida IPs
return {
lat: 27.9506,
lng: -82.4572,
city: 'Tampa',
confidence: 0.7
};
}
// Default to center of US
return {
lat: 39.8283,
lng: -98.5795,
city: 'Unknown',
confidence: 0.1
};
}
/**
* Parse browser geolocation position
*/
parseGeolocationPosition(position) {
return {
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy
};
}
/**
* Find nearest known area to coordinates
*/
findNearestKnownArea(lat, lng) {
let nearest = {
area_id: '',
distance: Infinity,
location: { lat: 0, lng: 0 }
};
for (const [areaId, coords] of Object.entries(area_coordinates_1.AREA_COORDINATES)) {
const distance = (0, geo_search_1.calculateDistance)(lat, lng, coords.lat, coords.lng);
if (distance < nearest.distance) {
nearest = {
area_id: areaId,
distance,
location: {
lat: coords.lat,
lng: coords.lng,
area_id: areaId
}
};
}
}
return nearest;
}
/**
* Generate geohash for coordinates
*/
generateGeohash(lat, lng, precision = 6) {
return geohash.encode(lat, lng, precision);
}
/**
* Enrich content with location data
*/
async enrichContentWithLocation(content) {
// Extract locations from content
const locations = await this.extractLocationsFromContent(content);
// Set primary location
let primaryLocation;
if (locations.length > 0) {
primaryLocation = {
lat: locations[0].lat,
lng: locations[0].lng
};
}
else if (content.primary_area) {
// Fallback to primary area
const loc = await this.getLocationFromArea(content.primary_area);
primaryLocation = loc || { lat: 0, lng: 0 };
}
else {
primaryLocation = { lat: 0, lng: 0 };
}
// Generate geohash
const geohash = this.generateGeohash(primaryLocation.lat, primaryLocation.lng);
// Extract location names for indexing
const locationNames = locations.map(loc => loc.area_id).filter(Boolean);
return {
...content,
locations,
primary_location: primaryLocation,
geohash,
location_names: locationNames
};
}
/**
* Normalize area name for matching
*/
normalizeAreaName(area) {
return area
.toLowerCase()
.trim()
.replace(/\./g, '')
.replace(/\s+/g, '-')
.replace(/^st-/, 'st-')
.replace(/^saint-/, 'st-');
}
/**
* Check if two area names match
*/
areaNamesMatch(input, areaId) {
const normalized = this.normalizeAreaName(input);
return normalized === areaId;
}
/**
* Get variations of area name for matching
*/
getAreaVariations(areaId) {
const baseName = areaId.replace(/-/g, ' ');
const variations = [baseName];
// Add variations
if (areaId.startsWith('st-')) {
variations.push(baseName.replace('st ', 'st. '));
variations.push(baseName.replace('st ', 'saint '));
}
if (areaId.includes('-')) {
// Handle hyphenated names
variations.push(areaId);
}
// Add "town n country" special case
if (areaId === 'town-n-country') {
variations.push('town n country');
variations.push('town and country');
}
return variations;
}
/**
* Clear cache
*/
clearCache() {
this.areaCache.clear();
}
}
exports.LocationService = LocationService;
//# sourceMappingURL=location-service.js.map