Files
tts_bot/README.md
Claude Owner 94a39e0d45 chore(docker): switch to node:22-bookworm-slim and add .env.example
- Dockerfile base now node:22-bookworm-slim (glibc) so better-sqlite3
  uses prebuilt binaries and node-gyp/python build deps are no longer
  required. Also satisfies @discordjs/voice node>=22.12 engine req.
- Drop redundant `mkdir -p dist` (build script handles it).
- Add .env.example covering TOKEN, APPID, PREFIX, DBPATH, GUILDID,
  CHZZK_NID_AUT/SES, SIGNATURE_HOST, TTSPATH, DEV, DEBUG, REPLACETEXT.
- README: update base image note.
2026-05-27 20:54:00 +09:00

118 lines
5.6 KiB
Markdown

# tts_bot
Discord 음성채널에서 채팅을 읽어주는 TTS 봇. TypeScript + discord.js 기반.
## 주요 기능
- 지정한 텍스트 채널의 채팅을 음성채널에서 자동 낭독 (`/tts channel register`로 채널 지정)
- 치지직(Chzzk) 알림 TTS 엔진 사용 (`utils/tts/Chzzk.ts`). 현재 코드는 `VoiceType.가람` 고정 (`VoiceType` enum에 다른 보이스도 정의돼 있어 코드 한 줄 수정으로 교체 가능)
- 대체 엔진으로 Google Translate TTS 구현체(`utils/tts/Google.ts`)가 포함돼 있으나 현재 비활성(`TTSClient.ts`에서 import 주석 처리). 사용하려면 import 교체 필요
- 시그니처(짤·효과음) 재생: 외부 시그니처 서버(`192.168.10.5:2967`)와 WebSocket으로 동기화해 채팅 중 키워드 매칭 시 mp3 삽입
- URL, 멘션, 이모지, 자주 쓰는 초성(ㄹㅇ, ㅇㅋ 등)을 자동 치환해 읽음
- 10분 idle 후 음성채널 자동 퇴장, 사용자 음성채널 이동 시 따라가기
## 명령어
| 명령어 | 설명 |
| --- | --- |
| `/tts channel make` | "TTS채널" 텍스트 채널을 새로 만들고 등록 |
| `/tts channel register [channel|channel_id]` | 기존 텍스트 채널을 TTS 입력 채널로 등록 |
| `/시그니처` (`/signature`) | 시그니처 관리 사이트 링크 |
| `/help` (`/도움말`) | 명령어 목록 |
| `/ping` (`/핑`) | 응답 지연 확인 |
메시지 prefix(`PREFIX` 환경변수)로도 `help`/`ping`/`시그니처`/`example`은 동일하게 호출된다. `tts`는 슬래시 전용이며, prefix `tts`는 현재 더미 응답("예시 명령어")만 보낸다.
## 기술 스택
- Node.js 20 (Dockerfile 기준) / TypeScript (strict 모드)
- `discord.js` v14, `@discordjs/voice`, `@discordjs/opus`
- `better-sqlite3` — 길드별 등록 채널 저장 (`db/schema.sql`)
- `fluent-ffmpeg` + `ffmpeg-static` — 시그니처 mp3 볼륨 조절, PCM 변환
- `ws` — 시그니처 서버 동기화
- `axios` — Chzzk / Google TTS HTTP 호출
## 디렉터리 구조
```
src/
index.ts # 엔트리: 싱글톤(client, handler, tts, signature) 구성
classes/
BotClient.ts # discord.js Client 확장 (embed/메시지 삭제 헬퍼)
Handler.ts # commands/ 자동 로드 및 슬래시 라우팅
TTSClient.ts # 메시지 → TTS 변환 파이프라인
VoiceSession.ts # 길드별 음성 연결/플레이어 관리
SignatureClient.ts # 시그니처 서버 WS 연결 + 파일 캐싱
commands/ # tts, signature, help, ping, example
events/ # clientReady, interactionCreate, messageCreate, voiceStateUpdate
utils/
Config.ts # 환경변수 게터 (누락 시 ReferenceError)
Database.ts # better-sqlite3 래퍼 (guild/user CRUD)
Logger.ts # colors 기반 타임스탬프 로거
Transcode.ts # mp3 Buffer → 48k/16bit/stereo PCM 스트림
Prod-commands.ts # 전역 슬래시 명령어 일괄 등록 스크립트
tts/ # Chzzk, Google, Utils(치환 사전)
db/
schema.sql # guilds, users 테이블
db.d.ts # 타입 정의
```
## 환경 변수
`.env` 또는 시스템 환경변수로 설정. 모든 값은 `Config.ts`에서 trim 후 읽음.
| 키 | 필수 | 설명 |
| --- | --- | --- |
| `APPID` | ✅ | Discord 애플리케이션 ID |
| `TOKEN` | ✅ | 봇 토큰 |
| `PREFIX` | ✅ | 메시지 명령어 prefix (예: `!`) |
| `DBPATH` | ✅ | SQLite 파일 경로 (예: `./db/data.db`) |
| `CHZZK_NID_AUT` | ✅ | 네이버 NID_AUT 쿠키 (치지직 TTS 인증) |
| `CHZZK_NID_SES` | ✅ | 네이버 NID_SES 쿠키 |
| `GUILDID` | △ | `DEV=true`일 때만 사용 (DEV 길드 한정 슬래시 등록 대상). 그 외에는 미설정이어도 무방 |
| `DEV` | 선택 | `true`면 글로벌 대신 `GUILDID`에만 슬래시 등록 |
| `DEBUG` | 선택 | `true`면 명령어 오류 스택 로깅 |
| `REPLACETEXT` | 선택 | 치환 사전(JSON 배열). 기본 사전(`def_replaceObj`)과 병합 |
| `SIGNATURE_HOST` | 선택 | 시그니처 서버 `host:port`. 미설정 시 `192.168.10.5:2967` 기본값 |
| `TTSPATH` | 선택 | `Config.ttsPath` getter만 정의돼 있고 현재 호출처 없음. 향후 사용 대비 환경변수만 받아둠 |
## 실행
```bash
# 의존성 설치
npm install
# 개발 (ts-node)
npm run dev
# 빌드 후 실행 (build 스크립트가 dist 디렉터리를 자동 생성)
npm run build
npm start
# 전역 슬래시 명령어 등록 (배포 파이프라인)
npm run prod
```
### Docker
```bash
docker build -t tts_bot .
docker run --env-file .env -v $(pwd)/db:/app/db tts_bot
```
Dockerfile은 `node:22-bookworm-slim` 기반이며 `ffmpeg`을 설치한다. (이전 `node:20-alpine` 은 musl 환경이라 `better-sqlite3` prebuilt 가 없어 node-gyp/python 빌드 의존성이 필요했고, `@discordjs/voice` 의 node>=22 요구도 충족하지 못해 변경했다.)
## 동작 흐름 요약
1. `messageCreate` → 등록된 TTS 채널이면 `TTSClient.tts()` 호출
2. 텍스트 전처리(URL/멘션/이모지 치환) → 시그니처 키워드 분할
3. 각 조각을 Chzzk TTS로 합성 또는 캐시된 시그니처 mp3 사용
4. mp3 Buffer 결합 → `Transcode`에서 PCM 변환 → `VoiceSession.player.play()`
5. 일정 시간 idle 시 세션 자동 종료, 사용자 채널 이동 시 따라감
## 참고
- 시그니처 서버 주소(`192.168.10.5:2967`)는 `SignatureClient.ts`에 하드코딩 — 환경에 맞게 수정 필요
- `commands/` 내 파일은 default export class 형태로 자동 로드되므로 새 명령어 추가 시 같은 패턴 유지
- 현재 `users` 테이블 스키마는 정의돼 있으나 코드에서 사용 흔적은 적음 (향후 확장 여지)