diff --git a/README.md b/README.md index 1597f84124d834c1c30b6854a4cd732e2474adbf..8c60df3e73d6233a44067a42c11a05979cb61fee 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,7 @@ API_USER_PW={CDA 사용자 PW (필수)} LOGIN_API_URL=https://{내부IP}/login STATS_API_URL=https://{내부IP}/secured/ui/common ``` + +## 샘플 질문 +2021년 6월 한달동안 가장많이 인바운드업무를 한 Agent 누구야? +2021년 6월 한달동안 콜 인입이 가장 많이 들어온 VDN알려줘. \ No newline at end of file diff --git a/src/tools/stat-tools.ts b/src/tools/stat-tools.ts index 8847bb0a80ecc6d2aa023f7a72d6afe845a9c8bc..a88be74086872822deb768eb6dcad0c472c6541d 100644 --- a/src/tools/stat-tools.ts +++ b/src/tools/stat-tools.ts @@ -228,18 +228,20 @@ export function registerStatTools(factory: ToolFactory, config: ApiConfig): void const payload = { _sqlName: ["cda_CallTimeResult_select"], - fromhour: "0000", - tohour: "239959", - use_yn: "Y", - gubun: 3, - org1_cd: "전체", - org2_cd: "전체", - org3_cd: "전체", - user_id: [], - edit_agent_id: "", + parameters: { + fromhour: "0000", + tohour: "239959", + use_yn: "Y", + gubun: 3, + org1_cd: "전체", + org2_cd: "전체", + org3_cd: "전체", + user_id: [], + edit_agent_id: "", + fromdate: fromDate, + todate: toDate, + }, _dataset: [], - fromdate: fromDate, - todate: toDate, }; let body: ApiResponse<{ cda_CallTimeResult_select?: StatsResultSet }>; @@ -311,9 +313,58 @@ export function registerStatTools(factory: ToolFactory, config: ApiConfig): void return `Record ${index + 1}\n${formatRecord(columns, row)}`; }); + const columnSchemas = buildColumnSchema(columns); + const recordObjects = filteredRecords.map((row) => mapRowToObject(columns, row)); + const acdcallsIndex = columns.findIndex((col) => col?.toLowerCase() === "acdcalls"); + const acdtimeIndex = columns.findIndex((col) => col?.toLowerCase() === "acdtime"); + + const totals = filteredRecords.reduce( + (acc, row) => { + acc.acdcalls += acdcallsIndex >= 0 ? toNumber(row[acdcallsIndex]) : 0; + acc.acdtime += acdtimeIndex >= 0 ? toNumber(row[acdtimeIndex]) : 0; + return acc; + }, + { acdcalls: 0, acdtime: 0 }, + ); + + const sampleRecord = recordObjects[0] ?? {}; + const sampleAcdcalls = toNumber(sampleRecord["acdcalls"]); + const sampleAcdtime = toNumber(sampleRecord["acdtime"]); + const sampleAgentName = String(sampleRecord["agent_name"] ?? "-"); + const sampleSuccessRate = + sampleAcdcalls > 0 ? sampleAcdtime / sampleAcdcalls : null; + const totalSuccessRate = totals.acdcalls > 0 ? totals.acdtime / totals.acdcalls : null; + + const successRateExplanation = sampleSuccessRate + ? `예: ${sampleAgentName}의 성공률(초/콜) = ${sampleAcdtime} ÷ ${sampleAcdcalls} = ${sampleSuccessRate.toFixed( + 2, + )}` + : "첫 번째 기록에 acdtime 또는 acdcalls 값이 없어 성공률 예시를 제공할 수 없습니다."; + + const structuredData = { + schema: columnSchemas, + records: recordObjects, + totals, + calculations: { + successRateFormula: "acdtime ÷ acdcalls", + successRateExample: sampleSuccessRate + ? { + agentName: sampleAgentName, + acdtime: sampleAcdtime, + acdcalls: sampleAcdcalls, + result: Number(sampleSuccessRate.toFixed(2)), + } + : null, + totalSuccessRate: totalSuccessRate ? Number(totalSuccessRate.toFixed(2)) : null, + }, + }; + const summary = [ `Agent stats for ${fromDate} to ${toDate}`, `Transactions returned: ${filteredRecords.length}`, + `IB 총 통화콜수(합계): ${totals.acdcalls}`, + `IB 총 통화시간(합계): ${formatDuration(totals.acdtime)} (${totals.acdtime} sec)`, + successRateExplanation, statusMessage, "", formattedRecords.join("\n\n"), @@ -326,6 +377,7 @@ export function registerStatTools(factory: ToolFactory, config: ApiConfig): void text: summary, }, ], + structuredData, }; }, ); @@ -473,3 +525,59 @@ function formatRecord(columns: string[], row: unknown[]): string { }); return values.join("\n"); } + +interface ColumnMeta { + label: string; + description: string; +} + +interface ColumnSchema { + name: string; + label: string; + description: string; +} + +const COLUMN_METADATA: Record = { + workdate: { label: "작업일/기간", description: "날짜 또는 기간" }, + starttime: { label: "콜 시작시간", description: "콜이 시작된 시각" }, + dept_nm: { label: "부서 이름", description: "콜을 담당한 부서 이름" }, + agent_id: { label: "사번/에이전트 ID", description: "에이전트 식별자" }, + user_id: { label: "사용자 아이디", description: "시스템 사용자 ID" }, + agent_name: { label: "에이전트 이름", description: "에이전트의 실명 또는 호칭" }, + acdcalls: { label: "IB 통화콜수", description: "인바운드 통화콜 수" }, + acdtime: { label: "IB 통화시간", description: "인바운드 통화에 소요된 총 시간(초)" }, + abncalls: { label: "IB 포기콜수", description: "인바운드 전화에서 고객이 포기한 횟수" }, + abntime: { label: "IB 포기시간", description: "포기 콜에 소요된 시간(초)" }, + da_acdcalls: { label: "IB-DA 통화콜수", description: "인바운드 DA 통화콜 수" }, + da_acdtime: { label: "IB-DA 통화시간", description: "DA 포함 인바운드 통화시간(초)" }, + da_abncalls: { label: "IB-DA 포기콜수", description: "DA 관련 포기 콜 수" }, + da_abntime: { label: "IB-DA 포기시간", description: "DA 관련 포기 콜에 소요된 시간(초)" }, + auxoutoffcalls: { label: "OB 시도콜수", description: "아웃바운드 시도 콜 수" }, + auxoutofftime: { label: "OB 통화콜수", description: "아웃바운드에서 실제 통화된 콜 수" }, + auxoutoffconncalls: { label: "OB 벨울림 포함시간", description: "OB 벨울림 포함 통화 시간" }, + auxoutofftalktime: { label: "OB 통화시간", description: "아웃바운드 통화에 실제 소요된 시간(초)" }, + acd_rate: { label: "IB 응대율", description: "인바운드 통화 중 응대된 비율(%)" }, + inout_calls: { label: "IB+OB 합계 콜수", description: "인바운드와 아웃바운드 콜의 합" }, + auxincalls: { label: "기타 인입콜수", description: "기타 인입 콜 수" }, + auxintime: { label: "기타 인입시간", description: "기타 인입 콜에 소요된 시간(초)" }, +}; + +function buildColumnSchema(columns: string[]): ColumnSchema[] { + return columns.map((columnName, index) => { + const key = columnName ?? `column${index + 1}`; + const meta = COLUMN_METADATA[key.toLowerCase()]; + return { + name: key, + label: meta?.label ?? key, + description: meta?.description ?? "설명 없음", + }; + }); +} + +function mapRowToObject(columns: string[], row: unknown[]): Record { + return columns.reduce>((acc, columnName, index) => { + const key = columnName ?? `column${index + 1}`; + acc[key] = row[index] ?? null; + return acc; + }, {}); +}