Amazonのアソシエイトとして、ラズパイダ(raspida.com)は適格販売により収入を得ています。詳しくは当サイトの プライバシーポリシーをご覧ください。

昨年ChatGPTが一般に開放されてから、非エンジニアがゆえ、プログラムコードを生成してもらっています。業務にも使えるのではないか、というくらい簡単に生成できて驚いてきました。

1年前には何度も修正しないと動作しなかったコードも、エラーを指摘すれば1回の修正で動作することも増えています。

学習のために、習作となるコードを生成してもらう意味では充分に使えるのではないでしょうか。

今回、簡単な在庫管理システムをPythonで生成してもらいました。

質問の仕方にもよりますが、必要なパッケージやライブラリ、動作の構成までも指南してくれます。

1回の修正で動作した

サーバが不要なDBであるsqliteを使い、とてもシンプルな在庫管理システムを頼んでみました。

例えば、こんな感じで頼んでみます。

Rレッド Rレッド
Pythonで在庫管理システムを作るコードを教えてください。備品のため販売価格はありません。仕入れ価格と個数、仕入れ日、仕入れ業者が必要です。Linux OSで動作させ、Webブラウザのフロントエンドにしたい。OSにインストールするパッケージと、実際のPythonコードを分けて教えてください。Pythonコードは基本の部分だけで結構です。

販売商品よりもデータが少ない備品類を想定し、必要最低限の項目にしました。

入力や表示はWebブラウザで行えるようにするシンプルな構成です。

project/
├── app.py
└── templates/
    └── index.html

最初は質問が悪かったのか、2つのファイル(app.pyとindex.html)はエラーが出て動きませんでしたが、エラーを指摘して1度の修正で動作しました。

HTML部分は後からCSSで見た目は変えられるので、そのまま進めます。英語になっている部分も書き換えるだけですからこのままです。

入力のインターフェイスに指定はしていませんから、シンプルに横一行になっています。

動作確認として適当に入力すると、下部に入力されたデータが表示されるようになっていました。

コードを参照して、独自にカスタマイズしていっても良いですが、こちらは非エンジニアなので更に追加修正を頼んで進めていくことにします。

Raspberry Pi OSでのインストール

Raspberry Pi OS上で同じように試したい人は、先ず必要なパッケージ類をインストールしないとなりません。これも指南してくれるのですけど、Raspberry Pi OSということもあり一部変更しました。

pipを使ったインストールは、以前のようにいきません。PEP668に準拠するためenvを使いました。

sqlite3だけaptでインストールしています。

ホームにzaikoディレクトリを作成し、後から中にtemplatesも作成しておきます。

sudo apt update
cd
mkdir zaiko
cd zaiko
python3 -m venv env

env/bin/pip3 install flask sqlalchemy flask-sqlalchemy SQLAlchemy
sudo apt install sqlite3
mkdir ~/zaiko/templates

最低限の環境ができたら、ChatGPTに提示されたPythonコード(app.py)とフロントエンドのコード(index.html)をコピペしました。

実行してローカルポート5000番で確認

実行はapp.pyです。envのパスを指定して実行させます。

~/zaiko/env/bin/python3 ~/zaiko/app.py

もし、zaikoディレクトリに移動したなら次のコマンドで実行します。

env/bin/python3 app.py

フロントエンドはローカルアドレスの5000番ポートが指定されています。Raspberry Pi OSのWebブラウザで確認してみます。

http://127.0.0.1:5000

■Pi 5は8GBモデルがオススメ

追加修正してみる

ChatGPTではこれまでを踏まえ続けられるため、追加修正もできます。

入力されたデータを一覧表示で表現するように頼みました。するとこうなります。

表形式で出てきました。

更にフィルタリングして絞り込めるように頼んでみます。

間にフィルタリングする項目が出てきました。

見た目はともかく、指定すると絞り込まれたリストに変更され、フィルタリングの選択を削除することで元に戻りました。

この2回の追加修正は、app.pyとindex.htmlをそれぞれ変更するだけです。データはデータベースとしてsqliteで管理されたままです。

2回ともエラーはありませんでした。スゴい。

個人で使うのに全く問題無い

生成されたコードを実際に使おうとした場合、個人利用で支障はないでしょう。

仮に業務で使いたいなら、もう少し手を加えないとならないのと、あまり複雑な構成にしなければ非エンジニアでも可能に思えました。

データの修正や削除の機能を追加したり、念のためcsvでエクスポートできるようにはしたいですね。

入力ではなく、csvを読み込ませる機能も欲しいので追加でChatGPTに提案してもらいましょう。

非エンジニアの味方

もしこれまでExcelで管理していたなら、Pythonとsqlite、flaskウェブアプリケーションに変更したいと思いませんか?

エンジニアさんはともかく、これまで非エンジニアには難しいことでした。今回のようにChatGPTでもここまでできるので、少し学習しておけば格段に敷居が下がりますね。

Raspberry Pi OSで試す

非エンジニアとして、プログラムの間違いを発見するような真似もできません。今回はコードを一切読まないで実行させました。全く確認していません。ただのコピペだけです。

Raspberry Pi OSでもpipの取扱が以前と異なるのでややこしいですが、数行で環境構築して実行する手軽さでトライできます。Pythonの環境があるRaspberry Pi OSならではです。

ChatGPTが生成したPythonのコードとhtmlのコードを残しておきますので、コピペして手元のRaspberry Pi OSで試してみてください。

はてな? はてな?
1つ気になるのは、このコードもどなたかが公開しているのとソックリなのかなという点です。

ChatGPTを使い、Raspberry Pi OSで在庫管理システムっぽいのを実行する記事でした。

app.py

from flask import Flask, request, jsonify, render_template
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///inventory.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    purchase_price = db.Column(db.Float, nullable=False)
    quantity = db.Column(db.Integer, nullable=False)
    purchase_date = db.Column(db.Date, nullable=False)
    supplier = db.Column(db.String(100), nullable=False)

    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'purchase_price': self.purchase_price,
            'quantity': self.quantity,
            'purchase_date': self.purchase_date.isoformat(),
            'supplier': self.supplier
        }

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/items', methods=['GET'])
def get_items():
    items = Item.query.all()
    return jsonify([item.to_dict() for item in items])

@app.route('/filter_items', methods=['GET'])
def filter_items():
    name = request.args.get('name')
    purchase_date = request.args.get('purchase_date')
    supplier = request.args.get('supplier')

    query = Item.query
    if name:
        query = query.filter(Item.name.like(f"%{name}%"))
    if purchase_date:
        query = query.filter(Item.purchase_date == datetime.strptime(purchase_date, '%Y-%m-%d').date())
    if supplier:
        query = query.filter(Item.supplier.like(f"%{supplier}%"))

    items = query.all()
    return jsonify([item.to_dict() for item in items])

@app.route('/item', methods=['POST'])
def add_item():
    data = request.get_json()
    new_item = Item(
        name=data['name'],
        purchase_price=data['purchase_price'],
        quantity=data['quantity'],
        purchase_date=datetime.strptime(data['purchase_date'], '%Y-%m-%d'),
        supplier=data['supplier']
    )
    db.session.add(new_item)
    db.session.commit()
    return jsonify(new_item.to_dict()), 201

@app.route('/item/<int:id>', methods=['PUT'])
def update_item(id):
    data = request.get_json()
    item = Item.query.get(id)
    if item is None:
        return jsonify({'message': 'Item not found'}), 404

    item.name = data['name']
    item.purchase_price = data['purchase_price']
    item.quantity = data['quantity']
    item.purchase_date = datetime.strptime(data['purchase_date'], '%Y-%m-%d')
    item.supplier = data['supplier']

    db.session.commit()
    return jsonify(item.to_dict())

@app.route('/item/<int:id>', methods=['DELETE'])
def delete_item(id):
    item = Item.query.get(id)
    if item is None:
        return jsonify({'message': 'Item not found'}), 404

    db.session.delete(item)
    db.session.commit()
    return jsonify({'message': 'Item deleted'})

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

templates/index.html

<!DOCTYPE html>
<html>
<head>
    <title>Inventory Management System</title>
    <style>
        table {
            width: 100%;
            border-collapse: collapse;
        }
        table, th, td {
            border: 1px solid black;
        }
        th, td {
            padding: 15px;
            text-align: left;
        }
    </style>
</head>
<body>
    <h1>Inventory Management System</h1>
    <form id="itemForm">
        <input type="text" id="name" placeholder="Name" required>
        <input type="number" id="purchase_price" placeholder="Purchase Price" step="0.01" required>
        <input type="number" id="quantity" placeholder="Quantity" required>
        <input type="date" id="purchase_date" required>
        <input type="text" id="supplier" placeholder="Supplier" required>
        <button type="submit">Add Item</button>
    </form>

    <h2>Filter Items</h2>
    <form id="filterForm">
        <input type="text" id="filter_name" placeholder="Name">
        <input type="date" id="filter_purchase_date">
        <input type="text" id="filter_supplier" placeholder="Supplier">
        <button type="submit">Filter</button>
    </form>

    <h2>Items List</h2>
    <table id="itemsTable">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Purchase Price</th>
                <th>Quantity</th>
                <th>Purchase Date</th>
                <th>Supplier</th>
            </tr>
        </thead>
        <tbody>
            <!-- Items will be dynamically added here -->
        </tbody>
    </table>

    <script>
        document.getElementById('itemForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const data = {
                name: document.getElementById('name').value,
                purchase_price: parseFloat(document.getElementById('purchase_price').value),
                quantity: parseInt(document.getElementById('quantity').value),
                purchase_date: document.getElementById('purchase_date').value,
                supplier: document.getElementById('supplier').value,
            };

            const response = await fetch('/item', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            });

            if (response.ok) {
                fetchItems();
            }
        });

        document.getElementById('filterForm').addEventListener('submit', async (e) => {
            e.preventDefault();
            const name = document.getElementById('filter_name').value;
            const purchase_date = document.getElementById('filter_purchase_date').value;
            const supplier = document.getElementById('filter_supplier').value;

            const params = new URLSearchParams();
            if (name) params.append('name', name);
            if (purchase_date) params.append('purchase_date', purchase_date);
            if (supplier) params.append('supplier', supplier);

            const response = await fetch(`/filter_items?${params.toString()}`);
            if (response.ok) {
                const items = await response.json();
                displayItems(items);
            }
        });

        async function fetchItems() {
            const response = await fetch('/items');
            if (response.ok) {
                const items = await response.json();
                displayItems(items);
            }
        }

        function displayItems(items) {
            const itemsTableBody = document.querySelector('#itemsTable tbody');
            itemsTableBody.innerHTML = '';
            items.forEach(item => {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td>${item.id}</td>
                    <td>${item.name}</td>
                    <td>${item.purchase_price}</td>
                    <td>${item.quantity}</td>
                    <td>${item.purchase_date}</td>
                    <td>${item.supplier}</td>
                `;
                itemsTableBody.appendChild(row);
            });
        }

        fetchItems();
    </script>
</body>
</html>