기능구현중
This commit is contained in:
150
server/api/ai/parse-my-report.post.ts
Normal file
150
server/api/ai/parse-my-report.post.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { query } from '../../utils/db'
|
||||
import { callOpenAI } from '../../utils/openai'
|
||||
import { requireAuth } from '../../utils/session'
|
||||
|
||||
interface ParsedTask {
|
||||
description: string
|
||||
hours: number
|
||||
isCompleted?: boolean
|
||||
}
|
||||
|
||||
interface ParsedProject {
|
||||
projectName: string
|
||||
matchedProjectId: number | null
|
||||
workTasks: ParsedTask[]
|
||||
planTasks: ParsedTask[]
|
||||
}
|
||||
|
||||
interface ParsedResult {
|
||||
projects: ParsedProject[]
|
||||
issueDescription: string | null
|
||||
vacationDescription: string | null
|
||||
remarkDescription: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* 개인 주간보고 텍스트 분석 (OpenAI)
|
||||
* POST /api/ai/parse-my-report
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const userId = await requireAuth(event)
|
||||
|
||||
const body = await readBody<{ rawText: string }>(event)
|
||||
|
||||
if (!body.rawText || body.rawText.trim().length < 5) {
|
||||
throw createError({ statusCode: 400, message: '분석할 텍스트를 입력해주세요.' })
|
||||
}
|
||||
|
||||
// 기존 프로젝트 목록 조회
|
||||
const projects = await query<any>(`
|
||||
SELECT project_id, project_code, project_name
|
||||
FROM wr_project_info
|
||||
WHERE project_status = 'IN_PROGRESS'
|
||||
`)
|
||||
|
||||
// 프로젝트 목록을 ID 포함해서 전달
|
||||
const projectList = projects.map(p => `[ID:${p.project_id}] ${p.project_code}: ${p.project_name}`).join('\n')
|
||||
|
||||
// OpenAI 분석
|
||||
const prompt = buildMyReportPrompt(body.rawText, projectList)
|
||||
const aiResponse = await callOpenAI(prompt, true)
|
||||
|
||||
let parsed: ParsedResult
|
||||
try {
|
||||
parsed = JSON.parse(aiResponse)
|
||||
} catch (e) {
|
||||
throw createError({ statusCode: 500, message: 'AI 응답 파싱 실패' })
|
||||
}
|
||||
|
||||
// 프로젝트 매칭
|
||||
if (parsed.projects) {
|
||||
for (const proj of parsed.projects) {
|
||||
if (!proj.matchedProjectId && proj.projectName) {
|
||||
const matched = projects.find((p: any) =>
|
||||
p.project_name.toLowerCase().includes(proj.projectName.toLowerCase()) ||
|
||||
proj.projectName.toLowerCase().includes(p.project_name.toLowerCase()) ||
|
||||
p.project_code.toLowerCase() === proj.projectName.toLowerCase()
|
||||
)
|
||||
if (matched) {
|
||||
proj.matchedProjectId = matched.project_id
|
||||
proj.projectName = matched.project_name
|
||||
}
|
||||
}
|
||||
|
||||
// workTasks 기본값
|
||||
proj.workTasks = (proj.workTasks || []).map((t: any) => ({
|
||||
description: t.description || '',
|
||||
hours: t.hours || 0,
|
||||
isCompleted: t.isCompleted !== false
|
||||
}))
|
||||
|
||||
// planTasks 기본값
|
||||
proj.planTasks = (proj.planTasks || []).map((t: any) => ({
|
||||
description: t.description || '',
|
||||
hours: t.hours || 0
|
||||
}))
|
||||
}
|
||||
|
||||
// 내용 없는 프로젝트 제외 (workTasks, planTasks 모두 비어있으면 제외)
|
||||
parsed.projects = parsed.projects.filter((proj: any) =>
|
||||
(proj.workTasks && proj.workTasks.length > 0) ||
|
||||
(proj.planTasks && proj.planTasks.length > 0)
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
parsed,
|
||||
projects
|
||||
}
|
||||
})
|
||||
|
||||
function buildMyReportPrompt(rawText: string, projectList: string): any[] {
|
||||
return [
|
||||
{
|
||||
role: 'system',
|
||||
content: `당신은 주간보고 내용을 분석하는 AI입니다.
|
||||
사용자가 입력한 텍스트를 분석하여 프로젝트별 업무 내용을 추출해주세요.
|
||||
|
||||
현재 등록된 프로젝트 목록 (형식: [ID:숫자] 코드: 이름):
|
||||
${projectList}
|
||||
|
||||
⚠️ 중요: 입력 텍스트에서 추출한 프로젝트명과 위 목록을 비교하여 가장 유사한 프로젝트의 ID를 matchedProjectId에 반환하세요.
|
||||
- 유사도 판단: 키워드 일치, 약어, 부분 문자열 등 고려
|
||||
- 예: "한우 유전체" → "보은 한우 온라인 유전체 분석" 매칭 가능
|
||||
- 예: "HEIS" → "보건환경연구원 HEIS" 매칭 가능
|
||||
- 매칭되는 프로젝트가 없으면 matchedProjectId는 null
|
||||
|
||||
응답은 반드시 아래 JSON 형식으로만 출력하세요:
|
||||
{
|
||||
"projects": [
|
||||
{
|
||||
"projectName": "입력에서 추출한 원본 프로젝트명",
|
||||
"matchedProjectId": 5,
|
||||
"workTasks": [
|
||||
{"description": "작업내용", "hours": 8, "isCompleted": true}
|
||||
],
|
||||
"planTasks": [
|
||||
{"description": "계획내용", "hours": 8}
|
||||
]
|
||||
}
|
||||
],
|
||||
"issueDescription": "이슈/리스크 내용 또는 null",
|
||||
"vacationDescription": "휴가일정 내용 또는 null",
|
||||
"remarkDescription": "기타사항 내용 또는 null"
|
||||
}
|
||||
|
||||
규칙:
|
||||
1. projectName은 입력 텍스트에서 추출한 원본 그대로
|
||||
2. matchedProjectId는 위 프로젝트 목록에서 가장 유사한 프로젝트의 ID (숫자)
|
||||
3. "금주 실적", "이번주", "완료" 등은 workTasks로 분류
|
||||
4. "차주 계획", "다음주", "예정" 등은 planTasks로 분류
|
||||
5. 시간이 명시되지 않은 경우 hours는 0으로
|
||||
6. JSON 외의 텍스트는 절대 출력하지 마세요`
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: rawText
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user