diff --git a/package.json b/package.json index eb91254..ce8733d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "db:create": "wrangler d1 create telegram-summary-db", "db:init": "wrangler d1 execute telegram-summary-db --file=schema.sql", "db:init:local": "wrangler d1 execute telegram-summary-db --local --file=schema.sql", - "tail": "wrangler tail" + "tail": "wrangler tail", + "chat": "npx tsx scripts/chat.ts" }, "devDependencies": { "@cloudflare/workers-types": "^4.20241127.0", diff --git a/scripts/chat.ts b/scripts/chat.ts new file mode 100644 index 0000000..d9051f4 --- /dev/null +++ b/scripts/chat.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env npx tsx +/** + * Telegram Bot CLI Chat Client + * - Worker의 /api/test 엔드포인트를 통해 직접 대화 + * - 사용법: npx tsx scripts/chat.ts + * 또는: npx tsx scripts/chat.ts "메시지" + */ + +import * as readline from 'readline'; + +const WORKER_URL = process.env.WORKER_URL || 'https://telegram-summary-bot.kappa-d8e.workers.dev'; +const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; +const USER_ID = process.env.TELEGRAM_USER_ID || '821596605'; + +interface TestResponse { + input: string; + response: string; + user_id: string; + error?: string; +} + +async function sendMessage(text: string): Promise { + if (!WEBHOOK_SECRET) { + return '❌ WEBHOOK_SECRET 환경변수가 필요합니다.\n export WEBHOOK_SECRET="your-secret"'; + } + + try { + const response = await fetch(`${WORKER_URL}/api/test`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + text, + user_id: USER_ID, + secret: WEBHOOK_SECRET, + }), + }); + + const data = await response.json() as TestResponse; + + if (data.error) { + return `❌ Error: ${data.error}`; + } + + return data.response; + } catch (error) { + return `❌ Request failed: ${error}`; + } +} + +async function interactiveMode() { + console.log('🤖 Telegram Bot CLI'); + console.log(`📡 ${WORKER_URL}`); + console.log(`👤 User: ${USER_ID}`); + console.log('─'.repeat(40)); + console.log('메시지를 입력하세요. 종료: exit\n'); + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + const prompt = () => { + rl.question('\x1b[36m>\x1b[0m ', async (input) => { + const text = input.trim(); + + if (text === 'exit' || text === 'quit' || text === 'q') { + console.log('👋 종료'); + rl.close(); + process.exit(0); + } + + if (!text) { + prompt(); + return; + } + + console.log('\x1b[33m⏳ 처리 중...\x1b[0m'); + const response = await sendMessage(text); + console.log(`\n\x1b[32m🤖\x1b[0m ${response}\n`); + prompt(); + }); + }; + + prompt(); +} + +async function main() { + const args = process.argv.slice(2); + + if (args.length > 0) { + // 단일 메시지 모드 + const text = args.join(' '); + const response = await sendMessage(text); + console.log(response); + } else { + // 대화형 모드 + await interactiveMode(); + } +} + +main().catch(console.error); diff --git a/src/index.ts b/src/index.ts index dbfc91c..62a3365 100644 --- a/src/index.ts +++ b/src/index.ts @@ -390,6 +390,64 @@ export default { } } + // 테스트 API - 메시지 처리 후 응답 직접 반환 + if (url.pathname === '/api/test' && request.method === 'POST') { + try { + const body = await request.json() as { text: string; user_id?: string; secret?: string }; + + // 간단한 인증 + if (body.secret !== env.WEBHOOK_SECRET) { + return Response.json({ error: 'Unauthorized' }, { status: 401 }); + } + + if (!body.text) { + return Response.json({ error: 'text required' }, { status: 400 }); + } + + const telegramUserId = body.user_id || '821596605'; + const chatIdStr = telegramUserId; + + // 사용자 조회/생성 + const userId = await getOrCreateUser(env.DB, telegramUserId, 'TestUser', 'testuser'); + + let responseText: string; + + // 명령어 처리 + if (body.text.startsWith('/')) { + const [command, ...argParts] = body.text.split(' '); + const args = argParts.join(' '); + responseText = await handleCommand(env, userId, chatIdStr, command, args); + } else { + // 1. 사용자 메시지 버퍼에 추가 + await addToBuffer(env.DB, userId, chatIdStr, 'user', body.text); + + // 2. AI 응답 생성 + responseText = await generateAIResponse(env, userId, chatIdStr, body.text, telegramUserId); + + // 3. 봇 응답 버퍼에 추가 + await addToBuffer(env.DB, userId, chatIdStr, 'bot', responseText); + + // 4. 임계값 도달시 프로필 업데이트 + const { summarized } = await processAndSummarize(env, userId, chatIdStr); + if (summarized) { + responseText += '\n\n👤 프로필이 업데이트되었습니다.'; + } + } + + // HTML 태그 제거 (CLI 출력용) + const plainText = responseText.replace(/<[^>]*>/g, ''); + + return Response.json({ + input: body.text, + response: plainText, + user_id: telegramUserId, + }); + } catch (error) { + console.error('[Test API] Error:', error); + return Response.json({ error: String(error) }, { status: 500 }); + } + } + // Telegram Webhook 처리 if (url.pathname === '/webhook') { // 보안 검증