# v8: 매출 분석 요청 ## 개요 이번 단계에서는 Stripe에서 조회한 매출 데이터를 ChatGPT에 전달하여 분석을 요청합니다. 효과적인 프롬프트 엔지니어링을 통해 실용적인 인사이트를 얻는 방법을 다룹니다. ## 분석 모듈 작성 ### src/chatgpt/analyze.ts ```typescript import { openai } from './client.js'; import { SalesStats, AnalysisResult } from '../types/index.js'; import { formatForChatGPT } from '../utils/formatter.js'; import { env } from '../config/env.js'; /** * 매출 데이터를 분석하는 시스템 프롬프트 */ const SYSTEM_PROMPT = `당신은 전문적인 비즈니스 애널리스트입니다. 당신의 역할: - 매출 데이터를 분석하여 핵심 인사이트를 도출합니다 - 데이터에 기반한 실용적인 비즈니스 제안을 제공합니다 - 명확하고 간결한 언어로 소통합니다 - 긍정적이면서도 개선점을 놓치지 않습니다 분석 시 고려사항: - 매출 규모와 거래 건수의 관계 - 카테고리별 매출 비중과 트렌드 - 시간대별 거래 패턴 - 평균 주문 금액(AOV)의 의미 - 실행 가능한 개선 방안`; /** * 매출 분석 프롬프트 생성 */ function createAnalysisPrompt(stats: SalesStats): string { const dataText = formatForChatGPT(stats); return `다음은 오늘(${stats.date})의 매출 데이터입니다: ${dataText} 위 데이터를 분석하여 다음 형식으로 제공해주세요: ## 📊 매출 요약 (전체 매출을 2-3문장으로 요약) ## 💡 주요 인사이트 (데이터에서 발견한 중요한 사실 3-5가지, 각각 1-2문장) ## 📈 개선 제안 (실행 가능한 구체적인 제안 2-3가지) ## 🎯 다음 단계 (즉시 실행할 수 있는 액션 아이템 2-3가지) 명확하고 실용적으로 작성해주세요.`; } /** * ChatGPT로 매출 분석 */ export async function analyzeSales(stats: SalesStats): Promise { console.log('🤖 ChatGPT 분석 시작...\n'); const prompt = createAnalysisPrompt(stats); try { const response = await openai.chat.completions.create({ model: env.openaiModel, messages: [ { role: 'system', content: SYSTEM_PROMPT, }, { role: 'user', content: prompt, }, ], max_tokens: env.openaiMaxTokens, temperature: env.openaiTemperature, }); const rawResponse = response.choices[0].message.content || ''; // 토큰 사용량 표시 if (response.usage) { console.log(`💰 토큰 사용: ${response.usage.total_tokens} (입력: ${response.usage.prompt_tokens}, 출력: ${response.usage.completion_tokens})`); } // 응답 파싱 const parsed = parseAnalysisResponse(rawResponse); console.log('✅ 분석 완료!\n'); return { ...parsed, rawResponse, }; } catch (error) { console.error('❌ 분석 중 에러 발생:', error); throw error; } } /** * ChatGPT 응답을 구조화된 데이터로 파싱 */ function parseAnalysisResponse(response: string): Omit { // 기본값 const result = { summary: '', insights: [] as string[], recommendations: [] as string[], }; // 섹션별로 분리 const sections = response.split('##').map((s) => s.trim()).filter(Boolean); sections.forEach((section) => { const lines = section.split('\n').filter((l) => l.trim()); const title = lines[0].toLowerCase(); // 매출 요약 if (title.includes('요약') || title.includes('summary')) { result.summary = lines .slice(1) .join(' ') .trim(); } // 주요 인사이트 if (title.includes('인사이트') || title.includes('insight')) { result.insights = lines .slice(1) .filter((l) => l.trim().match(/^[-•*\d]/)) .map((l) => l.replace(/^[-•*\d.)\s]+/, '').trim()); } // 개선 제안 + 다음 단계 if ( title.includes('제안') || title.includes('recommendation') || title.includes('다음') || title.includes('action') ) { const recs = lines .slice(1) .filter((l) => l.trim().match(/^[-•*\d]/)) .map((l) => l.replace(/^[-•*\d.)\s]+/, '').trim()); result.recommendations.push(...recs); } }); return result; } /** * 간단한 요약만 생성 */ export async function generateQuickSummary(stats: SalesStats): Promise { const prompt = `다음 매출 데이터를 한 문단(3-4문장)으로 요약해주세요: 날짜: ${stats.date} 총 매출: $${(stats.totalAmount / 100).toFixed(2)} 거래 건수: ${stats.totalCount} 평균 주문 금액: $${(stats.averageAmount / 100).toFixed(2)}`; const response = await openai.chat.completions.create({ model: env.openaiModel, messages: [ { role: 'system', content: '당신은 매출 데이터를 간결하게 요약하는 전문가입니다.', }, { role: 'user', content: prompt, }, ], max_tokens: 200, temperature: 0.7, }); return response.choices[0].message.content || ''; } ``` ## 분석 실행 스크립트 ### src/analyze-sales.ts ```typescript import { aggregateSalesData } from './stripe/fetch-data.js'; import { analyzeSales } from './chatgpt/analyze.js'; import { formatSalesStats } from './utils/formatter.js'; async function main() { console.log('📊 Stripe 매출 데이터 분석\n'); console.log('='.repeat(60)); try { // 1. Stripe에서 데이터 조회 console.log('\n📥 1단계: Stripe 데이터 조회 중...\n'); const stats = await aggregateSalesData(); if (stats.totalCount === 0) { console.log('⚠️ 오늘 거래가 없습니다.'); console.log('먼저 테스트 결제를 생성해주세요: npm run generate'); return; } // 기본 통계 출력 console.log(formatSalesStats(stats)); // 2. ChatGPT로 분석 console.log('\n' + '='.repeat(60)); console.log('\n🤖 2단계: ChatGPT 분석 중...\n'); const analysis = await analyzeSales(stats); // 3. 결과 출력 console.log('='.repeat(60)); console.log('\n🎯 분석 결과\n'); console.log('='.repeat(60)); console.log('\n## 📊 매출 요약\n'); console.log(analysis.summary); if (analysis.insights.length > 0) { console.log('\n## 💡 주요 인사이트\n'); analysis.insights.forEach((insight, index) => { console.log(`${index + 1}. ${insight}`); }); } if (analysis.recommendations.length > 0) { console.log('\n## 📈 개선 제안 및 다음 단계\n'); analysis.recommendations.forEach((rec, index) => { console.log(`${index + 1}. ${rec}`); }); } console.log('\n' + '='.repeat(60)); console.log('\n✨ 분석 완료!\n'); } catch (error) { console.error('\n💥 에러 발생:'); console.error(error); process.exit(1); } } main(); ``` ### package.json 업데이트 ```json { "scripts": { "analyze": "tsx src/analyze-sales.ts", "report": "tsx src/analyze-sales.ts" } } ``` ## 실행 및 테스트 ### 1. 테스트 결제 생성 ```bash npm run generate 15 ``` ### 2. 매출 분석 ```bash npm run analyze ``` ### 예상 출력 ``` 📊 Stripe 매출 데이터 분석 ============================================================ 📥 1단계: Stripe 데이터 조회 중... 📅 2025-11-28 결제 데이터 조회 중... ✅ 15건의 결제를 찾았습니다. === 매출 분석 (2025-11-28) === 📊 기본 통계 총 매출: $8,432.00 결제 건수: 15건 평균 결제 금액: $562.13 📦 카테고리별 매출 electronics: $3,890.00 (6건, 46.1%) books: $2,240.00 (4건, 26.6%) clothing: $1,502.00 (3건, 17.8%) home: $800.00 (2건, 9.5%) ⏰ 시간대별 결제 건수 09:00 | █ 1건 11:00 | ██ 2건 14:00 | ████ 4건 16:00 | ███ 3건 18:00 | ██ 2건 20:00 | ██ 2건 22:00 | █ 1건 💰 최고 결제 Top 5 1. $950.00 - Smart Watch 2. $820.00 - Mechanical Keyboard 3. $680.00 - The Pragmatic Programmer 4. $560.00 - Wireless Headphones 5. $490.00 - Winter Jacket ============================================================ 🤖 2단계: ChatGPT 분석 중... 🤖 ChatGPT 분석 시작... 💰 토큰 사용: 856 (입력: 542, 출력: 314) ✅ 분석 완료! ============================================================ 🎯 분석 결과 ============================================================ ## 📊 매출 요약 오늘 총 15건의 거래를 통해 $8,432의 견고한 매출을 달성했습니다. 건당 평균 $562.13으로 중상위 가격대의 상품들이 고르게 판매되었습니다. Electronics 카테고리가 전체 매출의 거의 절반을 차지하며 핵심 매출원으로 확인되었습니다. ## 💡 주요 인사이트 1. Electronics 카테고리가 46.1%의 매출 비중을 차지하며, 평균 주문 금액도 $648로 가장 높습니다. 이는 고객들이 고가 전자제품에 대한 구매 의향이 높다는 것을 보여줍니다. 2. 오후 2시(14시)에 거래가 가장 집중되어 있으며, 전체적으로 오후 시간대 (14-20시)에 80%의 거래가 발생했습니다. 점심 이후 쇼핑 패턴이 뚜렷합니다. 3. Books와 Clothing 카테고리도 각각 26.6%, 17.8%의 안정적인 비중을 보이며, 카테고리 다각화가 잘 이루어지고 있습니다. 4. Top 5 결제 중 4건이 $500 이상의 고가 상품이며, 이는 고객 세그먼트가 프리미엄 제품에 집중되어 있음을 시사합니다. ## 📈 개선 제안 및 다음 단계 1. Electronics의 높은 인기를 활용하여 관련 액세서리(케이블, 케이스, 충전기 등)를 번들로 제안하면 객단가를 더욱 높일 수 있습니다. 2. 오전 시간대(9-12시)의 거래가 전체의 20%에 불과하므로, 오전 한정 프로모션이나 Early Bird 할인을 통해 거래를 분산시킬 수 있습니다. 3. Home 카테고리의 매출 비중이 9.5%로 낮으므로, 이 카테고리의 상품 라인업을 확대하거나 계절별 프로모션을 기획해볼 가치가 있습니다. 4. 평균 주문 금액 $562를 기준으로 $600 이상 구매 시 무료 배송 등의 인센티브를 제공하여 객단가 상승을 유도할 수 있습니다. ============================================================ ✨ 분석 완료! ``` ## 프롬프트 엔지니어링 팁 ### 1. 명확한 역할 정의 ```typescript const SYSTEM_PROMPT = `당신은 전문적인 비즈니스 애널리스트입니다. 당신의 역할: - 매출 데이터를 분석하여 핵심 인사이트를 도출합니다 - 데이터에 기반한 실용적인 비즈니스 제안을 제공합니다`; ``` ### 2. 구체적인 형식 지정 ```typescript 위 데이터를 분석하여 다음 형식으로 제공해주세요: ## 📊 매출 요약 (전체 매출을 2-3문장으로 요약) ## 💡 주요 인사이트 (데이터에서 발견한 중요한 사실 3-5가지) ``` ### 3. 제약 조건 명시 ```typescript 제약 조건: - 각 인사이트는 1-2문장으로 작성 - 데이터에 근거한 사실만 언급 - 추측이나 가정은 피할 것 - 실행 가능한 제안만 포함 ``` ### 4. 예시 제공 (Few-shot Learning) ```typescript const EXAMPLE_ANALYSIS = ` 예시: ## 📊 매출 요약 오늘 20건의 거래를 통해 $12,450의 매출을 달성했습니다. 건당 평균 $622.50으로 안정적인 수준을 유지했습니다. ## 💡 주요 인사이트 1. Electronics 카테고리가 전체 매출의 55%를 차지하며 핵심 카테고리로 확인됨 2. 오후 2-5시 사이에 전체 거래의 60%가 집중되어 있음 `; // 프롬프트에 추가 const prompt = `${EXAMPLE_ANALYSIS}\n\n이제 다음 데이터를 분석해주세요:\n\n${dataText}`; ``` ## 고급 분석 기능 ### 비교 분석 ```typescript /** * 어제와 비교 분석 */ export async function compareWithYesterday( today: SalesStats, yesterday: SalesStats ): Promise { const prompt = `다음은 오늘과 어제의 매출 비교입니다: 오늘 (${today.date}): - 총 매출: $${(today.totalAmount / 100).toFixed(2)} - 거래 건수: ${today.totalCount} - 평균 주문: $${(today.averageAmount / 100).toFixed(2)} 어제 (${yesterday.date}): - 총 매출: $${(yesterday.totalAmount / 100).toFixed(2)} - 거래 건수: ${yesterday.totalCount} - 평균 주문: $${(yesterday.averageAmount / 100).toFixed(2)} 변화율과 주요 차이점을 분석하여 3-4문장으로 설명해주세요.`; const response = await openai.chat.completions.create({ model: env.openaiModel, messages: [ { role: 'system', content: '당신은 매출 트렌드 분석 전문가입니다.', }, { role: 'user', content: prompt, }, ], max_tokens: 300, }); return response.choices[0].message.content || ''; } ``` ### 목표 대비 분석 ```typescript /** * 목표 대비 실적 분석 */ export async function analyzeVsGoal( stats: SalesStats, goalAmount: number, goalCount: number ): Promise { const achievementRate = (stats.totalAmount / goalAmount) * 100; const countRate = (stats.totalCount / goalCount) * 100; const prompt = `오늘의 매출 목표와 실적: 목표: - 매출 목표: $${(goalAmount / 100).toFixed(2)} - 거래 목표: ${goalCount}건 실적: - 실제 매출: $${(stats.totalAmount / 100).toFixed(2)} (달성률: ${achievementRate.toFixed(1)}%) - 실제 거래: ${stats.totalCount}건 (달성률: ${countRate.toFixed(1)}%) 목표 달성 여부를 평가하고, 개선이 필요한 부분을 2-3가지 제안해주세요.`; const response = await openai.chat.completions.create({ model: env.openaiModel, messages: [ { role: 'user', content: prompt, }, ], max_tokens: 400, }); return response.choices[0].message.content || ''; } ``` ### 다국어 분석 ```typescript /** * 한국어/영어 선택 가능한 분석 */ export async function analyzeSalesMultiLang( stats: SalesStats, language: 'ko' | 'en' = 'ko' ): Promise { const langInstruction = language === 'ko' ? '한국어로 답변해주세요.' : 'Please respond in English.'; const systemPrompt = `${SYSTEM_PROMPT}\n\n${langInstruction}`; // ... 나머지 로직 } ``` ## 응답 캐싱 (비용 절감) ```typescript import fs from 'fs/promises'; import crypto from 'crypto'; /** * 분석 결과 캐싱 */ export async function analyzeSalesWithCache( stats: SalesStats ): Promise { const cacheDir = '.cache'; const hash = crypto .createHash('md5') .update(JSON.stringify(stats)) .digest('hex'); const cacheFile = `${cacheDir}/analysis-${hash}.json`; try { // 캐시 확인 const cached = await fs.readFile(cacheFile, 'utf-8'); console.log('📦 캐시된 분석 결과 사용'); return JSON.parse(cached); } catch { // 캐시 없음, 새로 분석 const result = await analyzeSales(stats); // 캐시 저장 await fs.mkdir(cacheDir, { recursive: true }); await fs.writeFile(cacheFile, JSON.stringify(result, null, 2)); return result; } } ``` ## 체크리스트 v8를 완료하기 전에 다음을 확인하세요: - [ ] `src/chatgpt/analyze.ts` 작성 - [ ] `src/analyze-sales.ts` 작성 - [ ] package.json 스크립트 추가 - [ ] 테스트 결제 생성 (`npm run generate`) - [ ] 분석 실행 (`npm run analyze`) - [ ] 프롬프트가 적절한 응답을 생성하는지 확인 - [ ] 응답 파싱이 제대로 작동하는지 확인 - [ ] 토큰 사용량 확인 ## 트러블슈팅 ### 1. 응답이 형식에 맞지 않음 **원인**: ChatGPT가 지정된 형식을 따르지 않음 **해결**: - 프롬프트에 형식을 더 명확히 지정 - 예시 추가 - Temperature 낮추기 (0.5 이하) ### 2. 분석이 너무 일반적임 **원인**: 구체적인 데이터가 부족하거나 프롬프트가 모호함 **해결**: - 더 많은 컨텍스트 제공 - 구체적인 질문 추가 - Few-shot 예시 제공 ### 3. 토큰 한도 초과 **원인**: 응답이 너무 김 **해결**: - `max_tokens` 증가 - 또는 요청을 여러 번으로 분할 ## 다음 단계 v9에서는 분석 결과를 더 보기 좋게 포맷팅하고 출력합니다. 준비할 것: - 분석이 정상적으로 작동하는지 확인 - 응답 품질 평가 --- **작성일**: 2025-11-28 **상태**: ✅ 완료 **다음**: v9 - 결과 포맷팅 및 출력