textblockrenderer 1.1.0__py3-none-any.whl
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.
- textblockrenderer/__init__.py +55 -0
- textblockrenderer/htmlparser.py +211 -0
- textblockrenderer/lang_constants.py +468 -0
- textblockrenderer/models.py +80 -0
- textblockrenderer/renderer.py +339 -0
- textblockrenderer/splitter.py +505 -0
- textblockrenderer-1.1.0.dist-info/METADATA +231 -0
- textblockrenderer-1.1.0.dist-info/RECORD +10 -0
- textblockrenderer-1.1.0.dist-info/WHEEL +4 -0
- textblockrenderer-1.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"""Language constants for text splitting."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
# 默认英语连词
|
|
6
|
+
EN_CONJUNCTIONS = {
|
|
7
|
+
"and",
|
|
8
|
+
"but",
|
|
9
|
+
"or",
|
|
10
|
+
"so",
|
|
11
|
+
"because",
|
|
12
|
+
"however",
|
|
13
|
+
"although",
|
|
14
|
+
"therefore",
|
|
15
|
+
"if",
|
|
16
|
+
"then",
|
|
17
|
+
"else",
|
|
18
|
+
"when",
|
|
19
|
+
"while",
|
|
20
|
+
"since",
|
|
21
|
+
"until",
|
|
22
|
+
"unless",
|
|
23
|
+
"whether",
|
|
24
|
+
"either",
|
|
25
|
+
"neither",
|
|
26
|
+
"nor",
|
|
27
|
+
"yet",
|
|
28
|
+
"for",
|
|
29
|
+
"as",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# 默认标点正则
|
|
33
|
+
DEFAULT_SENTENCE_END = re.compile(r"[.!?]$")
|
|
34
|
+
DEFAULT_COMMA_END = re.compile(r",$")
|
|
35
|
+
|
|
36
|
+
# 希腊语问号是 ; (0x037E)
|
|
37
|
+
EL_SENTENCE_END = re.compile(r"[.!?\u037E]$")
|
|
38
|
+
|
|
39
|
+
# 语言特定的句子结束符正则
|
|
40
|
+
SENTENCE_END_MAP = {
|
|
41
|
+
"EL": EL_SENTENCE_END,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# 语言特定的逗号正则
|
|
45
|
+
COMMA_END_MAP = {
|
|
46
|
+
# 可以在这里添加特定语言的逗号正则,目前全使用默认
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# 多语言连词映射
|
|
50
|
+
CONJUNCTIONS_MAP = {
|
|
51
|
+
"EN": EN_CONJUNCTIONS,
|
|
52
|
+
"CS": { # 捷克语
|
|
53
|
+
"a",
|
|
54
|
+
"ale",
|
|
55
|
+
"nebo",
|
|
56
|
+
"tak",
|
|
57
|
+
"protože",
|
|
58
|
+
"však",
|
|
59
|
+
"ačkoli",
|
|
60
|
+
"proto",
|
|
61
|
+
"pokud",
|
|
62
|
+
"pak",
|
|
63
|
+
"jinak",
|
|
64
|
+
"když",
|
|
65
|
+
"zatímco",
|
|
66
|
+
"od",
|
|
67
|
+
"dokud",
|
|
68
|
+
"zda",
|
|
69
|
+
"buď",
|
|
70
|
+
"ani",
|
|
71
|
+
"přesto",
|
|
72
|
+
"pro",
|
|
73
|
+
"jako",
|
|
74
|
+
},
|
|
75
|
+
"PL": { # 波兰语
|
|
76
|
+
"i",
|
|
77
|
+
"ale",
|
|
78
|
+
"lub",
|
|
79
|
+
"więc",
|
|
80
|
+
"ponieważ",
|
|
81
|
+
"jednak",
|
|
82
|
+
"chociaż",
|
|
83
|
+
"dlatego",
|
|
84
|
+
"jeśli",
|
|
85
|
+
"wtedy",
|
|
86
|
+
"inaczej",
|
|
87
|
+
"kiedy",
|
|
88
|
+
"podczas",
|
|
89
|
+
"odkąd",
|
|
90
|
+
"dopóki",
|
|
91
|
+
"czy",
|
|
92
|
+
"albo",
|
|
93
|
+
"ani",
|
|
94
|
+
"mimo",
|
|
95
|
+
"dla",
|
|
96
|
+
"jak",
|
|
97
|
+
},
|
|
98
|
+
"DE": { # 德语
|
|
99
|
+
"und",
|
|
100
|
+
"aber",
|
|
101
|
+
"oder",
|
|
102
|
+
"so",
|
|
103
|
+
"weil",
|
|
104
|
+
"jedoch",
|
|
105
|
+
"obwohl",
|
|
106
|
+
"deshalb",
|
|
107
|
+
"wenn",
|
|
108
|
+
"dann",
|
|
109
|
+
"sonst",
|
|
110
|
+
"wann",
|
|
111
|
+
"während",
|
|
112
|
+
"seit",
|
|
113
|
+
"bis",
|
|
114
|
+
"ob",
|
|
115
|
+
"entweder",
|
|
116
|
+
"weder",
|
|
117
|
+
"noch",
|
|
118
|
+
"doch",
|
|
119
|
+
"für",
|
|
120
|
+
"als",
|
|
121
|
+
},
|
|
122
|
+
"IT": { # 意大利语
|
|
123
|
+
"e",
|
|
124
|
+
"ma",
|
|
125
|
+
"o",
|
|
126
|
+
"quindi",
|
|
127
|
+
"perché",
|
|
128
|
+
"tuttavia",
|
|
129
|
+
"bbene",
|
|
130
|
+
"perciò",
|
|
131
|
+
"se",
|
|
132
|
+
"allora",
|
|
133
|
+
"altrimenti",
|
|
134
|
+
"quando",
|
|
135
|
+
"mentre",
|
|
136
|
+
"da",
|
|
137
|
+
"fino",
|
|
138
|
+
"che",
|
|
139
|
+
"o",
|
|
140
|
+
"né",
|
|
141
|
+
"ancora",
|
|
142
|
+
"per",
|
|
143
|
+
"come",
|
|
144
|
+
},
|
|
145
|
+
"TR": { # 土耳其语
|
|
146
|
+
"ve",
|
|
147
|
+
"ama",
|
|
148
|
+
"veya",
|
|
149
|
+
"bu",
|
|
150
|
+
"çünkü",
|
|
151
|
+
"ancak",
|
|
152
|
+
"rağmen",
|
|
153
|
+
"nedenle",
|
|
154
|
+
"eğer",
|
|
155
|
+
"sonra",
|
|
156
|
+
"aksi",
|
|
157
|
+
"ne",
|
|
158
|
+
"iken",
|
|
159
|
+
"beri",
|
|
160
|
+
"kadar",
|
|
161
|
+
"olup",
|
|
162
|
+
"ya",
|
|
163
|
+
"ne",
|
|
164
|
+
"henüz",
|
|
165
|
+
"için",
|
|
166
|
+
"olarak",
|
|
167
|
+
},
|
|
168
|
+
"HU": { # 匈牙利语
|
|
169
|
+
"és",
|
|
170
|
+
"de",
|
|
171
|
+
"vagy",
|
|
172
|
+
"tehát",
|
|
173
|
+
"mert",
|
|
174
|
+
"azonban",
|
|
175
|
+
"bár",
|
|
176
|
+
"ezért",
|
|
177
|
+
"ha",
|
|
178
|
+
"akkor",
|
|
179
|
+
"különben",
|
|
180
|
+
"amikor",
|
|
181
|
+
"miközben",
|
|
182
|
+
"mióta",
|
|
183
|
+
"amíg",
|
|
184
|
+
"hogy",
|
|
185
|
+
"vagy",
|
|
186
|
+
"sem",
|
|
187
|
+
"mégis",
|
|
188
|
+
"számára",
|
|
189
|
+
"mint",
|
|
190
|
+
},
|
|
191
|
+
"BG": { # 保加利亚语
|
|
192
|
+
"и",
|
|
193
|
+
"но",
|
|
194
|
+
"или",
|
|
195
|
+
"така",
|
|
196
|
+
"защото",
|
|
197
|
+
"обаче",
|
|
198
|
+
"въпреки",
|
|
199
|
+
"следователно",
|
|
200
|
+
"ако",
|
|
201
|
+
"тогава",
|
|
202
|
+
"иначе",
|
|
203
|
+
"когато",
|
|
204
|
+
"докато",
|
|
205
|
+
"откакто",
|
|
206
|
+
"докато",
|
|
207
|
+
"дали",
|
|
208
|
+
"или",
|
|
209
|
+
"нито",
|
|
210
|
+
"все",
|
|
211
|
+
"за",
|
|
212
|
+
"като",
|
|
213
|
+
},
|
|
214
|
+
"RU": { # 俄语
|
|
215
|
+
"и",
|
|
216
|
+
"но",
|
|
217
|
+
"или",
|
|
218
|
+
"так",
|
|
219
|
+
"потому",
|
|
220
|
+
"однако",
|
|
221
|
+
"хотя",
|
|
222
|
+
"поэтому",
|
|
223
|
+
"если",
|
|
224
|
+
"то",
|
|
225
|
+
"иначе",
|
|
226
|
+
"когда",
|
|
227
|
+
"пока",
|
|
228
|
+
"с",
|
|
229
|
+
"до",
|
|
230
|
+
"ли",
|
|
231
|
+
"либо",
|
|
232
|
+
"ни",
|
|
233
|
+
"еще",
|
|
234
|
+
"для",
|
|
235
|
+
"как",
|
|
236
|
+
},
|
|
237
|
+
"EL": { # 希腊语
|
|
238
|
+
"και",
|
|
239
|
+
"αλλά",
|
|
240
|
+
"ή",
|
|
241
|
+
"έτσι",
|
|
242
|
+
"επειδή",
|
|
243
|
+
"όμως",
|
|
244
|
+
"αν",
|
|
245
|
+
"επομένως",
|
|
246
|
+
"αν",
|
|
247
|
+
"τότε",
|
|
248
|
+
"αλλιώς",
|
|
249
|
+
"πότε",
|
|
250
|
+
"ενώ",
|
|
251
|
+
"από",
|
|
252
|
+
"μέχρι",
|
|
253
|
+
"είτε",
|
|
254
|
+
"είτε",
|
|
255
|
+
"ούτε",
|
|
256
|
+
"ακόμα",
|
|
257
|
+
"για",
|
|
258
|
+
"όπως",
|
|
259
|
+
},
|
|
260
|
+
"RO": { # 罗马尼亚语
|
|
261
|
+
"și",
|
|
262
|
+
"dar",
|
|
263
|
+
"sau",
|
|
264
|
+
"deci",
|
|
265
|
+
"pentru",
|
|
266
|
+
"totuși",
|
|
267
|
+
"deși",
|
|
268
|
+
"prin",
|
|
269
|
+
"dacă",
|
|
270
|
+
"atunci",
|
|
271
|
+
"altfel",
|
|
272
|
+
"când",
|
|
273
|
+
"în",
|
|
274
|
+
"de",
|
|
275
|
+
"până",
|
|
276
|
+
"fie",
|
|
277
|
+
"fie",
|
|
278
|
+
"nici",
|
|
279
|
+
"încă",
|
|
280
|
+
"pentru",
|
|
281
|
+
"ca",
|
|
282
|
+
},
|
|
283
|
+
"UK": { # 乌克兰语
|
|
284
|
+
"і",
|
|
285
|
+
"але",
|
|
286
|
+
"або",
|
|
287
|
+
"так",
|
|
288
|
+
"тому",
|
|
289
|
+
"проте",
|
|
290
|
+
"хоча",
|
|
291
|
+
"тому",
|
|
292
|
+
"якщо",
|
|
293
|
+
"тоdi",
|
|
294
|
+
"інакше",
|
|
295
|
+
"коли",
|
|
296
|
+
"поки",
|
|
297
|
+
"з",
|
|
298
|
+
"доки",
|
|
299
|
+
"чи",
|
|
300
|
+
"або",
|
|
301
|
+
"ні",
|
|
302
|
+
"ще",
|
|
303
|
+
"для",
|
|
304
|
+
"як",
|
|
305
|
+
},
|
|
306
|
+
"FR": { # 法语
|
|
307
|
+
"et",
|
|
308
|
+
"mais",
|
|
309
|
+
"ou",
|
|
310
|
+
"donc",
|
|
311
|
+
"parce",
|
|
312
|
+
"cependant",
|
|
313
|
+
"bien",
|
|
314
|
+
"conséquent",
|
|
315
|
+
"si",
|
|
316
|
+
"alors",
|
|
317
|
+
"sinon",
|
|
318
|
+
"quand",
|
|
319
|
+
"pendant",
|
|
320
|
+
"depuis",
|
|
321
|
+
"jusqu'à",
|
|
322
|
+
"sauf",
|
|
323
|
+
"que",
|
|
324
|
+
"soit",
|
|
325
|
+
"ni",
|
|
326
|
+
"pourtant",
|
|
327
|
+
"pour",
|
|
328
|
+
"comme",
|
|
329
|
+
},
|
|
330
|
+
"PT": { # 葡萄牙语
|
|
331
|
+
"e",
|
|
332
|
+
"mas",
|
|
333
|
+
"ou",
|
|
334
|
+
"então",
|
|
335
|
+
"porque",
|
|
336
|
+
"entanto",
|
|
337
|
+
"embora",
|
|
338
|
+
"portanto",
|
|
339
|
+
"se",
|
|
340
|
+
"então",
|
|
341
|
+
"senão",
|
|
342
|
+
"quando",
|
|
343
|
+
"enquanto",
|
|
344
|
+
"desde",
|
|
345
|
+
"até",
|
|
346
|
+
"se",
|
|
347
|
+
"ou",
|
|
348
|
+
"nem",
|
|
349
|
+
"ainda",
|
|
350
|
+
"para",
|
|
351
|
+
"como",
|
|
352
|
+
},
|
|
353
|
+
"HR": { # 克罗地亚语
|
|
354
|
+
"i",
|
|
355
|
+
"ali",
|
|
356
|
+
"ili",
|
|
357
|
+
"pa",
|
|
358
|
+
"jer",
|
|
359
|
+
"međutim",
|
|
360
|
+
"iako",
|
|
361
|
+
"stoga",
|
|
362
|
+
"ako",
|
|
363
|
+
"onda",
|
|
364
|
+
"inače",
|
|
365
|
+
"kada",
|
|
366
|
+
"dok",
|
|
367
|
+
"od",
|
|
368
|
+
"dok",
|
|
369
|
+
"bilo",
|
|
370
|
+
"bilo",
|
|
371
|
+
"ni",
|
|
372
|
+
"još",
|
|
373
|
+
"za",
|
|
374
|
+
"kao",
|
|
375
|
+
},
|
|
376
|
+
"NL": { # 荷兰语
|
|
377
|
+
"en",
|
|
378
|
+
"maar",
|
|
379
|
+
"of",
|
|
380
|
+
"dus",
|
|
381
|
+
"omdat",
|
|
382
|
+
"echter",
|
|
383
|
+
"hoewel",
|
|
384
|
+
"daarom",
|
|
385
|
+
"als",
|
|
386
|
+
"dan",
|
|
387
|
+
"anders",
|
|
388
|
+
"wanneer",
|
|
389
|
+
"terwijl",
|
|
390
|
+
"sinds",
|
|
391
|
+
"totdat",
|
|
392
|
+
"of",
|
|
393
|
+
"ofwel",
|
|
394
|
+
"noch",
|
|
395
|
+
"toch",
|
|
396
|
+
"voor",
|
|
397
|
+
"kzoals",
|
|
398
|
+
},
|
|
399
|
+
"DA": { # 丹麦语
|
|
400
|
+
"og",
|
|
401
|
+
"men",
|
|
402
|
+
"eller",
|
|
403
|
+
"så",
|
|
404
|
+
"fordi",
|
|
405
|
+
"imidlertid",
|
|
406
|
+
"skønt",
|
|
407
|
+
"derfor",
|
|
408
|
+
"hvis",
|
|
409
|
+
"så",
|
|
410
|
+
"ellers",
|
|
411
|
+
"når",
|
|
412
|
+
"mens",
|
|
413
|
+
"siden",
|
|
414
|
+
"indtil",
|
|
415
|
+
"om",
|
|
416
|
+
"enten",
|
|
417
|
+
"hverken",
|
|
418
|
+
"endnu",
|
|
419
|
+
"for",
|
|
420
|
+
"som",
|
|
421
|
+
},
|
|
422
|
+
"LT": { # 立陶宛语
|
|
423
|
+
"ir",
|
|
424
|
+
"bet",
|
|
425
|
+
"arba",
|
|
426
|
+
"tad",
|
|
427
|
+
"nes",
|
|
428
|
+
"tačiau",
|
|
429
|
+
"nors",
|
|
430
|
+
"todėl",
|
|
431
|
+
"jei",
|
|
432
|
+
"tada",
|
|
433
|
+
"kitaip",
|
|
434
|
+
"kada",
|
|
435
|
+
"kol",
|
|
436
|
+
"nuo",
|
|
437
|
+
"iki",
|
|
438
|
+
"ar",
|
|
439
|
+
"arba",
|
|
440
|
+
"nei",
|
|
441
|
+
"vis",
|
|
442
|
+
"dėl",
|
|
443
|
+
"kaip",
|
|
444
|
+
},
|
|
445
|
+
"NO": { # 挪威语
|
|
446
|
+
"og",
|
|
447
|
+
"men",
|
|
448
|
+
"eller",
|
|
449
|
+
"så",
|
|
450
|
+
"fordi",
|
|
451
|
+
"imidlertid",
|
|
452
|
+
"skjønt",
|
|
453
|
+
"derfor",
|
|
454
|
+
"hvis",
|
|
455
|
+
"så",
|
|
456
|
+
"ellers",
|
|
457
|
+
"når",
|
|
458
|
+
"mens",
|
|
459
|
+
"siden",
|
|
460
|
+
"inntil",
|
|
461
|
+
"om",
|
|
462
|
+
"enten",
|
|
463
|
+
"verken",
|
|
464
|
+
"ennå",
|
|
465
|
+
"for",
|
|
466
|
+
"som",
|
|
467
|
+
},
|
|
468
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Shared data models for text block rendering."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional, Tuple
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ColoredSpan:
|
|
10
|
+
"""带颜色和字号的文本片段"""
|
|
11
|
+
|
|
12
|
+
text: str
|
|
13
|
+
color: Optional[str] = None
|
|
14
|
+
font_size: Optional[int] = None # 字号(像素)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ColoredWord:
|
|
19
|
+
"""单个单词及其样式"""
|
|
20
|
+
|
|
21
|
+
word: str
|
|
22
|
+
color: Optional[str] = None
|
|
23
|
+
font_size: Optional[int] = None # 字号(像素),None 表示使用默认字号
|
|
24
|
+
force_newline: bool = False # 该单词后是否强制换行
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FontSpec(BaseModel):
|
|
28
|
+
"""字体配置"""
|
|
29
|
+
|
|
30
|
+
font_path: str
|
|
31
|
+
font_size: int
|
|
32
|
+
line_spacing: int = 4 # 额外行距
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class RenderConstraint(BaseModel):
|
|
36
|
+
"""渲染约束
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
max_width: 最大宽度(像素)
|
|
40
|
+
max_height: 最大高度(像素),设置为 0 表示高度无限制
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
max_width: int
|
|
44
|
+
max_height: int = 0 # 默认值 0 表示高度无限制
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SubtitleBlock(BaseModel):
|
|
48
|
+
"""纯文本字幕块"""
|
|
49
|
+
|
|
50
|
+
text: str
|
|
51
|
+
lines: List[str]
|
|
52
|
+
|
|
53
|
+
width: int
|
|
54
|
+
height: int
|
|
55
|
+
|
|
56
|
+
area_used: int
|
|
57
|
+
area_remaining: int
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ColoredSubtitleBlock(BaseModel):
|
|
61
|
+
"""支持颜色和字号的字幕块"""
|
|
62
|
+
|
|
63
|
+
plain_text: str # 纯文本(去除HTML标签)
|
|
64
|
+
colored_words: List[ColoredWord] # 带样式的单词列表
|
|
65
|
+
lines: List[List[ColoredWord]] # 按行分组的带样式单词
|
|
66
|
+
line_heights: List[int] = [] # 每行的高度(支持不同字号)
|
|
67
|
+
width: int
|
|
68
|
+
height: int
|
|
69
|
+
area_used: int
|
|
70
|
+
area_remaining: int
|
|
71
|
+
|
|
72
|
+
class Config:
|
|
73
|
+
arbitrary_types_allowed = True
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SplitConfig(BaseModel):
|
|
77
|
+
"""分割配置"""
|
|
78
|
+
|
|
79
|
+
min_words_per_block: int = Field(3, ge=1)
|
|
80
|
+
language: str = "EN"
|