生成AI×業務活用×非エンジニアの奮闘記|えーやい実験室

わりとどこにでもいる非エンジニアのおじさんが、生成AIを業務に活用するブログです。 小さな革命を起こしたり起こさなかったり、感謝されたり自画自賛したりします。 プログラミング知識ゼロでも、「ノーコード×無料×AI」でアプリ開発をエンジョイ中。

ChatGPT×Pythonで作る「条件を自由に変えられるExcel抽出アプリ」|非エンジニアでもGUIで業務改善!

 

あなたの会社にも、きっとありますよね。

Excelファイルの中から“この条件に合うデータだけ抽出して”」と言われる地味~な仕事。

 

たとえばこんな悩み。

 

  • 「毎月ちょっと条件が違うから、関数を毎回直すのがめんどい…」

  • 「どの列に条件を入れたか、わからなくなった!」

  • 「気づけば10枚以上のExcelを開いてCtrl+F地獄」

 

――これ、まるで迷路に落ちたエクセル探偵状態。

毎回頑張って関数を修正していたあの日々よ、さようなら!

 

今回は、ChatGPT×Pythonの力を借りて、「Excelを開かずに条件抽出ができるアプリ」を作ってみました。

 

しかも、Pythonコードを直接いじる必要はナシ。

列名や条件値は、Excelでカスタムするだけ!

 

つまり――

Pythonはむずかしい」と感じていたあなたでも、Excelの達人感覚”でアプリを使いこなせるというわけです。

 

Pythonでコードをいじるのはムリゲーだけど、Excelで条件変更できるならやってみたい!という、ぼくのように 大着な 好奇心旺盛な方は、ぜひ読んでみてください。

 

 

 

 

 

 

 

【課題】なぜExcel抽出作業は面倒なのか

 

Excelの抽出作業って、一見かんたんそうに見えて、地味にストレスですよね。

フィルターをかけて、並べ替えて、条件を変えて、また元に戻して…。

 

まるで「ちょっと片付けよう」と思って押し入れを開けたら、気づけば模様替えを始めてた週末のような泥沼です。

 

しかも、「この列が在庫」「この列が仕入先」「あっ、列順変わってた」

――と、毎回パニック。

 

そんな時こそ必殺Pythonです。

 

とはいえ、「コードなんて書けない!」という声もわかります。

 

だから今回も、ChatGPTにまるっと作ってもらうスタイルでいきましょう。

 

 

【解決策】ChatGPT×Pythonで“抽出アプリ”を作るとこう変わる

 

今回のアプリのすごいところは、ズバリ!

 

ExcelでもCSVでもOK
GUI画面で列名・条件・一致方法を自由に設定
✅ 除外条件も指定可能
✅ 並べ替え(昇順・降順)もワンクリック
✅ 結果はきれいなリストで表示+CSV保存もできる
 

これ、非エンジニアでもPythonアプリを“使う”だけの立場になれるやつです。

現場の声を代弁するならこんな感じ。

 
「条件を変えるたびにChatGPTに頼まなくていい」
Excelだけで設定変えられるの最高」
Pythonコード?なんかかっこいいけど触らなくていいなら助かる!」

 

 

【実演】GUIで条件を入力して抽出してみた!

 

💬 ChatGPTへの依頼プロンプト

今回は、ChatGPTにこんな感じでPythonアプリを依頼しました。
(※このプロンプトは、非エンジニアでもコピペして少し直すだけでOKです)

あなたはPythonのプロエンジニア兼UIデザイナーです。
以下の条件を満たす業務改善アプリを作ってください。

【アプリ概要】
・ExcelCSVの両方を読み込み、共通のキー(例:「品番」)で照合。
・条件は最大5件まで指定可。含む/一致/以上/以下など複数対応。
・条件と昇順/降順設定をExcelで事前に指定。
・GUItkinterで作成。大きめの文字と見やすいボタン配置。
・結果表示とは別に、ユーザー条件の上位3件をランキング表示。
・安全対策:データ削除や上書き処理は行わない。

【UI要件】
・フォルダ指定、抽出ボタン、結果表示エリア、ランキングエリアを配置。
・処理状況をメッセージで表示(例:「抽出中…」「完了しました!」)。
・GUIは日本語ラベルとわかりやすいボタンデザイン。

【スタイル】
・ttk.Styleを使用し、見やすいストライプ背景。
・ボタンは角丸で大きめ。背景は落ち着いたグレー基調。

 

 

 

 

 

🐍 ChatGPTが生成したPythonコード

ChatGPTが生成してくれたコードはこちら。
コピーボタン付きなので、そのまま貼り付けて動かせます。

# =======================================================
# 📌 Excel/CSV 抽出アプリ(完全版)
# - tkinter GUI
# - pandas で Excel/CSV を読み込み、条件で抽出
# - 条件は最大5件(Excelから読み込み可能)
# - 上位3つの最近使った条件ランキングを表示
# - 抽出結果を CSV 保存(上書き回避)
#
# 必要なライブラリ:
#   pip install pandas openpyxl
# =======================================================

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import pandas as pd
import os
from datetime import datetime

# ------------------------------
# ヘルパー関数
# ------------------------------
def safe_to_numeric(series):
    """数値比較できるように変換(失敗は NaN)"""
    return pd.to_numeric(series, errors='coerce')

def make_unique_path(path):
    """既存ファイルがあれば _copy, _copy2 ... を付与して返す"""
    base, ext = os.path.splitext(path)
    if not os.path.exists(path):
        return path
    i = 1
    new_path = f"{base}_copy{ext}"
    while os.path.exists(new_path):
        i += 1
        new_path = f"{base}_copy{i}{ext}"
    return new_path

def cond_to_string(cond_entries):
    """条件エントリ群を人が読める文字列にする"""
    parts = []
    for col, val, method in cond_entries:
        colv = col.get().strip()
        valv = val.get().strip()
        meth = method.get().strip()
        if colv and valv and meth:
            parts.append(f"{colv} {meth} {valv}")
    return " | ".join(parts) if parts else "(条件なし)"

# ------------------------------
# メインアプリ
# ------------------------------
class ExcelFilterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("🔎 Excel/CSV 抽出アプリ(条件カスタム可)")
        self.root.geometry("980x640")
        self.style = ttk.Style()
        try:
            self.style.theme_use("clam")
        except:
            pass
        self.style.configure("TButton", font=("Meiryo", 11))
        self.style.configure("TLabel", font=("Meiryo", 11))
        self.style.configure("Treeview", rowheight=26, font=("Meiryo", 10))
        self.style.configure("TFrame", background="#f7f7f7")
        
        # データ関連
        self.data = None
        self.source_path = None
        # 最近の条件(メモリ内保持、再起動で消える)
        self.recent_conditions = []

        self.create_widgets()

    def create_widgets(self):
        # --- 上部ボタン群 ---
        top_frame = ttk.Frame(self.root)
        top_frame.pack(fill="x", padx=10, pady=8)

        ttk.Button(top_frame, text="📂 ファイルを選択", command=self.load_file).pack(side="left", padx=6)
        self.lbl_file = ttk.Label(top_frame, text="未選択", width=50)
        self.lbl_file.pack(side="left", padx=6)

        ttk.Button(top_frame, text="⚙ 条件を読み込み (Excel)", command=self.load_conditions).pack(side="left", padx=6)
        ttk.Button(top_frame, text="🔍 抽出開始", command=self.filter_data).pack(side="left", padx=6)
        ttk.Button(top_frame, text="💾 結果をCSV保存", command=self.save_csv).pack(side="left", padx=6)
        ttk.Button(top_frame, text="❌ 閉じる", command=self.root.destroy).pack(side="right", padx=6)

        # --- メイン中央:条件エリアと結果エリアを左右で配置 ---
        main_pane = ttk.Panedwindow(self.root, orient=tk.HORIZONTAL)
        main_pane.pack(fill="both", expand=True, padx=10, pady=6)

        # 左:条件エリア
        cond_frame = ttk.Labelframe(main_pane, text="抽出条件(最大5件)")
        cond_frame.config(width=380)
        main_pane.add(cond_frame, weight=1)

        self.condition_entries = []
        for i in range(5):
            row = ttk.Frame(cond_frame)
            row.pack(fill="x", pady=4, padx=6)
            ttk.Label(row, text=f"{i+1}").pack(side="left", padx=(0,6))
            col_entry = ttk.Entry(row, width=16)
            col_entry.pack(side="left", padx=4)
            col_entry.insert(0, "")  # placeholder
            val_entry = ttk.Entry(row, width=14)
            val_entry.pack(side="left", padx=4)
            cmb = ttk.Combobox(row, values=["完全一致", "部分一致", "以上", "以下", "除外"], width=10)
            cmb.pack(side="left", padx=4)
            cmb.set("部分一致")
            self.condition_entries.append((col_entry, val_entry, cmb))

        # ソート指定
        sort_row = ttk.Frame(cond_frame)
        sort_row.pack(fill="x", pady=8, padx=6)
        ttk.Label(sort_row, text="並べ替え列").pack(side="left", padx=4)
        self.cmb_sort_col = ttk.Combobox(sort_row, values=[], width=18)
        self.cmb_sort_col.pack(side="left", padx=4)
        self.sort_var = tk.StringVar(value="昇順")
        ttk.Radiobutton(sort_row, text="昇順", variable=self.sort_var, value="昇順").pack(side="left", padx=4)
        ttk.Radiobutton(sort_row, text="降順", variable=self.sort_var, value="降順").pack(side="left", padx=4)

        # 最近の条件ランキング
        rank_frame = ttk.Labelframe(cond_frame, text="📈 最近の条件ランキング(上位3)")
        rank_frame.pack(fill="x", padx=6, pady=10)
        self.rank_labels = []
        for i in range(3):
            lbl = ttk.Label(rank_frame, text=f"{i+1}. (なし)", wraplength=300)
            lbl.pack(anchor="w", padx=6, pady=2)
            self.rank_labels.append(lbl)

        # 右:結果表示エリア
        result_frame = ttk.Labelframe(main_pane, text="抽出結果")
        result_frame.config(width=600)
        main_pane.add(result_frame, weight=3)

        # Treeview
        self.tree = ttk.Treeview(result_frame, columns=("dummy",), show="headings")
        self.tree.pack(fill="both", expand=True, padx=6, pady=6)
        # ストライプのためのタグ
        self.tree.tag_configure("odd", background="#ffffff")
        self.tree.tag_configure("even", background="#f2f6ff")

        # ステータスバー
        self.status_var = tk.StringVar(value="準備完了")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief="sunken", anchor="w")
        status_bar.pack(fill="x", padx=10, pady=(0,6))

    # ------------------------------
    # ファイル読み込み
    # ------------------------------
    def load_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx"), ("CSV files", "*.csv")])
        if not file_path:
            return
        try:
            ext = os.path.splitext(file_path)[1].lower()
            if ext == ".csv":
                df = pd.read_csv(file_path, dtype=str)
            else:
                df = pd.read_excel(file_path, dtype=str)
            # 読み込んだ全列を文字列扱いで保持(比較時に数値化)
            self.data = df
            self.source_path = file_path
            self.lbl_file.config(text=os.path.basename(file_path))
            self.status_var.set(f"読み込み完了: {os.path.basename(file_path)} ({len(df)}行)")
            # Treeview の列候補を更新
            cols = list(self.data.columns)
            self.cmb_sort_col['values'] = cols
            # ツリービューを初期表示しておく
            self.show_result(self.data.head(200))
        except Exception as e:
            messagebox.showerror("読み込みエラー", f"ファイルの読み込みに失敗しました。\n{e}")
            self.status_var.set("読み込み失敗")

    # ------------------------------
    # 条件設定 Excel 読み込み
    # ------------------------------
    def load_conditions(self):
        cond_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
        if not cond_path:
            return
        try:
            cond_df = pd.read_excel(cond_path, dtype=str)
            # 期待列: 列名, 条件値, 一致方法 (オプション: 種別)
            for i, (_, row) in enumerate(cond_df.iterrows()):
                if i >= 5:
                    break
                col = str(row.get("列名", "")).strip()
                val = str(row.get("条件値", "")).strip()
                method = str(row.get("一致方法", "")).strip()
                # 値を GUI にセット
                self.condition_entries[i][0].delete(0, tk.END)
                self.condition_entries[i][0].insert(0, col)
                self.condition_entries[i][1].delete(0, tk.END)
                self.condition_entries[i][1].insert(0, val)
                if method:
                    try:
                        self.condition_entries[i][2].set(method)
                    except:
                        pass
            messagebox.showinfo("条件読み込み", "条件設定を読み込みました。")
        except Exception as e:
            messagebox.showerror("条件読み込みエラー", f"条件ファイルの読み込みに失敗しました。\n{e}")

    # ------------------------------
    # データ抽出のコア
    # ------------------------------
    def filter_data(self):
        if self.data is None:
            messagebox.showwarning("未選択", "先にExcelまたはCSVファイルを読み込んでください。")
            return

        df = self.data.copy()
        # 条件順に適用
        used_conditions = []
        try:
            for col_entry, val_entry, cmb in self.condition_entries:
                col = col_entry.get().strip()
                val = val_entry.get().strip()
                method = cmb.get().strip()
                if not col or not val or not method:
                    continue  # 空はスキップ

                # 列存在チェック
                if col not in df.columns:
                    messagebox.showwarning("列エラー", f"列「{col}」がデータに存在しません。")
                    return

                # 部分一致 or 完全一致 or 数値比較 or 除外
                if method == "完全一致":
                    df = df[df[col].astype(str) == val]
                elif method == "部分一致":
                    df = df[df[col].astype(str).str.contains(val, na=False)]
                elif method in ("以上", "以下"):
                    # 数値に変換して比較(変換できない場合は警告)
                    col_num = safe_to_numeric(df[col])
                    try:
                        val_num = float(val)
                    except:
                        messagebox.showwarning("比較エラー", f"数値比較の条件値 '{val}' が数値として解釈できません。")
                        return
                    if method == "以上":
                        df = df[col_num >= val_num]
                    else:
                        df = df[col_num <= val_num]
                elif method == "除外":
                    # 除外は部分一致と完全一致の両方に対応(ここでは部分一致除外)
                    df = df[~df[col].astype(str).str.contains(val, na=False)]
                else:
                    # 未知の方法はスキップ
                    continue

                used_conditions.append((col, method, val))

            # 並べ替え
            sort_col = self.cmb_sort_col.get().strip()
            if sort_col:
                ascending = True if self.sort_var.get() == "昇順" else False
                # try numeric sort first
                try:
                    df_sort = df.copy()
                    df_sort[sort_col + "_num"] = safe_to_numeric(df_sort[sort_col])
                    if df_sort[sort_col + "_num"].notna().any():
                        df = df.sort_values(by=sort_col + "_num", ascending=ascending)
                        df = df.drop(columns=[sort_col + "_num"])
                    else:
                        df = df.sort_values(by=sort_col, ascending=ascending)
                except Exception:
                    try:
                        df = df.sort_values(by=sort_col, ascending=ascending)
                    except Exception:
                        pass

            # 結果表示
            self.show_result(df)
            cnt = len(df)
            self.status_var.set(f"抽出完了:{cnt} 件")
            messagebox.showinfo("抽出完了", f"{cnt} 件が抽出されました。")

            # 最近条件ランキングを更新(先頭3)
            cond_text = cond_to_string(self.condition_entries)
            if cond_text and cond_text != "(条件なし)":
                # recent_conditions に追加し、頻度で上位3を表示
                self.recent_conditions.insert(0, cond_text)
                # 重複削除かつ順序維持(先頭優先)
                seen = []
                uniq = []
                for c in self.recent_conditions:
                    if c not in seen:
                        uniq.append(c)
                        seen.append(c)
                self.recent_conditions = uniq[:20]  # 最大20保持
                for i in range(3):
                    if i < len(self.recent_conditions):
                        self.rank_labels[i].config(text=f"{i+1}. {self.recent_conditions[i]}")
                    else:
                        self.rank_labels[i].config(text=f"{i+1}. (なし)")

        except Exception as e:
            messagebox.showerror("抽出エラー", f"抽出処理中にエラーが発生しました。\n{e}")
            self.status_var.set("抽出失敗")

    # ------------------------------
    # ツリービュー表示
    # ------------------------------
    def show_result(self, df):
        # 既存削除
        for item in self.tree.get_children():
            self.tree.delete(item)
        if df is None or len(df) == 0:
            # カラムだけセット
            self.tree["columns"] = ("なし",)
            self.tree.heading("なし", text="(該当データなし)")
            return

        cols = list(df.columns)
        self.tree["columns"] = cols
        for col in cols:
            self.tree.heading(col, text=col)
            # 幅自動調整(簡易)
            self.tree.column(col, width=120, anchor="center")

        # 行データ挿入
        for i, (_, row) in enumerate(df.iterrows()):
            tag = "even" if i % 2 == 0 else "odd"
            vals = ["" if pd.isna(v) else str(v) for v in row.tolist()]
            self.tree.insert("", "end", values=vals, tags=(tag,))

    # ------------------------------
    # CSV保存
    # ------------------------------
    def save_csv(self):
        # collect current tree data
        items = self.tree.get_children()
        if not items:
            messagebox.showwarning("保存エラー", "保存する抽出結果がありません。")
            return
        file_path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV files", "*.csv")])
        if not file_path:
            return
        try:
            df = pd.DataFrame([self.tree.item(it)["values"] for it in items], columns=self.tree["columns"])
            save_path = make_unique_path(file_path)
            df.to_csv(save_path, index=False, encoding="utf-8-sig")
            messagebox.showinfo("保存完了", f"結果を {os.path.basename(save_path)} に保存しました。")
        except Exception as e:
            messagebox.showerror("保存エラー", f"CSV保存に失敗しました。\n{e}")

# ------------------------------
# 実行
# ------------------------------
if __name__ == "__main__":
    root = tk.Tk()
    app = ExcelFilterApp(root)
    root.mainloop()

 

⚠️ 注意:このアプリは練習用です。社内や顧客データを扱う場合は、必ずバックアップを取ってから実行してください。

 

📊 サンプルデータを自分で作って試そう!

あなたのPCでもアプリを検証できるように、サンプルデータを自動生成するPythonコードを用意しました!

import pandas as pd
import random
from datetime import datetime, timedelta
import os

# ==============================
# 📦 サンプルデータ生成スクリプト
# ==============================

output_dir = os.path.expanduser("~/Desktop")
os.makedirs(output_dir, exist_ok=True)

products = ["ボルトM8", "ナットM6", "ワッシャーS", "ベルトB", "モーターA", 
            "パッキンF", "シャフトG", "ホースH", "ギアI", "プレートJ"]
suppliers = ["田中商事", "鈴木製作所", "ABC金属", "高橋工業", "オオタ商会"]

records = []
for _ in range(50):
    p = random.choice(products)
    s = random.choice(suppliers)
    q = random.randint(1, 100)
    u = random.randint(100, 5000)
    d = (datetime.today() - timedelta(days=random.randint(0, 120))).strftime("%Y-%m-%d")
    records.append([p, s, q, u, q*u, d])

df = pd.DataFrame(records, columns=["品番", "仕入先", "数量", "単価", "金額", "入庫日"])
excel_path = os.path.join(output_dir, "sample_inventory_data.xlsx")
csv_path = os.path.join(output_dir, "sample_inventory_data.csv")

df.to_excel(excel_path, index=False, engine="openpyxl")
df.to_csv(csv_path, index=False, encoding="utf-8-sig")

cond_df = pd.DataFrame({
    "列名": ["仕入先", "数量", "単価"],
    "条件値": ["田中商事", "50", "1000"],
    "一致方法": ["完全一致", "以上", "以下"]
})
cond_path = os.path.join(output_dir, "条件設定.xlsx")
cond_df.to_excel(cond_path, index=False, engine="openpyxl")

print("✅ サンプルファイルをデスクトップに出力しました!")
print(f"・{excel_path}")
print(f"・{csv_path}")
print(f"・{cond_path}")

 

🧾 出力されるファイル

ファイル名 内容 用途
sample_inventory_data.xlsx メインの在庫データ 読込対象(Excel
sample_inventory_data.csv 同データのCSV 読込対象(CSV
条件設定.xlsx 抽出条件リスト アプリのデフォルト条件

 

 

GUIでは、列名・条件値・一致方法を最大5件まで入力できます。除外条件も同様に設定可能にしました。

 

さらに右側には「最近使った条件ランキング」が表示され、「そうそう、前回これ使った!」と再利用がしやすい設計です。

 

「抽出スタート」ボタンを押すと、条件に合った行だけがツリービューにずらっと表示され、結果をCSVとして保存することも可能です。

 

Pythonを知らなくても、“ちょっと便利な業務用ツール”を自分で動かせる――

そんな体験は、まさに生成AI時代の醍醐味ですね。

 

 

【実演】実際のアプリ画面(GUI)と動作検証

【実際の画面】自由条件Excel抽出アプリ 起動時

 

VSCodeにコピペしたプログラムを実行してみると…ご覧のとおり、ちゃんとアプリ画面が表示されました。依頼した条件のボタンは、一通り並んでいるようです。

 

では、左上の「ファイルを選択」から、読み込ませるためのサンプルExcelファイルを指定していきましょう。

 

【実際の画面】自由条件Excel抽出アプリ 指定Excelファイルを読み込んだ状態

 

Excelファイルを読み込んでくれました。あとは、これに条件指定してフィルタリングしてきます。今回は「"品番"を"ギア"」さらに「"単価"を"1000以上"」としてみましょう。

 

【実際の画面】自由条件Excel抽出アプリ 条件指定してフィルタリングしランキング表示した状態

 

「ヘイ、お待ち!」と言わんばかりに、秒で結果が表示されました。条件を変えて「抽出開始」すれば、ほかのパターンもできます。

 

今回のサンプルはとても簡素なデータですが、実際の職場・現場ではもっと多くのデータを蓄積している場合もあるはずです。

 

蓄積したデータ数が多いほど、「手間<アプリ時短」が顕著で効果が大きいはず。

 

繰り返しますが、このアプリはExcelで編集できるのが特徴なので、誰でも使いやすいんですね。

 

興味のある方はぜひ、列名や指定条件の単語などを応用した「自分専用」としてお試しください。

 

 

【評価】Excelでカスタムできる仕組みが神すぎた話

 

普通なら、抽出条件を変えるたびにPythonコードを修正しなきゃいけません。

でも今回は、「条件設定.xlsx」に条件を書き込むだけ。

 

次に起動したとき、その設定がGUIに自動で反映されます。

たとえばこのように書くだけでOKです:

 

列名 条件値 一致方法 種別(抽出/除外) 並べ替え方向
型式 AB- 部分一致 抽出 昇順
在庫数 10 以下 抽出  
顧客名 田中商事 完全一致 除外  

 

これなら、Pythonを知らなくても設定ファイルをExcelで編集できるので、いわば「ノーコードでPythonアプリを動かす感覚」です。

 

 

【注意点とコツ】AIに任せすぎないための3か条

 

AIが生成したコードを使うときに注意したいのは次の3点です。

 

① 会社のルールに沿って使う

個人情報や社外秘データはAIにアップロードしない。
ChatGPTは賢いけど、守秘義務の神様ではないのです。

② 最終チェックは必ず人間が行う

抽出ミスや条件の誤設定がないか、最終確認は人の目で。
AIを過信しすぎると、「あれ、数が合わないぞ?」地獄が待ってます。

③ 生成AIは“相談役”として使う

「AIが全部やってくれる」ではなく、
「AIに頼って自分の判断を早める」くらいがちょうどいい。

 

 

 

 

 

【まとめ】 ChatGPT×Pythonで作る「条件を自由に変えられるExcel抽出アプリ」

 

今回は、「Excelの条件を自由に変えられる抽出アプリ」をChatGPTとPythonで作る方法を紹介しました。

 

関数に埋もれて頭を抱えていたぼくの同志も、アプリひとつで“条件を変えてクリックするだけ”。

 

顕在ニーズは「作業の効率化」ですが、潜在ニーズは「自分の手でアプリをカスタマイズできる」こと。

 

Python×ChatGPTを使えば、非エンジニアでも自分専用ツールを作る時代なんです。

 

Pythonコード?Excelで設定できるなら、なんだか今日いける気がする!」

そう思った今が、第一歩を踏み出すチャンスです。

 

あると思います。

 

 

みなさんに読まれている関連記事

 

 

↓フォローは24時間365日受付中!
🚀 Xでフォローする(@gen_ai_note)

【ちょいコード活用まとめ】生成AI×業務活用×非エンジニアの奮闘記|えーやい実験室トップへ