feat: DuckDuckGo → Brave Search 교체 + 입금 알림 개선
## 검색 API 교체 - DuckDuckGo Instant Answer API → Brave Search API - 실제 웹 검색 결과 반환 (제목, 설명, URL) - Vault에 API 키 저장 (secret/brave-search) - Free AI 플랜: 2,000 queries/월 ## 시스템 프롬프트 개선 - 검색 도구 사용 조건 명시 (최신 정보, 실시간 가격 등) - 도구 description에 트리거 키워드 추가 ## 입금 알림 개선 - 자동 매칭 성공 시 사용자에게 Telegram 알림 전송 - tryAutoMatch() 반환값에 userId, amount 추가 ## 문서 업데이트 - Function Calling Tools 테이블에 트리거 키워드 컬럼 추가 - AI 시스템 프롬프트 섹션 추가 - Deposit Agent 프롬프트 수정 방법 문서화 - 자동 알림 시스템 섹션 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
77
CLAUDE.md
77
CLAUDE.md
@@ -156,6 +156,8 @@ curl https://telegram-summary-bot.kappa-d8e.workers.dev/webhook-info
|
|||||||
| Function Calling 무한 루프 | tool_choice 설정 오류 | `tool_choice: "auto"` 확인 |
|
| Function Calling 무한 루프 | tool_choice 설정 오류 | `tool_choice: "auto"` 확인 |
|
||||||
| 프로필 업데이트 안됨 | 메시지 20개 미만 | `/context`로 버퍼 수 확인 |
|
| 프로필 업데이트 안됨 | 메시지 20개 미만 | `/context`로 버퍼 수 확인 |
|
||||||
| Email Worker 파싱 실패 | SMS 형식 변경 | `index.ts`의 정규식 패턴 확인 |
|
| Email Worker 파싱 실패 | SMS 형식 변경 | `index.ts`의 정규식 패턴 확인 |
|
||||||
|
| **AI가 도구 호출 안 함** | 키워드 미인식 | 시스템 프롬프트 + 도구 description에 키워드 추가 |
|
||||||
|
| **예치금 최소 금액 제한** | Agent 프롬프트 문제 | Deposit Agent 프롬프트 수정 (OpenAI API) |
|
||||||
|
|
||||||
### 디버깅 명령어
|
### 디버깅 명령어
|
||||||
```bash
|
```bash
|
||||||
@@ -198,15 +200,15 @@ Telegram Webhook → Security Validation → Command/Message Router
|
|||||||
| `telegram.ts` | Telegram API | `sendMessage()`, `sendTypingAction()` |
|
| `telegram.ts` | Telegram API | `sendMessage()`, `sendTypingAction()` |
|
||||||
|
|
||||||
**Function Calling Tools (7개):**
|
**Function Calling Tools (7개):**
|
||||||
| 도구 | 함수명 | 외부 API |
|
| 도구 | 함수명 | 외부 API | 트리거 키워드 |
|
||||||
|------|--------|----------|
|
|------|--------|----------|---------------|
|
||||||
| 날씨 | `get_weather` | wttr.in |
|
| 날씨 | `get_weather` | wttr.in | 날씨 |
|
||||||
| 검색 | `web_search` | DuckDuckGo |
|
| 검색 | `web_search` | Brave Search | ~란, ~뭐야 |
|
||||||
| 시간 | `get_current_time` | 내장 |
|
| 시간 | `get_current_time` | 내장 | 몇 시, 시간 |
|
||||||
| 계산 | `calculate` | 내장 |
|
| 계산 | `calculate` | 내장 | 계산, +, -, *, / |
|
||||||
| 문서 | `lookup_docs` | Context7 |
|
| 문서 | `lookup_docs` | Context7 | 문서, 사용법, API |
|
||||||
| 도메인 | `manage_domain` | Domain Agent → Namecheap |
|
| 도메인 | `manage_domain` | Domain Agent → Namecheap | 도메인, 네임서버, WHOIS |
|
||||||
| 예치금 | `manage_deposit` | D1 |
|
| 예치금 | `manage_deposit` | Deposit Agent → D1 | **입금, 충전, 잔액, 계좌, 송금** |
|
||||||
|
|
||||||
**Data Layer (D1 SQLite):**
|
**Data Layer (D1 SQLite):**
|
||||||
| 테이블 | 용도 | 주요 컬럼 |
|
| 테이블 | 용도 | 주요 컬럼 |
|
||||||
@@ -265,6 +267,30 @@ case 'new_tool':
|
|||||||
// → AI 프롬프트의 system 메시지에 포함
|
// → AI 프롬프트의 system 메시지에 포함
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### AI 시스템 프롬프트 (`summary-service.ts`)
|
||||||
|
```
|
||||||
|
- 날씨, 시간, 계산, 검색 등의 요청은 제공된 도구를 사용하세요.
|
||||||
|
- 예치금, 입금, 충전, 잔액, 계좌 관련 요청은 반드시 manage_deposit 도구를 사용하세요.
|
||||||
|
금액 제한이나 규칙을 직접 판단하지 마세요.
|
||||||
|
- 도메인 관련 요청은 반드시 manage_domain 도구를 사용하세요.
|
||||||
|
```
|
||||||
|
|
||||||
|
**중요:** 메인 AI가 도구를 호출하지 않고 직접 답변하는 경우:
|
||||||
|
1. 시스템 프롬프트에 해당 키워드 추가 (`summary-service.ts:252-254`)
|
||||||
|
2. 도구 description에 키워드 명시 (`openai-service.ts` tools 배열)
|
||||||
|
|
||||||
|
### Deposit Agent 프롬프트 수정 방법
|
||||||
|
```bash
|
||||||
|
# Vault에서 API 키 조회
|
||||||
|
curl -s -H "X-Vault-Token: hvs.xxx" https://vault.anvil.it.com/v1/secret/data/openai
|
||||||
|
|
||||||
|
# Assistant 프롬프트 업데이트
|
||||||
|
curl -X POST 'https://api.openai.com/v1/assistants/asst_XMoVGU7ZwRpUPI6PHGvRNm8E' \
|
||||||
|
-H 'Authorization: Bearer sk-xxx' \
|
||||||
|
-H 'OpenAI-Beta: assistants=v2' \
|
||||||
|
-d @update-agent.json
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
@@ -279,6 +305,7 @@ case 'new_tool':
|
|||||||
| `DEPOSIT_AGENT_ID` | - | 예치금 관리 Assistant ID |
|
| `DEPOSIT_AGENT_ID` | - | 예치금 관리 Assistant ID |
|
||||||
| `DEPOSIT_ADMIN_ID` | - | 예치금 관리 권한 Telegram ID |
|
| `DEPOSIT_ADMIN_ID` | - | 예치금 관리 권한 Telegram ID |
|
||||||
| `BANK_API_SECRET` | - | 입금 알림 API 인증 키 (wrangler secret) |
|
| `BANK_API_SECRET` | - | 입금 알림 API 인증 키 (wrangler secret) |
|
||||||
|
| `BRAVE_API_KEY` | - | Brave Search API 키 (wrangler secret) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -292,7 +319,7 @@ case 'new_tool':
|
|||||||
| Namecheap API | 도메인 백엔드 | namecheap-api.anvil.it.com | 날짜: MM/DD/YYYY → ISO 변환 |
|
| Namecheap API | 도메인 백엔드 | namecheap-api.anvil.it.com | 날짜: MM/DD/YYYY → ISO 변환 |
|
||||||
| WHOIS API | WHOIS 조회 | whois-api-eight.vercel.app | ccSLD 미지원 |
|
| WHOIS API | WHOIS 조회 | whois-api-eight.vercel.app | ccSLD 미지원 |
|
||||||
| wttr.in | 날씨 | wttr.in | - |
|
| wttr.in | 날씨 | wttr.in | - |
|
||||||
| DuckDuckGo | 검색 | api.duckduckgo.com | - |
|
| Brave Search | 검색 | api.search.brave.com | Free AI 플랜 (2,000/월) |
|
||||||
| Vault | API 키 관리 | vault.anvil.it.com | - |
|
| Vault | API 키 관리 | vault.anvil.it.com | - |
|
||||||
| Gmail | 입금 SMS 수신 | deposit.anvil@gmail.com | Apps Script 연동 |
|
| Gmail | 입금 SMS 수신 | deposit.anvil@gmail.com | Apps Script 연동 |
|
||||||
| Apps Script | Gmail → Worker 연동 | script.google.com | 1분마다 실행, message_id 중복 방지 |
|
| Apps Script | Gmail → Worker 연동 | script.google.com | 1분마다 실행, message_id 중복 방지 |
|
||||||
@@ -306,7 +333,7 @@ case 'new_tool':
|
|||||||
[시나리오 1: 사용자 먼저]
|
[시나리오 1: 사용자 먼저]
|
||||||
"홍길동 50000원 입금" → bank_notifications 검색
|
"홍길동 50000원 입금" → bank_notifications 검색
|
||||||
↓
|
↓
|
||||||
매칭 O → confirmed | 매칭 X → pending
|
매칭 O → confirmed + 잔액↑ | 매칭 X → pending
|
||||||
|
|
||||||
[시나리오 2: SMS 먼저 - Gmail → Apps Script → Worker]
|
[시나리오 2: SMS 먼저 - Gmail → Apps Script → Worker]
|
||||||
은행 SMS → Gmail(deposit.anvil@gmail.com) → Apps Script (1분마다)
|
은행 SMS → Gmail(deposit.anvil@gmail.com) → Apps Script (1분마다)
|
||||||
@@ -317,9 +344,16 @@ case 'new_tool':
|
|||||||
↓
|
↓
|
||||||
deposit_transactions 검색 (pending)
|
deposit_transactions 검색 (pending)
|
||||||
↓
|
↓
|
||||||
매칭 O → confirmed + 잔액↑ | 매칭 X → 저장만
|
매칭 O → confirmed + 잔액↑ + 사용자/관리자 알림
|
||||||
|
매칭 X → 저장만 + 관리자 알림
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**알림 시스템:**
|
||||||
|
| 이벤트 | 사용자 알림 | 관리자 알림 |
|
||||||
|
|--------|-------------|-------------|
|
||||||
|
| 자동 매칭 성공 | ✅ 입금액 + 현재 잔액 | ✅ 입금 정보 + 매칭 완료 |
|
||||||
|
| 매칭 대기 (SMS만) | - | ✅ 입금 정보 + 대기 상태 |
|
||||||
|
|
||||||
**Gmail → Worker 연동:**
|
**Gmail → Worker 연동:**
|
||||||
- Gmail 계정: `deposit.anvil@gmail.com`
|
- Gmail 계정: `deposit.anvil@gmail.com`
|
||||||
- Apps Script: 1분마다 `is:unread 입금` 검색 → Worker API 호출
|
- Apps Script: 1분마다 `is:unread 입금` 검색 → Worker API 호출
|
||||||
@@ -340,6 +374,25 @@ Content-Type: application/json
|
|||||||
**입금 계좌:** 하나은행 427-910018-27104 (주식회사 아이언클래드)
|
**입금 계좌:** 하나은행 427-910018-27104 (주식회사 아이언클래드)
|
||||||
- Vault 경로: `secret/companies/ironclad-corp`
|
- Vault 경로: `secret/companies/ironclad-corp`
|
||||||
|
|
||||||
|
**Deposit Agent 핵심 규칙:**
|
||||||
|
```
|
||||||
|
1. 금액 제한 없음: 1원도 입금 가능
|
||||||
|
2. 입금 신고 시 반드시 입금자명 + 금액 확인 (빠지면 물어보기)
|
||||||
|
3. "계좌번호 주세요" → get_account_info 호출
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deposit Agent 도구:**
|
||||||
|
| 함수 | 설명 | 권한 |
|
||||||
|
|------|------|------|
|
||||||
|
| `get_balance` | 잔액 조회 | 모든 사용자 |
|
||||||
|
| `get_account_info` | 입금 계좌 안내 | 모든 사용자 |
|
||||||
|
| `request_deposit` | 입금 신고 | 모든 사용자 |
|
||||||
|
| `get_transactions` | 거래 내역 | 모든 사용자 |
|
||||||
|
| `cancel_transaction` | 입금 취소 | 모든 사용자 |
|
||||||
|
| `get_pending_list` | 대기 목록 | 관리자 |
|
||||||
|
| `confirm_deposit` | 입금 확인 | 관리자 |
|
||||||
|
| `reject_deposit` | 입금 거절 | 관리자 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Domain System
|
## Domain System
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -130,7 +130,7 @@ OpenAI Function Calling을 통해 AI가 자동으로 필요한 도구를 호출
|
|||||||
| 기능 | 예시 질문 | API |
|
| 기능 | 예시 질문 | API |
|
||||||
|------|-----------|-----|
|
|------|-----------|-----|
|
||||||
| **날씨** | "서울 날씨", "도쿄 날씨 알려줘" | wttr.in |
|
| **날씨** | "서울 날씨", "도쿄 날씨 알려줘" | wttr.in |
|
||||||
| **검색** | "파이썬이 뭐야", "클라우드플레어란" | DuckDuckGo |
|
| **검색** | "파이썬이 뭐야", "클라우드플레어란" | Brave Search |
|
||||||
| **시간** | "지금 몇 시야", "뉴욕 시간" | 내장 |
|
| **시간** | "지금 몇 시야", "뉴욕 시간" | 내장 |
|
||||||
| **계산** | "123 * 456", "100의 20%" | 내장 |
|
| **계산** | "123 * 456", "100의 20%" | 내장 |
|
||||||
| **문서** | "React hooks 사용법", "OpenAI API 예제" | Context7 |
|
| **문서** | "React hooks 사용법", "OpenAI API 예제" | Context7 |
|
||||||
@@ -181,15 +181,15 @@ OpenAI: 날씨 데이터를 자연어로 응답 생성
|
|||||||
│ bank_notifications│ ← 기존 은행 알림 확인
|
│ bank_notifications│ ← 기존 은행 알림 확인
|
||||||
└──────────────────┘
|
└──────────────────┘
|
||||||
│
|
│
|
||||||
├── 매칭 발견 → 즉시 confirmed + 잔액 증가
|
├── 매칭 발견 → 즉시 confirmed + 잔액 증가 (대화 중 응답)
|
||||||
│
|
│
|
||||||
└── 매칭 없음 → pending 상태로 대기
|
└── 매칭 없음 → pending 상태로 대기 (SMS 도착 시 자동 매칭 + 알림)
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
[시나리오 2: 은행 SMS가 먼저 도착]
|
[시나리오 2: 은행 SMS가 먼저 도착]
|
||||||
|
|
||||||
은행 SMS → Email Worker 수신
|
은행 SMS → Gmail → Apps Script
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌──────────────────┐
|
┌──────────────────┐
|
||||||
@@ -202,9 +202,10 @@ OpenAI: 날씨 데이터를 자연어로 응답 생성
|
|||||||
│ deposit_transactions│ ← 대기중 입금 확인
|
│ deposit_transactions│ ← 대기중 입금 확인
|
||||||
└──────────────────┘
|
└──────────────────┘
|
||||||
│
|
│
|
||||||
├── 매칭 발견 → 즉시 confirmed + 잔액 증가
|
├── 매칭 발견 → confirmed + 잔액 증가 + 사용자에게 Telegram 알림 🎉
|
||||||
|
│ + 관리자에게 Telegram 알림
|
||||||
│
|
│
|
||||||
└── 매칭 없음 → bank_notifications에 저장 (나중에 매칭)
|
└── 매칭 없음 → bank_notifications에 저장 + 관리자에게 알림 (대기)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 지원 기능
|
### 지원 기능
|
||||||
@@ -220,6 +221,25 @@ OpenAI: 날씨 데이터를 자연어로 응답 생성
|
|||||||
| `수동 확인` | 입금 수동 확정 처리 | 관리자 전용 |
|
| `수동 확인` | 입금 수동 확정 처리 | 관리자 전용 |
|
||||||
| `입금 거절` | 입금 요청 거절 | 관리자 전용 |
|
| `입금 거절` | 입금 요청 거절 | 관리자 전용 |
|
||||||
|
|
||||||
|
### 자동 알림 시스템
|
||||||
|
|
||||||
|
자동 매칭 성공 시 **사용자와 관리자 모두에게 Telegram 알림**이 전송됩니다.
|
||||||
|
|
||||||
|
| 이벤트 | 사용자 알림 | 관리자 알림 |
|
||||||
|
|--------|-------------|-------------|
|
||||||
|
| 자동 매칭 성공 | ✅ 입금액 + 현재 잔액 | ✅ 입금 정보 + 매칭 완료 |
|
||||||
|
| 매칭 대기 (SMS만) | - | ⏳ 입금 정보 + 대기 상태 |
|
||||||
|
|
||||||
|
**사용자가 받는 메시지 예시:**
|
||||||
|
```
|
||||||
|
✅ 입금 확인 완료!
|
||||||
|
|
||||||
|
입금액: 7원
|
||||||
|
현재 잔액: 7원
|
||||||
|
|
||||||
|
감사합니다! 🎉
|
||||||
|
```
|
||||||
|
|
||||||
### Gmail → Apps Script → Worker 연동
|
### Gmail → Apps Script → Worker 연동
|
||||||
|
|
||||||
SMS를 Gmail로 전달받아 Apps Script에서 Worker API를 호출합니다.
|
SMS를 Gmail로 전달받아 Apps Script에서 Worker API를 호출합니다.
|
||||||
@@ -229,6 +249,8 @@ SMS를 Gmail로 전달받아 Apps Script에서 Worker API를 호출합니다.
|
|||||||
은행 SMS → Gmail(deposit.anvil@gmail.com) → Apps Script (1분마다)
|
은행 SMS → Gmail(deposit.anvil@gmail.com) → Apps Script (1분마다)
|
||||||
↓
|
↓
|
||||||
POST /api/bank-notification → DB 저장 → 자동 매칭
|
POST /api/bank-notification → DB 저장 → 자동 매칭
|
||||||
|
↓
|
||||||
|
매칭 성공 → 사용자/관리자 Telegram 알림
|
||||||
```
|
```
|
||||||
|
|
||||||
**Apps Script 코드:**
|
**Apps Script 코드:**
|
||||||
@@ -389,6 +411,9 @@ wrangler secret put OPENAI_API_KEY
|
|||||||
|
|
||||||
# 입금 알림 API Secret (Apps Script 연동용)
|
# 입금 알림 API Secret (Apps Script 연동용)
|
||||||
wrangler secret put BANK_API_SECRET
|
wrangler secret put BANK_API_SECRET
|
||||||
|
|
||||||
|
# Brave Search API Key
|
||||||
|
wrangler secret put BRAVE_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
### Vault 연동 (선택)
|
### Vault 연동 (선택)
|
||||||
|
|||||||
68
src/index.ts
68
src/index.ts
@@ -223,6 +223,47 @@ export default {
|
|||||||
// 자동 매칭 시도
|
// 자동 매칭 시도
|
||||||
const matched = await tryAutoMatch(env.DB, notificationId as number, notification);
|
const matched = await tryAutoMatch(env.DB, notificationId as number, notification);
|
||||||
|
|
||||||
|
// 매칭 성공 시 사용자에게 알림
|
||||||
|
if (matched && env.BOT_TOKEN) {
|
||||||
|
const user = await env.DB.prepare(
|
||||||
|
'SELECT telegram_id FROM users WHERE id = ?'
|
||||||
|
).bind(matched.userId).first<{ telegram_id: string }>();
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
// 업데이트된 잔액 조회
|
||||||
|
const deposit = await env.DB.prepare(
|
||||||
|
'SELECT balance FROM user_deposits WHERE user_id = ?'
|
||||||
|
).bind(matched.userId).first<{ balance: number }>();
|
||||||
|
|
||||||
|
await sendMessage(
|
||||||
|
env.BOT_TOKEN,
|
||||||
|
parseInt(user.telegram_id),
|
||||||
|
`✅ <b>입금 확인 완료!</b>\n\n` +
|
||||||
|
`입금액: ${matched.amount.toLocaleString()}원\n` +
|
||||||
|
`현재 잔액: ${(deposit?.balance || 0).toLocaleString()}원\n\n` +
|
||||||
|
`감사합니다! 🎉`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 관리자에게 알림
|
||||||
|
if (env.BOT_TOKEN && env.DEPOSIT_ADMIN_ID) {
|
||||||
|
const statusMsg = matched
|
||||||
|
? `✅ 자동 매칭 완료! (거래 #${matched.transactionId})`
|
||||||
|
: '⏳ 매칭 대기 중 (사용자 입금 신고 필요)';
|
||||||
|
|
||||||
|
await sendMessage(
|
||||||
|
env.BOT_TOKEN,
|
||||||
|
parseInt(env.DEPOSIT_ADMIN_ID),
|
||||||
|
`🏦 <b>입금 알림</b>\n\n` +
|
||||||
|
`은행: ${notification.bankName}\n` +
|
||||||
|
`입금자: ${notification.depositorName}\n` +
|
||||||
|
`금액: ${notification.amount.toLocaleString()}원\n` +
|
||||||
|
`${notification.balanceAfter ? `잔액: ${notification.balanceAfter.toLocaleString()}원\n` : ''}` +
|
||||||
|
`\n${statusMsg}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Response.json({
|
return Response.json({
|
||||||
success: true,
|
success: true,
|
||||||
notification,
|
notification,
|
||||||
@@ -308,6 +349,29 @@ Documentation: https://github.com/your-repo
|
|||||||
// 자동 매칭 시도
|
// 자동 매칭 시도
|
||||||
const matched = await tryAutoMatch(env.DB, notificationId, notification);
|
const matched = await tryAutoMatch(env.DB, notificationId, notification);
|
||||||
|
|
||||||
|
// 매칭 성공 시 사용자에게 알림
|
||||||
|
if (matched && env.BOT_TOKEN) {
|
||||||
|
const user = await env.DB.prepare(
|
||||||
|
'SELECT telegram_id FROM users WHERE id = ?'
|
||||||
|
).bind(matched.userId).first<{ telegram_id: string }>();
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
// 업데이트된 잔액 조회
|
||||||
|
const deposit = await env.DB.prepare(
|
||||||
|
'SELECT balance FROM user_deposits WHERE user_id = ?'
|
||||||
|
).bind(matched.userId).first<{ balance: number }>();
|
||||||
|
|
||||||
|
await sendMessage(
|
||||||
|
env.BOT_TOKEN,
|
||||||
|
parseInt(user.telegram_id),
|
||||||
|
`✅ <b>입금 확인 완료!</b>\n\n` +
|
||||||
|
`입금액: ${matched.amount.toLocaleString()}원\n` +
|
||||||
|
`현재 잔액: ${(deposit?.balance || 0).toLocaleString()}원\n\n` +
|
||||||
|
`감사합니다! 🎉`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 관리자에게 알림
|
// 관리자에게 알림
|
||||||
if (env.BOT_TOKEN && env.DEPOSIT_ADMIN_ID) {
|
if (env.BOT_TOKEN && env.DEPOSIT_ADMIN_ID) {
|
||||||
const statusMsg = matched
|
const statusMsg = matched
|
||||||
@@ -444,7 +508,7 @@ async function tryAutoMatch(
|
|||||||
db: D1Database,
|
db: D1Database,
|
||||||
notificationId: number,
|
notificationId: number,
|
||||||
notification: BankNotification
|
notification: BankNotification
|
||||||
): Promise<{ transactionId: number } | null> {
|
): Promise<{ transactionId: number; userId: number; amount: number } | null> {
|
||||||
// 매칭 조건: 입금자명 + 금액이 일치하는 pending 거래
|
// 매칭 조건: 입금자명 + 금액이 일치하는 pending 거래
|
||||||
const pendingTx = await db.prepare(
|
const pendingTx = await db.prepare(
|
||||||
`SELECT dt.id, dt.user_id, dt.amount
|
`SELECT dt.id, dt.user_id, dt.amount
|
||||||
@@ -481,5 +545,5 @@ async function tryAutoMatch(
|
|||||||
).bind(pendingTx.id, notificationId),
|
).bind(pendingTx.id, notificationId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return { transactionId: pendingTx.id };
|
return { transactionId: pendingTx.id, userId: pendingTx.user_id, amount: pendingTx.amount };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const tools = [
|
|||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: 'search_web',
|
name: 'search_web',
|
||||||
description: '웹에서 정보를 검색합니다',
|
description: '웹에서 최신 정보를 검색합니다. 실시간 가격, 뉴스, 현재 날짜 이후 정보, 특정 사실 확인이 필요할 때 반드시 사용하세요. "비트코인 가격", "오늘 뉴스", "~란", "~뭐야" 등의 질문에 사용합니다.',
|
||||||
parameters: {
|
parameters: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@@ -136,7 +136,7 @@ const tools = [
|
|||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: 'manage_deposit',
|
name: 'manage_deposit',
|
||||||
description: '예치금을 관리합니다. 잔액 조회, 입금 신고(충전 요청), 거래 내역 조회, 입금 확인(관리자) 등을 수행할 수 있습니다. 사용자가 "입금했어", "송금했어", "충전하고 싶어", "잔액", "10000원 입금" 등의 말을 하면 이 도구를 사용합니다.',
|
description: '예치금을 관리합니다. 잔액 조회, 입금 계좌 안내, 입금 신고(충전 요청), 거래 내역 조회 등을 수행합니다. "입금", "충전", "잔액", "계좌", "계좌번호", "송금" 등의 키워드가 포함되면 반드시 이 도구를 사용하세요.',
|
||||||
parameters: {
|
parameters: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@@ -471,25 +471,39 @@ async function executeTool(name: string, args: Record<string, string>, env?: Env
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'search_web': {
|
case 'search_web': {
|
||||||
// 간단한 DuckDuckGo Instant Answer API
|
// Brave Search API
|
||||||
const query = args.query;
|
const query = args.query;
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
if (!env?.BRAVE_API_KEY) {
|
||||||
`https://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json&no_html=1`
|
return `🔍 검색 기능이 설정되지 않았습니다.`;
|
||||||
);
|
|
||||||
const data = await response.json() as any;
|
|
||||||
if (data.Abstract) {
|
|
||||||
return `🔍 검색 결과: ${query}\n\n${data.Abstract}\n\n출처: ${data.AbstractSource}`;
|
|
||||||
} else if (data.RelatedTopics?.length > 0) {
|
|
||||||
const topics = data.RelatedTopics.slice(0, 3)
|
|
||||||
.filter((t: any) => t.Text)
|
|
||||||
.map((t: any) => `• ${t.Text}`)
|
|
||||||
.join('\n');
|
|
||||||
return `🔍 관련 정보: ${query}\n\n${topics}`;
|
|
||||||
}
|
}
|
||||||
return `"${query}"에 대한 즉시 답변을 찾을 수 없습니다. 더 구체적인 질문을 해주세요.`;
|
const response = await fetch(
|
||||||
|
`https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=5`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-Subscription-Token': env.BRAVE_API_KEY,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!response.ok) {
|
||||||
|
return `🔍 검색 오류: ${response.status}`;
|
||||||
|
}
|
||||||
|
const data = await response.json() as any;
|
||||||
|
|
||||||
|
// Web 검색 결과 파싱
|
||||||
|
const webResults = data.web?.results || [];
|
||||||
|
if (webResults.length === 0) {
|
||||||
|
return `🔍 "${query}"에 대한 검색 결과가 없습니다.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = webResults.slice(0, 3).map((r: any, i: number) =>
|
||||||
|
`${i + 1}. <b>${r.title}</b>\n ${r.description}\n ${r.url}`
|
||||||
|
).join('\n\n');
|
||||||
|
|
||||||
|
return `🔍 검색 결과: ${query}\n\n${results}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return `검색 중 오류가 발생했습니다.`;
|
return `검색 중 오류가 발생했습니다: ${String(error)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,10 @@ ${context.previousSummary.summary}
|
|||||||
|
|
||||||
위 프로필을 바탕으로 사용자의 관심사와 맥락을 이해하고 개인화된 응답을 제공하세요.
|
위 프로필을 바탕으로 사용자의 관심사와 맥락을 이해하고 개인화된 응답을 제공하세요.
|
||||||
` : ''}
|
` : ''}
|
||||||
- 날씨, 시간, 계산, 검색 등의 요청은 제공된 도구를 사용하세요.
|
- 날씨, 시간, 계산 요청은 제공된 도구를 사용하세요.
|
||||||
|
- 최신 정보, 실시간 데이터, 현재 가격, 뉴스, 특정 사실 확인이 필요한 질문은 반드시 search_web 도구로 검색하세요. 자체 지식으로 답변하지 마세요.
|
||||||
|
- 예치금, 입금, 충전, 잔액, 계좌 관련 요청은 반드시 manage_deposit 도구를 사용하세요. 금액 제한이나 규칙을 직접 판단하지 마세요.
|
||||||
|
- 도메인 관련 요청은 반드시 manage_domain 도구를 사용하세요.
|
||||||
- 응답은 간결하고 도움이 되도록 한국어로 작성하세요.`;
|
- 응답은 간결하고 도움이 되도록 한국어로 작성하세요.`;
|
||||||
|
|
||||||
const recentContext = context.recentMessages.slice(-10).map((m) => ({
|
const recentContext = context.recentMessages.slice(-10).map((m) => ({
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export interface Env {
|
|||||||
DOMAIN_OWNER_ID?: string;
|
DOMAIN_OWNER_ID?: string;
|
||||||
DEPOSIT_AGENT_ID?: string;
|
DEPOSIT_AGENT_ID?: string;
|
||||||
DEPOSIT_ADMIN_ID?: string;
|
DEPOSIT_ADMIN_ID?: string;
|
||||||
|
BRAVE_API_KEY?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IntentAnalysis {
|
export interface IntentAnalysis {
|
||||||
|
|||||||
Reference in New Issue
Block a user