#!/usr/bin/env python3 """ Interactive tool to add contacts to master.csv Usage: python3 add_contacts.py Or: python3 add_contacts.py --file new_contacts.csv (bulk import) """ import csv, sys, os, argparse from pathlib import Path BASE = Path(__file__).parent CONTACTS_FILE = BASE / 'contacts' / 'master.csv' SEGMENTS = ['press', 'heritage', 'history', 'philosophy', 'lifestyle', 'substack', 'influencer', 'community', 'local', 'default'] FIELDNAMES = ['name', 'first_name', 'email', 'organisation', 'segment', 'notes', 'skip'] def read_existing_emails() -> set: emails = set() if CONTACTS_FILE.exists(): with open(CONTACTS_FILE, newline='', encoding='utf-8') as f: for row in csv.DictReader(f): if row.get('email'): emails.add(row['email'].strip().lower()) return emails def add_contact(row: dict, existing: set) -> bool: email = row.get('email', '').strip().lower() if not email: print(' ✗ No email — skipping') return False if email in existing: print(f' ✗ Duplicate: {email}') return False # Fill defaults if not row.get('first_name') and row.get('name'): row['first_name'] = row['name'].split()[0] if not row.get('segment'): row['segment'] = 'default' if row['segment'] not in SEGMENTS: print(f' ⚠ Unknown segment "{row["segment"]}" — using "default"') row['segment'] = 'default' row.setdefault('notes', '') row.setdefault('skip', '') with open(CONTACTS_FILE, 'a', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=FIELDNAMES, extrasaction='ignore') writer.writerow(row) existing.add(email) print(f' ✓ Added: {row["name"]} <{email}> [{row["segment"]}]') return True def interactive_mode(): existing = read_existing_emails() print(f'\nHermithire Contact Adder') print(f'Current contacts: {len(existing)}') print(f'Segments: {", ".join(SEGMENTS)}') print('Type "done" at any prompt to finish.\n') while True: email = input('Email: ').strip() if email.lower() in ('done', 'quit', 'q', ''): break name = input('Name: ').strip() if name.lower() == 'done': break first_name = input(f'First name [{name.split()[0]}]: ').strip() or name.split()[0] org = input('Organisation: ').strip() print(f'Segments: {", ".join(SEGMENTS)}') segment = input('Segment [default]: ').strip() or 'default' notes = input('Notes (optional): ').strip() add_contact({ 'name': name, 'first_name': first_name, 'email': email, 'organisation': org, 'segment': segment, 'notes': notes, 'skip': '' }, existing) print() print(f'\nDone. Total contacts: {len(existing)}') def bulk_import(filepath: str): existing = read_existing_emails() added = 0 with open(filepath, newline='', encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: if add_contact(dict(row), existing): added += 1 print(f'\nImported {added} new contacts. Total: {len(existing)}') if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--file', type=str, help='CSV file to bulk import') args = parser.parse_args() if args.file: bulk_import(args.file) else: interactive_mode()