ChatGPTに、動画変換(mpeg→gif 変換)するPythonスクリプトを書いてもらった

ChatGPTに、mpeg→gif 変換のPythonスクリプトを書いてもらいました。ブログに動画を張り付ける際、mpegが対応していないのでgifに変更していたのですが、オンラインで変換してくれるサービスを利用していたのですが、面倒なので手元でもできるように。

MoviePyは事前にインストールしておきます。MoviePyをインストールするとFFmpegも一緒にインストールされます。

なお、pythonではなく、下記のようなFFmpegコマンドラインだけで出来ますが、そこは好みで。

ffmpeg -i input.mpeg -vf "fps=10,scale=320:-1:flags=lanczos,split [s0] [s1]; [s0]palettegen [p]; [s1] [p]paletteuse" -loop 0 output.gif
指示文(プロンプト):

mpegからgifに変換するpythonプログラムを提示してください。MoviePyを利用してください。動画のサイズ(縦、横)、フレームレートも指定できるようにしてください。

回答:

MoviePyでmpegからgifに変換するプログラムは以下のようになります。


from moviepy.editor import VideoFileClip

# 入力ファイルのパス
input_file = "input.mp4"

# 出力ファイルのパス
output_file = "output.gif"

# 動画のサイズ(横幅、縦幅)
size = (320, 240)

# フレームレート
fps = 10

# 動画を読み込む
clip = VideoFileClip(input_file)

# サイズを変更する
clip = clip.resize(size)

# gifに変換して保存する
clip.write_gif(output_file, fps=fps)
    
結果:

以下のように成功しました。返還前の動画は下記のサイトからフリー素材を使わせてもらいました。
https://www.pexels.com/ja-jp/video/855282/

処理が開始されると下記のように表示されます。少し時間がかかります。

 

変換後のgifはこちら。

ChatGPTで、マトリックスに出てくる縦スクロール・アニメを作るjsコードを書いてもらった

ChatGPTで、マトリックスに出てくる縦スクロール・アニメを作るjsコードを書いてもらいました。

先に結果から。下記のように成功しました。表示する要素に指定する文字は、0-9,A-Zだけだと変化が乏しいので、記号や空白も混ぜて調整してます。記号とか漢字も混ぜると、より、それっぽくなるかも。

 

指示文(プロンプト):

映画マトリックスに出てくる、文字が上から下に縦スクロールしていくアニメーションを表示するjsプログラムを書いてください。HTMLの <canvas> 要素を使用してください。

 

回答:
  • 以下は、JavaScriptを使用して、マトリックスのように上から下に縦に流れる文字列アニメーションを表示する方法の例です。
  • このスクリプトは、ランダムに選択した文字列の配列から文字を選択し、指定された文字列の長さのマトリックスを初期化します。
  • それから、一定の間隔で、各行に対して文字列を表示し、配列の先頭に新しいランダムな文字を追加し、配列の最後から文字を削除して、アニメーションを作成します。
  • HTMLの canvas 要素を使用して、同じアニメーションを作成します。文字列を表示するために fillText() を使用し、キャンバスの背景を透過させるために fillRect() を使用しています。
  • また、CSScanvas 要素をスタイル設定しています。

<!DOCTYPE html>
<html>
<head>
	<title>Matrix Animation</title>
	<style>
		body {
			background-color: black;
			margin: 0;
			padding: 0;
			overflow: hidden;
		}
		canvas {
			display: block;
		}
	</style>
</head>
<body>
	<canvas id="canvas"></canvas>
	<script>
		// canvas要素を取得
		var canvas = document.getElementById("canvas");

		// canvasの大きさを設定
		canvas.width = window.innerWidth;
		canvas.height = window.innerHeight;

		// canvasの描画コンテキストを取得
		var ctx = canvas.getContext("2d");

		// 文字列の配列
		var chars = [" "," "," "," "," "," "," "," "," "," "," "," "," ",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","・","・","・","・","・","+","+","*","."*".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];

		// 文字列をランダムに選択
		function randomChar() {
			return chars[Math.floor(Math.random() * chars.length)];
		}

		// 文字列の長さ
		var length = 100;

		// 初期化
		var matrix = [];
		for (var i = 0; i < length; i++) {
			matrix[i] = [];
			for (var j = 0; j < window.innerHeight / 20; j++) {
				matrix[i][j] = randomChar();
			}
		}

		// 文字列を表示
		function draw() {
			ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
			ctx.fillRect(0, 0, canvas.width, canvas.height);

			ctx.fillStyle = "#0F0"; // 文字の色
			ctx.font = "15px Courier"; // フォント
			for (var i = 0; i < length; i++) {
				var row = matrix[i];
				for (var j = 0; j < row.length; j++) {
					var char = row[j];
					ctx.fillText(char, i * 20, j * 20);
				}
				matrix[i].unshift(randomChar());
				matrix[i].pop();
			}
		}

		// 一定間隔でアニメーションを表示
		setInterval(draw, 100);
	</script>
</body>
</html>
    

ChatGPTで、四字熟語クイズのPython-Flaskアプリを作ってみた

ChatGPTで、四字熟語クイズのPython-Flaskアプリを作ってみました。

さすがに一発完成となるコードが出てくる指示文にするのは難しかったので、最初に考えていた機能から削っていき、簡略化してます。本当はセッション機能とか点数計算とかも入れたかったのですが。。。面倒になってきたので諦めました。

事前に問題データを作成してDBに入れてます。DB定義は以下です。


DB名: quiz.db

テーブル名: quiz

カラム :

  • question  #問題文が入る
  • answer  #正解が入る
  • explanation  #解説が入る
  • level  #問題の難易度が1~3の数字で入る

 

指示文(プロンプト):

PythonとFlaskで、簡単なクイズアプリを作りたいです。問題はSQLiteのquiz.dbに格納しています。

DBからレコードを1つランダムに取り出して、取り出したレコードの question、answer、explanation、level の内容を表示するFlaskアプリを書いてください。

「Next」ボタンを押すと、再びランダムにレコードを選んで表示するようにしてください。HTMLテンプレートのコードも提示してください。

クイズ画面の表示は以下のようにしてください。
・最初に表示するのはquestionとlevel だけ
・「答えは?」という入力フォームを表示する 
・answer 、explanation は最初は非表示にする
・入力フォームの内容と answer が一致していれば「正解」と表示して、非表示にしていたanswer、explanationを表示する 
・入力フォームの内容と answer が一致していなければ「不正解」と表示して、非表示にしていたanswer、explanationを表示する
・「わからないので正解を見る」をクリックしても、不正解としてanswer、explanationが表示されるようにする

 

回答:

以下は、ランダムにquiz.dbから1つのレコードを取り出し、Flaskアプリケーションで表示するコード例です。 "Next"ボタンを押すと、別のランダムなレコードが表示されます。


from flask import Flask, render_template, request
import sqlite3
import random

app = Flask(__name__)

@app.route('/')
def index():
    # データベースの接続とカーソルの生成
    conn = sqlite3.connect('quiz.db')
    c = conn.cursor()
    # ランダムに1つのレコードを取得
    c.execute('SELECT * FROM quiz ORDER BY RANDOM() LIMIT 1')
    row = c.fetchone()
    # データベースとの接続を切断
    conn.close()
    # テンプレートに値を渡してレンダリング
    return render_template('quiz.html', question=row[0], answer=row[1], explanation=row[2], level=row[3])

@app.route('/next', methods=['POST'])
def next():
    # データベースの接続とカーソルの生成
    conn = sqlite3.connect('quiz.db')
    c = conn.cursor()
    # ランダムに1つのレコードを取得
    c.execute('SELECT * FROM quiz ORDER BY RANDOM() LIMIT 1')
    row = c.fetchone()
    # データベースとの接続を切断
    conn.close()
    # テンプレートに値を渡してレンダリング
    return render_template('quiz.html', question=row[0], answer=row[1], explanation=row[2], level=row[3])

if __name__ == '__main__':
    app.run(debug=True)
    

上記のコードでは、Flaskアプリケーションでルートパスと /next の2つのエンドポイントを作成します。ルートパスでは、データベースからランダムなレコードを取得し、HTMLテンプレートに値を渡してレンダリングします。次へボタンを押すと、/nextエンドポイントが呼び出され、同じランダムなレコードが再び取得されて、テンプレートに値を渡してレンダリングします。また、SQLiteのRANDOM()関数を使用して、ランダムなレコードを取得します。

HTMLテンプレートは、以下のようになります。


<!DOCTYPE html>
<html>
  <head>
    <title>Quiz</title>
    <style>
      #answer {
        display: none;
      }
      #result {
        font-size:40px;
        font-weight: bold;
        margin: 50px;
      }
    </style>
    <script>
          function showAnswer() {
            document.getElementById("answer").style.display = "block";
          }
    </script>
    <script>
      function checkAnswer(event) {
        event.preventDefault();
        const answerInput = document.getElementById("answerInput");
        const result = document.getElementById("result");
        const answer = "{{ answer }}";
        if (answerInput.value === answer) {
          result.innerHTML = "正解";
          document.getElementById("answer").style.display = "block";
        } else {
          result.innerHTML = "不正解";
          document.getElementById("answer").style.display = "block";
        }
      }
    </script>    
  </head>
  <body>
    <h1>Question:</h1>
    <p>{{ question }}</p>
    <p>Level: {{ level }}</p>

    <form onsubmit="checkAnswer(event)">
      <label for="answerInput">答えは?</label>
      <input type="text" id="answerInput" name="answerInput">
      <button type="submit">回答する</button>

    <button onclick="showAnswer()">わからないので正解を見る</button>

    </form>

    <div id="result"></div>
    <div id="answer">
      <h2>Answer:</h2>
      <p>{{ answer }}</p>
      <h2>Explanation:</h2>
      <p>{{ explanation }}</p>

<form method="POST" action="/next">
  <input type="submit" value="Next">
</form>

    </div>


  </body>
</html>

    
結果:

一応、動作しました。「正解」「不正解」をわかりやすく表示したりと、見た目は少しだけ手作業でcssを整えています。

 

 

ChatGPTに、OpenCVを使って顔検知するPythonコードを書いてもらった

ChatGPTに、OpenCVを使って顔検知するPythonコードを書いてもらいました。

OpenCVには顔検知機能がデフォルトで含まれているので、新たに機械学習をかけなくても(精度は別として)すぐ使えます。便利ですね。

指示文(プロンプト):

PythonopenCVを使って、指定された画像から顔を認識して、顔部分を赤色の罫線で囲って表示し、別名で保存するプログラムを提示してください。検知された顔の座標値も出力するようにしてください。

回答:

PythonopenCVを使って、指定された画像から顔を認識して、顔部分を赤色の罫線で囲って表示し、別名で保存するプログラムは以下のようになります。


import cv2

# 画像を読み込む
image = cv2.imread('image.jpg')

# 顔検出用のカスケード分類器を読み込む
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# 画像をグレースケールに変換
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 顔を検出
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)

# 検出された顔に赤色の罫線を描画
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
    print(f'Face detected at x={x}, y={y}, w={w}, h={h}')

# 結果を表示
cv2.imshow('Faces', image)

# 結果を別名で保存
cv2.imwrite('result.jpg', image)

# キー入力待ち
cv2.waitKey(0)

# ウィンドウを閉じる
cv2.destroyAllWindows()
    

上記のコードは、写真の中に複数の顔がある場合、全ての顔を赤色の罫線で囲うようになっています。`face_cascade.detectMultiScale`メソッドは、画像内のすべての顔を検出し、その座標を`faces`変数に格納します。その後、`for`ループを使用して、検出されたすべての顔に赤色の罫線を描画します。

結果:

下記のように成功しました。掲載している検知前画像はBing-Image Creatorで生成したものです。

検知前:

検知後:

ChatGPTに、住所の文字列から都道府県名と市区町村名をそれぞれ抽出して、DBに別途保存するPythonコードを書いてもらった

ChatGPTに、住所の文字列から都道府県名、市区町村名、それ以降をそれぞれ抽出して、DBに別途保存するPythonコードを書いてもらいました。ダミーの会員情報を作成した後、住所が都道府県や市区町村に分離されていなく、集計の都合などで別カラムにしたい場合を想定しています(ダミー生成時にきちんと分けておけば良いだけですが。。。)

 

指示文(プロンプト):

「鹿児島県鴨川市鍛冶ケ沢17丁目22番1号」のような住所を示すテキストから、都道府県、市区町村名、それ以降をそれぞれ取り出すPythonコードを書いてください。正規表現を使ってください。読み込むDBは「dummy_data.db」、テーブルは「dummy_data」、住所テキストは「full_address」になります。都道府県は「prefecture」、市区町村は「city」、それ以降の文字列は「address1」に格納したいです。

 

回答:

import re
import sqlite3

# DBに接続
conn = sqlite3.connect("dummy_data.db")
cur = conn.cursor()

# テーブルから住所を取得
cur.execute("SELECT id, full_address FROM dummy_data")
rows = cur.fetchall()

# 正規表現で市区町村名を抽出
pattern = r"(.+?[都道府県])(.+?[市区町村])(.+)"
for row in rows:
    id = row[0]
    address = row[1]
    match = re.match(pattern, address)
    if match:
        prefecture = match.group(1)
        # prefectureカラムに保存
        cur.execute("UPDATE dummy_data SET prefecture = ? WHERE id = ?", (prefecture, id))
        city = match.group(2)
        # cityカラムに保存
        cur.execute("UPDATE dummy_data SET city = ? WHERE id = ?", (city, id))
        address1 = match.group(3)
        # address1カラムに保存
        cur.execute("UPDATE dummy_data SET address1 = ? WHERE id = ?", (address1, id))

# DBを閉じる
conn.commit()
conn.close()
    
結果:

以下のように成功しました。ダミーなので住所自体は架空のものです。滋賀県板橋区は無いですし。

取り出し後、改めて最初と最後の10件を取り出して目視確認。都道府県別の数も処理の前後でdiffなどで比較して、それも完全一致してましたので、漏れはなさそうですね。

ChatGPTに100万件のダミー会員情報を作成してもらった

ChatGPTに100万件のダミー会員情報を作成するPythonコードを書いてもらいました。とりあえず基本的な項目だけですが。

 

指示文(プロンプト):

以下のカラムでダミーのデータ100万件を生成し、データベースに保存するPythonコードを作成してください。

・氏名(漢字)
・氏名(カタカナ)
・生年月日(YYYYMMDD)
・性別(男|女|その他)
・メールアドレス
・電話番号
・郵便番号号
・住所

 

回答:

以下は、PythonでSQLite3を使用してダミーデータを生成し、データベースに保存するサンプルコードです。氏名、生年月日、メールアドレス、電話番号、住所のデータは、Fakerライブラリを使用して生成しています。住所のデータは、日本の都道府県・市区町村のリストからランダムに選んでいます。


import sqlite3
from faker import Faker
import random
import time

# データベース接続の設定
conn = sqlite3.connect('dummy_data.db')
c = conn.cursor()

# テーブル作成
c.execute('''CREATE TABLE IF NOT EXISTS dummy_data
             (id INTEGER PRIMARY KEY AUTOINCREMENT,
             name_kanji TEXT,
             name_katakana TEXT,
             birthdate TEXT,
             gender TEXT,
             email TEXT,
             phone TEXT,
             zipcode TEXT,
             prefecture TEXT)''')

# Fakerライブラリのインスタンス生成
fake = Faker('ja_JP')

# ダミーデータの生成
start_time = time.time()
for i in range(1000000):
    name_kanji = fake.name()
    name_katakana = fake.name()
    birthdate = fake.date_of_birth(minimum_age=18, maximum_age=70).strftime('%Y%m%d')
    gender = random.choice(['男', '女', 'その他'])
    email = fake.email()
    phone = fake.phone_number()
    zipcode = fake.zipcode()
    address = fake.address().split()
    prefecture = address[0]
    
    # データベースに保存
    c.execute("INSERT INTO dummy_data (name_kanji, name_katakana, birthdate, gender, email, phone, zipcode, prefecture) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
              (name_kanji, name_katakana, birthdate, gender, email, phone, zipcode, prefecture))
    
    # 10000件ごとにコミット
    if i % 10000 == 0:
        conn.commit()

# コミットして接続を終了
conn.commit()
conn.close()

# 経過時間の表示
elapsed_time = time.time() - start_time
print(f'elapsed_time:{elapsed_time:.3f} sec')
    
結果:

以下のように成功しました。Fakerライブラリは事前にインストールしています。

処理にかかった時間も最後に表示してくれていますが、elapsed_time:109.482 sec でした。

ダミーデータを細かく指定して生成してくれるWebサービスなどもありますが、件数制限がある場合には、手元でサクサクと作れると便利ですね。

ChatGPTに1000万行のテスト用DBを作成してもらった

ChatGPTに1000万行のテスト用DBを作成してもらいました。大きなデータを扱う際、いきなり本番データをいじるのは怖いとき、大体のサイズや処理負荷をつかむために、テストDBを立てることがありますが、そういう想定です。

 

指示文(プロンプト):

10カラムからなるテーブルを作成して、ランダムな8桁の数字で1000万レコード文のデータを生成してデータベースに格納するPythonコードを作成してください。DBはSQLiteにしてください。

 

回答:

import sqlite3
import random

# データベースに接続
conn = sqlite3.connect('sample.db')
cur = conn.cursor()

# テーブルを作成
cur.execute('''CREATE TABLE IF NOT EXISTS sample_table
               (col1 INTEGER, col2 INTEGER, col3 INTEGER, col4 INTEGER, col5 INTEGER,
                col6 INTEGER, col7 INTEGER, col8 INTEGER, col9 INTEGER, col10 INTEGER)''')

# 1000万行のデータを生成して挿入
for i in range(10000000):
    row_data = []
    for j in range(10):
        row_data.append(random.randint(10000000, 99999999))  # 8桁のランダムな数字を生成
    cur.execute('INSERT INTO sample_table VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', row_data)

# コミットして接続を閉じる
conn.commit()
conn.close()
    
結果:

以下のように成功しました。作成にかかる時間計測部分は手動で追加してます。データをいったんPandassに展開してます。DBのサイズは585MBでした。

追記:

SQLiteとPandasでデータを扱う際、どのくらい速度差があるのでしょうか。扱うデータ次第なので一概には言えませんが、普通の感覚では高速なのはPandasですが、ちょっと気になったので計測してみたところ、結果は以下でした。

ランダムに10万行分のデータを取り出して、すべての値を合計する処理を比較
SQLiteeから直で操作した場合の処理時間:7.423秒
Pandasで操作した場合の処理時間:4.587秒