import { defineEventHandler, readBody, createError } from 'h3' import { query } from '../../utils/db' import OpenAI from 'openai' const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }) /** * 주간보고 PMO AI 리뷰 * POST /api/report/review */ export default defineEventHandler(async (event) => { const body = await readBody(event) const { reportId } = body if (!reportId) { throw createError({ statusCode: 400, message: 'reportId가 필요합니다.' }) } // 주간보고 조회 const reports = await query(` SELECT r.report_id, r.report_year, r.report_week, e.employee_name as author_name FROM wr_weekly_report r JOIN wr_employee_info e ON r.author_id = e.employee_id WHERE r.report_id = $1 `, [reportId]) if (reports.length === 0) { throw createError({ statusCode: 404, message: '주간보고를 찾을 수 없습니다.' }) } const report = reports[0] // Task 조회 const tasks = await query(` SELECT t.task_type, t.task_description, t.task_hours, t.is_completed, p.project_name FROM wr_weekly_report_task t JOIN wr_project_info p ON t.project_id = p.project_id WHERE t.report_id = $1 ORDER BY t.task_type, p.project_name `, [reportId]) if (tasks.length === 0) { throw createError({ statusCode: 400, message: '등록된 Task가 없습니다.' }) } // Task를 실적/계획으로 분리 const workTasks = tasks.filter((t: any) => t.task_type === 'WORK') const planTasks = tasks.filter((t: any) => t.task_type === 'PLAN') // 프롬프트용 텍스트 생성 let taskText = `[작성자] ${report.author_name}\n[기간] ${report.report_year}년 ${report.report_week}주차\n\n` if (workTasks.length > 0) { taskText += `[금주 실적]\n` workTasks.forEach((t: any) => { const status = t.is_completed ? '완료' : '진행중' taskText += `- ${t.project_name} / ${t.task_description} / ${t.task_hours}h / ${status}\n` }) taskText += '\n' } if (planTasks.length > 0) { taskText += `[차주 계획]\n` planTasks.forEach((t: any) => { taskText += `- ${t.project_name} / ${t.task_description} / ${t.task_hours}h\n` }) } // OpenAI PMO 리뷰 요청 const systemPrompt = `당신은 SI 프로젝트의 PMO(Project Management Officer)이자 주간보고 작성 코치입니다. 개발자들이 더 나은 주간보고를 작성할 수 있도록 구체적인 피드백과 가이드를 제공해주세요. [주간보고 작성의 목적] - 프로젝트 진행 현황을 명확히 파악 - 일정 지연이나 리스크를 사전에 감지 - 팀원 간 업무 공유 및 협업 촉진 [검토 기준 - 엄격하게 적용] 1. **실적의 구체성** (가장 중요!) - "DB 작업", "화면 개발", "API 개발" 같은 모호한 표현 지양 - 좋은 예시: "사용자 관리 테이블 3개(user, role, permission) 설계 및 생성" - 좋은 예시: "로그인 API 개발 - JWT 토큰 발급, 리프레시 토큰 구현" - 좋은 예시: "검색 화면 UI 구현 - 필터 조건 5개, 페이징, 엑셀 다운로드" - 어떤 기능/모듈/화면인지, 무엇을 구체적으로 했는지 명시되어야 함 2. **일정의 명확성** - "진행중"만 있고 완료 예정일이 없으면 부족 - 언제 완료될 예정인지, 진척률은 얼마인지 표기 권장 - 좋은 예시: "사용자 관리 화면 개발 (70% 완료, 1/10 완료 예정)" 3. **시간 산정의 적절성** - 8시간(1일) 이상 작업은 세부 내역이 필요 - 16시간(2일) 이상인데 내용이 한 줄이면 분리 필요 - "회의", "검토" 등은 별도 기재 권장 4. **차주 계획의 실현 가능성** - 계획이 너무 추상적이면 실행하기 어려움 - 구체적인 목표와 예상 산출물 명시 필요 - 좋은 예시: "결제 모듈 연동 - PG사 API 연동, 결제 테스트 완료 목표" [피드백 작성 규칙] - 각 Task별로 구체적인 개선 제안 제시 - 잘 작성된 부분은 "✅" 로 인정 - 보완이 필요한 부분은 "📝" 로 개선 방향 제시 - 일정 관련 질문은 "📅" 로 표시 - 리스크/우려사항은 "⚠️" 로 경고 - **반드시 어떻게 수정하면 좋을지 예시를 들어 설명** - 친절하지만 명확하게, 구체적인 작성 예시를 포함 - 마지막에 전체적인 작성 팁 1-2개 추가 [피드백 톤] - 비난하지 않고 코칭하는 느낌으로 - "~하면 더 좋겠습니다", "~로 수정해보시면 어떨까요?" 형태로 - 개선점뿐 아니라 잘한 점도 언급` const userPrompt = `다음 주간보고를 PMO 관점에서 상세히 리뷰해주세요. 특히 실적과 계획이 구체적으로 작성되었는지, 일정이 명확한지 중점적으로 검토해주세요. 모호한 표현이 있다면 어떻게 수정하면 좋을지 예시와 함께 피드백해주세요. ${taskText}` try { const response = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: userPrompt } ], max_tokens: 1500, temperature: 0.7 }) const review = response.choices[0]?.message?.content || '리뷰를 생성할 수 없습니다.' const reviewedAt = new Date().toISOString() // DB에 저장 await query(` UPDATE wr_weekly_report SET ai_review = $1, ai_review_at = $2 WHERE report_id = $3 `, [review, reviewedAt, reportId]) return { success: true, review, reviewedAt } } catch (error: any) { console.error('OpenAI API error:', error) throw createError({ statusCode: 500, message: 'AI 리뷰 생성 중 오류가 발생했습니다: ' + error.message }) } })