feat: Integrate VTS functionality and improve emoji response system

- Added VTSList function to read and process Excel file for V.T.S. entries.
- Implemented isVTS function to check if a given date is in the VTS list.
- Updated CreateImage class to conditionally display "with V.T.S." based on VTS status.
- Enhanced NameToEmoji function's prompt for clarity and formatting.
- Added exceljs dependency for Excel file handling.
- Modified playground.ts for testing VTS functionality.
This commit is contained in:
imnyang 2025-05-10 21:09:55 +09:00
commit 42be227916
6 changed files with 317 additions and 11 deletions

View file

@ -3,6 +3,7 @@ import { join } from "path";
import { createCanvas, loadImage, GlobalFonts } from "@napi-rs/canvas";
import { getMealInfo, NameToEmoji } from "./meal"; // 이 함수의 내용은 제공되지 않았으므로 그대로 둡니다.
import { getAllSchedules } from "./schedule";
import { isVTS } from "./vts";
GlobalFonts.registerFromPath('./template/Pretendard-Bold.ttf', 'Pretendard Bold')
GlobalFonts.registerFromPath('./template/NotoColorEmoji-Regular.ttf', 'NotoColorEmoji Regular')
@ -51,10 +52,10 @@ export class CreateImage {
ctx.fillStyle = "#89CAFF";
ctx.fillText(mealInfo.kcal, 945, 220);
/*if (vts.VTS(MLSV_YMD)) {
if (await isVTS(MLSV_YMD)) {
ctx.fillStyle = "#CDAD94";
ctx.fillText("with V.T.S.", 830, 225);
}*/ // VTS
ctx.fillText("with V.T.S.", 952.5, 245);
} // VTS 관련 코드 주석 처리
const outPath = path.join("./temp", `${MLSV_YMD}.png`); // 경로 수정: "./temp/" -> "./temp"
const buffer = canvas.toBuffer("image/png");

View file

@ -39,20 +39,28 @@ export async function NameToEmoji(name: string): Promise<string> {
new AzureKeyCredential(token),
);
const systemPrompt = `You are an emoji responder.
When given any word or phrase, you must reply with exactly one emoji per item, matching the meaning as closely as possible.
const systemPrompt = `**You are an emoji responder.**
When given any word or phrase, you **must reply with exactly one emoji per item**, matching the meaning as closely as possible.
**If multiple words or phrases are given, they will be separated by commas (,), and your emojis must also be separated by commas (,) in the same order.**
Do not include any words, explanations, or multiple emojisjust **one emoji per item**.
**Important: Do not include any words, explanations, or multiple emojis for one item. Reply with only one emoji per item.**
**Examples:**
Examples:
Q: 현미찹쌀밥
A: 🍚
Q:
A: 🐶
Q: 축구
A:
Q: 해넘이
A: 🌇
Q: 현미찹쌀밥,,
A: 🍚,🐶,
`;

93
app/lib/vts.ts Normal file
View file

@ -0,0 +1,93 @@
import ExcelJS from 'exceljs';
const filePath = './temp/vts.xlsx';
export async function VTSList(): Promise<string[]> {
const yellowCellValues: string[] = [];
const workbook = new ExcelJS.Workbook();
try {
await workbook.xlsx.readFile(filePath);
// 모든 시트를 순회하거나 특정 시트를 지정할 수 있습니다.
// 여기서는 첫 번째 시트를 대상으로 합니다.
const worksheet = workbook.worksheets[0]; // 또는 workbook.getWorksheet('Sheet1');
if (!worksheet) {
console.log('시트를 찾을 수 없습니다.');
return [];
}
// 1. 시트 내 "V.T.S." 문자열 포함 여부 확인 (전체 셀 순회 - 비효율적일 수 있음)
let containsVTS = false;
worksheet.eachRow((row) => {
row.eachCell((cell) => {
if (cell.value && cell.value.toString().includes('V.T.S.')) {
containsVTS = true;
return; // VTS 찾으면 더 이상 순회 안 함
}
});
if (containsVTS) return;
});
if (!containsVTS) {
console.log('시트 내에 "V.T.S." 문자열을 찾을 수 없습니다.');
return [];
}
// 2. 5번째 행 가져오기
const fifthRow = worksheet.getRow(5); // 행 번호는 1부터 시작
if (!fifthRow.hasValues) {
console.log('5번째 행에 데이터가 없습니다.');
return [];
}
// 3. 5번째 행의 각 셀 순회하며 배경색 확인
fifthRow.eachCell({ includeEmpty: false }, (cell, colNumber) => {
const cellFill = cell.style.fill;
// 배경색 확인 (exceljs는 ARGB 형태의 hex 값을 사용할 수 있습니다. 예: 'FFFFFFFF00')
// #FFFF00 (노란색)에 해당하는 ARGB 값은 FFFF00 입니다 (Alpha는 FF).
// 라이브러리 버전에 따라 fill.fgColor.argb 또는 다른 속성일 수 있습니다.
if (cellFill && cellFill.type === 'pattern' && cellFill.pattern === 'solid') {
const argbColor = cellFill.fgColor?.argb;
// console.log(`Cell ${cell.address} color: ${argbColor}`); // 디버깅용
// FFFF00 (노란색) 또는 ffFFFF00 (대소문자 무시)
if (argbColor && argbColor.toUpperCase().endsWith('FFFF00')) {
const cellValue = cell.value ? cell.value.toString() : '';
// 날짜를 변환하는 부분
const datePattern = /(\d{2})월 (\d{2})일/; // "04월 10일" 패턴
const match = cellValue.match(datePattern);
if (match) {
const month = match[1];
const day = match[2];
const currentYear = new Date().getFullYear(); // 현재 연도
// "현재년도0410" 형식으로 변환
const formattedDate = `${currentYear}${month}${day}`;
yellowCellValues.push(formattedDate);
console.log(`노란색 셀 발견: ${cell.address}, 값: ${formattedDate}`);
} else {
yellowCellValues.push(cellValue);
}
}
}
});
return yellowCellValues;
} catch (error) {
console.error('Excel 파일 처리 중 오류 발생:', error);
return [];
}
}
export async function isVTS(MLSV_YMD: string): Promise<boolean> {
const vtsList = await VTSList();
return vtsList.includes(MLSV_YMD);
}