teamsがあまりよろしくないので学食botを作る

この記事は[木更津高専 Advent Calender 2024](https://qiita.com/advent-calendar/2024/nit_kisarazu)の7日目の記事です
前: [Blenderとおでんの違い](https://qiita.com/Nimono-sleep-well/items/4a3fbdd2202d11ab6200) by  @Nimono-sleep-well さん
後: [CloudflareはDNSだけじゃない！](https://qiita.com/toreis/items/a31e1c59b40ca8604935) by @toreis さん

# 経緯
teamsでpdfを開こうとするとたまに開けないことがある。学食にかかわらず開けない。というか結構な確率で開けない。ほんとにどうにかしてくれ
ということで普段使うチャットツールのDiscordのBOTでつくるか、となりました。
# 環境
- discord.js 14.15.3
- node.js 22.9.0
- python 3.10.12
# 実装済み機能
- 定期学食送信(平日20:00)
- 今日と明日の学食の送信
# pdfから学食のデータを取り出す
まず学校からteamsに投稿されている学食のpdfの表からデータをpdfplumberで抽出していく
```python
import pdfplumber
import pandas as pd

pdf_path = "../data/1209.pdf" 
csv_path = "../data/output.csv"

# PDFから表を抽出
all_tables = []
with pdfplumber.open(pdf_path) as pdf:
    for page in pdf.pages:
        tables = page.extract_tables()
        for table in tables:
            # テーブルが空でないことを確認
            if table:
                df = pd.DataFrame(table[1:], columns=table[0])
                all_tables.append(df)

combined_df = pd.concat(all_tables, ignore_index = True)
combined_df.to_csv(csv_path, index = False, encoding = "utf-8")
print(f"{csv_path}に書き出しました")

# CSVファイルを読み込む
df = pd.read_csv(csv_path, encoding="utf-8", header=None)
```
pdf内の表を抽出してcsvファイルに書き出す

csvじゃ扱いづらいのでjsonに吐きだしていく
これがかなーーーーーーーーーーーーりやっっかい
学食のpdfはとてもとてもすばらしいのでよくわからない小さい文字が書かれている
これが原因でcsvの行と列がおかしなことになるしpdfごとに結果がことなる
たとえば`かけ うどんそば`これがなんと
|メニュー名  |Mon  |Tue  |
|---|---|---|
|かけ  |~  |~  |
|うどんそば  |~  |~  |

といった二行にわかれていたり、わかれてなかったりと摩訶不思議なことが発生します
この~~バケモノ~~pdfとなかよしになるのに開発全体の7割くらいもってかれました
```py
from createCsv import df
import string
import json
import pandas as pd

menus = ["Aset", "Bset", "curry", "dailySpecialUdonSoba", "UdonSoba", "dailySpecialRamenPasta", "ramen"]
idenMenus = ["Aセット", "Bセット", "カレー", "日替り", "かけ", "日替り", "ラーメン"]
week = ["Mon", "Tue", "Wed", "Thu", "Fri"]
weekIndex = []
menusIndex = []

with open("../data/lunch.json", "r") as f:
    lunch = json.load(f)

col: int = 2
row: int = 2

#曜日からインデックスを取得
for i in week:
    while True:
        data: string = df.iloc[row][col]
        if pd.isna(data):
            data = "None"

        if i in data:
            weekIndex.append(col)
            break
        else:
            col += 1

col = 0
row = 0
#メニューの行のインデックスを取得
for i in idenMenus:
    while True:
        data: string = df.iloc[row][col]
        if pd.isna(data):
            data = "None"

        if i in data:
            menusIndex.append(row)
            row += 2
            break
        else:
            row += 1

for i in range(len(menus)):
    for j in range(len(week)): 
        if pd.isna(df.iloc[menusIndex[i]][weekIndex[j]]):
            (lunch[menus[i]][week[j]]) = "今日はありません"
        else:
            (lunch[menus[i]][week[j]]) = df.iloc[menusIndex[i]][weekIndex[j]]
        
        
with open("../data/lunch.json", "w") as f:
    json.dump(lunch, f,indent = 4 , ensure_ascii=False)
```
こんな感じで無理やりjsonに落しこみます

# 学食の表示
bot部分はdiscord.jsで書きます
```js
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
const lunch = require("../data/lunch.json");

const days = ["Mon", "Tue", "Wed", "Thu", "Fri"];
const dispMenu = ["Aセット", "Bセット", "カレー", "日替わりうどん・そば", "うどん・そば", "日替わりラーメン・パスタ", "ラーメン"];
const menu = ["Aset", "Bset", "curry", "dailySpecialUdonSoba", "UdonSoba", "dailySpecialRamenPasta", "ramen"];

module.exports = {
	data: new SlashCommandBuilder()
		.setName("tomorrow")
		.setDescription("明日の学食を表示します")
        .setDMPermission(false),
        async execute(interaction) {
            const today = new Date().getDay();
            if ((today+1) === 0 || (today+1) === 6) {
                await interaction.reply("明日は休日です。学食はありません");
                return;
            }
            const embed = new EmbedBuilder()
                .setTitle("明日の学食")
                .setDescription("明日の学食は以下の通りです")
                .setFooter({text: "※内容は変更される可能性があります"})
                .setTimestamp()
                dispMenu.forEach((item, index) => {
                    embed.addFields({
                        name: item,
                        value: lunch[menu[index]][days[today]],
                        inline: false
                    });
                });
            await interaction.reply({ embeds: [embed]});
        }
};
```
discordからみるとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574075/b8db7f10-7102-9c9d-cc9b-d393bc85b425.png)
おいしそう
今日の学食や毎日20:00に送信されるものも基本的にこの表示です
定期実行はcronをつかっています
```js
cron.schedule("0 20 * * * ", async() => {
    const today = new Date().getDay();
    const embed = new EmbedBuilder()
        .setTitle("明日の学食")
        .setDescription("明日の学食は以下の通りです")
        .setFooter({text: "※内容は変更される可能性があります"})
        .setTimestamp()
        dispMenu.forEach((item, index) => {
            embed.addFields({
                name: item,
                value: lunch[menu[index]][days[today]],
                inline: false
            });
        });
        if ((today+1) === 0 || (today+1) === 6) {
            await interaction.channel.send("明日は休日です。学食はありません");
        }
        else {
            await interaction.channel.send({ embeds: [embed]});
        }    
});
```
# 実装したい機能
- pdfの取得の自動化
- アプリケーション
- ファイル操作の自動実行
# さいごに
pythonってすごい
学食はチゲうどんがいちばんおいしいです