📘

掲示板をchatGPT4oで生成

2024/08/18に公開

1. はじめに

最近、職場のグループウエアが吹っ飛ぶようになりました。一部の業務がグループウエアのメッセージ機能に依存したワークフローになっており、滞るので困りました。管理者の話では室温が上がっていたのが原因だったので、対策済みらしいのですが、不安は払拭できませんでした。トラブル発生時に補完できる仕組みが必要だと考えました。そこで、昔流行った簡単な掲示板をラズパイzero wで立ち上げようと思い、課金済みchatGPT4o(R6年7月上旬)にご協力頂きました。

ラズパイでfastAPIを動かす手順はこちらに記載しました。https://zenn.dev/dzonesasaki/articles/10e9275a261b3d

2. 指示文

プロンプトは次の通りです。

fastAPIでLAN内BBSを作ってください。
タイトルページと、スレッド表示ページの2面構成。
タイトルページは、新規スレッド作成欄とスレッド一覧の上下2フレーム構成。
新規スレッド作成は、タイトルを入力するだけにし、決定時のタイムスタンプと8桁乱数をtext形式のファイル名として作成する。
そのファイルの内容は、一行目がタイトル、それ以降はコンテンツ。コンテンツの1行目は日時、2行目は「投稿者:」に続き名前、3行目以降がコメントの本体で、コンテンツの区切りは-=-=-=-=-=kugiri=-=-=-=-=- という文字列を1行入れる。
スレッド表示ページは、上下2フレーム構成。
上のフレームは、スレッドのタイトルが表示され、名前入力枠の下に、70文字x5行のコメント入力枠があり、submitボタンがある。
下のフレームは、スレッドの内容が表示されている。
タイトルページに表示されるスレッド一覧は、スレッド辞書ファイルより生成され、ファイル名とタイトルが対になって、テキストファイルで記述される。
必要なスクリプトと、表示用htmlファイルを作成してください。

3. chatGPT4oの回答

FastAPIを使用して、指定された構成のLAN内BBSを作成するためのスクリプトとHTMLファイルを提供します。

ディレクトリ構成

bbs/
│
├── main.py
├── templates/
│   ├── index.html
│   └── thread.html
└── data/
    ├── threads/
    └── threads_list.txt

main.py

from fastapi import FastAPI, Request, Form
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
import os
import time
import random

app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

data_dir = "data"
threads_dir = os.path.join(data_dir, "threads")
threads_list_file = os.path.join(data_dir, "threads_list.txt")

if not os.path.exists(data_dir):
    os.makedirs(data_dir)
if not os.path.exists(threads_dir):
    os.makedirs(threads_dir)
if not os.path.exists(threads_list_file):
    with open(threads_list_file, 'w') as f:
        pass

def get_threads_list():
    threads = []
    with open(threads_list_file, 'r') as f:
        for line in f:
            filename, title = line.strip().split(' ', 1)
            threads.append({'filename': filename, 'title': title})
    return threads

@app.get("/")
async def read_index(request: Request):
    threads = get_threads_list()
    return templates.TemplateResponse("index.html", {"request": request, "threads": threads})

@app.post("/create_thread/")
async def create_thread(request: Request, title: str = Form(...)):
    timestamp = int(time.time())
    random_number = random.randint(10000000, 99999999)
    filename = f"{timestamp}_{random_number}.txt"
    with open(os.path.join(threads_dir, filename), 'w') as f:
        f.write(title + "\n")
    with open(threads_list_file, 'a') as f:
        f.write(f"{filename} {title}\n")
    return RedirectResponse(url="/", status_code=303)

@app.get("/thread/{filename}")
async def read_thread(request: Request, filename: str):
    with open(os.path.join(threads_dir, filename), 'r') as f:
        lines = f.readlines()
    title = lines[0].strip()
    content = "".join(lines[1:])
    return templates.TemplateResponse("thread.html", {"request": request, "title": title, "content": content, "filename": filename})

@app.post("/add_comment/")
async def add_comment(request: Request, filename: str = Form(...), name: str = Form(...), comment: str = Form(...)):
    timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
    new_comment = f"{timestamp}\n投稿者:{name}\n{comment}\n=-=-=-=-=-=kugiri=-=-=-=-=-\n"
    with open(os.path.join(threads_dir, filename), 'a') as f:
        f.write(new_comment)
    return RedirectResponse(url=f"/thread/{filename}", status_code=303)

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>掲示板</title>
</head>
<body>
    <h1>新規スレッド作成</h1>
    <form action="/create_thread/" method="post">
        <label for="title">タイトル:</label>
        <input type="text" id="title" name="title" required>
        <button type="submit">作成</button>
    </form>

    <h2>スレッド一覧</h2>
    <ul>
        {% for thread in threads %}
            <li><a href="/thread/{{ thread.filename }}">{{ thread.title }}</a></li>
        {% endfor %}
    </ul>
</body>
</html>

templates/thread.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <form action="/add_comment/" method="post">
        <input type="hidden" name="filename" value="{{ filename }}">
        <label for="name">名前:</label>
        <input type="text" id="name" name="name" required>
        <br>
        <label for="comment">コメント:</label>
        <textarea id="comment" name="comment" rows="5" cols="70" required></textarea>
        <br>
        <button type="submit">投稿</button>
    </form>

    <h2>コメント</h2>
    <pre>{{ content }}</pre>
</body>
</html>

このスクリプトとHTMLファイルを使うことで、LAN内で動作する基本的なBBSを作成できます。スクリプトは、新規スレッドの作成、スレッドの表示、およびコメントの追加をサポートしています。

4. 雑感:chatGPTは人の仕事を奪うのか?

動くスクリプトが出力されました。こちらとしては指示文を書くのに工夫した程度です。
この後、少し追加で依頼し、現在、稼働させています。
仕様を投げるだけでほぼ手を加えず実装できるというのは、本当に有り難いと思いました。

最近よく、youtubeやら書籍やらで「人工知能が人の仕事を奪う」みたいな見出しを見かけます。
今回のが人の仕事を置き換えたものであれば、確かにそうだろうと思いました。
しかし、私は、web系はよく判らないので、今回のレベルがどの程度なのか判りません。
ただ、私の感覚としては、こんなレベルならば、機械にやらせるべきだろうと思います。

そして、人間は、もう少し高度な仕事をしたら良いのだろうと思っています。
例えば、この殺風景な掲示板を綺麗に装飾したり、ユーザー管理機能を付けるとなると、仕様が複雑になります。
それを意図通りにchatGPTに出力させるのは、ちょっと困難だろうと感じています。

実は、掲載した指示文は何度か修正しています。まず初めはfastAPIと明記しなかったため、Flaskで稼働するスクリプト群が出力されました。Flaskは未経験だったので、再度fastAPIと明記しました。また、指示文に記載してあるフレーム構造が無視された出力になっています。会話の中で追加を依頼することで、フレーム形式になりました。

今から2,30年ぐらい前の頃は、紙投げ仕様というものがありました。酷いのになると、口頭で仕様を指示されました。きっちりとした開発になると、仕様書を書いて何度もレビューし、それを元に、協力会社さんにお願いするという作業もありました。
紙投げ仕様にしても、口頭仕様にしても、協力会社への依頼にしても、手戻りがありました。仕様の意図が完全には伝わらないのです。

chatGPTを利用した場合でも同様ですが、問題は、その仕様の精度と、仕上がりの精度です。
chatGPT4oでは、10行程度の仕様に対しても実装漏れありました。
これが、人であれば、もう少しまともな実装がなされると感じます。最もスピードは異なりますが。

業務では、完成品はソースコードを保管し、仕様書は仕様書できちんと保管します。それは、保守という業務があるからです。
保守をchatGPTがしてくれるのであれば、本当に人が不要になると思います。しかし、簡単な指示でも実装を漏らしたchatGPTには、保守は任せられませんし、そもそも保守をさせる仕組みを構築するのはかなり難しいです。
つまり、「今のchatGPTには、アマチュアレベルの作業ぐらいしか任せられない」というのが私の感想です。

なんとなく、毎回、こんな事を書いて終わる気がしています。老害と言われないようにしないと。

Discussion