twpipeline 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +21 -0
- data/README.md +236 -0
- data/bin/twpipeline +15 -0
- data/data/hplt/README.md +26 -0
- data/data/hplt/taiwan_domains.candidates.txt +300 -0
- data/data/hplt/taiwan_domains.txt +0 -0
- data/lib/twpipeline/bench.rb +55 -0
- data/lib/twpipeline/cli.rb +144 -0
- data/lib/twpipeline/frequency.rb +48 -0
- data/lib/twpipeline/jsonl.rb +30 -0
- data/lib/twpipeline/parallel.rb +92 -0
- data/lib/twpipeline/resources.rb +64 -0
- data/lib/twpipeline/rusage.rb +41 -0
- data/lib/twpipeline/segmenter.rb +134 -0
- data/lib/twpipeline/sorting.rb +51 -0
- data/lib/twpipeline/sources/hplt.rb +112 -0
- data/lib/twpipeline/stage.rb +71 -0
- data/lib/twpipeline/stages/count.rb +89 -0
- data/lib/twpipeline/stages/dedup.rb +46 -0
- data/lib/twpipeline/stages/evidence.rb +80 -0
- data/lib/twpipeline/stages/ingest.rb +66 -0
- data/lib/twpipeline/stages/lexicon.rb +16 -0
- data/lib/twpipeline/stages/normalize.rb +15 -0
- data/lib/twpipeline/stages/script.rb +14 -0
- data/lib/twpipeline/stages/segment.rb +50 -0
- data/lib/twpipeline/stages/tokenize.rb +42 -0
- data/lib/twpipeline/version.rb +5 -0
- data/lib/twpipeline.rb +59 -0
- data/sig/twpipeline.rbs +228 -0
- metadata +149 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 79331304e3921fe1d8dcbd3b47154688dfcbea28315e5e4f90a4f8c8cde3f2be
|
|
4
|
+
data.tar.gz: f4d2e3acc42108b52edce6f74a98683f1fb27aeeaabee6a8adfb48a3a52fb0fd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bc121f3c3ec181db6939aaf78b758d17c50d3882eb1150a877988cd24576596d7387716fc358b0946a2d1a57e2817d4141ccbc080f915f274de4ee4daf2232a4
|
|
7
|
+
data.tar.gz: e59bfc90d8989ca058e222f0d1f3bbcfb391644809bb7fadbb0bd867b438ba675098d057b43fdfa9cc98370c598596d7b97527e91891be03694a525d5ddabbe2
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — 2026-08-03
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
- Nine JSONL stages from raw crawl to n-gram tables: source gating (`01_ingest`),
|
|
8
|
+
MOE punctuation normalization (`02_normalize`), sentence segmentation
|
|
9
|
+
(`03_segment`), character-inventory and lexical-origin filtering (`04_script`,
|
|
10
|
+
`05_lexicon`, both delegated to twfilter 0.1.0), block-level evidence judgment
|
|
11
|
+
(`06_evidence`), exact type deduplication with boilerplate flagging
|
|
12
|
+
(`07_dedup`), Viterbi word segmentation (`08_tokenize`) and external-sort
|
|
13
|
+
n-gram counting with a publication floor and `--once-per host` semantics
|
|
14
|
+
(`09_count`)
|
|
15
|
+
- One record contract: stages add fields and typed findings, never remove them;
|
|
16
|
+
`--drop` is the only thing that discards a record
|
|
17
|
+
- Resource envelope: `--cores` / `--memory` with `TWP_CORES` / `TWP_MEMORY` and
|
|
18
|
+
autodetection; byte-bounded chunking; counting bounded by `sort -S`, not by a
|
|
19
|
+
hash table
|
|
20
|
+
- Per-stage measurement into `work/benchmarks.jsonl` via `getrusage(2)`, rendered
|
|
21
|
+
to BENCHMARKS.md
|
|
22
|
+
- HPLT source adapter with the `.tw` ∪ `html_lang` gate, hard regional TLD
|
|
23
|
+
exclusion and an allowlist hook (shipped empty, with 300 documented candidates)
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Den Patin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# twpipeline
|
|
2
|
+
|
|
3
|
+
Corpus construction for Taiwan Mandarin. Nine stages, one JSONL record contract,
|
|
4
|
+
`stdin` → `stdout`. Every stage is independently runnable and independently
|
|
5
|
+
verifiable. No record is ever discarded silently: rejection sets `ok: false` and
|
|
6
|
+
appends a typed finding; `--drop` is what removes it.
|
|
7
|
+
|
|
8
|
+
Linguistic decisions live in [twfilter](https://github.com/taiwan-corpora/twfilter); this repository is the
|
|
9
|
+
execution layer — sources, parallelism, external sorting, measurement.
|
|
10
|
+
|
|
11
|
+
For corpus linguists and dataset engineers who need Taiwan Mandarin
|
|
12
|
+
(`cmn-Hant-TW`) material with verifiable provenance. In: a web crawl or any
|
|
13
|
+
JSONL of documents. Out: filtered sentence types, word segmentation, n-gram and
|
|
14
|
+
frequency tables with per-host counting and a publication floor — the process
|
|
15
|
+
behind [twngrams](https://huggingface.co/datasets/taiwan-corpora/twngrams).
|
|
16
|
+
Single machine, no cluster: the full HPLT Taiwan slice (2.0 M documents)
|
|
17
|
+
builds in under two hours on a laptop.
|
|
18
|
+
|
|
19
|
+
## Pipeline
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
flowchart TD
|
|
23
|
+
subgraph acquire["acquisition"]
|
|
24
|
+
S1["<b>01_ingest</b> — source adapter<br/>HPLT gate: <code>.tw</code> ∪ <code>html_lang ∈ zh-TW</code> ∪ allowlist<br/>hard exclusion: <code>.cn .hk .mo .sg .my</code><br/><code>--host-cap N</code> bounds per-host concentration"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph shape["orthographic normalization — mandatory for publishable text"]
|
|
28
|
+
S2["<b>02_normalize</b> — MOE 《重訂標點符號手冊》<br/>“ ” → 「 」 · → ‧ … → …… — → ──<br/>fullwidth Latin → ASCII, invisibles stripped"]
|
|
29
|
+
S3["<b>03_segment</b> — sentence boundaries<br/>terminators <code>[。!?…;]+[」』)》〉]*</code>, <code>、</code> is not a boundary<br/>shape: han ∈ [6, 60], han ratio ≥ 0.65"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
subgraph origin["origin filter — mandatory"]
|
|
33
|
+
S4["<b>04_script</b> — character inventory<br/>MOE 常用 4 808 / 次常用 6 343 / 罕用 18 356 + 12 exceptions<br/>OpenCC STCharacters ∖ TSCharacters round-trip<br/>converted orthography 裏着衞爲説麽…"]
|
|
34
|
+
S5["<b>05_lexicon</b> — lexical origin<br/>149 hard + 38 soft mainland pairs, corpus-verified<br/>written Cantonese, Hong Kong and Singapore forms, foreign-topic tag, erhua two-window rule<br/>literary-Chinese density > 0.05 with ≥ 2 hits and ≥ 8 han"]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
subgraph corpus["corpus hygiene — optional, source-dependent"]
|
|
38
|
+
S6["<b>06_evidence</b> — block judgment<br/>window 300 sentences; reject block if any member fails<br/>require ≥ 1.0 Taiwan evidence per 100 sentences"]
|
|
39
|
+
S7["<b>07_dedup</b> — exact type dedup<br/>SHA-256 → 62-bit fingerprint<br/>flags types occurring on ≥ 5 distinct hosts as boilerplate"]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
subgraph measure["measurement"]
|
|
43
|
+
S8["<b>08_tokenize</b> — Viterbi over a unigram cost model<br/>EM re-estimation, max word length 8"]
|
|
44
|
+
S9["<b>09_count</b> — n-gram counting by external sort<br/><code>sort -S … --parallel …</code> ∘ <code>uniq -c</code><br/>frequency floor for publication (Google Ngram rule)"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7 --> S8 --> S9
|
|
48
|
+
S9 --> OUT["frequency, dispersion (DP),<br/>collocations (G², logDice)"]
|
|
49
|
+
|
|
50
|
+
classDef must fill:#0b3d2e,stroke:#0b3d2e,color:#fff
|
|
51
|
+
classDef may fill:#3d3a0b,stroke:#3d3a0b,color:#fff
|
|
52
|
+
class S2,S3,S4,S5 must
|
|
53
|
+
class S6,S7 may
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Green stages are mandatory for any Taiwan Mandarin corpus. Amber stages depend
|
|
57
|
+
on the source: block judgment assumes documents are topically coherent, type
|
|
58
|
+
deduplication assumes the source is web-scale.
|
|
59
|
+
|
|
60
|
+
## Record contract
|
|
61
|
+
|
|
62
|
+
One JSON object per line. Stages add fields; they never remove them.
|
|
63
|
+
|
|
64
|
+
| field | stage | meaning |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| `id`, `source` | 01 | stable identity |
|
|
67
|
+
| `url`, `host`, `gate` | 01 | provenance and the gate that admitted it |
|
|
68
|
+
| `register`, `doc_score` | 01 | HPLT web-register argmax, mean segment score |
|
|
69
|
+
| `text` | 01–02 | document text, then punctuation-normalized |
|
|
70
|
+
| `doc`, `index`, `han` | 03 | parent document, ordinal, han count |
|
|
71
|
+
| `tier` | 04 | 0 常用, 1 次常用, 2 罕用 |
|
|
72
|
+
| `evidence` | 06 | Taiwan evidence count over the block |
|
|
73
|
+
| `tokens` | 08 | word segmentation |
|
|
74
|
+
| `ok`, `findings[]` | all | verdict and every reason for it |
|
|
75
|
+
|
|
76
|
+
A finding is `{check, code, severity, detail}` with `severity ∈ {reject, mark}`.
|
|
77
|
+
|
|
78
|
+
## Install
|
|
79
|
+
|
|
80
|
+
Ruby ≥ 3.4. The only runtime dependency is
|
|
81
|
+
[twfilter](https://rubygems.org/gems/twfilter), pulled from RubyGems:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bundle install
|
|
85
|
+
bin/twpipeline stages
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
External sorting uses `gsort` (GNU coreutils) when installed and the system
|
|
89
|
+
`sort` otherwise; both understand `-S` and `--parallel`. Override with
|
|
90
|
+
`TWP_SORT`.
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
twpipeline run --source hplt --input cmn_Hant/7_1.jsonl.zst --cores 16 --memory 8G
|
|
96
|
+
cat raw.jsonl | twpipeline 04_script | twpipeline 05_lexicon > checked.jsonl
|
|
97
|
+
echo '這個政策有沒有經過評估?' | twpipeline check
|
|
98
|
+
twpipeline run --from 03_segment --to 07_dedup --drop --policy publishable
|
|
99
|
+
twpipeline resources
|
|
100
|
+
twpipeline stages
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`--policy corpus` (default) keeps everything Taiwan-attested. `--policy
|
|
104
|
+
publishable` restricts to MOE 常用 4 808, rejects soft mainland markers, and
|
|
105
|
+
enforces the strict MOE punctuation inventory — the boundary of what may reach a
|
|
106
|
+
commercial learner product.
|
|
107
|
+
|
|
108
|
+
## Resources
|
|
109
|
+
|
|
110
|
+
Cores and memory are read from `--cores` / `--memory`, then `TWP_CORES` /
|
|
111
|
+
`TWP_MEMORY`, then autodetection (all cores, half of physical memory).
|
|
112
|
+
`--ask` prompts interactively.
|
|
113
|
+
|
|
114
|
+
Streaming stages fork `cores` workers per chunk; chunk size is bounded by bytes
|
|
115
|
+
(`memory / 32`, capped at 1 GiB, overridable with `TWP_CHUNK_BYTES`), not by
|
|
116
|
+
line count, so a source of 12 KiB documents and a source of 40-byte sentences
|
|
117
|
+
both stay within the same envelope. Counting never holds a hash table: keys go
|
|
118
|
+
through `sort -S <memory> --parallel <cores>`, so peak resident size is set by
|
|
119
|
+
the flag, not by the corpus.
|
|
120
|
+
|
|
121
|
+
Every stage writes one line to `work/benchmarks.jsonl` — wall time, CPU seconds,
|
|
122
|
+
mean cores used, peak RSS, and the stage's own counters. The work directory
|
|
123
|
+
defaults to `../work` beside the checkout; override with `TWP_WORK`. See
|
|
124
|
+
[BENCHMARKS.md](BENCHMARKS.md).
|
|
125
|
+
|
|
126
|
+
## Findings
|
|
127
|
+
|
|
128
|
+
Measured on HPLT 3.0 `cmn_Hant`, quality bins 7–10 (4 116 754 documents). The
|
|
129
|
+
admission gate kept 2 001 161 documents: 541 467 by `.tw` host, 1 459 694 by
|
|
130
|
+
`html_lang`. All of them were carried through stages 02–07 in 28 minutes
|
|
131
|
+
(twfilter 0.1.0, the published tables):
|
|
132
|
+
|
|
133
|
+
| stage | in | out | lost |
|
|
134
|
+
| --- | ---: | ---: | ---: |
|
|
135
|
+
| 03_segment | 2 001 161 docs | 37 772 352 sentences | — |
|
|
136
|
+
| 04_script | 37 772 352 | 37 122 017 | 1.72 % |
|
|
137
|
+
| 05_lexicon | 37 122 017 | 36 455 533 | 1.80 % |
|
|
138
|
+
| 06_evidence | 36 455 533 | 29 089 952 | 20.20 % |
|
|
139
|
+
| 07_dedup | 29 089 952 | **12 339 761 types** | **57.58 %** |
|
|
140
|
+
|
|
141
|
+
Three results worth stating plainly.
|
|
142
|
+
|
|
143
|
+
**Deduplication dominates every linguistic filter.** More than half of all
|
|
144
|
+
segmented sentences are exact repeats of another sentence — an order of magnitude
|
|
145
|
+
more than the three origin filters remove between them. HPLT deduplicates
|
|
146
|
+
documents, not sentences, and the Taiwanese long tail is largely search-optimized
|
|
147
|
+
loan and hotel templates. Without stage 07 an n-gram table over this material
|
|
148
|
+
measures template frequency, not language.
|
|
149
|
+
|
|
150
|
+
A stratified 279 198-document sample drawn from the head of each bin file put
|
|
151
|
+
duplication at 71.0 % and evidence loss at 5.6 %; the true figures are 57.6 % and
|
|
152
|
+
20.2 %. Documents cluster by host inside a bin file, so a head sample overstates
|
|
153
|
+
local repetition and understates topical variety. Sample to find the shape of a
|
|
154
|
+
problem; measure on everything before publishing a number.
|
|
155
|
+
|
|
156
|
+
**The two gates differ, but less than a head sample suggests.** Unique
|
|
157
|
+
Taiwan-attested types produced per admitted document:
|
|
158
|
+
|
|
159
|
+
| gate | documents | unique types | types per document |
|
|
160
|
+
| --- | ---: | ---: | ---: |
|
|
161
|
+
| `.tw` host | 541 467 | 4 230 061 | **7.81** |
|
|
162
|
+
| `html_lang` on a generic TLD | 1 459 694 | 8 109 700 | **5.56** |
|
|
163
|
+
|
|
164
|
+
A 1.41× gradient, not the 2.4× the sample showed. The `html_lang` gate supplies
|
|
165
|
+
65.7 % of the final corpus at about two thirds of the per-document yield — worth keeping,
|
|
166
|
+
not worth trusting blindly. The `gate` field is preserved on every record, so
|
|
167
|
+
restricting to `.tw` afterwards costs nothing and remains available as a
|
|
168
|
+
higher-precision subset.
|
|
169
|
+
|
|
170
|
+
**Boilerplate is sub-sentential, so no amount of sentence deduplication removes
|
|
171
|
+
it.** The phrase 提供相關細節的諮詢服務 occurs 263 210 times in the deduplicated
|
|
172
|
+
corpus, inside 263 210 *distinct* sentences, across 222 900 documents — but only
|
|
173
|
+
**1 948 hosts**. Sentence dedup cannot see it (every string differs), per-document
|
|
174
|
+
counting cannot see it (every document differs), and `--host-cap` cannot see it
|
|
175
|
+
(the network spans 11 691 throwaway domains, none of them large). 貸款 comes out
|
|
176
|
+
as the 7th most frequent word in Taiwan Mandarin, which is false.
|
|
177
|
+
|
|
178
|
+
The fix is to change what a count means. `--once-per host` counts each n-gram
|
|
179
|
+
once per host instead of once per occurrence, so a frequency list measures *how
|
|
180
|
+
many independent sites use a phrase* rather than *how many times a template was
|
|
181
|
+
published*. On the phrase above that is a 135-fold correction. For web-derived
|
|
182
|
+
frequency this is the correct semantics regardless of spam: a generated page is
|
|
183
|
+
not an independent act of authorship.
|
|
184
|
+
|
|
185
|
+
Occurrence counting remains the default, because for an edited corpus — statutes,
|
|
186
|
+
news, dictionaries — repetition is evidence rather than noise.
|
|
187
|
+
|
|
188
|
+
Measured effect on the full corpus. 貸款 falls from rank 7 to rank **1 299**;
|
|
189
|
+
借錢, 包養, 二胎 and 信貸 drop below the 40-host floor and disappear entirely. The
|
|
190
|
+
1-gram list becomes 的 是 有 一 在 了 我 會 也 要 不 個, the 4-gram list 越來越多,
|
|
191
|
+
這是一個, 最重要的是, 更重要的是. In the run where both semantics were built,
|
|
192
|
+
published rows fell by 7 % at order 1 and 28 % at order 4.
|
|
193
|
+
|
|
194
|
+
**Known residual.** Eleven of the top hundred 4-grams are fragments of one
|
|
195
|
+
string: `讓人們盡情分享,將這個世界變得更開闊,聯繫更緊密` — the Chinese Facebook
|
|
196
|
+
tagline, carried by the social-plugin embed on roughly 3 900 hosts, about once
|
|
197
|
+
per host, so per-host counting cannot suppress it: those hosts really are
|
|
198
|
+
independent. This is third-party embedded interface text, a
|
|
199
|
+
different problem from spam, and it needs either HTML-level boilerplate stripping
|
|
200
|
+
upstream or an explicit stoplist. It contaminates 0.03 % of sentences but a
|
|
201
|
+
visible share of the 4-gram head.
|
|
202
|
+
|
|
203
|
+
The surviving corpus spans 149 022 hosts: top 10 hold 8.8 % of sentences, top 100
|
|
204
|
+
20.8 %, top 1000 46.3 %, top 10 000 82.8 %. Diffuse enough to be a corpus rather
|
|
205
|
+
than a scrape of a few sites, but the single largest host is `chinatimes.com` at
|
|
206
|
+
411 005 sentences — 3.3 % of everything, one newspaper. Concentration of one
|
|
207
|
+
rightsholder's expression, not total size, is what has drawn takedowns against
|
|
208
|
+
comparable datasets; cap per host before publishing anything that carries text.
|
|
209
|
+
|
|
210
|
+
## Layout
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
lib/twpipeline/
|
|
214
|
+
resources.rb cores and memory resolution
|
|
215
|
+
parallel.rb fork-based map, byte-bounded streaming
|
|
216
|
+
sorting.rb external sort, tally with a frequency floor
|
|
217
|
+
jsonl.rb record contract
|
|
218
|
+
bench.rb measurement, appended to work/benchmarks.jsonl
|
|
219
|
+
rusage.rb getrusage(2) via Fiddle
|
|
220
|
+
segmenter.rb Viterbi, EM re-estimation
|
|
221
|
+
frequency.rb deviation of proportions
|
|
222
|
+
stage.rb Stage, MapStage, registry
|
|
223
|
+
stages/ the nine stages
|
|
224
|
+
sources/ source adapters
|
|
225
|
+
tools/
|
|
226
|
+
regression.rb twfilter against every reference corpus
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Tests
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
bundle exec rake
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
RSpec suite plus RBS signature validation. Fixtures carry no corpus material;
|
|
236
|
+
the suite needs no data and no credentials.
|
data/bin/twpipeline
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
lib = File.expand_path("../lib", __dir__)
|
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
require "twpipeline"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
$LOAD_PATH.unshift(File.expand_path("../../twfilter/lib", __dir__))
|
|
11
|
+
require "twpipeline"
|
|
12
|
+
end
|
|
13
|
+
require "twpipeline/cli"
|
|
14
|
+
|
|
15
|
+
exit(TWPipeline::CLI.call(ARGV))
|
data/data/hplt/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# HPLT gate data
|
|
2
|
+
|
|
3
|
+
`taiwan_domains.txt` — the curated allowlist read by `01_ingest --allowlist`.
|
|
4
|
+
**Empty by default, and that is deliberate.**
|
|
5
|
+
|
|
6
|
+
`taiwan_domains.candidates.txt` — 300 hosts derived automatically from the
|
|
7
|
+
1 927 814 documents that failed both the `.tw` and the `html_lang` gates in HPLT
|
|
8
|
+
3.0 `cmn_Hant` bins 7–10. A host qualified on: ≥ 5 documents sampled, zero
|
|
9
|
+
origin-filter rejections, and ≥ 1.0 Taiwan evidence per 100 han characters.
|
|
10
|
+
|
|
11
|
+
The list is published as *candidates*, not as an allowlist, because its
|
|
12
|
+
precision is poor for the intended purpose. Ranked by evidence density, the top
|
|
13
|
+
of the list is `downloadcenter.intel.com`, `powerapps.microsoft.com`,
|
|
14
|
+
`developer.microsoft.com`, `dvdvideosoft.com`, `veed.io` — localized zh-TW
|
|
15
|
+
product pages. They pass every origin test because localization vendors use
|
|
16
|
+
correct Taiwanese IT vocabulary, but they are `production: translated`, not
|
|
17
|
+
native Taiwan Mandarin. Admitting them would reintroduce exactly the
|
|
18
|
+
translationese the provenance axes exist to exclude.
|
|
19
|
+
|
|
20
|
+
The 300 hosts would have added 2 812 of 859 049 sampled documents — 0.3 % more
|
|
21
|
+
volume for a measurable loss of precision. Curate by hand from the candidates
|
|
22
|
+
file, or leave the allowlist empty.
|
|
23
|
+
|
|
24
|
+
`tools/hplt_allowlist.rb` writes the full evidence table for every host
|
|
25
|
+
examined — documents, han characters, evidence per 100 han, rejection rate — to
|
|
26
|
+
`work/hplt/allowlist_report.tsv`.
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
173ng.com
|
|
2
|
+
1989wolfe.com
|
|
3
|
+
3dayseo.com
|
|
4
|
+
5xruby.com
|
|
5
|
+
9jgirl.com
|
|
6
|
+
accessories.ap.dell.com
|
|
7
|
+
adai69.blogspot.com
|
|
8
|
+
adobe.com
|
|
9
|
+
advertise.bingads.microsoft.com
|
|
10
|
+
aiot.innodisk.com
|
|
11
|
+
albertinformation.blogspot.com
|
|
12
|
+
amedeephotography.com
|
|
13
|
+
ancad.com
|
|
14
|
+
android.lisisoft.com
|
|
15
|
+
angela700422.pixnet.net
|
|
16
|
+
animebase.org
|
|
17
|
+
applewoods.org
|
|
18
|
+
aquia.tian.yam.com
|
|
19
|
+
arielku.tian.yam.com
|
|
20
|
+
artchen.dev
|
|
21
|
+
arubanetworks.com
|
|
22
|
+
asusfoundation.org
|
|
23
|
+
avast.com
|
|
24
|
+
bakesmith.taipei
|
|
25
|
+
barbachacha.com
|
|
26
|
+
baristatotw.blogspot.ca
|
|
27
|
+
beautyfashion-tw.com
|
|
28
|
+
beckysfashionlifestyle.com
|
|
29
|
+
best007.org
|
|
30
|
+
blog.adahsu.net
|
|
31
|
+
blog.alexw.net
|
|
32
|
+
blog.asuscloud.com
|
|
33
|
+
blog.balduran.cc
|
|
34
|
+
blog.cashwu.com
|
|
35
|
+
blog.changyy.org
|
|
36
|
+
blog.gslin.org
|
|
37
|
+
blog.jln.co
|
|
38
|
+
blog.jw910731.me
|
|
39
|
+
blog.miniasp.com
|
|
40
|
+
blog.monkeypotion.net
|
|
41
|
+
blog.poychang.net
|
|
42
|
+
blog.roroiii.com
|
|
43
|
+
blog.schokomi.com
|
|
44
|
+
blog.steveyi.net
|
|
45
|
+
blog.tedshd.io
|
|
46
|
+
blog.ueplay.com
|
|
47
|
+
blog.wabow.com
|
|
48
|
+
blog.wing0826.com
|
|
49
|
+
blog.yilang.org
|
|
50
|
+
bonwawa.blogspot.com
|
|
51
|
+
boringfreeware.blogspot.com
|
|
52
|
+
bouken.space
|
|
53
|
+
bt.cream123.com
|
|
54
|
+
buy.hpe.com
|
|
55
|
+
cadch.com
|
|
56
|
+
car.u-3c.com
|
|
57
|
+
casestudies.engenius.ai
|
|
58
|
+
cchsu.com
|
|
59
|
+
ccskin.com
|
|
60
|
+
changeanddiffusion.blogspot.com
|
|
61
|
+
cherstravel.com
|
|
62
|
+
chia0302.tian.yam.com
|
|
63
|
+
chinese.hu-hiu.xyz
|
|
64
|
+
chnlnkuo.blogspot.com
|
|
65
|
+
cloud-say.com
|
|
66
|
+
cognex.com
|
|
67
|
+
community.oppo.com
|
|
68
|
+
cool007.org
|
|
69
|
+
cyberformula.tian.yam.com
|
|
70
|
+
ddselectivefashion.com
|
|
71
|
+
delltechnologies.com
|
|
72
|
+
desa713.tian.yam.com
|
|
73
|
+
developer.microsoft.com
|
|
74
|
+
developers.facebook.com
|
|
75
|
+
diazue65.tian.yam.com
|
|
76
|
+
digital.ni.com
|
|
77
|
+
dinewithkirsty.com
|
|
78
|
+
divakalife.blogspot.com
|
|
79
|
+
docs.adobe.com
|
|
80
|
+
docs.blackberry.com
|
|
81
|
+
docs.plesk.com
|
|
82
|
+
docs.vmware.com
|
|
83
|
+
dokuroko.blog128.fc2.com
|
|
84
|
+
donation-networks.savedogs.org
|
|
85
|
+
downloadcenter.intel.com
|
|
86
|
+
dualsnake.tian.yam.com
|
|
87
|
+
duomaxwellr.blogspot.com
|
|
88
|
+
dvdvideosoft.com
|
|
89
|
+
easy.twmoneyloan.com
|
|
90
|
+
easyloan.taipei
|
|
91
|
+
enspyre.com
|
|
92
|
+
ericsk.org
|
|
93
|
+
estinet.com
|
|
94
|
+
event.asus.com
|
|
95
|
+
experience.dropbox.com
|
|
96
|
+
f4mglendo.tian.yam.com
|
|
97
|
+
fenixhsu.medium.com
|
|
98
|
+
fitnfun.biz
|
|
99
|
+
fortinet.com
|
|
100
|
+
forum.macuknow.com
|
|
101
|
+
fred-zone.blogspot.com
|
|
102
|
+
freedom.support.tm
|
|
103
|
+
fullstackladder.dev
|
|
104
|
+
furnacedigital.blogspot.com
|
|
105
|
+
gemstw.com
|
|
106
|
+
girlstalk.cc
|
|
107
|
+
go-traveler.com
|
|
108
|
+
go-tribe-ycc.blogspot.com
|
|
109
|
+
gomrcuriosity.com
|
|
110
|
+
goodmommom.net
|
|
111
|
+
grayliao.blogspot.com
|
|
112
|
+
harry811016.medium.com
|
|
113
|
+
help.mega.io
|
|
114
|
+
help.ptc.com
|
|
115
|
+
help.tableau.com
|
|
116
|
+
helpx.adobe.com
|
|
117
|
+
hitcon.org
|
|
118
|
+
hlisfab2015.blogspot.com
|
|
119
|
+
home.allproducts.com
|
|
120
|
+
hotzsoft.com
|
|
121
|
+
house-expert.com
|
|
122
|
+
how-to-make-money12.blogspot.com
|
|
123
|
+
huidu.io
|
|
124
|
+
hungryowl.typepad.com
|
|
125
|
+
hyperrate.com
|
|
126
|
+
ifans.pixnet.net
|
|
127
|
+
iiot.apacer.com
|
|
128
|
+
imsean.pixnet.net
|
|
129
|
+
indianic.com
|
|
130
|
+
infinitiessoft.com
|
|
131
|
+
ipoe.cc
|
|
132
|
+
jaceju.net
|
|
133
|
+
jerolin.tian.yam.com
|
|
134
|
+
jingshouse.blogspot.com
|
|
135
|
+
jjdtw.com
|
|
136
|
+
julianshen.blogspot.com
|
|
137
|
+
june-yu.com
|
|
138
|
+
juniper.net
|
|
139
|
+
kaiching.org
|
|
140
|
+
key.chtouch.com
|
|
141
|
+
khm-film.blogspot.com
|
|
142
|
+
kirkchen.logdown.com
|
|
143
|
+
kskb.eu.org
|
|
144
|
+
ktrees.com
|
|
145
|
+
labviewpro.net
|
|
146
|
+
land.gov.taipei
|
|
147
|
+
larrynote.com
|
|
148
|
+
larrynung.github.io
|
|
149
|
+
lbrwed.com
|
|
150
|
+
leasonellis.com
|
|
151
|
+
leonvhi.tian.yam.com
|
|
152
|
+
leoyeh-me.gitbook.io
|
|
153
|
+
letsgogonz.blogspot.co.nz
|
|
154
|
+
librarythings.info
|
|
155
|
+
lifewth.com
|
|
156
|
+
linda.sopili.net
|
|
157
|
+
line8.me
|
|
158
|
+
linux.vbird.org
|
|
159
|
+
logitechclub.com
|
|
160
|
+
lookerideas.net
|
|
161
|
+
luannukm1989.tian.yam.com
|
|
162
|
+
m.california-companies.com
|
|
163
|
+
magiclen.org
|
|
164
|
+
mahjong.caca888.net
|
|
165
|
+
mantoh247.tian.yam.com
|
|
166
|
+
marleen741115.tian.yam.com
|
|
167
|
+
mcafee.com
|
|
168
|
+
meritlilin.com
|
|
169
|
+
microsoftstore.com
|
|
170
|
+
midnightcoder.blogspot.com
|
|
171
|
+
mit-machining.com
|
|
172
|
+
mlytics.com
|
|
173
|
+
mobileapps.frederickwebb.com
|
|
174
|
+
moeimo2016.blogspot.com
|
|
175
|
+
moonpoet.com
|
|
176
|
+
morrisa41.tian.yam.com
|
|
177
|
+
movavi.com
|
|
178
|
+
mrs-mo.com
|
|
179
|
+
msdn.microsoft.com
|
|
180
|
+
museumms.blogspot.com
|
|
181
|
+
musewp.pro
|
|
182
|
+
mysabeauty.com
|
|
183
|
+
nctusdk.blogspot.com
|
|
184
|
+
netapp.com
|
|
185
|
+
nineblog.tian.yam.com
|
|
186
|
+
normansem.com
|
|
187
|
+
note.charlestw.com
|
|
188
|
+
novell.com
|
|
189
|
+
nubaby.cc
|
|
190
|
+
origin2.logitech.com
|
|
191
|
+
ouch1978.github.io
|
|
192
|
+
oursong.com
|
|
193
|
+
panypanla.blogspot.com
|
|
194
|
+
pccentertwschoolkf.blogspot.com
|
|
195
|
+
pdfshouce.com
|
|
196
|
+
peachwaneversay.blogspot.com
|
|
197
|
+
peterdavehello.org
|
|
198
|
+
petnii.com
|
|
199
|
+
pinhladysz.tian.yam.com
|
|
200
|
+
pipedrive.com
|
|
201
|
+
powerapps.microsoft.com
|
|
202
|
+
protonmail.com
|
|
203
|
+
pt2club.blogspot.com
|
|
204
|
+
pvencs.blogspot.com
|
|
205
|
+
radioecouteur.com
|
|
206
|
+
rafaelu8mr.tian.yam.com
|
|
207
|
+
rayaegis.com
|
|
208
|
+
redhat.com
|
|
209
|
+
richielin-mac.blogspot.com
|
|
210
|
+
roroiii.coderbridge.io
|
|
211
|
+
rpg2008.blogspot.com
|
|
212
|
+
rtaiwanr.wordpress.com
|
|
213
|
+
ruth7112.tian.yam.com
|
|
214
|
+
salesforce.com
|
|
215
|
+
sandrabb.pixnet.net
|
|
216
|
+
saverinthebox.com
|
|
217
|
+
sctaeaa.org
|
|
218
|
+
sflowerpp.tian.yam.com
|
|
219
|
+
shamitsu.com
|
|
220
|
+
sharkjiang.com
|
|
221
|
+
shingfay.tian.yam.com
|
|
222
|
+
shopaholicwifes.blogspot.it
|
|
223
|
+
shopifytaiwan.com
|
|
224
|
+
shuanet.com
|
|
225
|
+
shutterstock.com
|
|
226
|
+
si402.tian.yam.com
|
|
227
|
+
skype.com
|
|
228
|
+
slsp.auo.com
|
|
229
|
+
sonniekoenig.com
|
|
230
|
+
splunk.com
|
|
231
|
+
ssemble.com
|
|
232
|
+
ssuns.tian.yam.com
|
|
233
|
+
sszxfcxt.tian.yam.com
|
|
234
|
+
stardouble.tian.yam.com
|
|
235
|
+
stellahyc.pixnet.net
|
|
236
|
+
strangerckbe.tian.yam.com
|
|
237
|
+
strollmarket.com
|
|
238
|
+
study-area.org
|
|
239
|
+
support.norton.com
|
|
240
|
+
support.ubisoft.com
|
|
241
|
+
support.xbox.com
|
|
242
|
+
synology.com
|
|
243
|
+
synology.de
|
|
244
|
+
tacolin.blogspot.com
|
|
245
|
+
taiwan-photo-base.com
|
|
246
|
+
taiwan.arcsight.com
|
|
247
|
+
taiwan10000.com
|
|
248
|
+
taiwanese-association-of-norway.org
|
|
249
|
+
taiwanmooc.org
|
|
250
|
+
taiwannextgenfoundation.org
|
|
251
|
+
taiwantravelmap.com
|
|
252
|
+
telco.vmware.com
|
|
253
|
+
tgtf4s6bhrc.tian.yam.com
|
|
254
|
+
theonevfx.com
|
|
255
|
+
tos.ea.com
|
|
256
|
+
tpweddinggift.com
|
|
257
|
+
tsi.center
|
|
258
|
+
tso-liang-wu.gitbook.io
|
|
259
|
+
tukuyomimaid.blog126.fc2.com
|
|
260
|
+
tw.andys.pro
|
|
261
|
+
tw.aoc.com
|
|
262
|
+
tw.cansonic.com
|
|
263
|
+
tw.flux3dp.com
|
|
264
|
+
tw.ipswitch.com
|
|
265
|
+
tw.micron.com
|
|
266
|
+
tw.websense.com
|
|
267
|
+
twdn.net
|
|
268
|
+
twosevenths.com
|
|
269
|
+
twtybbs.com
|
|
270
|
+
vaderisme.tian.yam.com
|
|
271
|
+
vaemon.com
|
|
272
|
+
veed.io
|
|
273
|
+
vhbwxrlzghudo.tian.yam.com
|
|
274
|
+
vielgluck.tian.yam.com
|
|
275
|
+
visualstudio.com
|
|
276
|
+
vmware.com
|
|
277
|
+
w0.wetouch.me
|
|
278
|
+
weatherrisk.com
|
|
279
|
+
web.taiwanhot.net
|
|
280
|
+
websecurity.symantec.com
|
|
281
|
+
weebly.com
|
|
282
|
+
wemoscooter.com
|
|
283
|
+
windwithme.blogspot.com
|
|
284
|
+
wooddiylonlon.blogspot.com
|
|
285
|
+
wpbox.tips
|
|
286
|
+
wznote.blogspot.com
|
|
287
|
+
ya-boginhall-40.8rmi2.upcloudobjects.com
|
|
288
|
+
ya-boginhall-5.s3.nl-ams.scw.cloud
|
|
289
|
+
ya-boginhall-6.s3.pl-waw.scw.cloud
|
|
290
|
+
ya-catering-14.sfo3.digitaloceanspaces.com
|
|
291
|
+
yahootwtrip.tumblr.com
|
|
292
|
+
yingzaiandtei.blogspot.com
|
|
293
|
+
yiying.handysociality.com
|
|
294
|
+
yllan.org
|
|
295
|
+
youthfulcf.tian.yam.com
|
|
296
|
+
yuchengcomuseum.benchurl.com
|
|
297
|
+
yuhinas.blogspot.com
|
|
298
|
+
yurenju.medium.com
|
|
299
|
+
zh-tw.broadcom.com
|
|
300
|
+
zh.unifab.ai
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "time"
|
|
6
|
+
|
|
7
|
+
module TWPipeline
|
|
8
|
+
module Bench
|
|
9
|
+
Sample = Data.define(:label, :seconds, :cpu_seconds, :peak_rss_bytes, :facts) do
|
|
10
|
+
def cores_used = seconds.zero? ? 0.0 : cpu_seconds / seconds
|
|
11
|
+
|
|
12
|
+
def to_h
|
|
13
|
+
{
|
|
14
|
+
label: label,
|
|
15
|
+
seconds: seconds.round(3),
|
|
16
|
+
cpu_seconds: cpu_seconds.round(3),
|
|
17
|
+
cores_used: cores_used.round(2),
|
|
18
|
+
peak_rss_bytes: peak_rss_bytes
|
|
19
|
+
}.merge(facts)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
def path = Pathname(ENV.fetch("TWP_BENCHMARKS", TWPipeline.work.join("benchmarks.jsonl").to_s))
|
|
26
|
+
|
|
27
|
+
def measure(label, **facts)
|
|
28
|
+
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
29
|
+
cpu_before = cpu_seconds
|
|
30
|
+
result = yield
|
|
31
|
+
sample = Sample.new(
|
|
32
|
+
label: label,
|
|
33
|
+
seconds: Process.clock_gettime(Process::CLOCK_MONOTONIC) - started,
|
|
34
|
+
cpu_seconds: cpu_seconds - cpu_before,
|
|
35
|
+
peak_rss_bytes: peak_rss,
|
|
36
|
+
facts: facts.merge(result.is_a?(Hash) ? result : {})
|
|
37
|
+
)
|
|
38
|
+
record(sample)
|
|
39
|
+
sample
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def cpu_seconds
|
|
43
|
+
times = Process.times
|
|
44
|
+
times.utime + times.stime + times.cutime + times.cstime
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def peak_rss = Rusage.peak
|
|
48
|
+
|
|
49
|
+
def record(sample)
|
|
50
|
+
path.dirname.mkpath
|
|
51
|
+
path.open("a") { |io| io.puts(JSON.generate({at: Time.now.utc.iso8601}.merge(sample.to_h))) }
|
|
52
|
+
sample
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|