spb/uqo-research-db
Public
1# ============================================================2# SPID — extraction interface & record schema3# ============================================================4from __future__ import annotations56import hashlib7from dataclasses import dataclass, field, asdict8from typing import Protocol91011@dataclass12class ProjectMention:13 """A single project signal extracted from one filing section.1415 Mentions are the atomic unit; `resolve.py` merges many mentions16 (across filings & years) into a single Project with a timeline.17 """18 mention_id: str19 accession_number: str20 cik: str21 section_id: str22 section_name: str2324 project_name: str25 project_type: str26 description: str27 objective: str = ""2829 amount_usd: float | None = None30 amount_raw: str | None = None31 locations: list[str] = field(default_factory=list)32 technologies: list[str] = field(default_factory=list)33 partners: list[str] = field(default_factory=list)34 suppliers: list[str] = field(default_factory=list)35 benefits: list[str] = field(default_factory=list)36 risks: list[str] = field(default_factory=list)37 years: list[int] = field(default_factory=list)38 status: str = "mentioned"3940 confidence: float = 0.041 backend: str = "rules"4243 def to_row(self) -> dict:44 d = asdict(self)45 # store list fields as JSON-friendly via duckdb list[str]46 return d4748 @staticmethod49 def make_id(accession: str, section_id: str, ptype: str, anchor: str) -> str:50 h = hashlib.sha1(f"{accession}|{section_id}|{ptype}|{anchor}".encode()).hexdigest()51 return h[:20]525354class Extractor(Protocol):55 name: str5657 def extract(self, *, text: str, accession_number: str, cik: str,58 section_id: str, section_name: str) -> list[ProjectMention]:59 ...606162def get_extractor(backend: str):63 """Factory. `backend` in {'rules','llm'}."""64 backend = (backend or "rules").lower()65 if backend == "llm":66 from spid.extract.llm import LLMExtractor67 return LLMExtractor()68 from spid.extract.rules import RuleExtractor69 return RuleExtractor()70