Metadata-Version: 2.4
Name: pylmtranslator
Version: 0.1.0
Summary: Offline pre-translator for RPG Maker MV/MZ LMTranslator cache files.
Author: NoteBlockMR
License-Expression: MIT
Project-URL: Homepage, https://github.com/NoteBlockMR/LMRPGTranslator-Python
Project-URL: Repository, https://github.com/NoteBlockMR/LMRPGTranslator-Python
Project-URL: Issues, https://github.com/NoteBlockMR/LMRPGTranslator-Python/issues
Keywords: rpg-maker,translation,lm-studio,local-llm
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Games/Entertainment :: Role-Playing
Classifier: Topic :: Software Development :: Localization
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Dynamic: license-file

# LMRPGTranslator-Python

RPG Maker MV/MZ/XP/VX/VX Ace 게임의 **메시지를 추출 → 로컬 LLM(LM Studio)로 번역 → 적용**하는 오프라인 사전 번역기입니다.

기존 [LMTranslator.js](https://github.com/NoteBlockMR/LMRPGTranslator) 플러그인이 게임 플레이 중 **실시간**으로 번역하는 것과 달리, 이 도구는 게임을 켜기 전에 **미리 전부 번역**해 둡니다. 실시간 API 호출로 인한 렉이 없고, 번역 품질을 미리 검수할 수 있습니다.

> 원문은 그대로 두지 않고 두 가지 방식으로 "적용"할 수 있습니다.
> 1. **캐시 파일**(`LMTranslatorCache.json`) 생성 → MV/MZ의 LMTranslator.js 플러그인이 런타임에 읽어 표시
> 2. **게임 데이터 파일에 직접 덮어쓰기** (`--apply`) → 플러그인 없이도 번역 적용 (원본은 `.bak` 백업)

---

## 🚀 빠른 시작

```bash
pip install pylmtranslator
```

PyPI 릴리스 전 최신 GitHub 버전을 바로 설치하려면:

```bash
pip install git+https://github.com/NoteBlockMR/LMRPGTranslator-Python.git
```

RPG Maker 게임의 데이터 폴더가 있는 위치에서 실행합니다.

- MV/MZ: `data/` 또는 `www/data/`
- XP/VX/VX Ace: `Data/`

```bash
lmt
```

처음 실행하면 현재 폴더에 `config.yml`이 생성되고, 설정 내용이 터미널에 출력됩니다. `model`, `language`, `paths.data_dir`, `characters` 등을 수정한 뒤 다시 실행하세요.

```bash
lmt
```

캐시를 만든 뒤 게임 JSON 파일에 직접 적용하려면:

```bash
lmt --apply
```

---

## ✨ 특징

- **정확한 메시지 추출**: 메시지창(101/401), 스크롤 텍스트(105/405), 주석의 `<ActiveMessage>`(108/408)
- **Ruby 엔진 지원**: XP(`.rxdata`), VX(`.rvdata`), VX Ace(`.rvdata2`)의 Ruby Marshal 데이터를 직접 읽고 씀
- **이름박스/제어코드 보존**: `\n<...>` 화자 박스, `\N[id]` 배우 코드, `\C[n]`, `\I[n]`, `\.` 등 RPG Maker 제어코드를 그대로 유지
- **화자별 캐릭터 프롬프트**: 등장인물 성격/말투에 맞춘 번역
- **이름/용어 고정표(glossary)**: 인명·용어의 한글 표기를 일관되게 고정, 오표기 자동 보정
- **언어 검증 + 재시도**: 대상이 한국어인데 결과에 한글이 없으면 자동 재요청
- **원문 백업 + 재개**: 추출 결과를 백업해 두고, 중단되면 다음 실행 때 이어서 번역
- **크래시 안전 캐시**: 일정 개수마다 원자적으로 저장
- **진행률/ETA 표시**

---

## 📦 설치

Python 3.8+ 와 [LM Studio](https://lmstudio.ai/)가 필요합니다.

### PyPI에서 설치

```bash
pip install pylmtranslator
```

### GitHub에서 최신 버전 설치

```bash
pip install git+https://github.com/NoteBlockMR/LMRPGTranslator-Python.git
```

설치 후 `lmt` 명령을 사용할 수 있습니다.

```bash
lmt --help
```

소스에서 직접 실행하려면 다음처럼 의존성을 설치한 뒤 기존 스크립트 명령도 사용할 수 있습니다.

```bash
pip install -r requirements.txt
python lm_pretranslate.py --help
```

외부 의존성은 `PyYAML` 하나뿐입니다(설정 파일 파싱용). 나머지는 모두 Python 표준 라이브러리입니다.

LM Studio에서 모델을 로드하고 **Local Server → Start Server**(기본 포트 1234)를 켜 두세요.

---

## 🚀 사용법

### 1. 설정 (`config.yml`)

처음 실행하면 현재 폴더에 기본 `config.yml`이 생성됩니다.

```yaml
engine: "auto"              # auto, mv_mz, xp, vx, vxace

api:
  url: "http://localhost:1234/v1/chat/completions"
  model: "your-model-name"   # LM Studio에 로드된 모델 이름
  concurrency: 1             # 동시 번역 요청 수
  request_cooldown_ms: 0     # 오프라인 배치에서는 0이 가장 빠름

language:
  source: "English"          # 원문 언어
  target: "Korean"           # 번역 대상 언어

paths:
  data_dir: "data"           # MV/MZ는 data, XP/VX/VX Ace는 Data

rgss:
  encoding: "utf-8"          # XP/VX/VX Ace 문자열 인코딩. 필요 시 cp932/cp949

glossary: |
  Vore=보어|포어

characters:
  # 캐릭터별 말투 보정이 필요하면 아래처럼 추가합니다.
  # name 은 게임 메시지의 화자 이름과 정확히 같아야 합니다.
  - name: "Maria"
    personality: "차분하고 정중하지만 단호한 말투. 상대를 가볍게 놀리듯 말함."
    custom_prompt: ""

  - name: "Guard"
    personality: "거칠고 짧게 말하는 경비병. 명령조와 반말을 자주 사용함."
    custom_prompt: ""
```

캐릭터별 말투가 필요 없으면 `characters` 항목은 비워둬도 됩니다. 더 강하게 지시하고 싶은 캐릭터는 `custom_prompt`에 전용 프롬프트를 넣을 수 있습니다.

```yaml
characters:
  - name: "Narrator"
    personality: "담담하고 문학적인 나레이션."
    custom_prompt: |
      You are a professional game translator.
      Translate into natural Korean narration.
      Output only the translation.
```

프롬프트, 캐릭터 성격, 이름 고정표 등 자세한 항목은 생성된 `config.yml` 주석을 참고하세요.

### XP/VX/VX Ace 사용

XP/VX/VX Ace는 JSON이 아니라 Ruby Marshal 데이터 파일을 사용합니다.

| 엔진 | 데이터 파일 | 설정 |
|---|---|---|
| RPG Maker XP | `Data/*.rxdata` | `engine: "xp"` |
| RPG Maker VX | `Data/*.rvdata` | `engine: "vx"` |
| RPG Maker VX Ace | `Data/*.rvdata2` | `engine: "vxace"` |

`engine: "auto"`이면 데이터 폴더의 확장자를 보고 자동으로 감지합니다.

```yaml
engine: "vxace"

paths:
  data_dir: "Data"

rgss:
  encoding: "utf-8"
```

일본어 XP/VX 게임에서 글자가 깨지면 `rgss.encoding`을 `cp932`로 바꿔 보세요. 한국어 구형 게임 데이터라면 `cp949`가 맞을 수 있습니다.

### 2. 번역 (추출 → 캐시)

```bash
lmt
```

- 데이터 폴더의 모든 메시지를 추출해 원문을 백업(`LMTranslator_source.json`)하고, LM Studio로 번역해 캐시(`LMTranslatorCache.json`)에 저장합니다.
- 중단해도 다음 실행 때 캐시에 없는 것만 이어서 번역합니다(재개).

### 3. 적용 (캐시 → 게임 파일)

```bash
lmt --apply
```

- 캐시의 번역문을 `Map*.json`, `Map*.rvdata2` 등 데이터 파일에 **직접 덮어씁니다.** 원본은 최초 1회 `.bak`로 백업됩니다.
- 이 방식은 플러그인 없이 번역이 적용됩니다.

> 캐시 파일 방식은 MV/MZ의 LMTranslator.js 플러그인용입니다. XP/VX/VX Ace는 `--apply`로 Ruby 데이터 파일에 직접 적용하는 흐름을 사용하세요.

### 옵션

| 옵션 | 설명 |
|---|---|
| `--config <파일>` | 설정 파일 지정 (기본 `config.yml`) |
| `--dry-run` | 추출/미리보기만, 번역은 하지 않음 |
| `--limit N` | 앞 N개만 번역(테스트용) |
| `--no-resume` | 캐시를 무시하고 전부 다시 번역 |
| `--rescan` | 원문 백업을 무시하고 data 폴더를 다시 스캔 |
| `--apply` | 캐시를 게임 파일에 직접 덮어쓰기(+`.bak`) |

---

### DB 번역 안전장치

`scan.translate_database: true`를 켜면 아이템, 스킬, 장비, 상태, 시스템 용어 같은 DB 텍스트도 번역합니다. 적용할 때는 플러그인 오류를 피하기 위해 다음 토큰이 원문과 번역문에서 정확히 같은 경우에만 덮어씁니다.

- RPG Maker 제어코드: `\c[20]`, `\I[1]`, `\V[3]` 등
- 플러그인/노트 태그: `<Custom Eval>`, `<Enable Switch: 1>` 등
- 포맷 자리표시자: `%1`, `%2` 등

번역 모델이 이 토큰을 지우거나 바꾸면 해당 DB 항목은 원문을 유지하고, 적용 로그에 `안전하지 않은 DB 번역`으로 표시됩니다.

---

## ⚙️ 동작 원리

1. MV/MZ는 `data/*.json`, XP/VX/VX Ace는 `Data/*.rxdata/.rvdata/.rvdata2`를 스캔해 이벤트 커맨드(메시지/스크롤/주석)를 찾습니다.
2. 화자 이름과 본문을 분리하고(`\N[id]`는 배우 이름으로 해석), `화자||원문`을 키로 사용합니다.
3. 화자별 시스템 프롬프트 + 용어 고정표로 LM Studio에 번역을 요청합니다.
4. 언어 검증을 통과한 결과만 캐시에 저장합니다.
5. `--apply` 시 동일한 키 매칭으로 원문을 번역문으로 교체하되, 이름박스·제어코드·줄 구조는 보존합니다.

---

## ⚠️ 주의사항

- **저작권**: 이 저장소에는 게임 데이터(`data/`)가 포함되지 않습니다. 번역할 게임의 데이터는 본인이 정당하게 보유한 것이어야 합니다.
- **줄 밀림(overflow)**: 직접 적용(`--apply`) 방식은 런타임 자동 줄바꿈이 없습니다. 번역문이 길면 메시지창을 넘칠 수 있습니다(프롬프트로 줄 수를 제한하지만 완벽하지 않음).
- **백업**: `--apply`는 각 파일을 최초 1회 `.bak`로 백업합니다. 재번역하려면 `.bak`에서 복원하거나 원문 백업(`LMTranslator_source.json`)을 활용하세요.
- **모델 품질**: 작은 모델일수록 오역·제어코드 손상 가능성이 높습니다. 사전 번역이므로 속도보다 품질 좋은 모델을 권장합니다.

* 💖 [Patreon에서 후원하기](https://www.patreon.com/c/AINote/membership)
* 🌟 [AINote 멤버십 가입](https://www.patreon.com/c/AINote/membership)

---

## 📄 라이선스

MIT

---

## 🚢 관리자용: PyPI 배포 설정

PyPI Trusted Publisher 등록 폼에는 다음 값을 입력하세요.

| 항목 | 값 |
|---|---|
| PyPI 프로젝트 이름 | `pylmtranslator` |
| 소유자 | `NoteBlockMR` |
| 저장소 이름 | `LMRPGTranslator-Python` |
| Workflow 이름 | `publish.yml` |
| 환경 이름 | `pypi` |

GitHub에서 새 Release를 발행하거나 Actions에서 `Publish Python package` workflow를 수동 실행하면 PyPI에 업로드됩니다.

배포 전에 `pyproject.toml`의 `version` 값을 올려야 합니다. PyPI는 같은 버전 번호를 두 번 업로드할 수 없습니다.
