# 은랑(Silver Wolf) 확장 기술 아키텍처 & 데이터 소스 리서치 보고서
*Project Planetarium — 게임 정보 알림 봇 확장 설계 (Termux/Galaxy S21 환경, 솔로 개발)*

## TL;DR
- 6개 게임 × 5개 기능 중 **기능 1·2·4(리딤코드·리셋알람·방송알림)는 LLM이 거의 불필요한 스케줄러/API/파싱 작업**이고, **기능 3(뉴스)·5(자료 큐레이션)만 LLM 헤비**다. 따라서 은랑에는 Groq Qwen3.6-27b를 페르소나 대사에, Gemma 4 26B(무제한 TPM)를 뉴스 요약·라우팅에 배치하는 하이브리드가 최적이다.
- 방송 알림(기능 4)에서 **CHZZK 공식 Open API는 특정 채널 라이브 감지에 부적합**(글로벌 상위 20개 목록만 조회, channelId 필터 없음)하므로, 비공식 엔드포인트 `api.chzzk.naver.com/polling/v2/channels/{channelId}/live-status`(쿠키 불필요, 30~60초 폴링)를 쓰고, YouTube는 **WebSub 푸시(무료, 쿼터 0)**로 처리한다.
- 뉴스-RAG는 처음부터 은랑 안에 넣지 말고 별도 RAG 봇으로 분리하되, 은랑은 function-calling 툴로 그 봇을 호출하는 구조를 추천한다. Termux에는 **sqlite-vec**, 워크스테이션에는 ChromaDB/LanceDB가 현실적이며, 한국어 임베딩은 **KURE-v1 또는 BGE-m3-ko**가 최상위다.

## Key Findings

### 게임별 리딤코드 지원 여부 (기능 1)
| 게임 | 리딤코드 존재? | 공식 입력 경로 | 자동화/API 난이도 |
|---|---|---|---|
| 명조(Wuthering Waves) | O (버전 특별방송마다 3개, 24~48h 유효) | **게임 내에서만** (터미널→설정→기타→교환코드). 웹 리딤 사이트 없음 | 크롤링만 가능, 자동 입력 불가 |
| 호요버스(원신/스타레일/젠레스) | O | 공식 웹 리딤 페이지 + 게임 내 | **웹 리딤 API 존재** (`sg-hk4e-api.hoyoverse.com/common/apicdkey/api/webExchangeCdkey`) → 자동 입력 가능 |
| 니케(NIKKE) | O (CD-Key, 기념일/방송마다) | 게임 내 공지→CD-Key 교환 포털 (iOS는 별도) | 크롤링 위주 |
| 이터널 리턴 | O (쿠폰, A-Coin/스킨) | 게임 내 설정→서비스→쿠폰 입력 + 웹 | 크롤링, 일부 비회원 등록 페이지 |
| 카오스 제로 나이트메어 | O (STOVE 기반) | STOVE 쿠폰 페이지(`page.onstove.com`)/게임 내 | 크롤링, STOVE 페이지 파싱 |
| 발로란트(VALORANT) | △ (가챠 코드 아님, 코스메틱 전용) | Riot 리딤 페이지(`shop.riotgames.com/redeem`)/게임 내 | 이벤트성, 빈도 낮음 |

핵심 사실:
- **명조**: Kuro Games는 버전 업데이트 전 특별방송에서 3개 코드를 배포하고 24~48시간만 유효하다. WUTHERINGGIFT만 상시 코드. 웹 리딤 사이트가 없어 봇은 "코드 알림"만 가능하고 입력은 수동.
- **호요버스**: 유일하게 진짜 자동 리딤이 가능. `webExchangeCdkey` 엔드포인트에 uid/region/cdkey/game_biz(`hk4e_global` 등)를 넘기면 됨. 단 쿠키(cookie_token + stoken) 필요. 팬메이드 집계 API도 풍부: `hoyo-codes.seria.moe/codes?game=genshin|hkrpg|nap`, `torikushiii/hoyoverse-api`(`/mihoyo/{game}/codes`, IP당 2 req/s·burst 120).
- **발로란트**: Riot 본인이 "가챠 시스템이 아니다"라고 명시. 코드는 VCT 이벤트/Pride 캠페인 때 코스메틱(플레이어 카드/총기 장식/타이틀/스프레이)만. 빈도가 낮아 우선순위 최하.

### 안티봇 회피 전략
- **fandom.com**은 Cloudflare 403 (기지 사실). 대안: game8.co, pockettactics.com, mobalytics.gg, 호요버스 팬 API.
- 호요버스는 공식/반공식 JSON API로 HTML 파싱 회피 가능.
- STOVE(카제나), 공식 사이트(이터널 리턴 `playeternalreturn.com/posts/news`)는 비교적 파싱 친화적.
- 공통: User-Agent를 브라우저처럼 설정, 요청 간격 두기, 실패 시 지수 백오프, 결과를 SQLite에 캐시해 중복 요청 최소화.

### 뉴스/공지 소스 (기능 3·5)
| 게임 | 공식 소스 | 한국 커뮤니티/웹진 | 피드 여부 |
|---|---|---|---|
| 명조 | 공식 사이트(`wutheringwaves.kurogames.com`), 공식 X | 인벤 명조 게시판, 루리웹 | 루리웹 게시판 RSS |
| 호요버스 | HoYoLAB 뉴스 API(`/mihoyo/{game}/news/events|notices|info`) | 인벤, 루리웹 | 팬 API + HoYoLAB |
| 니케 | 공식 X(@NIKKE_en), 공식 디스코드, 게임 내 공지 | 인벤 니케, 루리웹 | 제한적 |
| 발로란트 | playvalorant.com 뉴스, 공식 X | 인벤 발로란트 | 공식 뉴스 페이지 |
| 이터널 리턴 | playeternalreturn.com/posts/news, dak.gg | 인벤, dak.gg | 공식 뉴스 + dak.gg 피드 |
| 카오스 제로 | STOVE 라운지, 공식 카카오/유튜브 | 루리웹 카제나 게시판, DC 마이너갤 | 루리웹 RSS |

한국 웹진 RSS:
- **루리웹**: 게시판 RSS 지원. 패턴 `https://bbs.ruliweb.com/{topmenu}/board/{게시판번호}/rss`, 게임공략 `https://bbs.ruliweb.com/game/{게임번호}/board/rss`. 뉴스 대표 게시판 1001.
- **인벤**: 전체 뉴스 피드 `http://webzine.inven.co.kr/news/rss.php` (기사 종류별 피드도 제공, RSS 모음 페이지 `inven.co.kr/board/powerbbs.php?come_idx=228`).
- **겜피드(gamfeed.com)**: 인벤/루리웹/게임메카/IGN/GameSpot 등 17개 매체 RSS를 모아주는 메타 소스 → 단일 진입점으로 활용 가능.

### YouTube 라이브/영상 감지 (기능 4·5)
- **YouTube Data API v3 기본 쿼터: 10,000 units/day.** 공식 문서(developers.google.com/youtube/v3/determine_quota_cost, 2026-06-01 업데이트)는 "Projects that enable the YouTube Data API have a default quota allocation of 100 search.list calls, 100 videos.insert calls, and 10,000 units per day"라고 명시 — `search.list`가 **100 units/호출**이라 사실상 **하루 100회가 상한**. 다채널 라이브 폴링에는 부적합.
- **무료 대안 1 — 채널별 RSS(완전 무료, 쿼터 0)**: `https://www.youtube.com/feeds/videos.xml?channel_id=CHANNEL_ID`. 신규 영상 감지에 적합.
- **무료 대안 2 — WebSub(PubSubHubbub) 푸시(권장)**: 허브 `https://pubsubhubbub.appspot.com/subscribe`에 `hub.mode=subscribe`, `hub.topic=https://www.youtube.com/xml/feeds/videos.xml?channel_id=ID`, `hub.callback=내 콜백URL`로 구독. 새 영상/제목·설명 변경 시 Atom 피드가 콜백으로 푸시됨. `<yt:videoId>`, `<yt:channelId>`로 식별.
  - 주의점(검증됨): YouTube WebSub는 비표준적. 라이브 시작 시점에 ping이 와도 피드가 아직 갱신 안 됐을 수 있고, 비공개 영상도 ping이 오며, 페이로드 title이 일반값("YouTube video feed")이고 썸네일/설명이 없음. → ping 수신 후 videoId로 Data API `videos.list`(1 unit)로 라이브 여부(`liveBroadcastContent`) 재확인하는 하이브리드가 정확.
  - WebSub 콜백은 공인 HTTPS 엔드포인트가 필요 → Termux 단독으로는 어려움. 워크스테이션 또는 무료 터널(Cloudflare Tunnel 등) 필요.

### CHZZK(치지직) 라이브 감지 (기능 4)
- **공식 Open API(개발자센터, openapi.chzzk.naver.com)**: `GET /open/v1/lives`는 **현재 진행 중 라이브 전체 목록만** 조회(size 1~20, 시청자순). **channelId 필터 없음** → 특정 채널 감시에 부적합(상위 20위 밖이면 못 찾음). Client 인증(Client-Id/Client-Secret) 필요. 90일간 사용량 0이면 앱 삭제. 429=TOO_MANY_REQUESTS이나 구체 수치 비공개. 앱 ID/이름에 'chzzk','치지직','naver','네이버' 금지. 2024.12 런칭.
- **비공식 엔드포인트(권장)**: `GET https://api.chzzk.naver.com/polling/v2/channels/{channelId}/live-status`. 응답 `content.status`가 **"OPEN"/"CLOSE"**, `liveTitle`, `concurrentUserCount`, `chatChannelId`, `livePollingStatusJson` 등 포함. **쿠키(NID_AUT/NID_SES) 불필요(익명 동작)**. 채널 정보는 `service/v1/channels/{channelId}`(`openLive` 불리언·`followerCount` 포함), 상세는 `service/v1/channels/{channelId}/live-detail`(HLS URL 포함).
  - 서버가 응답 안에 `callPeriodMilliSecond: 10000`(10초)를 권고. 봇은 **30~60초 폴링**이 안전. 브라우저 User-Agent 필수(기본 python-requests UA는 403 위험, `Referer: https://chzzk.naver.com/` 권장).
- **Python 라이브러리**: `python-chzzk`(jonghwanhyeon) — `await chzzk.live.status(channel_id=...)` 비공식 API, 본 용도에 최적. `chzzkpy`(gunyu1019) — v2부터 공식/비공식 둘 다 지원, 특정 채널 감지는 `chzzkpy.unofficial` 사용. kimcore/chzzk는 Node.js 원본(폴링 기본 30초).
  - 네이버 공식 입장(chzzkpy 메인테이너 회신): 비공식 API를 허가하지도 제지하지도 않으나 비정상 요청 시 계정 보호조치 가능 → 폴링 간격 준수.

### 재화 충전/리셋 알람 (기능 2) — LLM 불필요, 스케줄러 지식
- **원신/스타레일/젠레스**: 일일 리셋 04:00 서버시간. 서버별 Asia=UTC+8, Europe=UTC+1, America=UTC-5. **Asia 서버 04:00 = KST 05:00**(KST는 UTC+9). 주간 리셋은 월요일 04:00 서버시간. 점검은 06:00 UTC+8 일제.
- **원신 레진**: Genshin Impact Wiki(Fandom)에 따르면 "Original Resin passively regenerates at a rate of 1 unit every 8 minutes... 180 resin per 24 hours... Full replenishment (from 0 to 200) will take 26 hours and 40 minutes." 즉 **8분당 1 회복, 200 cap, 0→만충 26시간 40분**(200 cap은 v4.7(2024-06-05) 160→200 상향).
- **HoYoLAB 일일 출석 체크인 자동화**: `genshin.py` 라이브러리로 가능(쿠키 필요). 출석/리딤 자동화를 은랑 스케줄러에 통합 가능.
- 그 외 게임은 리셋 시각이 알려진 정적 지식 → cron 스케줄로 충분.

### 모델 배치 (B)
| 작업 | 위치 | 권장 모델 | 근거 |
|---|---|---|---|
| 페르소나 대사/채팅 | 은랑 | **Groq Qwen3.6-27b** | 한국어 페르소나 최상, LPU 고속, 1,000 RPD |
| 단순 알림 래핑 텍스트 | 은랑 | Groq llama-3.1-8b-instant | Groq 공식 기준 30 RPM / 14,400 RPD / 500,000 TPD로 free tier에서 가장 관대 |
| 뉴스 요약(기능 3) | 백엔드 | **Gemma 4 26B** | TPM 무제한 → 긴 기사 요약 적합, 1,500 RPD |
| 라우팅/function-calling | 백엔드 | Gemma 4 26B | native FC 우수, dense 추론 |
| 멀티모달(영상 썸네일 등) | 백엔드 | Gemini 3.1 Flash Lite | multimodal, 250K TPM / 500 RPD |
| RAG 임베딩 | 백엔드 | Gemini Embedding(100 RPM/1,000 RPD, 별도 쿼터) 또는 로컬 BGE-m3 | RAG 전용 |

> Groq free tier 일반 모델(Qwen3.6-27b·gpt-oss-120b·llama-3.3-70b·llama-4-scout 등)은 대체로 **30 RPM / 6,000 TPM / 1,000 RPD** 수준이므로(공식 문서 기준), 페르소나·요약 모델의 RPD 임계값 설계 시 이 한도를 기준으로 잡는다.

### RAG / Agentic RAG (C)
**벡터 스토어 비교**:
| 스토어 | Termux ARM | 워크스테이션(RX 6600) | 특징 |
|---|---|---|---|
| **sqlite-vec** | ◎ (단일 파일, 의존성 0, 기본 30MB RAM) | ◎ | Termux에 최적. KNN, SIMD. 소~중규모. sqlite-vss 후속 |
| ChromaDB | △ (의존성 무거움) | ◎ | 사용 편의 좋음, 임베딩 관리 내장 |
| LanceDB | △ | ◎ | 컬럼형, 디스크 기반 대용량 |
| FAISS | △ (빌드 까다로움) | ◎ | 최고속, 메타데이터 별도 |
| pgvector | × (Postgres 필요) | ○ | 기존 DB 통합 시 |

**한국어 임베딩 벤치(KURE 리포 기준, 한국어 검색 Recall)**: nlpai-lab/**KURE-v1**(0.687) > dragonkue/**BGE-m3-ko**(0.678) > BAAI/bge-m3(0.675) > multilingual-e5-large(0.658). KURE-v1은 Hugging Face 모델 카드 기준 "Korea University Retrieval Embedding"으로 BAAI/bge-m3에서 CachedGISTEmbedLoss로 파인튜닝되었고, 한국어 query-document 약 200만 쌍으로 학습, **1024차원·8192 시퀀스 길이**(저자 Youngjoon Jang, Junyoung Son, Taemin Lee, 2024). → 한국어 게임 뉴스 RAG엔 KURE-v1 또는 BGE-m3-ko 권장. Gemini Embedding은 도메인별 편차로 일부 벤치에서 하위. 재랭킹이 필요하면 `dragonkue/bge-reranker-v2-m3-ko`.

**Agentic RAG**: LLM이 라우터로서 (a)검색 필요 여부 (b)어느 소스(벡터DB/뉴스API/웹검색) (c)재검색 여부를 결정. Gemma 4의 native function-calling으로 @tool 레지스트리 패턴과 자연스럽게 결합 가능. ReAct(추론+행동 교대) 패턴 적용 — 단일 에이전트 라우터로 시작.

**통합 vs 분리 권장**: 뉴스-RAG는 **별도 RAG 봇으로 분리**하고 은랑은 function-calling으로 호출. 이유: (1)임베딩/벡터DB는 Termux 자원 부담 (2)RPD 쿼터 분리 (3)은랑은 경량 페르소나/알림 역할 유지 (4)RAG 봇은 워크스테이션에서 상시 인덱싱.

## Details

### 아키텍처 (D) — 4계층 구조
1. **스케줄러 계층** (Termux, APScheduler/cron):
   - 리딤코드 크롤: 게임별 6~24시간 주기 (명조는 특별방송 전후 집중).
   - 리셋 알람: cron 기반, KST 환산 고정 시각(원신 Asia 05:00 KST 등).
   - CHZZK 폴링: 채널별 30~60초.
   - YouTube: WebSub 푸시(폴링 아님) + RSS 백업 폴링 15~30분.

2. **데이터 소스 어댑터 계층** (게임별·플랫폼별 모듈):
   - `redeem/` : 호요버스(JSON API), 명조(game8/pockettactics 파싱), 니케/이터널/카제나(웹진·STOVE 파싱).
   - `news/` : RSS(루리웹/인벤/겜피드), HoYoLAB API, 공식 사이트.
   - `live/` : chzzk 어댑터(python-chzzk), youtube 어댑터(WebSub 콜백).
   - 각 어댑터는 표준화된 dict(코드/제목/URL/시각) 반환 → 중복 제거(이전 상태 SQLite 저장).

3. **LLM 계층**:
   - 라우터(Gemma 4 26B, native FC): 사용자 명령/이벤트를 @tool로 디스패치.
   - 하이브리드 출력: function call = 고정 핸들러 출력(코드 목록 등), 일반 채팅 = 페르소나 LLM 텍스트(Groq Qwen3.6-27b).
   - 구조적 명령은 regex 선처리(예: `!코드 명조`)로 LLM 토큰 절약.

4. **알림 계층** (Discord):
   - 알림 임베드 = 핸들러가 데이터 생성 → Groq로 은랑 페르소나(스네키 해커, 사용자=개척자) 한 줄 래핑.
   - 채널 분리(코드/뉴스/방송).

### Termux 제약
- 상시구동·배터리: Termux:Boot + wakelock, 배터리 최적화 예외. WebSub 콜백 서버는 공인 IP가 없어 Termux 단독 불가 → 워크스테이션 또는 Cloudflare Tunnel.
- GPU 없음: 로컬 임베딩(BGE-m3)은 CPU로 느림 → Termux는 sqlite-vec 저장/조회만, 임베딩 생성은 워크스테이션 또는 Gemini Embedding API.
- 폴링 쿼터 설계: YouTube는 WebSub로 쿼터 0 유지, search.list 금지. CHZZK 30~60초.

### 단계별 빌드 순서 (권장)
1. **Phase 1 — 리딤코드(기능 1)**: 기존 pockettactics 파서 확장. 호요버스 팬 API 먼저(가장 쉬움), 그 다음 명조/니케/이터널/카제나. 발로란트는 최후.
2. **Phase 2 — 리셋 알람(기능 2)**: 정적 스케줄 + cron. LLM 불필요, 빠른 성과.
3. **Phase 3 — 방송 알림(기능 4)**: CHZZK 비공식 폴링 + YouTube WebSub. 페르소나 래핑 도입(Groq 실험 시작점).
4. **Phase 4 — 뉴스(기능 3)**: RSS 수집 + Gemma 4 요약. 단순 요약부터.
5. **Phase 5 — 자료/라인업(기능 5) + RAG**: 별도 RAG 봇 구축, Agentic RAG로 확장.

## Recommendations
- **즉시**: Phase 1·2를 먼저 구현(저위험·고효용). 호요버스는 팬 API(`hoyo-codes.seria.moe`)로 시작해 HTML 파싱 회피.
- **Groq 실험은 Phase 3 알림 래핑에서 시작** — 저위험·페르소나 효과 큼. Qwen3.6-27b로 한국어 품질 검증 후 채팅까지 확대.
- **방송 알림은 CHZZK 비공식 + YouTube WebSub 조합**으로 쿼터 0 설계. 공식 CHZZK API는 특정 채널 감시 불가하므로 비공식 폴링 유지하되 30~60초 준수.
- **뉴스-RAG는 분리** — 은랑은 호출만. 워크스테이션에 ChromaDB/sqlite-vec + KURE-v1, Termux는 조회 클라이언트.
- **벤치마크/임계값**:
  - Groq 일반 모델 1,000 RPD 근접 시 알림 래핑을 llama-3.1-8b-instant(14,400 RPD)로 강등.
  - Gemma 4 1,500 RPD 근접 시 뉴스 요약 빈도 축소(요약 묶음 처리).
  - YouTube `search.list`가 하루 50회(쿼터 5,000 units) 넘으면 즉시 WebSub로 완전 전환.
  - CHZZK 403/429 발생 시 폴링 간격을 60→120초로 늘리고 User-Agent 점검.

## Caveats
- 명조·니케·이터널·카제나는 **자동 리딤 불가**(웹 API 부재 또는 게임 내 전용) → 봇은 알림까지만.
- 호요버스 자동 리딤은 쿠키/stoken 관리 필요하고 약관 위반 소지 → 개인 계정 한정·자기책임.
- CHZZK 비공식 API는 네이버가 공식 허가하지 않음 → 과도한 요청 시 계정 보호조치 위험. 공식 rate limit 수치 비공개.
- 팬메이드 호요버스 API(seria.moe, torikushiii 등)는 제3자 운영 → 가용성 보장 없음, 공식 소스 백업 필요.
- 일부 코드/일정(예: 명조 3.4 특별방송 2026-05-29 등)은 시점 의존적이며 변동.
- Groq Qwen3.6-27b의 한국어 페르소나 품질·function calling 지원, 그리고 사용자가 제시한 Gemma 4 26B/31B 등 일부 모델명·쿼터는 사용자 환경 가정에 기반하며 실측 검증을 권장한다.
