This commit is contained in:
imnyang 2025-05-31 01:07:25 +09:00
commit 6c4f5f799e
No known key found for this signature in database
GPG key ID: 356406A02D4AFA55
5 changed files with 416 additions and 11 deletions

View file

@ -1,3 +1,4 @@
import { Discord } from "./lib/discord";
import { CreateImage } from "./lib/image";
import { Login, Upload } from "./lib/instagram";
@ -29,6 +30,7 @@ async function main() {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
YYMMDD = tomorrow.toISOString().slice(0, 10).replace(/-/g, "").toString();
YYMMDD = "20250602";
console.log("📅 | date:", YYMMDD);
@ -51,7 +53,7 @@ async function main() {
}
try {
console.time("📷 | Create Post Image");
await CreateImage.PostMeal(YYMMDD);
const NutritionInfo = await CreateImage.PostMeal(YYMMDD);
console.timeEnd("📷 | Create Post Image");
console.time("📱 | Create Story Image");
@ -59,15 +61,37 @@ async function main() {
console.timeEnd("📱 | Create Story Image");
console.time("📤 | Upload Post");
let NutritionInfoText = ""
const entries = Object.entries(NutritionInfo ?? {}).filter(([_, value]) => value.toString().length > 0);
entries.forEach(([name, value], idx) => {
NutritionInfoText += `${name} : ${value.toString().replace(",", ", ")}`;
if (idx !== entries.length - 1) {
NutritionInfoText += "\n";
}
});
await Upload.Post(
`./temp/${YYMMDD}.png`,
`#인천상정중학교 #상정중학교 #급식 \n${YYMMDD}일자 급식`
[
`🍽️ | ${YYMMDD}일자 급식`,
"===========================",
"⚠️ 알레르기 유발 가능 성분이 포함되어 있습니다.",
NutritionInfoText,
"===========================",
"#인천상정중학교 #상정중학교 #급식"
].join("\n")
);
console.timeEnd("📤 | Upload Post");
console.time("📤 | Upload Story");
await Upload.Story(`./temp/${YYMMDD}-story.png`, YYMMDD);
console.timeEnd("📤 | Upload Story");
console.time("🤖 | Discord Webhook");
await Discord(YYMMDD);
console.timeEnd("🤖 | Discord Webhook");
} catch (error) {
console.error("❌ | Error during image creation or upload:", error);
} finally {

View file

@ -1,7 +1,7 @@
import path from "path";
import { join } from "path";
import { createCanvas, loadImage, GlobalFonts } from "@napi-rs/canvas";
import { getMealInfo, NameToEmoji } from "./meal"; // 이 함수의 내용은 제공되지 않았으므로 그대로 둡니다.
import { getMealInfo, getNutritionInfo, NameToEmoji, removeNutritionInfo } from "./meal"; // 이 함수의 내용은 제공되지 않았으므로 그대로 둡니다.
import { getAllSchedules } from "./schedule";
import { isVTS } from "./vts";
@ -9,7 +9,7 @@ GlobalFonts.registerFromPath('./template/Pretendard-Bold.ttf', 'Pretendard Bold'
GlobalFonts.registerFromPath('./template/NotoColorEmoji-Regular.ttf', 'NotoColorEmoji Regular')
export class CreateImage {
static async PostMeal(MLSV_YMD: string): Promise<void> {
static async PostMeal(MLSV_YMD: string): Promise<{ [key: string]: any } | undefined> {
const mealInfo = await getMealInfo(MLSV_YMD);
const img = await loadImage(path.join("./template/skeleton.png"));
const canvas = createCanvas(img.width, img.height);
@ -20,7 +20,7 @@ export class CreateImage {
ctx.fillStyle = "white";
ctx.textAlign = "left";
const lines = mealInfo.meal.split("\n").reverse();
const lines = removeNutritionInfo(mealInfo.meal).split("\n").reverse();
let emojis = (await NameToEmoji(lines.toString())).split(",");
if (lines.length !== emojis.length) {
@ -65,6 +65,16 @@ export class CreateImage {
console.log("🍲 | Meal Info Image Saved");
} catch (error) {
console.error("Error saving meal info image:", error);
} finally {
const meals = removeNutritionInfo(mealInfo.meal).split("\n");
const nutritionInfo = getNutritionInfo(mealInfo.meal);
const retrunValue: { [key: string]: any } = {};
for (let i = 0; i < meals.length; i++) {
const meal = (meals[i] ?? "").trim();
retrunValue[meal] = nutritionInfo[i] || [];
}
return retrunValue;
}
}

View file

@ -5,11 +5,31 @@ const KEY = process.env.NEIS_API_KEY;
export function removeNutritionInfo(value: string): string {
const lines = value.trim().split('\n');
const cleanedLines = lines.map(line => line.replace(/\(.*?\)/g, '').trim());
const cleanedLines = lines.map(line => line.replace(/\s*\([\d.,]+\)/g, '').trim());
const result = cleanedLines.join('\n');
return result;
}
const nutritionList = [
"난류", "우유", "메밀", "땅콩", "대두", "밀", "고등어", "게", "새우", "돼지고기",
"복숭아", "토마토", "아황산류", "호두", "닭고기", "쇠고기", "오징어", "조개류(굴, 전복, 홍합 포함)", "잣"
];
export function getNutritionInfo(value: string): string[][] {
const lines = value.trim().split('\n');
return lines.map(line => {
const indexes = line
.replace(/[()\s]/g, "")
.split(".")
.map(v => parseInt(v, 10) - 1)
.filter(i => i >= 0 && i < nutritionList.length);
return indexes
.map(i => nutritionList[i])
.filter((item): item is string => typeof item === "string");
});
}
export async function getMealInfo(MLSV_YMD: string): Promise<{ meal: string; date: string, kcal: string }> {
const url = `https://open.neis.go.kr/hub/mealServiceDietInfo?Type=json&ATPT_OFCDC_SC_CODE=E10&SD_SCHUL_CODE=7331071&MLSV_YMD=${MLSV_YMD}&KEY=${KEY}`;
const response = await fetch(url);
@ -17,7 +37,7 @@ export async function getMealInfo(MLSV_YMD: string): Promise<{ meal: string; dat
// @ts-ignore
const DDISH_NM = data.mealServiceDietInfo[1].row[0].DDISH_NM;
return {
meal: removeNutritionInfo(DDISH_NM.replace(/<br\s*\/?>/gi, '\n')),
meal: DDISH_NM.replace(/<br\s*\/?>/gi, '\n'),
date: MLSV_YMD,
// @ts-ignore
@ -32,7 +52,7 @@ export async function NameToEmoji(name: string): Promise<string> {
throw new Error("GITHUB_TOKEN environment variable is not set.");
}
const endpoint = "https://models.github.ai/inference";
const model = "openai/gpt-4.1";
const model = "openai/gpt-4.1-mini";
const client = ModelClient(
endpoint,

View file

@ -2,14 +2,24 @@
import { CreateImage } from "./lib/image";
//const YYMMDD = new Date().toISOString().slice(0, 10).replace(/-/g, "").toString();
const YYMMDD = "20250509"
const YYMMDD = "20250530"
//console.log(YYMMDD);
//Discord("20250509")
async function run() {
console.time("Post");
await CreateImage.PostMeal(YYMMDD);
const post = await CreateImage.PostMeal(YYMMDD);
console.timeEnd("Post");
console.log("Post created:", post);
let NutritionInfoText = "";
const entries = Object.entries(post ?? {}).filter(([_, value]) => value.toString().length > 0);
entries.forEach(([name, value], idx) => {
NutritionInfoText += `${name} : ${value.toString().replace(",", ", ")}`;
if (idx !== entries.length - 1) {
NutritionInfoText += "\n";
}
});
console.log("Nutrition Info Text:", NutritionInfoText);
console.time("Story");
await CreateImage.ConvertToStory(`./temp/${YYMMDD}.png`);
@ -18,6 +28,8 @@ async function run() {
run();
import { getAllSchedules } from "./lib/schedule";
//import { CreateImage } from "./lib/image";
@ -39,4 +51,13 @@ VTSList().then(results => {
} else {
console.log("\n5번째 행에서 노란색 배경의 셀을 찾지 못했거나, 'V.T.S.' 조건 불충족.");
}
});*/
});*/
/*
getAllSchedules()
.then((schedules) => {
console.log("학사 일정:", schedules);
})
.catch((error) => {
console.error("Error fetching schedules:", error);
});
*/