대규모 언어 모델(LLMs), 예를 들어 ChatGPT는 강력한 번역가로서의 능력을 보여주었습니다. 이는 문맥적 이해를 바탕으로 일반적인 자연어뿐만 아니라 단어 배열 무작위화(word scrambling)와 같은 비정형적인 형태의 글쓰기도 처리할 수 있습니다. 하지만, 정확한 지침을 따르도록 지시하고 모델 temperature 매개변수를 0로 설정하더라도, 항상 결정론적인 출력을 생성하거나 라인별 상관관계를 지키지 못하여 자막의 타이밍을 방해할 수 있습니다.
이 유틸리티는 OpenAI ChatGPT API를 사용하여 텍스트를 번역하며, 특히 SRT 자막에 초점을 맞춘 라인 기반 번역을 수행합니다. 이 번역기는 SRT 오버헤드를 제거하고 텍스트를 배치로 그룹화하여 토큰 사용량을 최적화함으로써, 과도한 토큰 소비 없이 임의 길이의 번역을 보장하는 동시에 입력 라인과 출력 간에 일대일 매칭을 유지합니다.
기능
- 웹 사용자 인터페이스(Web UI) 및 커맨드 라인 인터페이스(CLI)
- 구조화된 출력 (Structured Output): 더 간결한 결과를 위해 지원하며, Web UI와 CLI에서 기본적으로 활성화됩니다.
- 프롬프트 캐싱 (Prompt Caching): 번역된 데이터의 전체 컨텍스트, 시스템 명령어 및 번역 컨텍스트를 포함하여 패키징되므로 프롬프트 캐싱과 잘 작동합니다. 이는
-c, --context로 제어됩니다 (CLI 전용).
- Ollama(https://ollama.com/)와 같이 OpenAI API와 호환되는 모든 제공업체를 지원하며 로컬에서 실행할 수 있습니다.
- 라인 기반 배치 처리: 요청당 토큰 제한을 방지하고, 오버헤드 토큰 낭비를 줄이며, 일정 수준까지 번역 컨텍스트를 유지합니다.
- 선택적 OpenAI 검열 도구 확인: 모델이 번역을 거부할 가능성이 매우 높을 경우 토큰 낭비를 방지하며,
--use-moderator로 활성화됩니다 (CLI 전용).
- 스트리밍 프로세스 출력
- 분당 요청 수(RPM) 속도 제한 (rate limits)
- 진행 상황 재개 (CLI 전용)
설정
참고: https://github.com/openai/openai-quickstart-node#setup
- Node.js 버전
>= 20이 필요합니다. 이 README는 bash 셸 환경을 가정합니다.
- 이 저장소를 클론합니다
git clone https://github.com/Cerlancism/chatgpt-subtitle-translator
- 디렉토리로 이동합니다
```bash
cd chatgpt-subtitle-translator
npm install
- 실행 권한을 부여합니다
```bash
chmod +x cli/translator.mjs
.env.example을 .env로 복사합니다
cp .env.example .env
- 새로 생성된 `.env` 파일에 제공업체 API 키를 추가합니다. OpenAI가 아닌 제공업체의 경우, `OPENAI_BASE_URL`을 해당 OpenAI 호환 `/v1` 엔드포인트로 설정합니다 (`.env.example`의 주석 처리된 예시 참조).
## CLI
```bash
cli/translator.mjs --help
사용법: translator [옵션]
ChatGPT API 기반 번역 도구
옵션:
-
--from <언어>
소스 언어 (기본값: "")
-
--to <언어>
타겟 언어 (기본값: "English")
-
-s, --system-instruction <지침>
프롬프트 시스템 지침 템플릿 Translate ${from} to ${to}를 이 텍스트로 재정의하며, --from 및 --to 옵션을 무시합니다
-
-i, --input <파일>
.srt 형식 또는 일반 텍스트 파일의 내용으로 구성된 입력 소스 텍스트
-
-o, --output <파일>
출력 파일 이름. 입력 파일 이름을 기반으로 기본 설정됨
-
-r, --structured <모드>
구조화된 응답 형식 모드. (기본값: array, 선택지: array, object, timestamp, agent, none)
array: 입력과 출력을 배열 형식으로 구조화합니다.
object: 입력과 출력을 키가 지정된 객체로 구조화합니다.
timestamp: 각 항목의 텍스트와 함께 시작 시간을 제공하여(배치 시작 시점 대비 밀리초 단위의 개별 항목 오프셋/길이), 인접한 항목을 하나로 병합할 수 있게 합니다. 배치는 출력 시간 범위 경계가 입력과 일치하지 않을 때만 재시도하며 (다른 모드들은 모든 줄 수 불일치에 대해 재시도하는 것과 달리) 재시도로 인한 토큰 낭비를 크게 줄입니다. 입력 및 출력의 타임스탬프 때문에 배치당 더 많은 토큰을 사용합니다. 출력 항목 수는 입력과 다를 수 있으므로 진행 파일 재개는 지원되지 않습니다.
agent: 기본 옵션이 적용된 agent 서브커맨드에 대한 별칭입니다. 전체 구성을 위해서는 전용 서브커맨드를 사용하십시오. Agent Mode 참조.
none: 레거시 호환성 모드로, 구조화된 출력을 비활성화합니다.
-
-c, --context <토큰>
프롬프트 캐싱과 잘 작동하도록 토큰 예산까지 번역 기록을 포함합니다. 기본값: 2000. 제한 없는 기록을 포함하려면 0으로 설정하십시오.
권장 값: 현재 배치와 시스템 프롬프트를 위한 여유 공간을 확보하기 위해 <tokens>를 모델의 최대 컨텍스트 길이의 약 50%로 설정하십시오. 예를 들어, 128K 컨텍스트 모델의 경우: --context 64000. --batch-sizes가 생략된 경우, 배치 크기는 이 예산으로부터 파생됩니다.
-
-b, --batch-sizes <sizes>
JSON 배열 형식으로 번역 프롬프트 슬라이스에 대한 증가 순서의 배치 크기
각 번역 프롬프트에 포함할 줄 수의 개수이며, 이 줄들이 토큰 제한 내에 있을 것으로 추정됩니다.
출력된 줄 수의 양이 일치하지 않는 경우, 이 숫자는 배열의 값에 따라 단계적으로 감소하며 궁극적으로 1에 도달합니다.
배치 크기가 클수록 일반적으로 더 효율적인 토큰 활용을 가져오고 잠재적으로 더 나은 문맥적 번역을 제공합니다.
하지만 출력된 줄 수의 양이 일치하지 않거나 토큰 제한을 초과하면 토큰 낭비가 발생하여, 더 작은 배치 크기로 배치를 재전송해야 합니다.
생략된 경우, 배치 크기는 --context 토큰 예산에 따라 배치별로 자동으로 결정됩니다. 각 배치는 트림(trim)으로 인해 확보된 컨텍스트 창의 부분에 여러 개의 히스토리 배치가 들어갈 수 있도록 크기가 조정되며, 프롬프트 캐시를 활성화 상태로 유지합니다. 입력 토큰당 히스토리 비용은 번역된 배치로부터 측정됩니다. 이 크기는 남은 줄들에 균등하게 분배되며 배치당 100줄로 제한됩니다. 실패 시, 크기가 줄어들고 재시도하며; 최소값에 도달하면 번역은 단일 항목 모드로 전환됩니다. 감소 후에는 연속적으로 성공하는 배치를 따라 단계적으로 다시 증가합니다.
-
-g, --guard-repetition <threshold>
스트리밍 응답을 중단하기 전의 패턴 반복 최소 횟수 (기본값: 10). 모델이 스트리밍 중에 반복 루프에 빠지면, 응답은 중단되고 더 작은 배치로 재시도됩니다. 이를 0으로 설정하면 반복 감지가 비활성화됩니다.
-
--initial-prompts <prompts>: 번역을 위한 초기 프롬프트 (JSON 형식) (기본값: "[]")
--use-moderator: OpenAI Moderation 도구 사용
--moderation-model <model>: (기본값: "omni-moderation-latest") https://developers.openai.com/api/docs/models
--no-prefix-number: 라인 앞에 숫자 인덱스를 붙이지 않음. -r, --structured array|object|timestamp에서는 무시됨 - 이 경우 접두사 숫자는 항상 비활성화됩니다.
--no-line-matching: 일대일 라인 수량 입력/출력 매칭을 강제하지 않음. -r, --structured timestamp에서는 무시됨 - 항목이 병합될 수 있으므로 라인 매칭은 항상 비활성화됩니다.
-p, --plain-text <text>: 이 일반 텍스트 인수로 입력 소스 텍스트를 제공합니다. -r, --structured timestamp 모드 또는 agent 하위 명령어를 -r timestamp와 함께 사용할 때는 지원되지 않습니다.
--no-stream: 터미널로 스트림 진행 출력을 비활성화합니다 (기본값으로 스트리밍이 켜져 있습니다).
--log-level <level>: 로그 레벨 (기본값: debug, 선택지: trace, debug, info, warn, error, silent)
--silent: --log-level silent와 동일합니다.
--quiet: --log-level silent와 동일합니다.
GPT용 추가 옵션: https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create
-m, --model <모델>
(기본값: "gpt-4o-mini") https://developers.openai.com/api/docs/models
--reasoning_effort <reasoning_effort>
추론 모델의 추론 노력에 제약을 가합니다. 허용되는 값은 모델에 따라 다릅니다 (예: "low", "medium", "high"). 설정하지 않으면 모델 기본값을 따르며, "none"을 사용하면 추론/사고 과정을 완전히 비활성화합니다 (OpenAI o-series/GPT-5+ 및 Ollama를 통한 Qwen3와 같은 오픈 모델에서 지원).
-t, --temperature <temperature>
사용할 샘플링 온도입니다. 번역의 결정성을 높이려면 0과 같이 낮은 값을 설정해야 합니다 (기본값: 0).
--top_p <top_p>
핵심 샘플링(Nucleus sampling) 매개변수, top_p 확률 질량입니다.
--presence_penalty <presence_penalty>
지금까지의 텍스트에서 토큰이 존재하는 것에 기반한 패널티입니다.
--frequency_penalty <frequency_penalty>
지금까지의 텍스트에서 토큰이 출현하는 빈도에 기반한 패널티입니다.
--logit_bias <logit_bias>
완성(completion) 과정에서 특정 토큰이 나타날 가능성을 수정합니다.
에이전트 모드 (Agent Mode)
다중 패스 에이전트 기반 번역을 위한 하위 명령어입니다. 모든 표준 번역 옵션을 허용합니다.
cli/translator.mjs agent --help
에이전트 모드는 번역 전에 여러 단계를 거칩니다:
개요 (Overview) - 파일 샘플링을 통해 콘텐츠 개요(파일 식별자, 길이, 장르/톤, 등장인물 이름)를 생성하고 원본 언어를 감지합니다.
계획 수립 (Planning) - 토큰 경계가 있는 창으로 파일을 스캔합니다. 각 창은 배치 요약(등장인물, 장소, 사건, 톤)을 생성합니다. 이 요약들은 통합되어 정제된 번역 지침을 생성하는 데 사용됩니다.
번역 (Translation) - 풍부해진 지침을 사용하여 번역을 수행합니다. 첫 번째 배치 이후에는 진행하기 전에 대상 언어를 확인하기 위해 출력 샘플이 검사됩니다.
구조화된 모드(Structured mode)는 기본적으로 array를 사용하며, 타임스탬프 모드를 사용하려면 --structured timestamp를 전달하십시오.
cli/translator.mjs agent --input subtitles.srt --from Japanese --to English
...
--no-refine
계획 단계 끝의 최종 지침 정제 단계를 건너뛰고 원래 시스템 지침을 직접 사용합니다.
--no-fitting
계획 요약 및 통합을 위한 LLM 기반 토큰 범위 맞춤화를 건너뜁니다. 요약은 토큰 범위와 관계없이 있는 그대로 사용됩니다.
--context-summary <요약>
문맥 요약을 직접 제공하여 계획 단계를 완전히 우회하고 바로 번역으로 진행합니다.
예시
일반 텍스트
cli/translator.mjs --plain-text "你好"
표준 출력
이모지
cli/translator.mjs --to "Emojis" --plain-text "Chuck Norris can walk with the animals, talk with the animals; grunt and squeak and squawk with the animals... and the animals, without fail, always say 'yessir Mr. Norris'."
표준 출력
👨🦰💪🚶♂️🦜🐒🐘🐅🐆🐎🐖🐄🐑🦏🐊🐢🐍🐿️🐇🐿️❗️🌳💬😲👉🤵👨🦰👊=🐕🐑🐐🦌🐘🦏🦍🦧🦓🐅🦌🦌🦌🐆🦍🐘🐘🐗🦓=👍🤵.
혼란시키기 (Scrambling)
cli/translator.mjs --system-instruction "단어의 시작과 끝 글자만 유지하면서 문자를 무작위로 섞으시오" --no-prefix-number --no-line-matching --plain-text "Chuck Norris can walk with the animals, talk with the animals;"
표준 출력
Cuhck Nroris can wakl wtih the aiamnls, talk wtih the aiamnls;
원래대로 복구하기 (Unscrambling)
cli/translator.mjs --system-instruction "문자를 영어로 되돌려 복구하시오" --no-prefix-number --no-line-matching --plain-text "Cuhck Nroris can wakl wtih the aiamnls, talk wtih the aiamnls;"
표준 출력
Chuck Norris can walk with the animals, talk with the animals;