"""Fetch company data from accelerator sources and generate embeddings.""" import argparse import json from pathlib import Path import numpy as np from src.embeddings import Embedder, embeddings_filename from src.sources import ALL_SOURCES DATA_DIR = Path(__file__).resolve().parent.parent / "data" FIELD_NAMES = ["problem", "solution", "industry", "customer"] def build_search_text(c: dict) -> str: parts = [] if c.get("one_liner"): parts.append(c["one_liner"]) if c.get("long_description"): parts.append(c["long_description"]) if c.get("tags"): parts.append("Tags: " + ", ".join(c["tags"])) if c.get("industries"): parts.append("Industries: " + ", ".join(c["industries"])) return ". ".join(parts) if parts else c.get("name", "") def build_field_texts(c: dict) -> list[str]: return [ c.get("_problem") or c.get("one_liner") or c.get("name", ""), c.get("_solution") or c.get("one_liner") or "", c.get("_industry") or " ".join(c.get("industries") or c.get("tags") or []), c.get("_customer") or "", ] def main(): parser = argparse.ArgumentParser(description="Ingest accelerator company data") parser.add_argument( "--source", choices=[*ALL_SOURCES.keys(), "all"], default="all", help="Which source to ingest (default: all)", ) parser.add_argument( "--embed-only", action="store_true", help="Skip fetching; re-embed existing data/companies.json only", ) parser.add_argument( "--multi", action="store_true", help="Create per-field embeddings (problem/solution/industry/customer) instead of single blob", ) args = parser.parse_args() DATA_DIR.mkdir(parents=True, exist_ok=True) if args.embed_only: companies_path = DATA_DIR / "companies.json" if not companies_path.exists(): print(f"No {companies_path} found. Run a full ingest first.") return with open(companies_path) as f: all_companies = json.load(f) print(f"Loaded {len(all_companies)} companies from {companies_path}") else: sources_to_run = ALL_SOURCES if args.source == "all" else {args.source: ALL_SOURCES[args.source]} all_companies: list[dict] = [] for name, module in sources_to_run.items(): print(f"\n{'='*60}") print(f"Ingesting: {name}") print(f"{'='*60}") try: companies = module.fetch() all_companies.extend(companies) print(f" -> {len(companies)} companies from {name}") except Exception as e: print(f" !! Error fetching {name}: {e}") if not all_companies: print("No companies fetched. Exiting.") return print(f"\nTotal companies across all sources: {len(all_companies)}") embedder = Embedder() if args.multi: print(f"Generating MULTI-FIELD embeddings for {len(all_companies)} companies " f"(provider: {embedder.provider}, dim: {embedder.dim}, fields: {len(FIELD_NAMES)}) ...") per_field: list[list[str]] = [[] for _ in FIELD_NAMES] for c in all_companies: fields = build_field_texts(c) for k, text in enumerate(fields): per_field[k].append(text if text else " ") field_matrices = [] for k, field_name in enumerate(FIELD_NAMES): print(f"\n [{field_name}] Embedding {len(per_field[k])} texts ...") mat = embedder.embed_batch(per_field[k]) field_matrices.append(mat) embeddings = np.stack(field_matrices, axis=1) # (N, 4, dim) print(f" -> Multi-field embedding shape: {embeddings.shape}") else: texts = [build_search_text(c) for c in all_companies] print(f"Generating embeddings for {len(texts)} companies (provider: {embedder.provider}, dim: {embedder.dim}) ...") embeddings = embedder.embed_batch(texts) print(f" -> Embedding matrix shape: {embeddings.shape}") companies_path = DATA_DIR / "companies.json" embeddings_path = DATA_DIR / embeddings_filename(embedder.provider, multi=args.multi) if not args.embed_only: with open(companies_path, "w") as f: json.dump(all_companies, f, separators=(",", ":")) print(f"Saved {companies_path} ({companies_path.stat().st_size / 1024:.0f} KB)") np.save(embeddings_path, embeddings) print(f"Saved {embeddings_path} ({embeddings_path.stat().st_size / 1024 / 1024:.1f} MB)") if not args.embed_only: by_source = {} for c in all_companies: by_source.setdefault(c.get("source", "unknown"), 0) by_source[c["source"]] += 1 print(f"\nBreakdown: {by_source}") print("Done!") if __name__ == "__main__": main()