Kai72828 commited on
Commit
e876913
ยท
verified ยท
1 Parent(s): 52a7593

Upload 11 files

Browse files
Files changed (2) hide show
  1. app.py +1 -0
  2. translation.py +164 -107
app.py CHANGED
@@ -1274,6 +1274,7 @@ def _step5_translate() -> None:
1274
  provider=prov, model=model, api_key=key,
1275
  fmt=fmt, ssafile=subs, filename=fname,
1276
  system_prompt=sys_prompt,
 
1277
  )
1278
  # Stash checkpoint into job so thread can resume
1279
  if cp_data:
 
1274
  provider=prov, model=model, api_key=key,
1275
  fmt=fmt, ssafile=subs, filename=fname,
1276
  system_prompt=sys_prompt,
1277
+ preset_key=st.session_state.get("prompt_preset", "adult_18"),
1278
  )
1279
  # Stash checkpoint into job so thread can resume
1280
  if cp_data:
translation.py CHANGED
@@ -207,131 +207,140 @@ def _chunk(lst: list, size: int) -> list:
207
 
208
 
209
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
210
- # Prompts โ€” Multi-Preset System (revamped: zero redundancy, each rule said once)
211
  #
212
  # Architecture: build_system_prompt() assembles 4 non-overlapping layers:
213
  # 1. STYLE โ€” tone / register / swearing (preset-specific)
214
  # 2. TERMS โ€” special terms to preserve (culture-specific)
215
  # 3. NOUNS โ€” proper noun handling (noun_style ร— culture, generated once)
216
- # 4. TECH โ€” count rule / tags / glossary / output (always identical)
217
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
218
 
219
- # โ”€โ”€ Layer 1: STYLE blocks (preset-specific) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
220
 
221
- # Header is generated dynamically from preset + culture โ€” not hardcoded here.
222
- # Each STYLE block covers only: register, tone, swearing policy.
223
- # "Don't add / don't remove" is stated once globally in TECH โ€” not repeated here.
 
 
 
 
 
 
 
224
 
225
  _STYLE_STANDARD = """\
226
- แ€™แ€ผแ€”แ€บแ€™แ€ฌ subtitle แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บแ€•แ€Šแ€ฌแ€›แ€พแ€„แ€บ โ€” general / family-safe contentแ‹
227
-
228
- แ€‡แ€ฌแ€แ€บแ€€แ€ฑแ€ฌแ€„แ€บ voice แ€€แ€ญแ€ฏ แ€‘แ€ฏแ€แ€บแ€•แ€ฑแ€ธ โ€” AI voice แ€™แ€Ÿแ€ฏแ€แ€บ:
229
- โ€ข แ€šแ€ฑแ€ฌแ€€แ€บแ€ปแ€ฌแ€ธแ€€แ€ผแ€™แ€บแ€ธ / villain โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + แ€€แ€ฝ/แ€—แ€ป/แ€€แ€ฝแ€ฌ (family-safe range แ€แ€ฝแ€„แ€บ)
230
- โ€ข แ€™แ€ญแ€”แ€บแ€ธแ€€แ€œแ€ฑแ€ธ โ†’ แ€€แ€ปแ€™/แ€„แ€ซ + แ€€แ€ฝแ€ฌ/แ€Ÿแ€ฑแ€ท
231
- โ€ข Elder / boss / formal โ†’ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™
232
- โ€ข Comic / light โ†’ แ€•แ€ผแ€ฑแ€ฌแ€•แ€ผแ€ฑแ€ฌแ€†แ€ญแ€ฏแ€†แ€ญแ€ฏ colloquial
233
- แ€†แ€ฒแ€…แ€€แ€ฌแ€ธ / แ€€แ€ผแ€™แ€บแ€ธ โ†’ source แ intensity แ€€แ€ญแ€ฏ แ€‘แ€ญแ€”แ€บแ€ธแ€žแ€ญแ€™แ€บแ€ธแ€•แ€ผแ€ฎแ€ธ family-safe แ€™แ€ผแ€”แ€บแ€™แ€ฌ equivalent แ€žแ€ฏแ€ถแ€ธแ€•แ€ซ\
 
234
  """
235
 
236
  _STYLE_ADULT = """\
237
- แ€™แ€ผแ€”แ€บแ€™แ€ฌ subtitle แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บแ€•แ€Šแ€ฌแ€›แ€พแ€„แ€บ โ€” mature / 18+ contentแ‹
238
-
239
- แ€‡แ€ฌแ€แ€บแ€€แ€ฑแ€ฌแ€„แ€บ voice แ€€แ€ญแ€ฏ แ€‘แ€ฏแ€แ€บแ€•แ€ฑแ€ธ โ€” AI voice แ€™แ€Ÿแ€ฏแ€แ€บ:
240
- โ€ข แ€šแ€ฑแ€ฌแ€€แ€บแ€ปแ€ฌแ€ธแ€€แ€ผแ€™แ€บแ€ธ / villain / แ€‚แ€ญแ€ฏแ€แ€บแ€ธ โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ/แ€€แ€ฑแ€ฌแ€„แ€บ + แ€€แ€ฝ/แ€—แ€ป/แ€€แ€ฝแ€ฌ
241
- โ€ข แ€™แ€ญแ€”แ€บแ€ธแ€€แ€œแ€ฑแ€ธ แ€›แ€„แ€บแ€ธแ€”แ€พแ€ฎแ€ธ โ†’ แ€€แ€ปแ€™/แ€„แ€ซ/แ€”แ€„แ€บ + แ€€แ€ฝแ€ฌ/แ€Ÿแ€ฑแ€ท
242
- โ€ข Boss / formal โ†’ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ (แ€•แ€ผแ€„แ€บแ€ธแ€‘แ€”แ€บ) แ€žแ€ญแ€ฏแ€ทแ€™แ€Ÿแ€ฏแ€แ€บ แ€„แ€ซ (dominant)
243
- โ€ข Comic / light โ†’ แ€•แ€ผแ€ฑแ€ฌแ€•แ€ผแ€ฑแ€ฌแ€†แ€ญแ€ฏแ€†แ€ญแ€ฏ colloquial
244
- Strong language โ€” source แ exact weight แ€€แ€ญแ€ฏ แ€‘แ€ญแ€”แ€บแ€ธแ€žแ€ญแ€™แ€บแ€ธ:
245
- English source โ†’ English แ€‘แ€ฌแ€ธ (Fuck / Shit / Bitch / Bastard / Asshole)
246
- Other lang source โ†’ nearest English equivalent แ€‘แ€ฌแ€ธ\
 
247
  """
248
 
249
  _STYLE_ANIME = """\
250
- แ€™แ€ผแ€”แ€บแ€™แ€ฌ subtitle แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บแ€•แ€Šแ€ฌแ€›แ€พแ€„แ€บ โ€” Japanese anime / drama / mangaเฅค
251
-
252
- แ€‡แ€ฌแ€แ€บแ€€แ€ฑแ€ฌแ€„แ€บ vocal style แ€€แ€ญแ€ฏ แ€‘แ€ญแ€”แ€บแ€ธแ€žแ€ญแ€™แ€บแ€ธ:
253
- โ€ข Energetic / shonen โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + แ€€แ€ฝ/แ€—แ€ป colloquial
254
- โ€ข Tsundere โ†’ แ€แ€Šแ€บแ€„แ€ผแ€ญแ€™แ€บแ€•แ€ผแ€ฎแ€ธ แ€’แ€ฑแ€ซแ€žแ€€แ€ป, แ€•แ€ผแ€แ€บแ€žแ€ฌแ€ธ
255
- โ€ข Kuudere / cool โ†’ แ€แ€ญแ€ฏแ€›แ€พแ€„แ€บแ€ธ แ€•แ€ผแ€แ€บแ€žแ€ฌแ€ธ
256
- โ€ข Cute / moe โ†’ แ€€แ€ปแ€™ + แ€”แ€ฐแ€ธแ€Šแ€ถแ€ท
257
- โ€ข Elder / sensei โ†’ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€›แ€พแ€„แ€บ formal
258
- Strong language โ†’ English แ€‘แ€ฌแ€ธ (Fuck / Shit / Bitch)\
 
259
  """
260
 
261
  _STYLE_CDRAMA = """\
262
- แ€™แ€ผแ€”แ€บแ€™แ€ฌ subtitle แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บแ€•แ€Šแ€ฌแ€›แ€พแ€„แ€บ โ€” Chinese drama / wuxia / xianxia / movieแ‹
263
-
264
- Tone โ€” formal yet emotional, dramatic pacing แ€€แ€ญแ€ฏ แ€‘แ€ญแ€”แ€บแ€ธแ€žแ€ญแ€™แ€บแ€ธ:
265
- โ€ข Emperor / high noble โ†’ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ dignified formal
266
- โ€ข Common folk โ†’ แ€žแ€ฌแ€™แ€”แ€บ colloquial
267
- โ€ข Villain / schemer โ†’ แ€€แ€ผแ€™แ€บแ€ธแ€แ€™แ€บแ€ธ แ€•แ€ผแ€แ€บแ€žแ€ฌแ€ธ
268
- โ€ข Romantic / poetic lines โ†’ weight แ€€แ€ญแ€ฏ แ€™แ€•แ€ปแ€ฑแ€ฌแ€€แ€บแ€…แ€ฑ โ€” nearest แ€™แ€ผแ€”แ€บแ€™แ€ฌ emotional equivalent\
 
 
269
  """
270
 
271
  _STYLE_KDRAMA = """\
272
- แ€™แ€ผแ€”แ€บแ€™แ€ฌ subtitle แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บแ€•แ€Šแ€ฌแ€›แ€พแ€„แ€บ โ€” Korean drama / movie / webtoon adaptationแ‹
273
-
274
- Tone โ€” emotional intensity, sincerity แ€€แ€ญแ€ฏ แ€‘แ€ญแ€”แ€บแ€ธแ€žแ€ญแ€™แ€บแ€ธ:
275
- โ€ข Chaebol / CEO โ†’ formal, measured, restrained
276
- โ€ข Young adult โ†’ modern colloquial โ€” แ€„แ€ซ/แ€€แ€ปแ€™ + แ€€แ€ฝแ€ฌ/แ€Ÿแ€ฑแ€ท/แ€—แ€ป
277
- โ€ข Elder / parent โ†’ authoritative + caring register
278
- โ€ข Romantic moments โ†’ emotional weight แ€™แ€•แ€ปแ€ฑแ€ฌแ€€แ€บแ€กแ€ฑแ€ฌแ€„แ€บ
279
- Strong language โ†’ English แ€‘แ€ฌแ€ธ\
 
280
  """
281
 
282
  _STYLE_FORMAL = """\
283
- แ€™แ€ผแ€”แ€บแ€™แ€ฌ subtitle แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บแ€•แ€Šแ€ฌแ€›แ€พแ€„แ€บ โ€” documentary / news / educational narrationแ‹
284
-
285
- Register โ€” objective, formal, educated standard Myanmar:
286
- โ€ข Narration โ†’ แ€•แ€Šแ€ฌแ€แ€แ€บ standard register (แ€•แ€ผแ€ฑแ€ฌแ€•แ€ผแ€ฑแ€ฌแ€†แ€ญแ€ฏแ€†แ€ญแ€ฏ colloquial แ€™แ€žแ€ฏแ€ถแ€ธแ€›)
287
- โ€ข Expert quotes โ†’ semi-formal educated
288
- โ€ข Technical terms โ†’ precise Myanmar equivalent; แ€™แ€›แ€พแ€ญแ€œแ€ปแ€พแ€„แ€บ (English term) แ€•แ€ผแ€„แ€บแ€•แ€€แ€ฝแ€„แ€บแ€ธ
289
- โ€ข Numbers / dates / statistics โ†’ exact\
 
290
  """
291
 
292
  # โ”€โ”€ Layer 2: TERMS blocks (culture-specific special terms) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
293
- # Only stated here โ€” never repeated in preset STYLE or NOUNS layer.
294
 
295
- _TERMS_WESTERN = "" # no special terms needed
296
 
297
  _TERMS_JAPANESE = """\
298
- Japanese special terms โ€” แ€ค rule แ€แ€ฝแ€ฑแ€žแ€Šแ€บ noun style แ€€แ€ญแ€ฏ override แ€™แ€œแ€ฏแ€•แ€บ โ€” term handling แ€žแ€ฌ:
299
- โ€ข Honorifics (-san / -kun / -chan / -senpai / -sensei / -sama / -dono / -nii / -nee) โ†’ as-is แ€‘แ€ฌแ€ธ แ€žแ€ญแ€ฏแ€ทแ€™แ€Ÿแ€ฏแ€แ€บ natural แ€™แ€ผแ€”แ€บแ€™แ€ฌ (Glossary แ€•แ€ซแ€œแ€ปแ€พแ€„แ€บ Glossary)
300
- โ€ข Anime / otaku terms (baka, kawaii, nakama, sugoi, yare yare etc.) โ†’ English as-is แ€‘แ€ฌแ€ธ
301
- โ€ข Game / isekai system terms (HP, MP, Level, Skill, Quest, Guild, Status) โ†’ English as-is
302
- โ€ข Cultural terms (onsen, matsuri, bento, senpai-kouhai) โ†’ English / Romaji as-is\
303
  """
304
 
305
  _TERMS_CHINESE = """\
306
- Chinese special terms โ€” แ€ค rule แ€แ€ฝแ€ฑแ€žแ€Šแ€บ noun style แ€€แ€ญแ€ฏ override แ€™แ€œแ€ฏแ€•แ€บ โ€” term handling แ€žแ€ฌ:
307
- โ€ข Relationship / title terms โ†’ Pinyin as-is แ€‘แ€ฌแ€ธ:
308
- Shifu, Shidi/Shixiong/Shijie, Gege/Jiejie/Meimei/Didi, A'niang/Niang, Wangye, Gongzi, Guniang
309
- โ€ข Wuxia / Xianxia terms โ†’ English / Pinyin:
310
- Golden Core, Nascent Soul, cultivation, qi, meridians, sect, immortal, spiritual root
311
- โ€ข Historical titles โ†’ English: Emperor, Empress, Crown Prince, Noble Consort, Imperial Guard\
312
  """
313
 
314
  _TERMS_KOREAN = """\
315
- Korean special terms โ€” แ€ค rule แ€แ€ฝแ€ฑแ€žแ€Šแ€บ noun style แ€€แ€ญแ€ฏ override แ€™แ€œแ€ฏแ€•แ€บ โ€” term handling แ€žแ€ฌ:
316
- โ€ข Relationship / honorifics โ†’ Romanized as-is แ€‘แ€ฌแ€ธ:
317
- Oppa, Unnie, Hyung, Noona, Sunbae, Hoobae, Sajangnim, Seonsaengnim
318
- โ€ข Speech level โ€” Korean ์กด๋Œ“๋ง โ†’ formal แ€™แ€ผแ€”แ€บแ€™แ€ฌ | ๋ฐ˜๋ง โ†’ colloquial แ€™แ€ผแ€”แ€บแ€™แ€ฌ
319
- โ€ข Cultural terms โ†’ Romanized as-is: Ramyeon, Tteokbokki, Hanbok, Jjimjilbang, Aegyo\
320
  """
321
 
322
  _TERMS_THAI = """\
323
- Thai / SE Asian special terms โ€” แ€ค rule แ€แ€ฝแ€ฑแ€žแ€Šแ€บ noun style แ€€แ€ญแ€ฏ override แ€™แ€œแ€ฏแ€•แ€บ โ€” term handling แ€žแ€ฌ:
324
- โ€ข Honorifics (Khun, Phi, Nong) โ†’ Romanized as-is แ€žแ€ญแ€ฏแ€ทแ€™แ€Ÿแ€ฏแ€แ€บ natural แ€™แ€ผแ€”แ€บแ€™แ€ฌ equivalent
325
- โ€ข Cultural terms โ†’ Romanized as-is: Wai, Songkran, Muay Thai, Tuk-tuk\
326
  """
327
 
328
- _TERMS_UNIVERSAL = "" # mixed/unknown
329
 
330
  # โ”€โ”€ Layer 3: NOUNS block (generated from noun_style ร— culture) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
331
- # Generated once by _noun_block() โ€” never appears in STYLE or TERMS.
332
 
333
  def _noun_block(style: str, culture_key: str) -> str:
334
- """Single source of truth for proper noun handling rule."""
335
  script = {
336
  "japanese": "Romaji",
337
  "chinese": "Pinyin",
@@ -342,47 +351,51 @@ def _noun_block(style: str, culture_key: str) -> str:
342
  }.get(culture_key, "romanized")
343
 
344
  examples = {
345
- "western": [("Victor","แ€—แ€…แ€บแ€แ€ฌ"), ("Hope Street","แ€Ÿแ€ฏแ€แ€บแ€•แ€บแ€…แ€‘แ€›แ€ญแ€แ€บ"), ("London","แ€œแ€”แ€บแ€’แ€”แ€บ")],
346
- "japanese": [("Sasuke","แ€†แ€†แ€ฐแ€€แ€ฑ"), ("Tokyo","แ€แ€ญแ€ฏแ€€แ€ปแ€ญแ€ฏ"), ("Konoha","แ€€แ€ญแ€ฏแ€”แ€ญแ€ฏแ€Ÿแ€ฌ")],
347
- "chinese": [("Wei Wuxian","แ€แ€ฑแ€แ€ฐแ€›แ€พแ€ปแ€ฌแ€ธ"), ("Beijing","แ€•แ€ฑแ€€แ€ปแ€„แ€บแ€ธ"), ("Yunmeng","แ€šแ€ฝแ€”แ€บแ€™แ€ญแ€”แ€บ")],
348
- "korean": [("Park Seo-jun","แ€•แ€ซแ€ทแ€†แ€ฑแ€‚แ€ปแ€ฝแ€”แ€บ"), ("Seoul","แ€†แ€ญแ€ฏแ€ธแ€œแ€บ"), ("Busan","แ€•แ€ฐแ€†แ€™แ€บ")],
349
- "thai": [("Prayuth","แ€•แ€ผแ€ฌแ€›แ€แ€บ"), ("Chiang Mai","แ€แ€ปแ€„แ€บแ€ธแ€™แ€ญแ€ฏแ€„แ€บ"), ("Bangkok","แ€˜แ€”แ€บแ€€แ€ฑแ€ฌแ€€แ€บ")],
350
- "universal": [("Victor","แ€—แ€…แ€บแ€แ€ฌ"), ("Sakura","แ€†แ€ฌแ€€แ€ฐแ€›แ€ฌ"), ("Madison","แ€™แ€แ€บแ€’แ€…แ€บแ€†แ€„แ€บ")],
351
  }.get(culture_key, [("Victor","แ€—แ€…แ€บแ€แ€ฌ"), ("Hope Street","แ€Ÿแ€ฏแ€แ€บแ€•แ€บแ€…แ€‘แ€›แ€ญแ€แ€บ"), ("London","แ€œแ€”แ€บแ€’แ€”แ€บ")])
352
 
353
  if style == "phonetic":
354
- ex_lines = "\n".join(f' {e} โ†’ {p}' for e, p in examples)
355
  return (
356
- f"PROPER NOUNS โ€” Myanmar Phonetic:\n"
357
- f"แ€”แ€ฌแ€™แ€Šแ€บ / แ€”แ€ฑแ€›แ€ฌ / แ€กแ€–แ€ฝแ€ฒแ€ท โ†’ แ€™แ€ผแ€”แ€บแ€™แ€ฌ แ€กแ€žแ€ถแ€‘แ€ฝแ€€แ€บ transliteration (แ€กแ€“แ€ญแ€•แ€นแ€•แ€ฌแ€šแ€บ แ€™แ€˜แ€ฌแ€žแ€ฌแ€™แ€•แ€ผแ€”แ€บแ€›)\n"
358
  f"{ex_lines}\n"
359
- f"Glossary แ€•แ€ซ โ†’ Glossary แ€กแ€แ€ญแ€ฏแ€„แ€บแ€ธ | แ€™แ€•แ€ซ โ†’ phonetic"
360
  )
361
  else:
362
- ex_lines = "\n".join(f' "{e}" โ†’ "{e}" โœ— not "{p}"' for e, p in examples)
363
  return (
364
  f"PROPER NOUNS โ€” {script} spelling:\n"
365
- f"แ€”แ€ฌแ€™แ€Šแ€บ / แ€”แ€ฑแ€›แ€ฌ / แ€กแ€–แ€ฝแ€ฒแ€ท โ†’ {script} แ€™แ€ฐแ€›แ€„แ€บแ€ธ spelling (แ€™แ€•แ€ผแ€ฑแ€ฌแ€„แ€บแ€ธแ€›แŠ แ€™แ€˜แ€ฌแ€žแ€ฌแ€™แ€•แ€ผแ€”แ€บแ€›)\n"
366
  f"{ex_lines}\n"
367
- f"Glossary แ€•แ€ซ โ†’ Glossary แ€กแ€แ€ญแ€ฏแ€„แ€บแ€ธ | แ€™แ€•แ€ซ โ†’ {script} แ€™แ€ฐแ€›แ€„แ€บแ€ธ"
368
  )
369
 
370
  # โ”€โ”€ Layer 4: TECH block (always identical) ๏ฟฝ๏ฟฝ๏ฟฝโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
371
 
372
  _TECH = """\
373
- RULES (non-negotiable):
374
- 1. Source แ€™แ€•แ€ซแ€žแ€ฑแ€ฌแ€กแ€›แ€ฌ แ€™แ€–แ€ผแ€Šแ€ทแ€บแ€› โ€” source แ€•แ€ซแ€žแ€ฑแ€ฌแ€กแ€›แ€ฌ แ€™แ€”แ€ฏแ€แ€บแ€›
375
- 2. แ€™แ€ผแ€”แ€บแ€™แ€ฌ speaker แ€žแ€˜แ€ฌแ€ word order แ€€แ€ญแ€ฏ แ€žแ€ฏแ€ถแ€ธ โ€” source language structure แ€€แ€ญแ€ฏ copy แ€™แ€€แ€ฐแ€ธแ€›
376
- 3. Same character = same pronoun + speech style แ€แ€…แ€บแ€žแ€ฌแ€ธแ€แ€Šแ€บแ€ธ
377
- 4. ASS tags ({\\an8} / {\\pos} / {\\be5} / {\\fad} etc.) + โ™ช + โŽ โ†’ as-is แ€‘แ€ฌแ€ธ
378
- 5. Glossary term โ†’ Glossary แ€‘แ€ฒแ€€ value แ€€แ€ญแ€ฏแ€žแ€ฌ แ€žแ€ฏแ€ถแ€ธแ€›แ€™แ€Šแ€บ
379
-
380
- COUNT: Input N items โ†’ output EXACTLY N items. Merge / split เธซเน‰เธฒเธกแ‹
381
- โŒ "แ€’แ€ซแ€žแ€Šแ€บ แ€€แ€ฑแ€ฌแ€„แ€บแ€ธแ€™แ€ฝแ€”แ€บแ€žแ€ฑแ€ฌแ€›แ€œแ€’แ€บแ€แ€…แ€บแ€แ€ฏแ€–แ€ผแ€…แ€บแ€žแ€Šแ€บ" โœ… "แ€’แ€ซแ€€แ€แ€ฑแ€ฌแ€ท แ€€แ€ฑแ€ฌแ€„แ€บแ€ธแ€แ€ฒแ€ท outcome แ€•แ€ฒ"
382
- โŒ "แ€žแ€„แ€บแ€žแ€Šแ€บ แ€คแ€”แ€ฑแ€›แ€ฌแ€แ€ฝแ€„แ€บ แ€˜แ€ฌแ€€แ€ผแ€ฑแ€ฌแ€„แ€ทแ€บแ€›แ€พแ€ญแ€”แ€ฑแ€žแ€”แ€Šแ€บแ€ธ" โœ… "แ€™แ€„แ€บแ€ธ แ€’แ€ฎแ€™แ€พแ€ฌ แ€˜แ€ฌแ€œแ€ฌแ€œแ€ฏแ€•แ€บแ€แ€ฌแ€œแ€ฒ"
383
- โŒ "แ€€แ€ฐแ€Šแ€ฎแ€•แ€ฑแ€ธแ€•แ€ซแŠ แ€€แ€ปแ€ฑแ€ธแ€‡แ€ฐแ€ธแ€•แ€ผแ€ฏแ" (source: "Help!") โœ… "แ€€แ€ฐแ€Šแ€ฎแ€•แ€ซ"
384
-
385
- Output: JSON array only, EXACTLY n items. No markdown, no explanation.
 
 
 
 
386
  ["แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ แ", "แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ แ‚", ..., "แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ n"]\
387
  """
388
 
@@ -508,6 +521,42 @@ def _strip_html(text: str) -> str:
508
  return re.sub(r'<[^>]+>', '', text)
509
 
510
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
  # Thread-local override for count-mismatch retry feedback
512
  # _translate_chunk_safe sets [0] = error message; _call_chunk_once injects it
513
  _chunk_once_override: list = [None]
@@ -774,7 +823,8 @@ def translate_all(
774
  session_state: dict | None = None,
775
  resume: bool = False,
776
  cooldown: float | None = None,
777
- system_prompt: str | None = None, # from build_system_prompt(); None = default
 
778
  ) -> list:
779
  """
780
  Translate subtitle text lines in chunks.
@@ -936,6 +986,11 @@ def translate_all(
936
  + (f" | {fallbacks} chunks original" if fallbacks else "")
937
  )
938
 
 
 
 
 
 
939
  # Final length guarantee
940
  assert len(result) == len(lines), \
941
  f"Length invariant broken: {len(result)} != {len(lines)}"
@@ -955,7 +1010,8 @@ def run_translation_bg(
955
  fmt: str,
956
  ssafile,
957
  filename: str,
958
- system_prompt: str | None = None, # from build_system_prompt()
 
959
  ) -> threading.Thread:
960
  """
961
  Spawn background thread for translation.
@@ -991,6 +1047,7 @@ def run_translation_bg(
991
  session_state=session_st,
992
  resume=bool(cp_init),
993
  system_prompt=system_prompt,
 
994
  )
995
 
996
  # Build output file
 
207
 
208
 
209
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
210
+ # Prompts โ€” Multi-Preset System (zero redundancy, each rule said once)
211
  #
212
  # Architecture: build_system_prompt() assembles 4 non-overlapping layers:
213
  # 1. STYLE โ€” tone / register / swearing (preset-specific)
214
  # 2. TERMS โ€” special terms to preserve (culture-specific)
215
  # 3. NOUNS โ€” proper noun handling (noun_style ร— culture, generated once)
216
+ # 4. TECH โ€” count rule / tags / glossary / output / examples (always identical)
217
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
218
 
219
+ # โ”€โ”€ Core philosophy (shared, referenced only by TECH) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
220
+ # Written once here for maintainability โ€” injected into _TECH below.
221
 
222
+ # โ”€โ”€ Layer 1: STYLE blocks (preset-specific) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
223
+ # Covers: who is speaking, what register, how to handle strong language.
224
+ # Does NOT repeat: "don't add/remove" (that's TECH), nouns (that's NOUNS).
225
+ #
226
+ # DEFAULT PRONOUN RULE (applies to all presets):
227
+ # แ€„แ€ซ/แ€™แ€„แ€บแ€ธ is the natural default for most dialogue.
228
+ # แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ only when the character is genuinely being servile/formal
229
+ # (e.g. servant to emperor, soldier to commanding officer, student to professor).
230
+ # Unknown gender โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ. Ambiguous context โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ.
231
+ # แ€™แ€†แ€ฏแ€ถแ€ธแ€–แ€ผแ€แ€บแ€”แ€ญแ€ฏแ€„แ€บแ€›แ€„แ€บ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ แ€žแ€ฏแ€ถแ€ธ โ€” แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ แ€™แ€žแ€ฏแ€ถแ€ธแ‹
232
 
233
  _STYLE_STANDARD = """\
234
+ You are a Myanmar subtitle translator. Output natural spoken Myanmar โ€” the way a real person talks, not the way a textbook translates.
235
+
236
+ VOICE: Reproduce the character's actual voice. Ask yourself: "แ€™แ€ผแ€”แ€บแ€™แ€ฌแ€œแ€ฐแ€แ€…แ€บแ€šแ€ฑแ€ฌแ€€แ€บ แ€’แ€ฎ situation แ€™แ€พแ€ฌ แ€แ€€แ€šแ€บ แ€˜แ€ฌแ€•แ€ผแ€ฑแ€ฌแ€™แ€œแ€ฒ?"
237
+ DEFAULT pronouns โ€” แ€„แ€ซ/แ€™แ€„แ€บแ€ธ for most characters. Only use แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ when the character is genuinely being servile or very formal (servant โ†’ master, cadet โ†’ commander). Unknown gender โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ.
238
+ โ€ข Rough / villain โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ/แ€€แ€ฑแ€ฌแ€„แ€บ + แ€€แ€ฝ/แ€—แ€ป/แ€€แ€ฝแ€ฌ (แ€™แ€†แ€ฒแ€› โ€” family-safe)
239
+ โ€ข Female casual โ†’ แ€„แ€ซ/แ€€แ€ปแ€™ + แ€€แ€ฝแ€ฌ/แ€Ÿแ€ฑแ€ท/แ€”แ€ฑแ€ฌแ€บ
240
+ โ€ข Gentle / romantic โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + แ€”แ€ฐแ€ธแ€Šแ€ถแ€ทแ€žแ€ฑแ€ฌแ€Ÿแ€”แ€บ
241
+ โ€ข Comic โ†’ แ€•แ€ผแ€ฑแ€ฌแ€•แ€ผแ€ฑแ€ฌแ€†แ€ญแ€ฏแ€†แ€ญแ€ฏ แ€•แ€ฑแ€ซแ€ทแ€•แ€ฑแ€ซแ€ทแ€•แ€ซแ€ธแ€•แ€ซแ€ธ
242
+ Strong language โ†’ source intensity แ€€แ€ญแ€ฏ family-safe แ€™แ€ผแ€”แ€บแ€™แ€ฌ equivalent แ€–แ€ผแ€„แ€ทแ€บ แ€‘แ€ญแ€”แ€บแ€ธแ€žแ€ญแ€™แ€บแ€ธ\
243
  """
244
 
245
  _STYLE_ADULT = """\
246
+ You are a Myanmar subtitle translator. Output natural spoken Myanmar โ€” the way a real person talks, not the way a textbook translates.
247
+
248
+ VOICE: Reproduce the character's actual voice. Ask yourself: "แ€™แ€ผแ€”แ€บแ€™แ€ฌแ€œแ€ฐแ€แ€…แ€บแ€šแ€ฑแ€ฌแ€€แ€บ แ€’แ€ฎ situation แ€™แ€พแ€ฌ แ€แ€€แ€šแ€บ แ€˜แ€ฌแ€•แ€ผแ€ฑแ€ฌแ€™แ€œแ€ฒ?"
249
+ DEFAULT pronouns โ€” แ€„แ€ซ/แ€™แ€„แ€บแ€ธ for most characters. Only use แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ when the character is genuinely being servile or formally subordinate. Unknown gender โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ.
250
+ โ€ข Rough / gang / villain โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ/แ€€แ€ฑแ€ฌแ€„แ€บ/แ€Ÿแ€ฑแ€ทแ€€แ€ฑแ€ฌแ€„แ€บ + แ€€แ€ฝ/แ€—แ€ป/แ€€แ€ฝแ€ฌ
251
+ โ€ข Female casual / hostile โ†’ แ€„แ€ซ/แ€”แ€„แ€บ + แ€€แ€ฝแ€ฌ/แ€Ÿแ€ฑแ€ท/แ€™
252
+ โ€ข Dominant / boss โ†’ แ€„แ€ซ + แ€•แ€ผแ€„แ€บแ€ธแ€‘แ€”แ€บแ€Ÿแ€”แ€บ
253
+ โ€ข Light / comic โ†’ แ€•แ€ผแ€ฑแ€ฌแ€•แ€ผแ€ฑแ€ฌแ€†แ€ญแ€ฏแ€†แ€ญแ€ฏ แ€•แ€ฑแ€ซแ€ทแ€•แ€ฑแ€ซแ€ทแ€•แ€ซแ€ธแ€•แ€ซแ€ธ
254
+ Strong language โ€” keep the exact weight of the source:
255
+ English source โ†’ English as-is (Fuck / Shit / Bitch / Bastard / Asshole)
256
+ Other language โ†’ nearest English equivalent\
257
  """
258
 
259
  _STYLE_ANIME = """\
260
+ You are a Myanmar subtitle translator. Output natural spoken Myanmar โ€” the way a real person talks, not the way a textbook translates.
261
+
262
+ VOICE: Reproduce the character's vocal personality. Ask yourself: "แ€™แ€ผแ€”แ€บแ€™แ€ฌแ€œแ€ฐแ€แ€…แ€บแ€šแ€ฑแ€ฌแ€€แ€บ แ€’แ€ฎ character แ€œแ€ญแ€ฏ แ€˜แ€ฌแ€•แ€ผแ€ฑแ€ฌแ€™แ€œแ€ฒ?"
263
+ DEFAULT pronouns โ€” แ€„แ€ซ/แ€™แ€„แ€บแ€ธ. Only use แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ for genuinely servile/formal moments (student โ†’ sensei in apology, servant to lord).
264
+ โ€ข Energetic / shonen โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + แ€€แ€ฝ/แ€—แ€ป แ€กแ€œแ€ฑแ€ทแ€€แ€ป
265
+ โ€ข Tsundere โ†’ แ€•แ€ผแ€แ€บแ€žแ€ฌแ€ธแ€•แ€ผแ€ฎแ€ธ แ€’แ€ฑแ€ซแ€žแ€•แ€ปแ€ฑแ€ฌแ€€แ€บแ€แ€„แ€บ โ€” แ€„แ€ซ/แ€™แ€„แ€บแ€ธ แ€แ€„แ€บแ€ธแ€แ€„แ€บแ€ธ
266
+ โ€ข Kuudere / cold โ†’ แ€แ€ญแ€ฏแ€แ€ญแ€ฏ แ€•แ€ผแ€แ€บแ€žแ€ฌแ€ธ แ€›แ€ญแ€ฏแ€ธแ€›แ€ญแ€ฏแ€ธ
267
+ โ€ข Cute / moe โ†’ แ€„แ€ซ/แ€€แ€ปแ€™ + particle: แ€”แ€ฑแ€ฌแ€บ/แ€›แ€พแ€„แ€บ + แ€žแ€ถแ€แ€ปแ€ญแ€ฏ
268
+ โ€ข Villain โ†’ แ€€แ€ผแ€™แ€บแ€ธ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ/แ€€แ€ฑแ€ฌแ€„แ€บ
269
+ Strong language โ†’ English as-is (Fuck / Shit / Bitch)\
270
  """
271
 
272
  _STYLE_CDRAMA = """\
273
+ You are a Myanmar subtitle translator. Output natural spoken Myanmar โ€” the way a real person talks, not the way a textbook translates.
274
+
275
+ VOICE: Preserve the dramatic weight and emotional layering of Chinese drama. Ask yourself: "แ€™แ€ผแ€”แ€บแ€™แ€ฌแ€œแ€ฐแ€แ€…แ€บแ€šแ€ฑแ€ฌแ€€แ€บ แ€’แ€ฎ scene แ€™แ€พแ€ฌ แ€˜แ€ฌแ€•แ€ผแ€ฑแ€ฌแ€™แ€œแ€ฒ?"
276
+ DEFAULT pronouns โ€” แ€„แ€ซ/แ€™แ€„แ€บแ€ธ. แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ only for genuine servile situations (servant before emperor, disciple before master in formal address).
277
+ โ€ข Commoner / young โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ colloquial
278
+ โ€ข Villain / schemer โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + แ€€แ€ผแ€™แ€บแ€ธแ€แ€™แ€บแ€ธแ€Ÿแ€”แ€บ
279
+ โ€ข Noble in private โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + dignified
280
+ โ€ข Noble in court ceremony โ†’ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ (genuine formal ritual only)
281
+ Poetic / dramatic lines โ†’ preserve emotional weight in natural Myanmar; แ€Ÿแ€”แ€บแ€†แ€”แ€บแ€†แ€”แ€บ formal Myanmar แ€™แ€žแ€ฏแ€ถแ€ธ\
282
  """
283
 
284
  _STYLE_KDRAMA = """\
285
+ You are a Myanmar subtitle translator. Output natural spoken Myanmar โ€” the way a real person talks, not the way a textbook translates.
286
+
287
+ VOICE: Preserve K-drama emotional intensity and sincerity. Ask yourself: "แ€™แ€ผแ€”แ€บแ€™แ€ฌแ€œแ€ฐแ€แ€…แ€บแ€šแ€ฑแ€ฌแ€€แ€บ แ€’แ€ฎ feeling แ€™แ€พแ€ฌ แ€˜แ€ฌแ€•แ€ผแ€ฑแ€ฌแ€™แ€œแ€ฒ?"
288
+ DEFAULT pronouns โ€” แ€„แ€ซ/แ€™แ€„แ€บแ€ธ. แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€™ only for genuine formal subordinate moments (employee to CEO in official setting, child formal apology to elder).
289
+ โ€ข Young adult / peers โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + แ€€แ€ฝแ€ฌ/แ€Ÿแ€ฑแ€ท/แ€—แ€ป
290
+ โ€ข Emotional / romantic โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + weight แ€€แ€ญแ€ฏแ€žแ€ญแ€™แ€บแ€ธ
291
+ โ€ข Chaebol / CEO (private) โ†’ แ€„แ€ซ/แ€™แ€„แ€บแ€ธ + measured
292
+ โ€ข Elder / authority (official) โ†’ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ/แ€€แ€ปแ€™ (genuine only)
293
+ Strong language โ†’ English as-is\
294
  """
295
 
296
  _STYLE_FORMAL = """\
297
+ You are a Myanmar subtitle translator for documentary, news, and educational content. Output clear, objective, educated standard Myanmar.
298
+
299
+ Register: Formal written Myanmar โ€” แ€•แ€Šแ€ฌแ€แ€แ€บ standard. No colloquial แ€„แ€ซ/แ€™แ€„แ€บแ€ธ โ€” use แ€žแ€„แ€บ/แ€€แ€ปแ€ฝแ€”แ€บแ€ฏแ€•แ€บ or avoid pronouns where natural.
300
+ โ€ข Narration โ†’ formal, neutral, third-person where possible
301
+ โ€ข Expert dialogue โ†’ semi-formal educated register
302
+ โ€ข Interview subject โ†’ natural but measured
303
+ Technical terms โ†’ precise Myanmar equivalent; if none exists, keep (English term) in parentheses.
304
+ Numbers / dates / statistics โ†’ exact.\
305
  """
306
 
307
  # โ”€โ”€ Layer 2: TERMS blocks (culture-specific special terms) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
308
 
309
+ _TERMS_WESTERN = ""
310
 
311
  _TERMS_JAPANESE = """\
312
+ Japanese terms (keep as-is โ€” these are NOT proper nouns, noun-style rule does not apply):
313
+ โ€ข Honorific suffixes: -san / -kun / -chan / -senpai / -sensei / -sama / -dono / -nii / -nee โ†’ keep or use natural Myanmar equivalent (Glossary wins)
314
+ โ€ข Anime/otaku: baka, kawaii, nakama, sugoi, yare yare, ara ara โ†’ English as-is
315
+ โ€ข Game/isekai system: HP, MP, Level, Skill, Quest, Guild, Status, Rank โ†’ English as-is
316
+ โ€ข Cultural: onsen, matsuri, bento, senpai-kouhai โ†’ English/Romaji as-is\
317
  """
318
 
319
  _TERMS_CHINESE = """\
320
+ Chinese terms (keep as-is โ€” these are NOT proper nouns, noun-style rule does not apply):
321
+ โ€ข Relationship/title: Shifu, Shidi/Shixiong/Shijie, Gege/Jiejie/Meimei/Didi, A'niang, Wangye, Gongzi, Guniang โ†’ Pinyin as-is
322
+ โ€ข Wuxia/Xianxia: Golden Core, Nascent Soul, cultivation, qi, meridians, sect, immortal, spiritual root โ†’ English/Pinyin as-is
323
+ โ€ข Court titles: Emperor, Empress, Crown Prince, Noble Consort, Imperial Guard โ†’ English as-is\
 
 
324
  """
325
 
326
  _TERMS_KOREAN = """\
327
+ Korean terms (keep as-is โ€” these are NOT proper nouns, noun-style rule does not apply):
328
+ โ€ข Relationship/honorifics: Oppa, Unnie, Hyung, Noona, Sunbae, Hoobae, Sajangnim, Seonsaengnim โ†’ Romanized as-is
329
+ โ€ข Speech level: ์กด๋Œ“๋ง โ†’ formal Myanmar register | ๋ฐ˜๋ง โ†’ colloquial Myanmar register
330
+ โ€ข Cultural: Ramyeon, Tteokbokki, Hanbok, Jjimjilbang, Aegyo โ†’ Romanized as-is\
 
331
  """
332
 
333
  _TERMS_THAI = """\
334
+ Thai/SE Asian terms (keep as-is โ€” these are NOT proper nouns, noun-style rule does not apply):
335
+ โ€ข Honorifics: Khun, Phi, Nong โ†’ Romanized as-is or natural Myanmar equivalent
336
+ โ€ข Cultural: Wai, Songkran, Muay Thai, Tuk-tuk โ†’ Romanized as-is\
337
  """
338
 
339
+ _TERMS_UNIVERSAL = ""
340
 
341
  # โ”€โ”€ Layer 3: NOUNS block (generated from noun_style ร— culture) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
342
 
343
  def _noun_block(style: str, culture_key: str) -> str:
 
344
  script = {
345
  "japanese": "Romaji",
346
  "chinese": "Pinyin",
 
351
  }.get(culture_key, "romanized")
352
 
353
  examples = {
354
+ "western": [("Victor","แ€—แ€…แ€บแ€แ€ฌ"), ("Hope Street","แ€Ÿแ€ฏแ€แ€บแ€•แ€บแ€…แ€‘แ€›แ€ญแ€แ€บ"), ("London","แ€œแ€”แ€บแ€’แ€”แ€บ")],
355
+ "japanese": [("Sasuke","แ€†แ€†แ€ฐแ€€แ€ฑ"), ("Tokyo","แ€แ€ญแ€ฏแ€€แ€ปแ€ญแ€ฏ"), ("Konoha","แ€€แ€ญแ€ฏแ€”แ€ญแ€ฏแ€Ÿแ€ฌ")],
356
+ "chinese": [("Wei Wuxian","แ€แ€ฑแ€แ€ฐแ€›แ€พแ€ปแ€ฌแ€ธ"), ("Beijing","แ€•แ€ฑแ€€แ€ปแ€„แ€บแ€ธ"), ("Yunmeng","แ€šแ€ฝแ€”แ€บแ€™แ€ญแ€”แ€บ")],
357
+ "korean": [("Park Seo-jun","แ€•แ€ซแ€ทแ€†แ€ฑแ€‚แ€ปแ€ฝแ€”แ€บ"), ("Seoul","แ€†แ€ญแ€ฏแ€ธแ€œแ€บ"), ("Busan","แ€•แ€ฐแ€†แ€™แ€บ")],
358
+ "thai": [("Prayuth","แ€•แ€ผแ€ฌแ€›แ€แ€บ"), ("Chiang Mai","แ€แ€ปแ€„แ€บแ€ธแ€™แ€ญแ€ฏแ€„แ€บ"), ("Bangkok","แ€˜แ€”แ€บแ€€แ€ฑแ€ฌแ€€แ€บ")],
359
+ "universal": [("Victor","แ€—แ€…แ€บแ€แ€ฌ"), ("Sakura","แ€†แ€ฌแ€€แ€ฐแ€›แ€ฌ"), ("Madison","แ€™แ€แ€บแ€’แ€…แ€บแ€†แ€„แ€บ")],
360
  }.get(culture_key, [("Victor","แ€—แ€…แ€บแ€แ€ฌ"), ("Hope Street","แ€Ÿแ€ฏแ€แ€บแ€•แ€บแ€…แ€‘แ€›แ€ญแ€แ€บ"), ("London","แ€œแ€”แ€บแ€’แ€”แ€บ")])
361
 
362
  if style == "phonetic":
363
+ ex_lines = "\n".join(f" {e} โ†’ {p}" for e, p in examples)
364
  return (
365
+ f"PROPER NOUNS โ€” Phonetic Myanmar:\n"
366
+ f"Names / places / organizations โ†’ Myanmar phonetic transliteration only (meaning-translation เธซเน‰เธฒเธก)\n"
367
  f"{ex_lines}\n"
368
+ f"Glossary แ€•แ€ซ โ†’ Glossary | แ€™แ€•แ€ซ โ†’ phonetic"
369
  )
370
  else:
371
+ ex_lines = "\n".join(f' "{e}" not "{p}"' for e, p in examples)
372
  return (
373
  f"PROPER NOUNS โ€” {script} spelling:\n"
374
+ f"Names / places / organizations โ†’ keep {script} original spelling unchanged\n"
375
  f"{ex_lines}\n"
376
+ f"Glossary แ€•แ€ซ โ†’ Glossary | แ€™แ€•แ€ซ โ†’ {script} แ€™แ€ฐแ€›แ€„แ€บแ€ธ"
377
  )
378
 
379
  # โ”€โ”€ Layer 4: TECH block (always identical) ๏ฟฝ๏ฟฝ๏ฟฝโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
380
 
381
  _TECH = """\
382
+ ABSOLUTE RULES:
383
+ 1. แ€™แ€•แ€ญแ€ฏแ€‘แ€Šแ€ทแ€บ แ€™แ€”แ€ฏแ€แ€บ โ€” source แ€™แ€•แ€ซแ€žแ€ฑแ€ฌแ€กแ€›แ€ฌ แ€™แ€–แ€ผแ€Šแ€ทแ€บแ€›แŠ แ€•แ€ซแ€žแ€ฑแ€ฌแ€กแ€›แ€ฌ แ€™แ€•แ€šแ€บแ€›
384
+ 2. แ€™แ€ผแ€”แ€บแ€™แ€ฌ word order โ€” source language sentence structure copy แ€™แ€€แ€ฐแ€ธแ€›
385
+ 3. แ€€แ€ญแ€ฏแ€šแ€บแ€›แ€ฑแ€ธ consistency โ€” same character แ€แ€…แ€บแ€€แ€ปแ€•แ€บแ€แ€Šแ€บแ€ธ pronoun + style แ€žแ€ฏแ€ถแ€ธ
386
+ 4. ASS tags ({\\an8} {\\pos} {\\be5} {\\fad} etc.) + โ™ช + โŽ โ†’ as-is แ€‘แ€ฌแ€ธ
387
+ 5. Glossary term แ€•แ€ซ โ†’ Glossary value แ€€แ€ญแ€ฏแ€žแ€ฌ แ€žแ€ฏแ€ถแ€ธแŠ แ€€แ€ฝแ€ฒแ€•แ€ผแ€ฌแ€ธแ€žแ€ฑแ€ฌแ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ แ€™แ€žแ€ฏแ€ถแ€ธแ€›
388
+
389
+ COUNT: Input N โ†’ output EXACTLY N. Merge / split เธซเน‰เธฒเธกแ‹
390
+
391
+ NATURAL vs AI โ€” แ€’แ€ฎ pattern แ€แ€ฑแ€€แ€ญแ€ฏ แ€›แ€พแ€ฑแ€ฌแ€„แ€บ:
392
+ โŒ "แ€’แ€ซแ€žแ€Šแ€บ แ€€แ€ฑแ€ฌแ€„แ€บแ€ธแ€™แ€ฝแ€”แ€บแ€žแ€ฑแ€ฌแ€›แ€œแ€’แ€บแ€แ€…แ€บแ€แ€ฏแ€–แ€ผแ€…แ€บแ€žแ€Šแ€บ" โœ… "แ€’แ€ซแ€€แ€แ€ฑแ€ฌแ€ท แ€€แ€ฑแ€ฌแ€„แ€บแ€ธแ€แ€ฒแ€ท outcome แ€•แ€ฒ"
393
+ โŒ "แ€žแ€„แ€บแ€žแ€Šแ€บ แ€คแ€”แ€ฑแ€›แ€ฌแ€žแ€ญแ€ฏแ€ท แ€˜แ€ฌแ€€แ€ผแ€ฑแ€ฌแ€„แ€ทแ€บแ€›แ€ฑแ€ฌแ€€แ€บแ€œแ€ฌแ€žแ€”แ€Šแ€บแ€ธ" โœ… "แ€™แ€„แ€บแ€ธ แ€’แ€ฎแ€™แ€พแ€ฌ แ€˜แ€ฌแ€œแ€ฌแ€œแ€ฏแ€•แ€บแ€แ€ฌแ€œแ€ฒ"
394
+ โŒ "แ€€แ€ปแ€ฝแ€”แ€บแ€ฏแ€•แ€บแ€€แ€ญแ€ฏ แ€€แ€ฐแ€Šแ€ฎแ€•แ€ฑแ€ธแ€•แ€ซ แ€€แ€ปแ€ฑแ€ธแ€‡แ€ฐแ€ธแ€•แ€ผแ€ฏแ" โœ… "แ€€แ€ฐแ€Šแ€ฎแ€•แ€ซ" / "แ€€แ€ฐแ€Šแ€ฎแ€€แ€ฝแ€ฌ"
395
+ โŒ "แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ แ€žแ€„แ€ทแ€บแ€€แ€ญแ€ฏ แ€แ€ปแ€…แ€บแ€•แ€ซแ€žแ€Šแ€บ" โœ… "แ€„แ€ซ แ€™แ€„แ€บแ€ธแ€€แ€ญแ€ฏ แ€แ€ปแ€…แ€บแ€แ€šแ€บ"
396
+ โŒ "แ€‘แ€ญแ€ฏแ€”แ€Šแ€บแ€ธแ€กแ€แ€ญแ€ฏแ€„แ€บแ€ธ แ€€แ€ปแ€ฝแ€”แ€บแ€ฏแ€•แ€บแ€แ€ญแ€ฏแ€ท แ€†แ€ฑแ€ฌแ€„แ€บแ€›แ€ฝแ€€แ€บแ€›แ€™แ€Šแ€บ" โœ… "แ€กแ€ฒแ€ทแ€œแ€ญแ€ฏแ€†แ€ญแ€ฏแ€›แ€„แ€บ แ€„แ€ซแ€แ€ญแ€ฏแ€ท แ€œแ€ฏแ€•แ€บแ€›แ€™แ€พแ€ฌแ€•แ€ฒ"
397
+
398
+ Output: JSON array, EXACTLY n items. No markdown, no preamble.
399
  ["แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ แ", "แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ แ‚", ..., "แ€˜แ€ฌแ€žแ€ฌแ€•แ€ผแ€”แ€บ n"]\
400
  """
401
 
 
521
  return re.sub(r'<[^>]+>', '', text)
522
 
523
 
524
+ # Pronoun substitution table โ€” applied after translation.
525
+ # Each entry: (pattern_string, replacement)
526
+ # Skipped for "formal" / "custom" presets.
527
+ _PRONOUN_SUBS: list[tuple] = [
528
+ # 1st person formal โ†’ natural
529
+ (r'แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ', 'แ€„แ€ซ'),
530
+ (r'แ€€แ€ปแ€ฝแ€”แ€บแ€™', 'แ€„แ€ซ'),
531
+ # 2nd person formal โ†’ natural
532
+ (r'แ€แ€„แ€บแ€—แ€ปแ€ฌแ€ธ', 'แ€™แ€„แ€บแ€ธ'),
533
+ ]
534
+ # Compile once
535
+ _PRONOUN_RE: list[tuple] = [
536
+ (re.compile(p), r) for p, r in _PRONOUN_SUBS
537
+ ]
538
+
539
+ def _naturalize_pronouns(text: str) -> str:
540
+ """
541
+ Replace formal pronouns with natural spoken equivalents.
542
+ แ€€แ€ปแ€ฝแ€”แ€บแ€แ€ฑแ€ฌแ€บ โ†’ แ€„แ€ซ | แ€€แ€ปแ€ฝแ€”แ€บแ€™ โ†’ แ€€แ€ปแ€™ | แ€แ€„แ€บแ€—แ€ปแ€ฌแ€ธ โ†’ แ€™แ€„แ€บแ€ธ
543
+ Applied after translation for all non-formal presets.
544
+ Does NOT touch ASS tags ({...}) or music markers.
545
+ """
546
+ # Don't touch content inside ASS override tag blocks
547
+ # Split on { } boundaries to protect tags
548
+ parts = re.split(r'(\{[^}]*\})', text)
549
+ out = []
550
+ for part in parts:
551
+ if part.startswith('{'):
552
+ out.append(part) # ASS tag โ€” untouched
553
+ else:
554
+ for pattern, replacement in _PRONOUN_RE:
555
+ part = pattern.sub(replacement, part)
556
+ out.append(part)
557
+ return ''.join(out)
558
+
559
+
560
  # Thread-local override for count-mismatch retry feedback
561
  # _translate_chunk_safe sets [0] = error message; _call_chunk_once injects it
562
  _chunk_once_override: list = [None]
 
823
  session_state: dict | None = None,
824
  resume: bool = False,
825
  cooldown: float | None = None,
826
+ system_prompt: str | None = None,
827
+ preset_key: str = "adult_18", # used to decide pronoun post-processing
828
  ) -> list:
829
  """
830
  Translate subtitle text lines in chunks.
 
986
  + (f" | {fallbacks} chunks original" if fallbacks else "")
987
  )
988
 
989
+ # โ”€โ”€ Post-process: naturalize pronouns (skip for formal/custom presets) โ”€โ”€
990
+ _SKIP_NATURALIZE = {"formal", "custom"}
991
+ if preset_key not in _SKIP_NATURALIZE:
992
+ result = [_naturalize_pronouns(line) for line in result]
993
+
994
  # Final length guarantee
995
  assert len(result) == len(lines), \
996
  f"Length invariant broken: {len(result)} != {len(lines)}"
 
1010
  fmt: str,
1011
  ssafile,
1012
  filename: str,
1013
+ system_prompt: str | None = None,
1014
+ preset_key: str = "adult_18",
1015
  ) -> threading.Thread:
1016
  """
1017
  Spawn background thread for translation.
 
1047
  session_state=session_st,
1048
  resume=bool(cp_init),
1049
  system_prompt=system_prompt,
1050
+ preset_key=preset_key,
1051
  )
1052
 
1053
  # Build output file