ChatGPTを使って「クイズ☆タレント名鑑」のワンコーナーを蘇らせたい

「クイズ☆タレント名鑑」という番組をご存知ですか？

「水曜日のダウンタウン」の演出をされている藤井健太郎さんが、かつて手掛けていた番組です。
私はこの番組が大好きでした。

その番組のワンコーナーに「モノマネ芸人いる？いない？クイズ」というものがありました。

このコーナーは、アパレル君 / コマツ・デラックス / GO!ピロミ などといった多くのモノマネ芸人風の名前の中から、
実在すると思った芸人の名前を回答者が選び、実際にいたら正解、いなかったら不正解というもの。

放送終了から10年以上経ち、このコーナーのことなどまったく忘れていた私に、ふと天啓が舞い降りました。
<br>
**"ChatGPTを使えば存在しないモノマネ芸人を無限に作れる！！！"**
<br>
昔好きだったテレビ番組を復活させられるかもしれません。
さっそく作っていきましょう。

### 偽モノマネ芸人の生成
芸人さんのようなセンスのあるネーミングをChatGPTに考えさせるのは難しいのでは？と考えた方も多いかもしれません。

しかし、この１年、業務時間の大半をプロンプトチューニングに捧げてきた私にかかれば、そんなことは造作もありません。


```プロンプト.
あなたはセンスのあるbotです。
モノマネ芸人の芸名を考えてください。
元の名前をもじって、違う意味や逆の意味が生まれると良い芸名です。
### 例
アントニオ猪木→アントキの猪木
所ジョージ→所々ジョージ
佐藤栄作→佐藤B作
ひろゆき→ひろゆかない

### 入力
石田純一（いしだじゅんいち）
小栗旬（おぐりしゅん）
宇多田ヒカル（うただひかる）

### 出力フォーマット
それぞれ３つ芸名の候補を挙げてください。
元の名前→芸名１、芸名２、芸名３
```

これをGPT-4に入力すると...
```出力.
石田純一→石ころ純一、石投げ純一、石化純一
小栗旬→小栗不旬、小栗季節外れ、小栗熟成
宇多田ヒカル→宇多田ピカル、宇多田ヒカらない、宇多だヒカル
```


すばら！！！！

「もじって」みたいな指示を理解できるのがエグいですね。
まあ実際には、ゴミみたいな芸名も出力されるので、
大量出力した中から私が良いと感じた芸名を選抜するという手順を踏み、
100体の偽モノマネ芸人を作り出しました。


### 真モノマネ芸人の収集
ここが意外に難航しました。
いかした名前のモノマネ芸人が見つかりません。

いや、いるのでしょうが、ネットにあまり情報が見つかりません。
まだ地上波に露出していない人も多いのでしょう。

当時のスタッフさんすごい...
おそらく事務所に聞き込みしたり、地下ライブに潜ったりしたんだと思います。

私にそこまでのガッツはないので、いくつかのWEBサイトの情報をもとに、なんとか50件ほどの正解データを用意しました。


### クイズ画面の作成
フレームワークはflaskを使用しました。


```python:app.py
from flask import Flask, render_template
import random

app = Flask(__name__)

@app.route("/quiz")
def quiz():
    with open("true_mononames.txt", "r", encoding="utf-8") as f:
        true_mononames = f.readlines()
    with open("false_mononames.txt", "r", encoding="utf-8") as f:
        false_mononames = f.read().readlines()

    # 正解をランダムに３つ選ぶ
    sampled_true_mononames = random.sample(true_mononames, 3)

    # クイズリストを作成
    quiz_list = []
    for sampled_true_mononame in sampled_true_mononames:
        true_name, true_description = sampled_true_mononame.split("\t")
        # 不正解をランダムに3つ選び、不正解データから削除
        sampled_false_mononames = random.sample(false_mononames, 3)
        for sampled_false_mononame in sampled_false_mononames:
            false_mononames.remove(sampled_false_mononame)
        # 正解１つと不正解３つをセットにした選択肢を作成
        choices = [
            {"name": true_name, "correct": True, },
            {"name": sampled_false_mononames[0], "correct": False, },
            {"name": sampled_false_mononames[1], "correct": False, },
            {"name": sampled_false_mononames[2], "correct": False, },
        ]
        # 選択肢の順番をシャッフル
        random.shuffle(choices)
        quiz = {
            "description": true_description,
            "choices": choices,
        }
        quiz_list.append(quiz)
    
    return render_template("quiz.html", quiz_list=quiz_list, )

if __name__ == "__main__":
    app.run(host="0.0.0.0")


```


```html:quiz.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>この芸人いる？いない？クイズ</title>
    <link rel="stylesheet" href="/static/css/quiz.css">
    <link rel="icon" href="/static/image/favicon.png" type="image/png">
    <meta name="viewport" content="width=device-width,initial-scale=1">
</head>

<body>
    <div class="instruction">いる芸人を選べ</div>
    <div class="quiz-box"></div>
    <div class="eval-box"></div>
    <div class="comment-box"></div>
    <div class="bottom-box"></div>

    <script type="text/javascript">
        // 変数の初期化
        let correctCount = 0;
        let countable = true;
        let qi = 0;
        
        // flaskのデータをjsで受け取る
        const quizList = {{ quiz_list | tojson }};

        // クイズを表示する関数
        function displayQuiz(quiz) {
            const choices = quiz.choices

            const quizBox = document.querySelector('.quiz-box');
            const evalBox = document.querySelector('.eval-box');
            const commentBox = document.querySelector('.comment-box');
            const bottomBox = document.querySelector('.bottom-box');
            quizBox.innerHTML = '';
            evalBox.innerHTML = '';
            commentBox.innerHTML = '';
            bottomBox.innerHTML = '';

            countable = true; // 正解数をカウントできる状態にする

            for (let ci = 0; ci < choices.length; ci++) {
                const choiceButton = document.createElement('button');
                choiceButton.textContent = choices[ci].name;
                choiceButton.dataset.correct = choices[ci].correct;
                choiceButton.classList.add('choice-button');
                quizBox.appendChild(choiceButton);
            }

            const choiceButtons = document.querySelectorAll('.choice-button');
            choiceButtons.forEach(choiceButton => {
                choiceButton.addEventListener('click', () => {
                    // 選択肢のボタンからincorrectクラスを削除
                    choiceButtons.forEach(choiceButton => {
                        choiceButton.classList.remove('incorrect');
                    });

                    const isCorrect = choiceButton.dataset.correct === 'true';
                    if (isCorrect) {
                        // ボタンにクラスを付与
                        choiceButton.classList.add('correct');

                        // 円を表示
                        evalBox.innerHTML = '';
                        const circle = document.createElement('div');
                        circle.classList.add('circle');
                        evalBox.appendChild(circle);

                        // 正解コメント表示
                        commentBox.innerHTML = '';
                        const comment = document.createElement('div');
                        comment.textContent = `います！${quiz.description}のモノマネ芸人です`;
                        comment.classList.add('comment');
                        commentBox.appendChild(comment);

                        // 正解数をカウント
                        if (countable) {
                            correctCount += 1;
                            countable = false;
                        }


                        if (qi === quizList.length - 1) {
                            // 最終問題のときは結果を表示する
                            const result = document.createElement('div');
                            result.innerText = `${correctCount}/3正解しました`;
                            bottomBox.appendChild(result);

                            // リトライボタンを表示する
                            const retryButton = document.createElement('button');
                            retryButton.innerText = 'もう一度遊ぶ';
                            retryButton.addEventListener('click', () => {
                                location.reload();
                            });
                            retryButton.classList.add('retry-button');
                            bottomBox.appendChild(retryButton);


                        } else {
                            // 最終問題以外のときは、次の問題へボタンを表示する
                            const nextButton = document.createElement('button');
                            nextButton.innerText = '次の問題へ';
                            nextButton.addEventListener('click', () => {
                                qi += 1;
                                displayQuiz(quizList[qi]);
                                nextButton.remove();

                            });
                            nextButton.classList.add('next-button');
                            bottomBox.appendChild(nextButton);
                        }

                    } else {
                        // 選択されたボタンにincorrectクラスを付与する
                        choiceButton.classList.add('incorrect');

                        // バツを表示
                        evalBox.innerHTML = '';
                        const cross = document.createElement('div');
                        cross.classList.add('cross');
                        evalBox.appendChild(cross);

                        // 不正解コメント表示
                        commentBox.innerHTML = '';
                        const comment = document.createElement('div');
                        comment.textContent = `いません！もう一度選んで`;
                        comment.classList.add('comment');
                        commentBox.appendChild(comment);

                        // 1度不正解を選んだら、正解数がカウントされない状態にする
                        if (countable) {
                            countable = false;
                        }
                    }
                });
            });

        }

        // クイズの1問目を表示する
        displayQuiz(quizList[qi]);

    </script>

</body>
```


### いざ！復活の時！
それではさっそくサイトにアクセスしてみましょう。

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254014/39874303-573e-8331-d27f-f3ae5f95a63e.png">

...おおおおおおお！！！

.........
.......
..............

むっっっっっっっっっっっずい！！！
<br>
全員いそう。
<br>
ナンとルーを持ったインド人風のきゃりーぱみゅぱみゅが目に浮かびますね。

ちなみに、この問題の正解は、
「福山はさまる」です。
<br>
他の問題もなかなかの難問ぞろい。
以下から遊べるようにしたので、是非みなさんも挑戦してください。
https://faniest.com/quiz