import { query } from '../../utils/db' import { callOpenAIVision, REPORT_PARSE_SYSTEM_PROMPT } from '../../utils/openai' const ADMIN_EMAIL = 'coziny@gmail.com' interface ParsedTask { description: string hours: number } interface ParsedProject { projectName: string workTasks: ParsedTask[] planTasks: ParsedTask[] } interface ParsedReport { employeeName: string employeeEmail: string | null projects: ParsedProject[] issueDescription: string | null vacationDescription: string | null remarkDescription: string | null } interface ParsedResult { reportYear: number reportWeek: number weekStartDate: string weekEndDate: string reports: ParsedReport[] } /** * 이미지에서 주간보고 분석 (OpenAI Vision) * POST /api/admin/parse-image */ export default defineEventHandler(async (event) => { // 관리자 권한 체크 const userId = getCookie(event, 'user_id') if (!userId) { throw createError({ statusCode: 401, message: '로그인이 필요합니다.' }) } const currentUser = await query(` SELECT employee_email FROM wr_employee_info WHERE employee_id = $1 `, [userId]) if (!currentUser[0] || currentUser[0].employee_email !== ADMIN_EMAIL) { throw createError({ statusCode: 403, message: '관리자만 사용할 수 있습니다.' }) } const body = await readBody<{ images: string[] }>(event) if (!body.images || body.images.length === 0) { throw createError({ statusCode: 400, message: '분석할 이미지를 업로드해주세요.' }) } if (body.images.length > 10) { throw createError({ statusCode: 400, message: '이미지는 최대 10장까지 업로드 가능합니다.' }) } // OpenAI Vision 분석 const aiResponse = await callOpenAIVision(REPORT_PARSE_SYSTEM_PROMPT, body.images) let parsed: ParsedResult try { parsed = JSON.parse(aiResponse) } catch (e) { throw createError({ statusCode: 500, message: 'AI 응답 파싱 실패' }) } // 주차 정보 기본값 설정 (AI가 파싱 못한 경우) const now = new Date() if (!parsed.reportYear) { parsed.reportYear = now.getFullYear() } if (!parsed.reportWeek) { // ISO 주차 계산 const startOfYear = new Date(now.getFullYear(), 0, 1) const days = Math.floor((now.getTime() - startOfYear.getTime()) / (24 * 60 * 60 * 1000)) parsed.reportWeek = Math.ceil((days + startOfYear.getDay() + 1) / 7) } if (!parsed.weekStartDate || !parsed.weekEndDate) { // 현재 주의 월요일~일요일 계산 const day = now.getDay() const monday = new Date(now) monday.setDate(now.getDate() - (day === 0 ? 6 : day - 1)) const sunday = new Date(monday) sunday.setDate(monday.getDate() + 6) parsed.weekStartDate = monday.toISOString().split('T')[0] parsed.weekEndDate = sunday.toISOString().split('T')[0] } // 기존 직원 목록 조회 const employees = await query(` SELECT employee_id, employee_name, employee_email FROM wr_employee_info WHERE is_active = true `) // 기존 프로젝트 목록 조회 const projects = await query(` SELECT project_id, project_code, project_name FROM wr_project_info WHERE project_status != 'COMPLETED' `) // 직원 및 프로젝트 매칭 const matchedReports = parsed.reports.map(report => { let matchedEmployee = null if (report.employeeEmail) { matchedEmployee = employees.find( (e: any) => e.employee_email.toLowerCase() === report.employeeEmail?.toLowerCase() ) } if (!matchedEmployee) { matchedEmployee = employees.find( (e: any) => e.employee_name === report.employeeName ) } const matchedProjects = report.projects.map(proj => { const existingProject = projects.find((p: any) => p.project_name.includes(proj.projectName) || proj.projectName.includes(p.project_name) ) return { ...proj, matchedProjectId: existingProject?.project_id || null, matchedProjectCode: existingProject?.project_code || null, matchedProjectName: existingProject?.project_name || null, isNewProject: !existingProject } }) return { ...report, matchedEmployeeId: matchedEmployee?.employee_id || null, matchedEmployeeName: matchedEmployee?.employee_name || null, matchedEmployeeEmail: matchedEmployee?.employee_email || null, isEmployeeMatched: !!matchedEmployee, isNewEmployee: !matchedEmployee && !!report.employeeEmail, projects: matchedProjects } }) return { success: true, parsed: { reportYear: parsed.reportYear, reportWeek: parsed.reportWeek, weekStartDate: parsed.weekStartDate, weekEndDate: parsed.weekEndDate, reports: matchedReports }, employees: employees.map((e: any) => ({ employeeId: e.employee_id, employeeName: e.employee_name, employeeEmail: e.employee_email })), projects: projects.map((p: any) => ({ projectId: p.project_id, projectCode: p.project_code, projectName: p.project_name })) } })