Import birth data in bulk into HD Prism without triggering LLM/AI reading generation.
saved_charts SQLite tablePOST /api/readings/generate — only when a user opens a chartcreateBodygraph() + createSavedChart() directly inserts charts without any LLM callsapps/api/src/)| Module | Function | Purpose |
|---|---|---|
models/bodygraph.ts |
createBodygraph(name, dateUtc, location) |
Computes HD chart from UTC Date + location string |
descriptions/descriptionDb.ts |
createSavedChart({id, userId, name, chartJson, chartFingerprint}) |
Persists chart to SQLite |
descriptions/descriptionDb.ts |
listSavedChartsForUser(userId) |
Check for existing charts (dedup) |
interpretation/chartFingerprint.ts |
computeChartFingerprint(bodygraphObj) |
SHA256 hash for caching |
Script must live inside apps/api/ for relative imports to resolve. Run with npx tsx:
cd apps/api
npx tsx scripts/import-<source>.ts [json-path] [userId] [--dry-run]
import * as fs from "fs";
import * as crypto from "crypto";
import { DateTime } from "luxon";
import { createBodygraph } from "../src/models/bodygraph";
import { createSavedChart, listSavedChartsForUser } from "../src/descriptions/descriptionDb";
import { computeChartFingerprint } from "../src/interpretation/chartFingerprint";
const DEFAULT_USER_ID = "e05b2131-3833-4056-b7db-3dc6850da5c2"; // firemountain@gmail.com
// Suppress noisy Swiss Eph console.log
const originalLog = console.log;
function suppressLog() {
console.log = (...args: any[]) => {
const msg = args.join(" ");
if (/^[✅⏭️⚠️❌🔮📋📁✨⏳]/.test(msg)) originalLog(...args);
};
}
function main() {
const dryRun = process.argv.includes("--dry-run");
const userId = /* from args or default */;
// 1. Load source data
// 2. Filter to Persons with birth data
// 3. Parse coordinates, dates, timezones from source format
// 4. Convert local time + IANA timezone -> UTC via Luxon
// 5. Call createBodygraph(name, dateUtc, locationString)
// 6. Attach timezoneUsed + birthDateTimeUTC to bodygraph
// 7. Call createSavedChart() with fingerprint
// 8. Deduplicate by name (case-insensitive) against listSavedChartsForUser()
suppressLog();
for (const record of records) {
const dtLocal = DateTime.local(y, m, d, h, min, { zone: tz });
const dateUtc = dtLocal.toJSDate();
const bg = createBodygraph(name, dateUtc, locationStr);
(bg as any).timezoneUsed = tz;
(bg as any).birthDateTimeUTC = dateUtc.toISOString();
const fp = computeChartFingerprint(bg as any);
if (!dryRun) {
createSavedChart({
id: crypto.randomUUID(),
userId,
name,
chartJson: JSON.stringify(bg),
chartFingerprint: fp,
});
}
}
console.log = originalLog;
}
Time Nomad uses "33.8650 S, 151.2094 E" format:
const match = coord.match(/([\d.]+)\xb0\s*([NS])\s*,\s*([\d.]+)\xb0\s*([EW])/i);
const lat = parseFloat(match[1]) * (match[2] === "S" ? -1 : 1);
const lon = parseFloat(match[3]) * (match[4] === "W" ? -1 : 1);
getDb() is NOT exported - use listSavedChartsForUser() instead for dedup checkscreateBodygraph takes UTC Date, not local - always convert via DateTime.local(..., { zone: tz }).toJSDate()createBodygraph(name, dateUtc, location) only uses location for display; the actual astrology is computed from the UTC datetsx is available on the VPS - no need for ts-node or compilationdateTimeZone - fall back to currentGeoTimeZone