@tricoteuses/senat 3.1.21 → 3.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +32 -32
- package/README.md +326 -326
- package/lib/add-js-extensions-v2.js +23 -0
- package/lib/add-js-extensions.js +17 -0
- package/lib/aggregates.d.ts +52 -0
- package/lib/aggregates.js +930 -0
- package/lib/aggregates.mjs +713 -0
- package/lib/aggregates.ts +833 -0
- package/lib/config.d.ts +10 -0
- package/lib/config.js +16 -0
- package/lib/config.mjs +16 -0
- package/lib/config.ts +26 -0
- package/lib/databases.d.ts +2 -0
- package/lib/databases.js +26 -0
- package/lib/databases.mjs +57 -0
- package/lib/databases.ts +71 -0
- package/lib/datasets.d.ts +34 -0
- package/lib/datasets.js +233 -0
- package/lib/datasets.mjs +78 -0
- package/lib/datasets.ts +118 -0
- package/lib/fields.d.ts +10 -0
- package/lib/fields.js +68 -0
- package/lib/fields.mjs +22 -0
- package/lib/fields.ts +29 -0
- package/lib/git.d.ts +26 -0
- package/lib/git.js +167 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +1 -0
- package/lib/index.mjs +7 -0
- package/lib/index.ts +64 -0
- package/lib/inserters.d.ts +98 -0
- package/lib/inserters.js +500 -0
- package/lib/inserters.mjs +360 -0
- package/lib/inserters.ts +521 -0
- package/lib/legislatures.json +38 -0
- package/lib/loaders.d.ts +58 -0
- package/lib/loaders.js +286 -0
- package/lib/loaders.mjs +158 -0
- package/lib/loaders.ts +271 -0
- package/lib/model/agenda.d.ts +6 -0
- package/lib/model/agenda.js +148 -0
- package/lib/model/ameli.d.ts +51 -0
- package/lib/model/ameli.js +149 -0
- package/lib/model/ameli.mjs +84 -0
- package/lib/model/ameli.ts +100 -0
- package/lib/model/commission.d.ts +18 -0
- package/lib/model/commission.js +269 -0
- package/lib/model/debats.d.ts +67 -0
- package/lib/model/debats.js +95 -0
- package/lib/model/debats.mjs +43 -0
- package/lib/model/debats.ts +68 -0
- package/lib/model/documents.d.ts +12 -0
- package/lib/model/documents.js +151 -0
- package/lib/model/dosleg.d.ts +7 -0
- package/lib/model/dosleg.js +326 -0
- package/lib/model/dosleg.mjs +196 -0
- package/lib/model/dosleg.ts +240 -0
- package/lib/model/index.d.ts +7 -0
- package/lib/model/index.js +7 -0
- package/lib/model/index.mjs +5 -0
- package/lib/model/index.ts +15 -0
- package/lib/model/questions.d.ts +45 -0
- package/lib/model/questions.js +89 -0
- package/lib/model/questions.mjs +71 -0
- package/lib/model/questions.ts +93 -0
- package/lib/model/scrutins.d.ts +13 -0
- package/lib/model/scrutins.js +114 -0
- package/lib/model/seance.d.ts +3 -0
- package/lib/model/seance.js +267 -0
- package/lib/model/sens.d.ts +146 -0
- package/lib/model/sens.js +454 -0
- package/lib/model/sens.mjs +415 -0
- package/lib/model/sens.ts +516 -0
- package/lib/model/texte.d.ts +7 -0
- package/lib/model/texte.js +256 -0
- package/lib/model/texte.mjs +208 -0
- package/lib/model/texte.ts +229 -0
- package/lib/model/util.d.ts +9 -0
- package/lib/model/util.js +38 -0
- package/lib/model/util.mjs +19 -0
- package/lib/model/util.ts +32 -0
- package/lib/parsers/texte.d.ts +7 -0
- package/lib/parsers/texte.js +228 -0
- package/lib/raw_types/ameli.d.ts +914 -0
- package/lib/raw_types/ameli.js +5 -0
- package/lib/raw_types/ameli.mjs +163 -0
- package/lib/raw_types/debats.d.ts +207 -0
- package/lib/raw_types/debats.js +5 -0
- package/lib/raw_types/debats.mjs +58 -0
- package/lib/raw_types/dosleg.d.ts +1619 -0
- package/lib/raw_types/dosleg.js +5 -0
- package/lib/raw_types/dosleg.mjs +438 -0
- package/lib/raw_types/questions.d.ts +419 -0
- package/lib/raw_types/questions.js +5 -0
- package/lib/raw_types/questions.mjs +11 -0
- package/lib/raw_types/senat.d.ts +11368 -0
- package/lib/raw_types/senat.js +5 -0
- package/lib/raw_types/sens.d.ts +8248 -0
- package/lib/raw_types/sens.js +5 -0
- package/lib/raw_types/sens.mjs +508 -0
- package/lib/raw_types_kysely/ameli.d.ts +915 -0
- package/lib/raw_types_kysely/ameli.js +7 -0
- package/lib/raw_types_kysely/ameli.mjs +5 -0
- package/lib/raw_types_kysely/ameli.ts +951 -0
- package/lib/raw_types_kysely/debats.d.ts +207 -0
- package/lib/raw_types_kysely/debats.js +7 -0
- package/lib/raw_types_kysely/debats.mjs +5 -0
- package/lib/raw_types_kysely/debats.ts +222 -0
- package/lib/raw_types_kysely/dosleg.d.ts +3532 -0
- package/lib/raw_types_kysely/dosleg.js +7 -0
- package/lib/raw_types_kysely/dosleg.mjs +5 -0
- package/lib/raw_types_kysely/dosleg.ts +3621 -0
- package/lib/raw_types_kysely/questions.d.ts +414 -0
- package/lib/raw_types_kysely/questions.js +7 -0
- package/lib/raw_types_kysely/questions.mjs +5 -0
- package/lib/raw_types_kysely/questions.ts +426 -0
- package/lib/raw_types_kysely/sens.d.ts +4394 -0
- package/lib/raw_types_kysely/sens.js +7 -0
- package/lib/raw_types_kysely/sens.mjs +5 -0
- package/lib/raw_types_kysely/sens.ts +4499 -0
- package/lib/raw_types_schemats/ameli.d.ts +539 -0
- package/lib/raw_types_schemats/ameli.js +2 -0
- package/lib/raw_types_schemats/ameli.mjs +2 -0
- package/lib/raw_types_schemats/ameli.ts +601 -0
- package/lib/raw_types_schemats/debats.d.ts +127 -0
- package/lib/raw_types_schemats/debats.js +2 -0
- package/lib/raw_types_schemats/debats.mjs +2 -0
- package/lib/raw_types_schemats/debats.ts +145 -0
- package/lib/raw_types_schemats/dosleg.d.ts +977 -0
- package/lib/raw_types_schemats/dosleg.js +2 -0
- package/lib/raw_types_schemats/dosleg.mjs +2 -0
- package/lib/raw_types_schemats/dosleg.ts +2193 -0
- package/lib/raw_types_schemats/questions.d.ts +235 -0
- package/lib/raw_types_schemats/questions.js +2 -0
- package/lib/raw_types_schemats/questions.mjs +2 -0
- package/lib/raw_types_schemats/questions.ts +249 -0
- package/lib/raw_types_schemats/sens.d.ts +6915 -0
- package/lib/raw_types_schemats/sens.js +2 -0
- package/lib/raw_types_schemats/sens.mjs +2 -0
- package/lib/raw_types_schemats/sens.ts +2907 -0
- package/lib/scripts/convert_data.js +354 -0
- package/lib/scripts/convert_data.mjs +181 -0
- package/lib/scripts/convert_data.ts +243 -0
- package/lib/scripts/data-download.d.ts +1 -0
- package/lib/scripts/data-download.js +12 -0
- package/lib/scripts/datautil.d.ts +8 -0
- package/lib/scripts/datautil.js +34 -0
- package/lib/scripts/datautil.mjs +16 -0
- package/lib/scripts/datautil.ts +19 -0
- package/lib/scripts/images/transparent_150x192.jpg +0 -0
- package/lib/scripts/images/transparent_155x225.jpg +0 -0
- package/lib/scripts/parse_textes.d.ts +1 -0
- package/lib/scripts/parse_textes.js +44 -0
- package/lib/scripts/parse_textes.mjs +46 -0
- package/lib/scripts/parse_textes.ts +65 -0
- package/lib/scripts/retrieve_agenda.d.ts +1 -0
- package/lib/scripts/retrieve_agenda.js +132 -0
- package/lib/scripts/retrieve_cr_commission.d.ts +1 -0
- package/lib/scripts/retrieve_cr_commission.js +364 -0
- package/lib/scripts/retrieve_cr_seance.d.ts +6 -0
- package/lib/scripts/retrieve_cr_seance.js +347 -0
- package/lib/scripts/retrieve_documents.d.ts +3 -0
- package/lib/scripts/retrieve_documents.js +219 -0
- package/lib/scripts/retrieve_documents.mjs +249 -0
- package/lib/scripts/retrieve_documents.ts +298 -0
- package/lib/scripts/retrieve_open_data.d.ts +1 -0
- package/lib/scripts/retrieve_open_data.js +315 -0
- package/lib/scripts/retrieve_open_data.mjs +217 -0
- package/lib/scripts/retrieve_open_data.ts +268 -0
- package/lib/scripts/retrieve_senateurs_photos.d.ts +1 -0
- package/lib/scripts/retrieve_senateurs_photos.js +147 -0
- package/lib/scripts/retrieve_senateurs_photos.mjs +147 -0
- package/lib/scripts/retrieve_senateurs_photos.ts +177 -0
- package/lib/scripts/retrieve_videos.d.ts +1 -0
- package/lib/scripts/retrieve_videos.js +461 -0
- package/lib/scripts/shared/cli_helpers.d.ts +95 -0
- package/lib/scripts/shared/cli_helpers.js +91 -0
- package/lib/scripts/shared/cli_helpers.ts +36 -0
- package/lib/scripts/shared/util.d.ts +4 -0
- package/lib/scripts/shared/util.js +35 -0
- package/lib/scripts/shared/util.ts +33 -0
- package/lib/scripts/test_iter_load.d.ts +1 -0
- package/lib/scripts/test_iter_load.js +12 -0
- package/lib/src/ameli.d.ts +66 -0
- package/lib/src/ameli.js +1 -0
- package/lib/src/config.d.ts +43 -0
- package/lib/src/config.js +37 -0
- package/lib/src/conversion_textes.d.ts +11 -0
- package/lib/src/conversion_textes.js +320 -0
- package/lib/src/databases.d.ts +3 -0
- package/lib/src/databases.js +26 -0
- package/lib/src/databases_postgres.d.ts +4 -0
- package/lib/src/databases_postgres.js +23 -0
- package/lib/src/datasets.d.ts +38 -0
- package/lib/src/datasets.js +247 -0
- package/lib/src/db_types/ameli.d.ts +1762 -0
- package/lib/src/db_types/ameli.js +1074 -0
- package/lib/src/db_types/debats.d.ts +380 -0
- package/lib/src/db_types/debats.js +266 -0
- package/lib/src/db_types/dosleg.d.ts +2954 -0
- package/lib/src/db_types/dosleg.js +2005 -0
- package/lib/src/db_types/questions.d.ts +699 -0
- package/lib/src/db_types/questions.js +493 -0
- package/lib/src/db_types/sens.d.ts +7843 -0
- package/lib/src/db_types/sens.js +4691 -0
- package/lib/src/debats.d.ts +38 -0
- package/lib/src/debats.js +1 -0
- package/lib/src/dosleg.d.ts +142 -0
- package/lib/src/dosleg.js +193 -0
- package/lib/src/git.d.ts +27 -0
- package/lib/src/git.js +251 -0
- package/lib/src/loaders.d.ts +52 -0
- package/lib/src/loaders.js +260 -0
- package/lib/src/model/agenda.d.ts +6 -0
- package/lib/src/model/agenda.js +148 -0
- package/lib/src/model/ameli.d.ts +67 -0
- package/lib/src/model/ameli.js +150 -0
- package/lib/src/model/ameli_postgres.d.ts +67 -0
- package/lib/src/model/ameli_postgres.js +150 -0
- package/lib/src/model/commission.d.ts +19 -0
- package/lib/src/model/commission.js +269 -0
- package/lib/src/model/debats.d.ts +39 -0
- package/lib/src/model/debats.js +112 -0
- package/lib/src/model/documents.d.ts +32 -0
- package/lib/src/model/documents.js +182 -0
- package/lib/src/model/dosleg.d.ts +144 -0
- package/lib/src/model/dosleg.js +468 -0
- package/lib/src/model/index.d.ts +7 -0
- package/lib/src/model/index.js +7 -0
- package/lib/src/model/questions.d.ts +54 -0
- package/lib/src/model/questions.js +91 -0
- package/lib/src/model/scrutins.d.ts +48 -0
- package/lib/src/model/scrutins.js +121 -0
- package/lib/src/model/seance.d.ts +3 -0
- package/lib/src/model/seance.js +267 -0
- package/lib/src/model/sens.d.ts +112 -0
- package/lib/src/model/sens.js +385 -0
- package/lib/src/model/util.d.ts +1 -0
- package/lib/src/model/util.js +15 -0
- package/lib/src/other_types/questions.d.ts +2 -0
- package/lib/src/other_types/questions.js +1 -0
- package/lib/src/questions.d.ts +53 -0
- package/lib/src/questions.js +1 -0
- package/lib/src/raw_types/ameli.d.ts +1762 -0
- package/lib/src/raw_types/ameli.js +1074 -0
- package/lib/src/raw_types/debats.d.ts +380 -0
- package/lib/src/raw_types/debats.js +266 -0
- package/lib/src/raw_types/dosleg.d.ts +2954 -0
- package/lib/src/raw_types/dosleg.js +2005 -0
- package/lib/src/raw_types/questions.d.ts +699 -0
- package/lib/src/raw_types/questions.js +493 -0
- package/lib/src/raw_types/senat.d.ts +11372 -0
- package/lib/src/raw_types/senat.js +5 -0
- package/lib/src/raw_types/sens.d.ts +7843 -0
- package/lib/src/raw_types/sens.js +4691 -0
- package/lib/src/raw_types_schemats/ameli.d.ts +541 -0
- package/lib/src/raw_types_schemats/ameli.js +2 -0
- package/lib/src/raw_types_schemats/debats.d.ts +127 -0
- package/lib/src/raw_types_schemats/debats.js +2 -0
- package/lib/src/raw_types_schemats/dosleg.d.ts +977 -0
- package/lib/src/raw_types_schemats/dosleg.js +2 -0
- package/lib/src/raw_types_schemats/questions.d.ts +237 -0
- package/lib/src/raw_types_schemats/questions.js +2 -0
- package/lib/src/raw_types_schemats/sens.d.ts +2709 -0
- package/lib/src/raw_types_schemats/sens.js +2 -0
- package/lib/src/rich_types/agenda.d.ts +45 -0
- package/lib/src/rich_types/agenda.js +1 -0
- package/lib/src/rich_types/compte_rendu.d.ts +83 -0
- package/lib/src/rich_types/compte_rendu.js +1 -0
- package/lib/src/rich_types/dosleg.js +0 -7
- package/lib/src/rich_types/sessions.d.ts +6 -0
- package/lib/src/rich_types/sessions.js +19 -0
- package/lib/src/rich_types/texte.d.ts +72 -0
- package/lib/src/rich_types/texte.js +15 -0
- package/lib/src/scripts/convert_data.js +4 -5
- package/lib/src/scripts/retrieve_cr_commission.js +1 -1
- package/lib/src/scripts/retrieve_open_data.js +39 -0
- package/lib/src/scripts/retrieve_videos.js +1 -2
- package/lib/src/scripts/shared/incremental_import_sql.js +859 -859
- package/lib/src/scripts/shared/schema_version.js +84 -84
- package/lib/src/scripts/shared/staging_metadata_sql.js +214 -214
- package/lib/src/scripts/test_iter_load.d.ts +1 -0
- package/lib/src/scripts/test_iter_load.js +12 -0
- package/lib/src/scripts/validate_prefixed_tables.js +12 -12
- package/lib/src/sens.d.ts +104 -0
- package/lib/src/sens.js +1 -0
- package/lib/src/server/ameli.js +11 -13
- package/lib/src/server/conversion_textes.js +107 -107
- package/lib/src/server/debats.js +10 -15
- package/lib/src/server/documents.js +22 -25
- package/lib/src/server/dosleg.js +33 -44
- package/lib/src/server/questions.js +10 -11
- package/lib/src/server/scrutins.js +3 -7
- package/lib/src/server/sens.js +19 -36
- package/lib/src/types/agenda.d.ts +45 -0
- package/lib/src/types/agenda.js +1 -0
- package/lib/src/types/ameli.d.ts +1762 -0
- package/lib/src/types/ameli.js +1074 -0
- package/lib/src/types/compte_rendu.d.ts +83 -0
- package/lib/src/types/compte_rendu.js +1 -0
- package/lib/src/types/debats.d.ts +380 -0
- package/lib/src/types/debats.js +266 -0
- package/lib/src/types/dosleg.d.ts +2954 -0
- package/lib/src/types/dosleg.js +2005 -0
- package/lib/src/types/questions.d.ts +699 -0
- package/lib/src/types/questions.js +493 -0
- package/lib/src/types/sens.d.ts +7843 -0
- package/lib/src/types/sens.js +4691 -0
- package/lib/src/types/sessions.d.ts +6 -0
- package/lib/src/types/sessions.js +19 -0
- package/lib/src/types/texte.d.ts +72 -0
- package/lib/src/types/texte.js +15 -0
- package/lib/src/validators/config.d.ts +9 -0
- package/lib/src/validators/config.js +10 -0
- package/lib/src/videos/match.js +4 -4
- package/lib/strings.d.ts +1 -0
- package/lib/strings.js +18 -0
- package/lib/strings.mjs +18 -0
- package/lib/strings.ts +26 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/types/agenda.d.ts +44 -0
- package/lib/types/agenda.js +1 -0
- package/lib/types/ameli.d.ts +5 -0
- package/lib/types/ameli.js +1 -0
- package/lib/types/ameli.mjs +13 -0
- package/lib/types/ameli.ts +21 -0
- package/lib/types/compte_rendu.d.ts +83 -0
- package/lib/types/compte_rendu.js +1 -0
- package/lib/types/debats.d.ts +2 -0
- package/lib/types/debats.js +1 -0
- package/lib/types/debats.mjs +2 -0
- package/lib/types/debats.ts +6 -0
- package/lib/types/dosleg.d.ts +70 -0
- package/lib/types/dosleg.js +1 -0
- package/lib/types/dosleg.mjs +151 -0
- package/lib/types/dosleg.ts +284 -0
- package/lib/types/questions.d.ts +2 -0
- package/lib/types/questions.js +1 -0
- package/lib/types/questions.mjs +1 -0
- package/lib/types/questions.ts +3 -0
- package/lib/types/sens.d.ts +10 -0
- package/lib/types/sens.js +1 -0
- package/lib/types/sens.mjs +1 -0
- package/lib/types/sens.ts +12 -0
- package/lib/types/sessions.d.ts +5 -0
- package/lib/types/sessions.js +84 -0
- package/lib/types/sessions.mjs +43 -0
- package/lib/types/sessions.ts +42 -0
- package/lib/types/texte.d.ts +74 -0
- package/lib/types/texte.js +16 -0
- package/lib/types/texte.mjs +16 -0
- package/lib/types/texte.ts +76 -0
- package/lib/typings/windows-1252.d.js +2 -0
- package/lib/typings/windows-1252.d.mjs +2 -0
- package/lib/typings/windows-1252.d.ts +11 -0
- package/lib/utils/cr_spliting.d.ts +28 -0
- package/lib/utils/cr_spliting.js +265 -0
- package/lib/utils/date.d.ts +10 -0
- package/lib/utils/date.js +100 -0
- package/lib/utils/nvs-timecode.d.ts +7 -0
- package/lib/utils/nvs-timecode.js +79 -0
- package/lib/utils/reunion_grouping.d.ts +9 -0
- package/lib/utils/reunion_grouping.js +361 -0
- package/lib/utils/reunion_odj_building.d.ts +5 -0
- package/lib/utils/reunion_odj_building.js +154 -0
- package/lib/utils/reunion_parsing.d.ts +23 -0
- package/lib/utils/reunion_parsing.js +209 -0
- package/lib/utils/scoring.d.ts +14 -0
- package/lib/utils/scoring.js +147 -0
- package/lib/utils/string_cleaning.d.ts +7 -0
- package/lib/utils/string_cleaning.js +57 -0
- package/lib/validators/config.d.ts +9 -0
- package/lib/validators/config.js +10 -0
- package/lib/validators/config.mjs +54 -0
- package/lib/validators/config.ts +79 -0
- package/lib/validators/senat.d.ts +0 -0
- package/lib/validators/senat.js +28 -0
- package/lib/validators/senat.mjs +24 -0
- package/lib/validators/senat.ts +26 -0
- package/package.json +119 -117
- package/lib/src/other_types/collaborateurs.d.ts +0 -5
- package/lib/src/parsers/collaborateurs.d.ts +0 -44
- package/lib/src/parsers/collaborateurs.js +0 -157
- package/lib/src/scripts/retrieve_collaborateurs.js +0 -166
- package/lib/tests/collaborateurs.test.js +0 -115
- /package/lib/{src/other_types/collaborateurs.js → add-js-extensions-v2.d.ts} +0 -0
- /package/lib/{src/scripts/retrieve_collaborateurs.d.ts → add-js-extensions.d.ts} +0 -0
- /package/lib/{tests/collaborateurs.test.d.ts → scripts/convert_data.d.ts} +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import fs, { ensureDir } from "fs-extra";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import * as cheerio from "cheerio";
|
|
5
|
+
import { COMMISSION_FOLDER, DATA_ORIGINAL_FOLDER, DATA_TRANSFORMED_FOLDER } from "../loaders";
|
|
6
|
+
import { loadAgendaForDate, parseCommissionMetadataFromHtml, linkCRtoCommissionGroup } from "../utils/cr_spliting";
|
|
7
|
+
import { cleanTitle, extractDayH3Sections, parseCommissionCRSectionFromDom } from "../model/commission";
|
|
8
|
+
import commandLineArgs from "command-line-args";
|
|
9
|
+
import { commonOptions } from "./shared/cli_helpers";
|
|
10
|
+
import { sessionStartYearFromDate } from "../model/seance";
|
|
11
|
+
import { getSessionsFromStart } from "../types/sessions";
|
|
12
|
+
import { ensureAndClearDir, fetchWithRetry } from "./shared/util";
|
|
13
|
+
import { jaccard, jaccardTokenSim } from "../utils/scoring";
|
|
14
|
+
class CommissionCRDownloadError extends Error {
|
|
15
|
+
constructor(message, url) {
|
|
16
|
+
super(`An error occurred while retrieving Commission CR ${url}: ${message}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const optionsDefinitions = [
|
|
20
|
+
...commonOptions,
|
|
21
|
+
{ name: "concurrency", type: Number, defaultValue: 6, help: "Max parallel downloads" },
|
|
22
|
+
{ name: "politenessMs", type: Number, defaultValue: 150, help: "Delay per worker (ms)" },
|
|
23
|
+
{
|
|
24
|
+
help: "parse and convert comptes-rendus des débats into JSON",
|
|
25
|
+
name: "parseDebats",
|
|
26
|
+
type: Boolean,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
const options = commandLineArgs(optionsDefinitions);
|
|
30
|
+
const COMMISSION_HUBS = {
|
|
31
|
+
"Commission des affaires étrangères": [
|
|
32
|
+
"https://www.senat.fr/compte-rendu-commissions/affaires-etrangeres.html",
|
|
33
|
+
"https://www.senat.fr/compte-rendu-commissions/affaires-etrangeres_archives.html",
|
|
34
|
+
],
|
|
35
|
+
"Commission des affaires économiques": [
|
|
36
|
+
"https://www.senat.fr/compte-rendu-commissions/economie.html",
|
|
37
|
+
"https://www.senat.fr/compte-rendu-commissions/economie_archives.html",
|
|
38
|
+
],
|
|
39
|
+
"Commission de l'amenagement du territoire et du développement durable": [
|
|
40
|
+
"https://www.senat.fr/compte-rendu-commissions/developpement-durable.html",
|
|
41
|
+
"https://www.senat.fr/compte-rendu-commissions/developpement-durable_archives.html",
|
|
42
|
+
],
|
|
43
|
+
"Commission de la culture": [
|
|
44
|
+
"https://www.senat.fr/compte-rendu-commissions/culture.html",
|
|
45
|
+
"https://www.senat.fr/compte-rendu-commissions/culture_archives.html",
|
|
46
|
+
],
|
|
47
|
+
"Commission des finances": [
|
|
48
|
+
"https://www.senat.fr/compte-rendu-commissions/finances.html",
|
|
49
|
+
"https://www.senat.fr/compte-rendu-commissions/finances_archives.html",
|
|
50
|
+
],
|
|
51
|
+
"Commission des lois": [
|
|
52
|
+
"https://www.senat.fr/compte-rendu-commissions/lois.html",
|
|
53
|
+
"https://www.senat.fr/compte-rendu-commissions/lois_archives.html",
|
|
54
|
+
],
|
|
55
|
+
"Commission des affaires sociales": [
|
|
56
|
+
"https://www.senat.fr/compte-rendu-commissions/affaires-sociales.html",
|
|
57
|
+
"https://www.senat.fr/compte-rendu-commissions/affaires-sociales_archives.html",
|
|
58
|
+
],
|
|
59
|
+
"Commission des affaires européennes": [
|
|
60
|
+
"https://www.senat.fr/compte-rendu-commissions/affaires-europeennes.html",
|
|
61
|
+
"https://www.senat.fr/compte-rendu-commissions/affaires-europeennes_archives.html",
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
async function harvestWeeklyLinksFromHub(hubUrl) {
|
|
65
|
+
const res = await fetchWithRetry(hubUrl);
|
|
66
|
+
if (!res.ok)
|
|
67
|
+
return [];
|
|
68
|
+
const html = await res.text();
|
|
69
|
+
const $ = cheerio.load(html);
|
|
70
|
+
const out = [];
|
|
71
|
+
$("a[href]").each((_, a) => {
|
|
72
|
+
const href = ($(a).attr("href") || "").trim();
|
|
73
|
+
const m = href.match(/\/compte-rendu-commissions\/(\d{8})\/([a-z0-9\-]+)\.html$/i);
|
|
74
|
+
if (m) {
|
|
75
|
+
const url = href.startsWith("http") ? href : new URL(href, hubUrl).toString();
|
|
76
|
+
out.push(url);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return Array.from(new Set(out));
|
|
80
|
+
}
|
|
81
|
+
async function discoverCommissionWeeklyPages(fromSession) {
|
|
82
|
+
const results = [];
|
|
83
|
+
for (const [commissionKey, hubs] of Object.entries(COMMISSION_HUBS)) {
|
|
84
|
+
for (const hubUrl of hubs) {
|
|
85
|
+
try {
|
|
86
|
+
const links = await harvestWeeklyLinksFromHub(hubUrl);
|
|
87
|
+
for (const url of links) {
|
|
88
|
+
const m = url.match(/\/compte-rendu-commissions\/(\d{8})\/([a-z0-9\-]+)\.html$/i);
|
|
89
|
+
if (!m)
|
|
90
|
+
continue;
|
|
91
|
+
const yyyymmdd = m[1];
|
|
92
|
+
const year = Number(yyyymmdd.slice(0, 4));
|
|
93
|
+
const month = Number(yyyymmdd.slice(4, 6));
|
|
94
|
+
const session = month >= 10 ? year : year - 1;
|
|
95
|
+
if (session < fromSession)
|
|
96
|
+
continue;
|
|
97
|
+
results.push({ url, yyyymmdd, commissionKey });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
console.warn(`[COM-CR][hub-fail] ${hubUrl} → ${e?.message ?? e}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return results.sort((a, b) => a.yyyymmdd.localeCompare(b.yyyymmdd));
|
|
106
|
+
}
|
|
107
|
+
function toHourShort(hhmm) {
|
|
108
|
+
if (!hhmm)
|
|
109
|
+
return null;
|
|
110
|
+
const m = hhmm.match(/^(\d{2}):(\d{2})$/);
|
|
111
|
+
return m ? `${m[1]}${m[2]}` : null;
|
|
112
|
+
}
|
|
113
|
+
function timeToMinutes(hhmm) {
|
|
114
|
+
const [h, m] = hhmm.split(":").map((n) => parseInt(n, 10));
|
|
115
|
+
return (h || 0) * 60 + (m || 0);
|
|
116
|
+
}
|
|
117
|
+
async function tryDownload(url) {
|
|
118
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
119
|
+
if (res.status === 404)
|
|
120
|
+
return null;
|
|
121
|
+
if (!res.ok)
|
|
122
|
+
throw new CommissionCRDownloadError(String(res.status), url);
|
|
123
|
+
const ab = await res.arrayBuffer();
|
|
124
|
+
return Buffer.from(ab);
|
|
125
|
+
}
|
|
126
|
+
function normOrgane(s) {
|
|
127
|
+
return s
|
|
128
|
+
.toLowerCase()
|
|
129
|
+
.normalize("NFD")
|
|
130
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
131
|
+
.replace(/&/g, " et ")
|
|
132
|
+
.replace(/[^a-z0-9\s-]/g, " ")
|
|
133
|
+
.replace(/\s+/g, " ")
|
|
134
|
+
.trim();
|
|
135
|
+
}
|
|
136
|
+
function toTokens(s) {
|
|
137
|
+
return new Set(normOrgane(s)
|
|
138
|
+
.split(/\s+/)
|
|
139
|
+
.filter((t) => t.length >= 3 && !["commission", "des", "de", "du", "d", "la", "le", "les", "et"].includes(t)));
|
|
140
|
+
}
|
|
141
|
+
function reunionOrganeCandidates(h) {
|
|
142
|
+
const any = h;
|
|
143
|
+
const out = [any.organeSlug, any.organeKey, any.organe, h.titre].filter(Boolean);
|
|
144
|
+
return Array.from(new Set(out.map(normOrgane)));
|
|
145
|
+
}
|
|
146
|
+
function organeSimilarity(h, commissionKey) {
|
|
147
|
+
const keyTokens = toTokens(commissionKey.replace(/-/g, " "));
|
|
148
|
+
const cand = reunionOrganeCandidates(h).map(toTokens);
|
|
149
|
+
let best = 0;
|
|
150
|
+
for (const B of cand)
|
|
151
|
+
best = Math.max(best, jaccard(keyTokens, B));
|
|
152
|
+
return best; // 0..1
|
|
153
|
+
}
|
|
154
|
+
function timeProximityScore(h, openHHMM, maxDeltaMin) {
|
|
155
|
+
if (!openHHMM)
|
|
156
|
+
return 0;
|
|
157
|
+
const hhmm = (h.startTime ?? null);
|
|
158
|
+
if (!hhmm)
|
|
159
|
+
return 0;
|
|
160
|
+
const d = Math.abs(timeToMinutes(hhmm) - timeToMinutes(openHHMM));
|
|
161
|
+
if (d > maxDeltaMin)
|
|
162
|
+
return 0;
|
|
163
|
+
return 1 - d / maxDeltaMin; // 0..1 (1 = même heure)
|
|
164
|
+
}
|
|
165
|
+
function titleSimilarity(reunion, sectionTitle) {
|
|
166
|
+
const t = reunion.titre ?? "";
|
|
167
|
+
const o = reunion.objet ?? "";
|
|
168
|
+
if (!sectionTitle.trim())
|
|
169
|
+
return 0;
|
|
170
|
+
const sTit = jaccardTokenSim(t, sectionTitle);
|
|
171
|
+
const sObj = jaccardTokenSim(o, sectionTitle);
|
|
172
|
+
return Math.max(sTit, sObj);
|
|
173
|
+
}
|
|
174
|
+
async function retrieveCommissionCRs(options = {}) {
|
|
175
|
+
const dataDir = options["dataDir"];
|
|
176
|
+
const fromSession = Number(options["fromSession"]);
|
|
177
|
+
const concurrency = Number(options["concurrency"] ?? 6);
|
|
178
|
+
const politenessMs = Number(options["politenessMs"] ?? 150);
|
|
179
|
+
const commissionsRootDir = path.join(dataDir, COMMISSION_FOLDER);
|
|
180
|
+
const originalRoot = path.join(commissionsRootDir, DATA_ORIGINAL_FOLDER);
|
|
181
|
+
if (!options["keepDir"]) {
|
|
182
|
+
ensureAndClearDir(originalRoot);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
ensureDir(originalRoot);
|
|
186
|
+
}
|
|
187
|
+
const discovered = await discoverCommissionWeeklyPages(fromSession);
|
|
188
|
+
console.log(`[COM-CR][discover] ${discovered.length} links (>= session ${fromSession})`);
|
|
189
|
+
const jobs = discovered.map(({ url, yyyymmdd, commissionKey }) => {
|
|
190
|
+
const d = new Date(Number(yyyymmdd.slice(0, 4)), Number(yyyymmdd.slice(4, 6)) - 1, Number(yyyymmdd.slice(6, 8)));
|
|
191
|
+
const session = sessionStartYearFromDate(d);
|
|
192
|
+
const dir = path.join(originalRoot, String(session), commissionKey);
|
|
193
|
+
fs.ensureDirSync(dir);
|
|
194
|
+
const slug = url.replace(/^.*\/(\d{8})\/([^\/]+)\.html$/i, "$2");
|
|
195
|
+
const outPath = path.join(dir, `${yyyymmdd}.${slug}.html`);
|
|
196
|
+
return { url, outPath, yyyymmdd, commissionKey };
|
|
197
|
+
});
|
|
198
|
+
console.log(`[COM-CR] Downloading ${jobs.length} links → ${path.relative(process.cwd(), originalRoot)}`);
|
|
199
|
+
let completed = 0, saved = 0, skipped = 0, notFound = 0;
|
|
200
|
+
const workers = Array.from({ length: Math.max(1, concurrency) }, async () => {
|
|
201
|
+
while (true) {
|
|
202
|
+
const job = jobs.shift();
|
|
203
|
+
if (!job)
|
|
204
|
+
break;
|
|
205
|
+
const { url, outPath, yyyymmdd } = job;
|
|
206
|
+
try {
|
|
207
|
+
if (await fs.pathExists(outPath)) {
|
|
208
|
+
skipped++;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
const buf = await tryDownload(url);
|
|
212
|
+
if (!buf) {
|
|
213
|
+
notFound++;
|
|
214
|
+
console.warn(`[COM-CR][404] ${url} → week=${yyyymmdd}`);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
await fs.writeFile(outPath, buf);
|
|
218
|
+
saved++;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
console.error(`[COM-CR][err] ${url} → ${e?.message || e}`);
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
completed++;
|
|
227
|
+
if (politenessMs > 0)
|
|
228
|
+
await new Promise((r) => setTimeout(r, politenessMs));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
await Promise.all(workers);
|
|
233
|
+
console.log(`[COM-CR] done: saved=${saved} | skipped=${skipped} | 404=${notFound} | total=${completed}`);
|
|
234
|
+
const sessions = getSessionsFromStart(options["fromSession"]);
|
|
235
|
+
const comRoot = path.join(dataDir, COMMISSION_FOLDER);
|
|
236
|
+
const transformedRoot = path.join(comRoot, DATA_TRANSFORMED_FOLDER);
|
|
237
|
+
if (options["keepDir"])
|
|
238
|
+
ensureDir(transformedRoot);
|
|
239
|
+
else
|
|
240
|
+
ensureAndClearDir(transformedRoot);
|
|
241
|
+
for (const session of sessions) {
|
|
242
|
+
const originalSessionDir = path.join(originalRoot, String(session));
|
|
243
|
+
if (!(await fs.pathExists(originalSessionDir)))
|
|
244
|
+
continue;
|
|
245
|
+
const commissionDirs = (await fs.readdir(originalSessionDir, { withFileTypes: true }))
|
|
246
|
+
.filter((d) => d.isDirectory())
|
|
247
|
+
.map((d) => d.name); // ex: "affaires-etrangeres", "finances", etc.
|
|
248
|
+
for (const commissionKey of commissionDirs) {
|
|
249
|
+
const commissionDir = path.join(originalSessionDir, commissionKey);
|
|
250
|
+
const htmlFiles = (await fs.readdir(commissionDir)).filter((f) => /\.html?$/i.test(f)).sort();
|
|
251
|
+
let totalFiles = 0;
|
|
252
|
+
let linkedFiles = 0;
|
|
253
|
+
for (const f of htmlFiles) {
|
|
254
|
+
const htmlPath = path.join(commissionDir, f);
|
|
255
|
+
let meta;
|
|
256
|
+
let raw = "";
|
|
257
|
+
try {
|
|
258
|
+
raw = await fs.readFile(htmlPath, "utf8");
|
|
259
|
+
meta = parseCommissionMetadataFromHtml(raw, f);
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
console.warn(`[COM-CR][PRE][${session}] Cannot read/parse ${f}:`, e);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (!meta?.days?.length)
|
|
266
|
+
continue;
|
|
267
|
+
const $ = cheerio.load(raw, { xmlMode: false });
|
|
268
|
+
for (const day of meta.days) {
|
|
269
|
+
const yyyymmdd = day.date.replace(/-/g, "");
|
|
270
|
+
const dt = new Date(Number(day.date.slice(0, 4)), Number(day.date.slice(5, 7)) - 1, Number(day.date.slice(8, 10)));
|
|
271
|
+
const daySession = sessionStartYearFromDate(dt);
|
|
272
|
+
let hits = await loadAgendaForDate(dataDir, yyyymmdd, daySession);
|
|
273
|
+
console.log(`[COM-CR][TRANSFORM] ${f} → ${hits.length} agenda events on ${day.date} :`);
|
|
274
|
+
const sections = extractDayH3Sections($, day.date);
|
|
275
|
+
if (sections.length === 0) {
|
|
276
|
+
console.warn(`[COM-CR][TRANSFORM] no sections found for ${f} on ${day.date}, skipping.`);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const MAX_TIME_DELTA_MIN = 120;
|
|
280
|
+
const ORGANE_GATE = 0.55;
|
|
281
|
+
const TITLE_GATE = 0.2;
|
|
282
|
+
const W_ORG = 0.4;
|
|
283
|
+
const W_TIM = 0.4;
|
|
284
|
+
const W_TIT = 0.2;
|
|
285
|
+
for (let sIdx = 0; sIdx < sections.length; sIdx++) {
|
|
286
|
+
const sec = sections[sIdx];
|
|
287
|
+
let best = null;
|
|
288
|
+
let reason = "fallback-none";
|
|
289
|
+
if (hits.length) {
|
|
290
|
+
const scored = hits
|
|
291
|
+
.map((h) => {
|
|
292
|
+
const sOrg = organeSimilarity(h, commissionKey); // 0..1
|
|
293
|
+
const sTim = timeProximityScore(h, sec.time ?? day.openTime ?? null, MAX_TIME_DELTA_MIN); // 0..1
|
|
294
|
+
const sTit = titleSimilarity(h, sec.title); // 0..1
|
|
295
|
+
const total = W_ORG * sOrg + W_TIM * sTim + W_TIT * sTit;
|
|
296
|
+
return { h, sOrg, sTim, sTit, total };
|
|
297
|
+
})
|
|
298
|
+
.filter((x) => x.sOrg >= ORGANE_GATE && x.sTit >= TITLE_GATE)
|
|
299
|
+
.sort((a, b) => b.total - a.total);
|
|
300
|
+
if (scored[0]) {
|
|
301
|
+
best = scored[0].h;
|
|
302
|
+
reason =
|
|
303
|
+
scored[0].sTit >= Math.max(scored[0].sOrg, scored[0].sTim)
|
|
304
|
+
? "title"
|
|
305
|
+
: scored[0].sOrg >= scored[0].sTim
|
|
306
|
+
? "organe"
|
|
307
|
+
: "time";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const hourShort = toHourShort(day.openTime) ?? "NA";
|
|
311
|
+
const cr = parseCommissionCRSectionFromDom($, htmlPath, {
|
|
312
|
+
dateISO: day.date,
|
|
313
|
+
hourShort,
|
|
314
|
+
organe: commissionKey,
|
|
315
|
+
section: sec,
|
|
316
|
+
matched: best ?? undefined,
|
|
317
|
+
});
|
|
318
|
+
if (!cr) {
|
|
319
|
+
console.warn(`[COM-CR][TRANSFORM] parse failed for section#${sIdx} ${path.basename(htmlPath)} → ${best ? best.uid : "NO-GROUP"} (${commissionKey})`);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
const fileUid = cr.uid;
|
|
323
|
+
const transformedSessionDir = path.join(transformedRoot, String(daySession));
|
|
324
|
+
fs.ensureDirSync(transformedSessionDir);
|
|
325
|
+
const outPath = path.join(transformedSessionDir, `${fileUid}.json`);
|
|
326
|
+
await fs.writeJSON(outPath, cr, { spaces: 2 });
|
|
327
|
+
const titreGuess = cleanTitle(sections[sIdx].title) || "Commission du " + day.date;
|
|
328
|
+
const up = await linkCRtoCommissionGroup({
|
|
329
|
+
dataDir,
|
|
330
|
+
dateISO: day.date,
|
|
331
|
+
organeDetected: commissionKey,
|
|
332
|
+
hourShort,
|
|
333
|
+
crUid: fileUid,
|
|
334
|
+
titreGuess,
|
|
335
|
+
groupUid: best ? best.uid : undefined,
|
|
336
|
+
});
|
|
337
|
+
totalFiles++;
|
|
338
|
+
if (up.created || up.updated)
|
|
339
|
+
linkedFiles++;
|
|
340
|
+
else {
|
|
341
|
+
console.warn(`[COM-CR][AGENDA][WARN] CR ${fileUid} (section#${sIdx}) not linked (reason=${reason})`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (!options["silent"]) {
|
|
347
|
+
console.log(`[COM-CR][SESSION ${session}][${commissionKey}] Processed ${totalFiles} CR files, linked to agenda: ${linkedFiles}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async function main() {
|
|
353
|
+
const dataDir = options["dataDir"];
|
|
354
|
+
assert(dataDir, "Missing argument: data directory");
|
|
355
|
+
console.time("CRI processing time");
|
|
356
|
+
await retrieveCommissionCRs(options);
|
|
357
|
+
console.timeEnd("CRI processing time");
|
|
358
|
+
}
|
|
359
|
+
main()
|
|
360
|
+
.then(() => process.exit(0))
|
|
361
|
+
.catch((error) => {
|
|
362
|
+
console.error(error);
|
|
363
|
+
process.exit(1);
|
|
364
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Needs to be ran after retrieve_agenda.ts script !
|
|
3
|
+
* - downloads the ZIP of comptes-rendus des débats (CRI) from data.senat.fr
|
|
4
|
+
* - extracts XML files, distributes them by session/year
|
|
5
|
+
*/
|
|
6
|
+
export declare function retrieveCriXmlDump(dataDir: string, options?: Record<string, any>): Promise<void>;
|