\documentclass[11pt]{article} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage[french]{babel} \usepackage[margin=1in]{geometry} \usepackage{amsmath,amssymb} \usepackage{booktabs} \usepackage{longtable} \usepackage{array} \usepackage{xcolor} \usepackage{graphicx} \graphicspath{{figures/}} \usepackage{enumitem} \usepackage{multicol} \usepackage{listings} \usepackage{titlesec} \usepackage{caption} \usepackage[hidelinks,colorlinks=true,linkcolor=blue!45!black,urlcolor=blue!45!black]{hyperref} \definecolor{codebg}{RGB}{245,246,248} \definecolor{kw}{RGB}{27,58,91} \lstset{ basicstyle=\ttfamily\small, backgroundcolor=\color{codebg}, frame=single, rulecolor=\color{gray!30}, breaklines=true, columns=fullflexible, keywordstyle=\color{kw}\bfseries, showstringspaces=false, xleftmargin=4pt, framexleftmargin=4pt, } \titleformat{\section}{\large\bfseries\color{kw}}{\thesection}{0.6em}{} \titleformat{\subsection}{\normalsize\bfseries}{\thesubsection}{0.6em}{} \setlist{itemsep=2pt,topsep=3pt} \captionsetup{font=small,labelfont=bf} \newcommand{\code}[1]{\texttt{\small #1}} \title{\bfseries SPID — SEC Project Intelligence Database\\[0.3em] \large Documentation technique : présentation de la base de données\\ et de sa construction} \author{% Manel Kammoun \quad Djerrycharli Tandjambianda \quad Simon-Pierre Boucher\\[0.3em] \small \href{mailto:manel.kammoun@uqo.ca}{manel.kammoun@uqo.ca} \quad \href{mailto:djerrycharli.tandjambianda@uqo.ca}{djerrycharli.tandjambianda@uqo.ca} \quad \href{mailto:simon-pierre.boucher@uqo.ca}{simon-pierre.boucher@uqo.ca}\\[0.4em] \small D\'epartement des sciences administratives, Universit\'e du Qu\'ebec en Outaouais} \date{\today} \begin{document} \maketitle \begin{abstract} \noindent Ce document présente \textbf{SPID} (\emph{SEC Project Intelligence Database}), une base de données qui reconstruit le \emph{portefeuille de projets stratégiques} des sociétés cotées américaines directement à partir du texte brut de leurs documents réglementaires déposés auprès de la SEC. À partir de \textbf{153\,894} sections de filings (formulaires 10-K, 10-Q et 8-K) déposés par \textbf{500} entreprises entre 2010 et 2026, un extracteur fondé sur un grand modèle de langage produit \textbf{39\,930} mentions de projets, résolues en \textbf{19\,227} projets distincts dotés de chronologies, d'un graphe de connaissances de \textbf{32\,226} n\oe uds et d'embeddings sémantiques. Le document décrit en détail le corpus source, l'architecture du pipeline, chacune des cinq étapes de traitement (ingestion, extraction, résolution, graphe, embeddings), le schéma complet de la base, les statistiques du jeu de données construit, le coût et le débit du traitement, ainsi que les limites et les modalités d'utilisation. \end{abstract} \tableofcontents \clearpage % ===================================================================== \section{Vue d'ensemble} % ===================================================================== La plupart des analyses empiriques traitent les filings de la SEC (10-K, 10-Q, 8-K) comme des \emph{documents financiers}. SPID adopte une perspective différente : il les traite comme une source massive d'\textbf{intelligence sur les projets d'entreprise} --- nouveaux produits, programmes de R\&D, initiatives d'intelligence artificielle, expansions d'usines, centres de données, migrations infonuagiques, intégrations post-acquisition, programmes d'investissement, expansions géographiques, partenariats, transition énergétique, pipelines de médicaments, automatisation, etc. L'unité d'analyse de SPID n'est ni le document ni l'entreprise, mais le \textbf{projet}. La base ajoute une « couche projet » par-dessus le corpus EDGAR existant : extraction $\rightarrow$ résolution $\rightarrow$ chronologies $\rightarrow$ graphe de connaissances $\rightarrow$ embeddings $\rightarrow$ recherche $\rightarrow$ analytique, le tout persistant dans un unique fichier DuckDB (\code{data/db/spid.duckdb}). \begin{table}[h] \centering \caption{Chiffres clés de la base construite (exécution complète, juin 2026).} \begin{tabular}{lr} \toprule Élément & Valeur \\ \midrule Entreprises couvertes & 500 \\ Sections de filings traitées & 153\,894 \\ Mentions de projets extraites & 39\,930 \\ Projets résolus & 19\,227 \\ Lignes de chronologie (timeline) & 39\,930 \\ N\oe uds du graphe de connaissances & 32\,226 \\ Arêtes du graphe de connaissances & 33\,176 \\ Embeddings de projets (384-d) & 19\,227 \\ Secteurs GICS & 11 \\ Types de projets (taxonomie) & 21 \\ Localisations distinctes & 3\,080 \\ Projets avec montant divulgué & 9\,321 (48{,}5\,\%) \\ Montant médian divulgué & 718 M\$ US \\ \bottomrule \end{tabular} \end{table} % ===================================================================== \section{Le corpus source} % ===================================================================== SPID est construit \emph{par-dessus} le corpus EDGAR de l'UQO, qui réside dans \code{../data} et que SPID consomme en lecture seule. \begin{table}[h] \centering \caption{Actifs du corpus source utilisés par SPID.} \small \begin{tabular}{lll} \toprule Actif & Volume & Usage par SPID \\ \midrule \code{data/raw/sec/} & 88 Go, 500 entreprises & HTML brut des 10-K (sectionné à la demande) \\ \code{parquet/filings/} & 134\,124 filings & métadonnées (cik, ticker, dates, formulaire) \\ \code{parquet/filing\_sections/} & 127\,800 sections & texte pré-segmenté (10-Q + 8-K) \\ \code{parquet/companies/} & métadonnées entreprises & secteur / SIC / état \\ \bottomrule \end{tabular} \end{table} \paragraph{Point non trivial.} Le pipeline en amont n'avait segmenté que les formulaires \textbf{10-Q et 8-K}; les 10-K étaient restés en HTML brut. L'étape d'ingestion de SPID (\S\ref{sec:ingest}) nettoie et segmente le HTML brut des 10-K pour que ces documents circulent dans le même pipeline d'extraction. Les sections pré-segmentées et les sections 10-K ingérées sont réunies dans une vue unifiée \code{v\_sections}. \begin{table}[h] \centering \caption{Décompte des sections éligibles à l'extraction (au moins 30 mots), par formulaire, après ingestion des 10-K.} \begin{tabular}{lrr} \toprule Formulaire & Sections & Entreprises (CIK) \\ \midrule 8-K & 103\,926 & 497 \\ 10-K & 27\,164 & 497 \\ 10-Q & 22\,804 & 84 \\ \midrule \textbf{Total} & \textbf{153\,894} & 500 \\ \bottomrule \end{tabular} \end{table} % ===================================================================== \section{Architecture du pipeline} % ===================================================================== Le traitement s'organise en cinq étapes séquentielles, chacune persistant son résultat dans DuckDB de manière incrémentale et reprenable. \begin{center} \small \setlength{\fboxsep}{6pt} \fbox{\begin{minipage}{0.93\textwidth} \ttfamily HTML brut 10-K ----> [1. INGEST] nettoyage + sectionnement (Items 1/1A/2/7) \\ \phantom{xxxxxxxxxxxxxxxxxxxxx} | \\ filing\_sections (10-Q/8-K) --+--> v\_sections (flux unifie) \\ \phantom{xxxxxxxxxxxxxxxxxxxxxxxxxx} | \\ \phantom{xx}[2. EXTRACT] backend enfichable : rules (gratuit) | llm (gpt-4o-mini) \\ \phantom{xxxxxxxxxx} | \ \ --> project\_mentions \\ \phantom{xxxxxxxxxx} v \\ \phantom{xx}[3. RESOLVE] fusion des mentions --> projects + project\_timeline \\ \phantom{xxxxxxxxxx} +--> [4. GRAPH] kg\_nodes / kg\_edges (+ export Cypher/parquet) \\ \phantom{xxxxxxxxxx} +--> [5. EMBED] project\_embeddings (MiniLM 384-d) --> recherche semantique \end{minipage}} \end{center} Les modules correspondants se trouvent dans \code{spid/} : \code{ingest.py}, \code{extract/} (\code{rules.py}, \code{llm.py}), \code{pipeline.py}, \code{resolve.py}, \code{graph.py}, \code{embed.py}, \code{search.py}, \code{analytics.py}, \code{store.py}, \code{taxonomy.py}, \code{config.py}, \code{\_\_main\_\_.py} (CLI). % ===================================================================== \section{Étape 1 — Ingestion des 10-K}\label{sec:ingest} % ===================================================================== Module : \code{spid/ingest.py}. Comme le corpus amont ne segmentait pas les 10-K, cette étape lit le HTML brut de chaque dépôt 10-K (\code{data/raw/sec//10-K//}), le nettoie et en extrait les \emph{Items} les plus denses en projets. \paragraph{Procédé.} \begin{enumerate} \item \textbf{Sélection du fichier primaire} : pour chaque accession, on retient le plus gros fichier \code{.htm/.html/.txt} du répertoire. \item \textbf{Nettoyage HTML} : suppression des balises \code{script}, \code{style} et \code{table} via BeautifulSoup (\code{lxml}), conversion en texte, dé-échappement des entités HTML, normalisation des espaces et des sauts de ligne. \item \textbf{Découpage en Items} : une expression régulière repère les en-têtes « ITEM~n » et conserve uniquement les Items à forte densité de projets : \textbf{1 (Business)}, \textbf{1A (Risk Factors)}, \textbf{2 (Properties)}, \textbf{7/7A (MD\&A)}. Les ébauches de table des matières (corps $<$ 400 caractères) sont écartées; pour chaque Item on garde la plus longue occurrence (corps réel plutôt que renvoi). \item \textbf{Persistance} : les sections obtenues sont écrites dans la table \code{spid\_sections} (clé primaire = identifiant aléatoire), avec un compte de mots. L'opération est \emph{idempotente} : une accession déjà ingérée est sautée. \end{enumerate} \paragraph{Résultat de l'exécution.} \textbf{7\,654} filings 10-K traités $\rightarrow$ \textbf{27\,164} lignes de sections (contre 2\,126 auparavant, couvrant désormais l'ensemble des 500 entreprises au lieu de 40). % ===================================================================== \section{Étape 2 — Extraction par modèle de langage}\label{sec:extract} % ===================================================================== Modules : \code{spid/pipeline.py} (moteur) et \code{spid/extract/llm.py} (extracteur). Le backend par défaut est \textbf{\code{gpt-4o-mini}} d'OpenAI en mode JSON, mais l'interface est compatible OpenAI : un simple changement de deux variables d'environnement permet de viser la passerelle de cluster \code{llm.maclustr.io} ou tout modèle local. \subsection{Maîtrise du coût : le « gate » et le « focus »} Pour borner le coût par appel : \begin{itemize} \item \textbf{Project gate} : avant tout appel, une expression régulière de vocabulaire-projet (\code{\_PROJECT\_GATE}) filtre les sections. Une section sans signal de projet ne déclenche \emph{aucun} appel API. Le nombre d'appels facturés est donc bien inférieur au nombre total de sections. \item \textbf{Focus} : pour les sections retenues, seules les \emph{fenêtres} de texte autour des signaux de projet sont envoyées (budget $\approx$ 9\,000 caractères, fenêtres fusionnées), le contenu total étant plafonné à $\approx$ 14\,000 caractères par appel quelle que soit la longueur de la section. \end{itemize} \subsection{Schéma d'extraction (sortie JSON stricte)} Le modèle reçoit une consigne système d'analyste financier et renvoie un objet \code{\{"projects": [...]\}} où chaque projet respecte le schéma suivant : \begin{lstlisting} { "project_name": "", // nom court (officiel si mentionne) "project_type": "", // EXACTEMENT un des 21 types de la taxonomie "description": "", // 1 phrase, ancree dans le texte (pas de speculation) "objective": "", // le but / le pourquoi "status": "planned | in_progress | completed | mentioned", "amount_usd": 0, // montant USD si indique, sinon null "locations": [], "technologies": [], "partners": [], "benefits": [], "risks": [], "years": [], "confidence": 0.0 // 0..1 : a quel point c'est un vrai projet concret } \end{lstlisting} \paragraph{Règles imposées au modèle.} N'extraire que des initiatives réelles (pas de \emph{boilerplate} de facteurs de risque ni d'hypothèses); ne pas inventer de faits (montants et lieux doivent apparaître dans le texte); préférer peu de projets de qualité à beaucoup de projets vagues. La température est fixée à 0 et le mode JSON est activé. Les appels sont parallélisés (\code{--workers}); une politique de reprise gère les codes 429 et 5xx. \paragraph{Post-traitement.} Chaque projet renvoyé est normalisé : le \code{project\_type} est ramené à la taxonomie (correspondance exacte puis floue, défaut \code{technology\_deployment}); le statut est validé; les montants sont convertis en \code{float}; les listes sont nettoyées et tronquées. Un identifiant de mention \textbf{stable} est calculé : \[ \code{mention\_id} = \text{SHA-1}(\;\code{accession} \mid \code{section\_id} \mid \code{type} \mid \code{anchor}\;)[0{:}20]. \] Cette stabilité rend tout le pipeline \emph{incrémental et reprenable} : ré-exécuter une extraction réinsère les mêmes lignes (\code{INSERT OR REPLACE}) sans double comptage. Les mentions de confiance $<$ 0{,}45 sont écartées. \paragraph{Résultat de l'exécution.} \textbf{39\,930} mentions extraites sur les 153\,894 sections, traitées en 34 lots d'entreprises (15 CIK par lot) avec journal de points de reprise (\code{logs/extract\_done\_ciks.txt}). % ===================================================================== \section{Étape 3 — Résolution des projets} % ===================================================================== Module : \code{spid/resolve.py}. Un même projet physique est généralement mentionné dans plusieurs filings et sur plusieurs années. La résolution \textbf{fusionne les mentions} (par entreprise, type de projet et ancre normalisée) en projets uniques, chacun doté : \begin{itemize} \item d'une \textbf{localisation canonique}, d'un \textbf{montant agrégé}, d'un \textbf{statut} courant et d'une \textbf{liste de technologies} consolidée; \item de dates \textbf{first\_seen / last\_seen} et d'années \textbf{first\_year / last\_year}; \item d'un nombre de mentions et de filings, et d'une confiance moyenne; \item d'une \textbf{chronologie} (\code{project\_timeline}) conservant chaque mention datée, son formulaire, son statut, son montant et un extrait. \end{itemize} \paragraph{Résultat de l'exécution.} 39\,930 mentions $\rightarrow$ \textbf{19\,227} projets distincts; 39\,930 lignes de chronologie conservées. % ===================================================================== \section{Étape 4 — Graphe de connaissances} % ===================================================================== Module : \code{spid/graph.py}. À partir des projets résolus, on dérive un graphe orienté de cinq types de n\oe uds et trois types d'arêtes, puis on l'exporte en parquet et en Cypher (import Neo4j) dans \code{data/exports/}. \begin{table}[h] \centering \caption{Composition du graphe de connaissances (exécution complète).} \begin{tabular}{llr} \toprule Type de n\oe ud & Préfixe d'identifiant & Nombre \\ \midrule Project & \code{P:} & 19\,227 \\ Partner & \code{PR:} & 7\,640 \\ Location & \code{L:} & 3\,080 \\ Technology & \code{T:} & 1\,779 \\ Company & \code{C:} & 500 \\ \midrule \textbf{Total n\oe uds} & & \textbf{32\,226} \\ \textbf{Total arêtes} & & \textbf{33\,176} \\ \bottomrule \end{tabular} \end{table} Les arêtes relient : \code{Company} $\xrightarrow{\text{owns}}$ \code{Project}, \code{Project} $\xrightarrow{\text{uses}}$ \code{Technology}, et \code{Project} $\xrightarrow{\text{located\_in}}$ \code{Location}. \begin{figure}[h] \centering \begin{minipage}{0.46\textwidth}\centering \includegraphics[width=\textwidth]{fig_degree_dist.pdf} \end{minipage}\hfill \begin{minipage}{0.52\textwidth}\centering \includegraphics[width=\textwidth]{fig_tech_network.pdf} \end{minipage} \caption{Le graphe de connaissances. \emph{Gauche} : distribution des degrés (échelle log-log), à queue lourde, signature d'une structure proche du « sans échelle ». \emph{Droite} : réseau de co-occurrence des technologies (deux technologies reliées lorsqu'elles servent dans un même projet); la détection de communautés révèle quatre écosystèmes technologiques (modularité 0{,}52), les technologies de la transition énergétique occupant les positions les plus centrales.} \label{fig:graph} \end{figure} \paragraph{Note de robustesse.} À l'échelle du corpus complet, la construction du graphe heurtait une violation de clé primaire (identifiants de partenaires repliés en minuscules avec étiquettes de casse variable; CIK aux nom/secteur variables). La correction agrège ces n\oe uds par \code{GROUP BY} avec \code{any\_value()}. % ===================================================================== \section{Étape 5 — Embeddings et recherche sémantique} % ===================================================================== Module : \code{spid/embed.py}. Le texte de chaque projet (nom + description + objectif) est encodé en un vecteur de \textbf{384 dimensions} par le modèle \textbf{\code{all-MiniLM-L6-v2}} (\code{sentence-transformers}, local et gratuit). Les vecteurs sont stockés dans \code{project\_embeddings} et permettent la recherche sémantique (\code{spid semantic "AI projects launched by banks"}) par similarité cosinus, ainsi que le regroupement thématique en aval. \paragraph{Résultat de l'exécution.} \textbf{19\,227} embeddings (un par projet), dimension 384. \begin{figure}[h] \centering \includegraphics[width=0.74\textwidth]{fig_embedding_tsne.pdf} \caption{Projection t-SNE bidimensionnelle des embeddings de projets (échantillon stratifié de 5\,000 projets), colorée par thème ($K$-means). Les thèmes se séparent tout en se chevauchant aux frontières, reflétant l'espace sémantique continu des initiatives d'entreprise et confirmant que la structure non supervisée recouvre largement la taxonomie supervisée.} \label{fig:tsne} \end{figure} % ===================================================================== \section{Schéma de la base de données} % ===================================================================== La base est un unique fichier DuckDB. SPID expose le corpus source en \textbf{vues en lecture seule} (\code{src\_filings}, \code{src\_sections}, \code{src\_companies}, \code{v\_sections}) et écrit ses propres tables. Le tableau ci-dessous récapitule les tables persistées. \begin{longtable}{p{3.4cm} r p{8.5cm}} \toprule Table & Lignes & Colonnes principales \\ \midrule \endhead \code{spid\_sections} & 27\,164 & section\_id (PK), accession\_number, section\_name, item\_number, text, word\_count \\ \addlinespace \code{project\_mentions} & 39\,930 & mention\_id (PK), accession\_number, cik, section\_id, project\_name, project\_type, description, objective, amount\_usd, amount\_raw, locations[], technologies[], partners[], suppliers[], benefits[], risks[], years[], status, confidence, backend, ticker, company\_name, form\_type, filing\_date, fiscal\_year, sector \\ \addlinespace \code{projects} & 19\,227 & project\_id (PK), cik, ticker, company\_name, sector, project\_type, project\_name, canonical\_location, technologies[], status, total\_amount\_usd, n\_mentions, n\_filings, first\_seen, last\_seen, first\_year, last\_year, avg\_confidence, description \\ \addlinespace \code{project\_timeline} & 39\,930 & project\_id, accession\_number, filing\_date, form\_type, status, amount\_usd, confidence, snippet \\ \addlinespace \code{kg\_nodes} & 32\,226 & node\_id (PK), node\_type, label, props (JSON) \\ \addlinespace \code{kg\_edges} & 33\,176 & src, rel, dst, props (JSON) \\ \addlinespace \code{project\_embeddings} & 19\,227 & project\_id (PK), model, dim, vector (FLOAT[]) \\ \bottomrule \caption{Tables persistées par SPID dans \code{data/db/spid.duckdb}.} \end{longtable} % ===================================================================== \section{Statistiques du jeu de données construit} % ===================================================================== \begin{figure}[h] \centering \includegraphics[width=0.7\textwidth]{fig_mentions_by_year.pdf} \caption{Mentions de projets extraites par année et par formulaire. Le corpus est à peu près équilibré dans le temps (environ 2\,000 à 2\,800 mentions par an), avec une croissance d'environ 2{,}2\,\% par an et un palier après 2020. Les 8-K et les 10-K fournissent l'essentiel des signaux de projet.} \label{fig:mentions} \end{figure} \begin{figure}[h] \centering \begin{minipage}{0.49\textwidth}\centering \includegraphics[width=\textwidth]{fig_type_distribution.pdf} \end{minipage}\hfill \begin{minipage}{0.49\textwidth}\centering \includegraphics[width=\textwidth]{fig_sector_type_heatmap.pdf} \end{minipage} \caption{\emph{Gauche} : distribution des projets selon les 21 catégories de la taxonomie (l'intégration post-M\&A domine). \emph{Droite} : composition en types de projets par secteur GICS (parts normalisées par ligne) --- les secteurs se spécialisent fortement (énergie/utilities dans la construction, TI dans le déploiement technologique, santé dans les pipelines).} \label{fig:typesector} \end{figure} \begin{table}[h] \centering \caption{Répartition des projets par type (extrait des principaux types).} \small \begin{tabular}{lrr} \toprule Type de projet & Projets & Capital annoncé (G\$) \\ \midrule M\&A integration & 7\,274 & 14\,864{,}9 \\ Capex program & 2\,085 & 4\,602{,}6 \\ Plant construction & 1\,252 & 463{,}0 \\ Partnership & 1\,239 & 440{,}4 \\ Cost reduction & 1\,141 & 725{,}7 \\ Geographic expansion & 1\,031 & 175{,}0 \\ Infrastructure & 906 & 1\,002{,}3 \\ Product launch & 819 & 48{,}8 \\ Technology deployment & 698 & 190{,}4 \\ Manufacturing expansion & 552 & 145{,}6 \\ \bottomrule \end{tabular} \end{table} \begin{table}[h] \centering \caption{Répartition par secteur GICS (projets et capital annoncé).} \small \begin{tabular}{lrr} \toprule Secteur & Projets & Capital annoncé (G\$) \\ \midrule Industrials & 2\,708 & 2\,128{,}6 \\ Health Care & 2\,475 & 2\,767{,}3 \\ Information Technology & 2\,225 & 2\,931{,}4 \\ Consumer Discretionary & 2\,220 & 1\,310{,}8 \\ Utilities & 1\,956 & 2\,725{,}9 \\ Financials & 1\,908 & 4\,832{,}3 \\ Consumer Staples & 1\,483 & 1\,332{,}5 \\ Real Estate & 1\,400 & 901{,}5 \\ Energy & 1\,109 & --- \\ Materials & 914 & --- \\ Communication Services & 829 & --- \\ \bottomrule \end{tabular} \end{table} \paragraph{Note sur les montants.} Le capital « annoncé » est la somme des montants \emph{divulgués}, auto-déclarés et hétérogènes en portée; il doit se lire comme un \textbf{ordre de grandeur supérieur} et non comme un total d'investissement net (un même programme pluriannuel peut être mentionné --- et compté --- dans plusieurs filings, et les très grandes valeurs d'entreprise de M\&A dominent la somme). % ===================================================================== \section{Coût, débit et reproductibilité} % ===================================================================== \begin{itemize} \item \textbf{Coût marginal} : de l'ordre du dixième de cent US par section traitée. L'exécution complète sur les 153\,894 sections est estimée à $\approx$ 100--130 \$ US de \code{gpt-4o-mini} aux tarifs courants. \item \textbf{Débit} : appels LLM parallélisés (16 \emph{workers}); résolution, graphe et analytique sont du pur SQL DuckDB et passent à l'échelle de millions de mentions. \item \textbf{Mémoire bornée} : l'extraction complète est exécutée par lots de CIK (15 par lot) afin de ne pas matérialiser les 153\,894 sections d'un seul coup (ce qui dépassait la limite de 2 Go des tampons de chaînes Arrow de DuckDB; option \code{arrow\_large\_buffer\_size} activée par sécurité). \item \textbf{Reprenable} : grâce aux identifiants de mention stables (\code{INSERT OR REPLACE}) et à un journal de points de reprise par lot, une interruption ne re-facture jamais le travail déjà effectué. \end{itemize} % ===================================================================== \section{Utilisation} % ===================================================================== Interface en ligne de commande (depuis \code{project-db/}) : \begin{lstlisting}[language=bash] PY=../.venv/bin/python # 1. Sectionner les 10-K bruts (optionnel : ciblage par tickers/CIK) PYTHONPATH=. $PY -m spid ingest --tickers NVDA,AAPL,MSFT # 2. Extraire les projets (backend LLM par defaut) PYTHONPATH=. $PY -m spid extract --backend llm --forms 10-K,10-Q,8-K --workers 12 # ... ou la base deterministe gratuite PYTHONPATH=. $PY -m spid extract --backend rules --sample 50 # 3. Resoudre, construire graphe + embeddings PYTHONPATH=. $PY -m spid resolve PYTHONPATH=. $PY -m spid graph PYTHONPATH=. $PY -m spid embed # 4. Explorer PYTHONPATH=. $PY -m spid analytics PYTHONPATH=. $PY -m spid search "data center" --type data_center --min-amount 5e8 PYTHONPATH=. $PY -m spid semantic "AI projects launched by banks" PYTHONPATH=. $PY -m spid stats # Tout le pipeline en une commande PYTHONPATH=. $PY -m spid all --backend llm \end{lstlisting} \paragraph{API HTTP optionnelle.} \code{uvicorn spid.api:app --port 8088} expose \code{/projects}, \code{/semantic} et \code{/analytics}. \paragraph{Configuration.} Les secrets et paramètres sont dans \code{project-db/.env} (non versionné) : \code{OPENAI\_API\_KEY}, \code{SPID\_LLM\_BASE\_URL}, \code{SPID\_LLM\_MODEL} (défaut \code{gpt-4o-mini}), \code{SPID\_EMBED\_MODEL} (défaut \code{all-MiniLM-L6-v2}), \code{SPID\_BACKEND}. % ===================================================================== \section{Limites} % ===================================================================== \begin{itemize} \item SPID mesure la \emph{divulgation} de projets, non les projets eux-mêmes : une initiative jamais évoquée dans un filing est invisible, et les incitations à divulguer varient selon les firmes et le temps. \item Les montants sont auto-déclarés, de portée inconsistante (coût total de programme, dépense annuelle, ou valeur de transaction) et souvent absents (48{,}5\,\% des projets en portent un). \item L'extraction LLM peut produire des faux positifs et des faux négatifs; le seuil de confiance et les contraintes d'ancrage les réduisent, mais il n'existe pas encore d'échantillon étiqueté manuellement assez grand pour estimer précisément précision et rappel. \item La résolution fusionne les mentions de façon heuristique : une fusion trop agressive sous-estime le nombre de projets, une fusion trop conservatrice le surestime. \item L'échantillon de 500 entreprises est orienté vers les grandes capitalisations américaines matures; la validité externe aux petites firmes ou aux firmes privées est limitée. \end{itemize} % ===================================================================== \appendix \section{Taxonomie complète des types de projets} % ===================================================================== La taxonomie compte 21 catégories mutuellement exclusives (voir \code{spid/taxonomy.py}) : \begin{multicols}{2}\small \begin{enumerate}[leftmargin=*] \item \code{manufacturing\_expansion} \item \code{plant\_construction} \item \code{data\_center} \item \code{cloud\_migration} \item \code{ai\_initiative} \item \code{digital\_transformation} \item \code{erp\_implementation} \item \code{rd\_program} \item \code{product\_launch} \item \code{drug\_pipeline} \item \code{ma\_integration} \item \code{geographic\_expansion} \item \code{capex\_program} \item \code{supply\_chain} \item \code{automation} \item \code{sustainability} \item \code{energy\_transition} \item \code{infrastructure} \item \code{cost\_reduction} \item \code{partnership} \item \code{technology\_deployment} \end{enumerate} \end{multicols} \end{document}