Files
telegram-bot-workers/README.md
kappa 28ac6737ad docs: README에 Deposit Agent 개선사항 추가
- 사용법 예시 섹션 추가
- 자연어 금액 인식 (만원, 5천원 등)
- 즉시 실행 (확인 없이 바로 처리)
- 간편 취소 (최근 pending 자동 선택)
- 동시 요청 허용

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 12:04:40 +09:00

594 lines
18 KiB
Markdown

# Cloudflare Workers 텔레그램 봇
> Cloudflare Workers + D1 + OpenAI를 활용한 사용자 프로필 기반 텔레그램 봇
## 목차
1. [개요](#개요)
2. [아키텍처](#아키텍처)
3. [Function Calling](#function-calling)
4. [예치금 시스템](#예치금-시스템)
5. [도메인 관리](#도메인-관리)
6. [프로젝트 구조](#프로젝트-구조)
7. [배포 가이드](#배포-가이드)
8. [보안 설정](#보안-설정)
9. [봇 명령어](#봇-명령어)
---
## 개요
### 주요 기능
- **OpenAI GPT-4o-mini**: 고품질 AI 응답 및 Function Calling 지원
- **사용자 프로필**: 대화에서 사용자의 관심사, 목표, 맥락을 추출하여 프로필 구축
- **Function Calling**: 날씨, 검색, 시간, 계산, **문서 조회**, **도메인 관리**, **예치금 관리** 등 AI가 자동으로 도구 호출
- **Context7 연동**: 프로그래밍 라이브러리 공식 문서 실시간 조회
- **Domain Agent**: OpenAI Assistants API 기반 도메인 관리 에이전트 연동
- **Deposit Agent**: OpenAI Assistants API 기반 예치금 관리 에이전트 연동
- **예치금 시스템**: 은행 입금 자동 감지 + 사용자 신고 매칭으로 자동 충전
- **Email Worker**: SMS → 메일 → 자동 파싱으로 입금 알림 처리
- **무한 컨텍스트**: 슬라이딩 윈도우(3개)로 프로필 유지, 무제한 대화 기억
- **개인화 응답**: 프로필 기반으로 맞춤형 AI 응답 제공
- **폴백 지원**: OpenAI 미설정 시 Workers AI(Llama)로 자동 전환
### 기술 스택
| 서비스 | 용도 |
|--------|------|
| **Workers** | 서버리스 런타임 |
| **D1** | SQLite 데이터베이스 |
| **OpenAI** | GPT-4o-mini + Function Calling |
| **Context7** | 라이브러리 문서 조회 API |
| **Domain Agent** | 도메인 관리 (OpenAI Assistants) |
| **Deposit Agent** | 예치금 관리 (OpenAI Assistants) |
| **Namecheap API** | 도메인 조회/관리 백엔드 |
| **Email Workers** | SMS → 메일 파싱 (입금 알림) |
| **Workers AI** | 폴백용 (Llama 3.1 8B) |
---
## 아키텍처
### 메시지 처리 흐름
```
[사용자 메시지]
┌──────────────────┐
│ Cloudflare │
│ Worker │
└──────────────────┘
┌──────────────────┐
│ OpenAI API │ ← GPT-4o-mini
│ (Function Call) │ 도구 호출 자동 판단
└──────────────────┘
┌───┴───┬───────┬───────┬───────┬───────┬───────┐
▼ ▼ ▼ ▼ ▼ ▼ ▼
[날씨] [검색] [시간] [계산] [문서] [도메인] [예치금]
│ │ │ │ │ │ │
│ │ │ │ │ │ └── Deposit Agent (Assistants API)
│ │ │ │ │ │ ↓
│ │ │ │ │ └── Domain Agent D1 (자동 매칭)
│ │ │ │ │ ↓
│ │ │ │ └── Context7 Namecheap API
└───┬───┴───────┴───────┴───────┴───────────────────┘
┌──────────────────┐
│ 최종 응답 생성 │
└──────────────────┘
[D1 저장] → [Telegram 응답]
```
### 사용자 프로필 시스템
```
[사용자 메시지]
┌──────────────────┐
│ message_buffer │ ← 최대 19개 (20개 되면 프로필 업데이트)
└──────────────────┘
│ 20개 도달
┌──────────────────┐
│ 프로필 분석 │ ← 사용자 발언만 추출하여 분석
│ (OpenAI) │ 봇 응답은 무시
└──────────────────┘
┌──────────────────┐
│ summaries │ ← 최근 3개만 유지 (슬라이딩 윈도우)
│ [v1] [v2] [v3] │
└──────────────────┘
```
### 프로필 분석 내용
| 추출 정보 | 설명 |
|-----------|------|
| **관심사** | 사용자가 자주 언급하는 주제 |
| **목표** | 해결하려는 문제, 달성하려는 것 |
| **맥락** | 직업, 상황, 배경 정보 |
| **선호도** | 좋아하는 것, 싫어하는 것 |
| **질문 패턴** | 무엇에 대해 알고 싶어하는지 |
---
## Function Calling
OpenAI Function Calling을 통해 AI가 자동으로 필요한 도구를 호출합니다.
### 지원 기능
| 기능 | 예시 질문 | API |
|------|-----------|-----|
| **날씨** | "서울 날씨", "도쿄 날씨 알려줘" | wttr.in |
| **검색** | "파이썬이 뭐야", "클라우드플레어란" | Brave Search |
| **시간** | "지금 몇 시야", "뉴욕 시간" | 내장 |
| **계산** | "123 * 456", "100의 20%" | 내장 |
| **문서** | "React hooks 사용법", "OpenAI API 예제" | Context7 |
| **도메인** | "도메인 목록", "anvil.it.com 네임서버", ".com 가격", "google.com whois" | Domain Agent + WHOIS API |
| **예치금** | "잔액 확인", "충전하고 싶어", "10000원 입금했어" | D1 + Email Worker |
### 동작 방식
```
사용자: "서울 날씨 어때?"
OpenAI: "get_weather 함수를 호출해야겠다"
Worker: wttr.in API 호출 → 날씨 데이터 수신
OpenAI: 날씨 데이터를 자연어로 응답 생성
응답: "🌤 서울 날씨\n온도: 5°C\n습도: 45%..."
```
---
## 예치금 시스템
은행 계좌 입금 기반 예치금 충전 시스템입니다. 사용자 신고와 은행 SMS 알림을 양방향으로 자동 매칭합니다.
### 입금 계좌
| 은행 | 계좌번호 | 예금주 |
|------|----------|--------|
| 하나은행 | 427-910018-27104 | 주식회사 아이언클래드 |
> **Vault 경로**: `secret/companies/ironclad-corp` @ `vault.anvil.it.com`
### 자동 매칭 흐름
```
[시나리오 1: 사용자가 먼저 신고]
사용자: "홍길동 50000원 입금했어"
┌──────────────────┐
│ bank_notifications│ ← 기존 은행 알림 확인
└──────────────────┘
├── 매칭 발견 → 즉시 confirmed + 잔액 증가 (대화 중 응답)
└── 매칭 없음 → pending 상태로 대기 (SMS 도착 시 자동 매칭 + 알림)
```
```
[시나리오 2: 은행 SMS가 먼저 도착]
은행 SMS → Gmail → Apps Script
┌──────────────────┐
│ SMS 파싱 │ ← 입금자명, 금액, 은행 추출
│ (하나/KB/신한) │
└──────────────────┘
┌──────────────────┐
│ deposit_transactions│ ← 대기중 입금 확인
└──────────────────┘
├── 매칭 발견 → confirmed + 잔액 증가 + 사용자에게 Telegram 알림 🎉
│ + 관리자에게 Telegram 알림
└── 매칭 없음 → bank_notifications에 저장 + 관리자에게 알림 (대기)
```
### 지원 기능
| 기능 | 설명 | 권한 |
|------|------|------|
| `잔액 조회` | 현재 예치금 잔액 확인 | 모든 사용자 |
| `계좌 안내` | 입금 계좌 정보 표시 | 모든 사용자 |
| `입금 신고` | 입금자명 + 금액으로 충전 요청 | 모든 사용자 |
| `거래 내역` | 최근 거래 내역 조회 | 모든 사용자 |
| `입금 취소` | 대기중 입금 취소 (번호 없으면 최근 pending 자동 선택) | 모든 사용자 |
| `대기 목록` | 미처리 입금 목록 조회 | 관리자 전용 |
| `수동 확인` | 입금 수동 확정 처리 | 관리자 전용 |
| `입금 거절` | 입금 요청 거절 | 관리자 전용 |
### 사용법 예시
```
# 잔액 확인
"잔액" → "현재 잔액: 10,000원"
# 계좌 안내
"입금할게요" → 계좌 정보 안내
# 입금 신고 (자연어 금액 인식 지원)
"홍길동 5000원 입금했어" → 즉시 처리
"홍길동 만원 입금" → 10,000원으로 인식
"홍길동 5천원" → 5,000원으로 인식
# 거래 내역
"거래 내역" → "#5: 입금 10원 ✓ (01/17)"
# 간편 취소
"취소해줘" → 가장 최근 pending 자동 취소
```
**특징:**
- 🔢 **자연어 금액**: "만원", "5천원", "삼만오천원" 등 자동 변환
-**즉시 실행**: 입금자명+금액 있으면 확인 없이 바로 처리
- 📋 **동시 요청**: 기존 pending 있어도 새 입금 신고 가능
- 🗑️ **간편 취소**: 거래번호 없이 "취소해줘"만으로 최근 pending 취소
### 자동 알림 시스템
자동 매칭 성공 시 **사용자와 관리자 모두에게 Telegram 알림**이 전송됩니다.
| 이벤트 | 사용자 알림 | 관리자 알림 |
|--------|-------------|-------------|
| 자동 매칭 성공 | ✅ 입금액 + 현재 잔액 | ✅ 입금 정보 + 매칭 완료 |
| 매칭 대기 (SMS만) | - | ⏳ 입금 정보 + 대기 상태 |
**사용자가 받는 메시지 예시:**
```
✅ 입금 확인 완료!
입금액: 7원
현재 잔액: 7원
감사합니다! 🎉
```
### Gmail → Apps Script → Worker 연동
SMS를 Gmail로 전달받아 Apps Script에서 Worker API를 호출합니다.
**흐름:**
```
은행 SMS → Gmail(deposit.anvil@gmail.com) → Apps Script (1분마다)
POST /api/bank-notification → DB 저장 → 자동 매칭
매칭 성공 → 사용자/관리자 Telegram 알림
```
**Apps Script 코드:**
```javascript
function checkBankEmails() {
var threads = GmailApp.search('is:unread 입금', 0, 10);
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
var message = messages[j];
if (!message.isUnread()) continue;
var messageId = message.getId();
var body = message.getPlainBody();
try {
UrlFetchApp.fetch(
'https://telegram-summary-bot.kappa-d8e.workers.dev/api/bank-notification',
{
method: 'POST',
contentType: 'application/json',
payload: JSON.stringify({
content: body,
messageId: messageId,
secret: 'BANK_API_SECRET 값'
})
}
);
} catch (e) {
console.log('Error: ' + e);
}
}
threads[i].markRead();
}
}
```
**트리거 설정:** 시간 기반 → 분 타이머 → 1분마다
**지원 은행 SMS 패턴:**
- 하나은행 (Web발신): `[Web발신] 하나,01/16, 23:30 427******27104 입금5원 황병하`
- 하나은행 (기존): `[하나은행] 01/16 14:30 입금 50,000원 홍길동 잔액 1,234,567원`
- KB국민: `[KB] 입금 50,000원 01/16 14:30 홍길동`
- 신한: `[신한] 01/16 입금 50,000원 홍길동`
---
## 도메인 관리
OpenAI Assistants API 기반 도메인 관리 에이전트입니다.
### 지원 기능
| 기능 | 설명 | 권한 |
|------|------|------|
| `도메인 목록` | 내 도메인 목록 조회 | 소유자 |
| `도메인 정보` | 도메인 상세 정보 (만료일 등) | 소유자 |
| `네임서버 조회` | 현재 네임서버 확인 | 누구나 |
| `네임서버 변경` | 네임서버 설정 변경 | 소유자 |
| `가격 조회` | TLD/ccSLD 등록 가격 (원화) | 누구나 |
| `WHOIS 조회` | 공개 WHOIS 정보 (RDAP) | 누구나 |
| `가용성 확인` | 도메인 등록 가능 여부 | 누구나 |
### 가격 조회
Namecheap 가격 + 13% 마진, 매일 환율 업데이트
```
사용자: ".com 가격"
봇: ".com 도메인 등록 가격은 20,000원입니다."
사용자: "it.com 가격"
봇: "it.com 도메인 등록 가격은 55,000원입니다."
```
지원 TLD: com, net, org, io, me, info, biz, it.com, uk.com 등
### WHOIS 조회
자체 WHOIS API 서버(Vercel)를 통해 TCP 43 포트로 직접 쿼리
```
사용자: "google.com whois"
봇: 등록일, 만료일, 네임서버, 등록기관 정보 표시
```
- **WHOIS API**: `https://whois-api-eight.vercel.app`
- **지원 TLD**: com, net, org, io, co, me, kr, jp, cn, uk, de, fr 등 40+ TLD
- **ccSLD 미지원**: it.com, uk.com, us.com 등 사설 레지스트리는 WHOIS 비공개
---
## 프로젝트 구조
```
telegram-bot-workers/
├── src/
│ ├── index.ts # 메인 Worker
│ ├── types.ts # 타입 정의
│ ├── security.ts # Webhook 보안 검증
│ ├── telegram.ts # Telegram API 유틸
│ ├── summary-service.ts # 프로필 분석 서비스
│ ├── openai-service.ts # OpenAI + Function Calling
│ ├── deposit-agent.ts # 예치금 에이전트 (Assistants API)
│ ├── n8n-service.ts # n8n 연동 (선택)
│ └── commands.ts # 봇 명령어 핸들러
├── schema.sql # D1 스키마
├── wrangler.toml # Wrangler 설정
├── n8n-workflow-example.json # n8n 워크플로우 예시
├── package.json
├── tsconfig.json
└── README.md
```
---
## 배포 가이드
### 1. 프로젝트 설정
```bash
cd telegram-bot-workers
npm install
```
### 2. D1 데이터베이스
현재 설정:
```toml
[[d1_databases]]
binding = "DB"
database_name = "telegram-conversations"
database_id = "c285bb5b-888b-405d-b36f-475ae5aed20e"
```
스키마:
- `users` - 사용자 정보
- `message_buffer` - 메시지 임시 저장
- `summaries` - 프로필 저장
- `user_deposits` - 예치금 계정
- `deposit_transactions` - 예치금 거래 내역
- `bank_notifications` - 은행 입금 알림 (SMS 파싱)
### 3. Secrets 설정
```bash
# Bot Token (BotFather에서 발급)
wrangler secret put BOT_TOKEN
# Webhook Secret
wrangler secret put WEBHOOK_SECRET
# OpenAI API Key (필수)
wrangler secret put OPENAI_API_KEY
# 입금 알림 API Secret (Apps Script 연동용)
wrangler secret put BANK_API_SECRET
# Brave Search API Key
wrangler secret put BRAVE_API_KEY
```
### Vault 연동 (선택)
API 키는 HashiCorp Vault에서 중앙 관리됩니다.
```bash
# Vault에서 OpenAI API 키 조회
vault kv get secret/openai
# 저장된 정보
# - api_key: OpenAI API 키
# - email: kappa.inouter@gmail.com (계정 관리용)
# Vault에서 키 가져와서 Worker에 설정
OPENAI_KEY=$(vault kv get -field=api_key secret/openai)
echo $OPENAI_KEY | wrangler secret put OPENAI_API_KEY
```
> **참고**: Vault 서버: `https://vault.anvil.it.com`
### 4. 배포
```bash
wrangler deploy
```
### 5. Webhook 설정
```bash
curl https://telegram-summary-bot.kappa-d8e.workers.dev/setup-webhook
curl https://telegram-summary-bot.kappa-d8e.workers.dev/webhook-info
```
---
## 보안 설정
### Webhook 보안 검증
| 검증 항목 | 설명 |
|-----------|------|
| **Secret Token** | `X-Telegram-Bot-Api-Secret-Token` 헤더 검증 |
| **Timing-safe 비교** | 타이밍 공격 방지 |
| **Timestamp** | 60초 이내 메시지만 처리 |
| **Rate Limiting** | 30req/분/사용자 |
### API 키 관리
| 키 | 저장 위치 | 비고 |
|----|-----------|------|
| `BOT_TOKEN` | Wrangler Secret | BotFather 발급 |
| `WEBHOOK_SECRET` | Wrangler Secret | 자동 생성 |
| `OPENAI_API_KEY` | Wrangler Secret + Vault | kappa.inouter@gmail.com |
**Vault 경로**: `secret/openai` @ `vault.anvil.it.com`
---
## 봇 명령어
### 사용자 명령어
| 명령어 | 설명 |
|--------|------|
| `/start` | 봇 시작, 기능 소개 |
| `/help` | 도움말 |
| `/profile` | 내 프로필 보기 |
| `/reset` | 대화 초기화 (확인 필요) |
| `/reset-confirm` | 초기화 확인 (실제 삭제) |
### 개발자 명령어 (숨김)
| 명령어 | 설명 |
|--------|------|
| `/context` | 현재 컨텍스트 상태 (버퍼 수, 프로필 버전) |
| `/stats` | 대화 통계 |
| `/debug` | 디버그 정보 |
---
## 설정값
`wrangler.toml`:
```toml
name = "telegram-summary-bot"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[ai]
binding = "AI"
[vars]
SUMMARY_THRESHOLD = "20"
MAX_SUMMARIES_PER_USER = "3"
N8N_WEBHOOK_URL = "https://n8n.anvil.it.com"
DOMAIN_AGENT_ID = "asst_MzPFKoqt7V4w6bc0UwcXU4ob"
DOMAIN_OWNER_ID = "821596605"
DEPOSIT_AGENT_ID = "asst_XMoVGU7ZwRpUPI6PHGvRNm8E"
DEPOSIT_ADMIN_ID = "821596605"
[[d1_databases]]
binding = "DB"
database_name = "telegram-conversations"
database_id = "c285bb5b-888b-405d-b36f-475ae5aed20e"
```
---
## 비용 예측
### 월간 예상 비용
| 사용량 | D1 | OpenAI | Workers | 총 |
|--------|-----|--------|---------|-----|
| 1만 메시지 | $0 | ~$0.20 | $0 | **~$0.20** |
| 10만 메시지 | $0 | ~$2.00 | $0 | **~$2.00** |
| 100만 메시지 | $0 | ~$20.00 | ~$0.30 | **~$20.30** |
> GPT-4o-mini: 입력 $0.15/1M, 출력 $0.60/1M 토큰
---
## API 엔드포인트
| 경로 | 메서드 | 설명 |
|------|--------|------|
| `/` | GET | 서비스 정보 |
| `/health` | GET | 헬스 체크 |
| `/webhook-info` | GET | Webhook 상태 |
| `/setup-webhook` | GET | Webhook 설정 |
| `/webhook` | POST | Telegram Webhook |
| `/api/bank-notification` | POST | 입금 알림 API (Apps Script 연동) |
---
## 참고
- [OpenAI API](https://platform.openai.com/docs)
- [Cloudflare D1](https://developers.cloudflare.com/d1/)
- [Cloudflare Workers](https://developers.cloudflare.com/workers/)
- [Telegram Bot API](https://core.telegram.org/bots/api)
- [Context7 API](https://context7.com/docs/api-guide)
---
## 소스 코드
**Gitea**: https://gitea.anvil.it.com/kaffa/telegram-bot-workers