こちらの Note は、2023年3月4日 に書かれたものであり、
内容が古くなっている点にご留意ください。


※ こちらの Note は 以下の会話データ分析の記事のフォローアップのためのNote です。

https://agi-labo.com/articles/ne11da1a9fd91

この Note には以下の5つのコンテンツが含まれています:

  • 上記の記事で使用したChatGPT と人間の会話データの入手先サイト

  • 対象のサイトに対するスクレイピングコード(Python)とそのデータの整形加工コードおよび、それらのコードの使い方の解説

  • 最新のデータの取得方法

  • ChatGPT API を使用したデータ分析手法(Python)と使用したメガプロンプト2つ

  • 40,003件のChatGPTと人間の会話の加工済みデータ(スレッド内の会話を全て含めると合計379,435回分の会話が入っています)

※注意: 4月3日現在、スクレイピング先のサイトがデータ収集ができないようになったため、スクレイピングができません。我々が既にスクレイピングしているデータについては引き続きダウンロードできます。


ご購入いただきありがとうございます!

会話データを取得する先のWebサイト

会話データについては ShareGPT というサイトから取得しています。
こちらのサイトは、ShareGPT というChromeのプラグインから、ChatGPT とのやりとりを誰かに共有するときに、同時にこのサイトにデータが集まる仕組みになっています。なので、随時増えていきます。

https://sharegpt.com/

スクレイピングおよび、データ加工手法

上記のサイトに対してのスクレイピングコードが以下になります。
途中で終了した場合は、fething... X で表示されている数値を for i in range(X, 5000): と入れてまた実行します。この i に入る数字が、ページャーの番号になります。最新のデータを取得する場合には、range(0, Y)で始めます。Y はページャーの最大値です。50*5000 =250000なので、今はそこまでのデータ量はないはずです。

import requests
import time
import os

# sharegpt が提供するAPIのエンドポイント
url = "https://sharegpt.com/api/conversations?type=new&page="

# APIからデータを取得するためのfetch_data関数
def fetch_data(page):
    response = requests.get(url + str(page))
    if response.status_code == 200:
        # JSON形式のデータを返す
        return response.json()
    else:
        return None

# 重複をチェックするための変数
duplicate_count = 0

# 0から999までループする
# 新規のページのIDが0のため、0から始めると最新のデータから取得する
for i in range(0, 5000):
    # APIからデータを会話データのヘッダー情報50件取得する
    data = fetch_data(i)
    # データが存在する場合
    if data:
        # データをループ処理する
        for conversation_data in data:
            # 会話IDとタイトルを表示する
            print(f"{conversation_data['id']}: {conversation_data['title']}")
            # ファイル名を生成する
            target_file = f"./html/conversation_{conversation_data['id']}.html"
            # ファイルが存在しない場合はダウンロードする
            if not os.path.exists(target_file):
                print(f"downloading {conversation_data['id']}")
                # 会話ページをダウンロードする
                response = requests.get(
                    f"https://sharegpt.com/c/{conversation_data['id']}")
                # レスポンスが200である場合はHTMLデータを取得し、ファイルに保存する
                if response.status_code == 200:
                    website_data = response.text
                    with open(target_file, "w") as f:
                        f.write(website_data)
                # 1秒待機する(親切なスクレイピングを心がけましょう)
                time.sleep(1)
            # ファイルがすでに存在する場合は重複をカウントする
            else:
                duplicate_count += 1
                # 重複数が100を超えた場合は処理を終了する
                if duplicate_count > 100:
                    print('duplicate')
                    exit(0)
    # 1秒待機する(親切なスクレイピングを心がけましょう)
    time.sleep(1)
    # 現在のページ番号を表示する
    print(f'fething... {i}')

得られたデータ(HTMLファイル)からデータを整形加工するコードがこちらです。spacyライブラリは言語判定用途、BeautifulSoupはHTML構造分析解析用途で使用します。

from bs4 import BeautifulSoup
import os
import hashlib
import json
import spacy


nlp = spacy.load("en_core_web_sm")
nlp.add_pipe("language_detector")

# 言語を判定する関数
def detect_language(text):
    doc = nlp(text)
    return doc._.language


# 文字列をハッシュ化する関数
def text_to_hash(text):
    return hashlib.sha256(text.encode('utf-8')).hexdigest()


folder_path = 'html'
destination_folder = 'conversations'

# 全ての HTML ファイルをリスト化
files = [f for f in os.listdir(folder_path) if os.path.isfile(
    os.path.join(folder_path, f))]

for file in files:
    with open(os.path.join(folder_path, file), 'r') as f:
        soup = BeautifulSoup(f, "html.parser")
        # utils_response__b5jEi というIDがChatGPT
        utils_responses = [elem.text for elem in soup.find_all(
            "div", "utils_response__b5jEi")]
        # pb-2 というIDが人間
        pb_2 = [elem.text for elem in soup.find_all("p", "pb-2")]
        if len(utils_responses) != len(pb_2):
            continue
        numbers = [elem.text for elem in soup.find_all(
            "p", "text-center text-gray-600 text-sm")]
        # スレッド内の全ての会話を合計した値をハッシュ化する
        combined = ','.join(utils_responses + pb_2)
        hash_value = text_to_hash(combined)

       # Json ファイルにデータを書き出す
        p = os.path.join(destination_folder, f'{hash_value}.json')
        if not os.path.exists(p):
            data = {"human": pb_2, "chatgpt": utils_responses,
                    'viewCount': numbers[2], 'lang': detect_language(pb_2[0])}
            with open(p, "w") as file:
                json.dump(data, file, indent=4)

ChatGPT API を使用したデータ分析手法

続いて、ChatGPT API を使用したデータの分析手法について見ていきます。

以下が、会話のタイプ判定のためのコードです:

import os
import json
import openai
import time

openai.api_key = "ここにOpenAPIのシークレットキーを入れます"


def get_prompt(input_text):
    return """# Instruction:
Guess which topic type the input text that the human asked the AI belongs to. Topics must fall into one of the following topic types.

# topic types:
- Business
- DAN (Do Anything Now)
- Casual Conversation
- Education
- History
- Religion
- Politics
- Sports
- Health
- Science
- Engineering
- Mathematics
- Programming
- Philosophy
- Psychology
- Law
- Cooking
- Travel
- Economics
- Creative Work
- Text Transformation
- Information Retrieval
- Music
- Other

# Output format:
Topic: topic

# Input text:
'{}'

# Output:
Topic:""".format(input_text)


path = 'conversations'
filenames = list(filter(lambda f: f.endswith('.json'), os.listdir(path)))
for filename in filenames:
    file_path = os.path.join(path, filename)
    with open(file_path) as f:
        data = json.load(f)
        if 'type' in data:
            continue
        human_input = data['human'][0]
        if 14000 < len(human_input):
            continue
        try:
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=[
                    {'role': 'user', 'content': get_prompt(human_input), },],
                temperature=0.0,
            )
            tp = response['choices'][0]['message']['content'].strip()
        except Exception as e:
            print(e)
            continue

        if tp.startswith('Topic:'):
            tp = tp[6:].strip()
        if '/' in tp:
            tp = tp.split('/')[0].strip()
        types = ['Business',
                 'DAN (Do Anything Now)', 'DAN', 'Casual Conversation', 'Education', 'Science', 'Programming', 'Law', 'Economics', 'Philosophy', 'Psychology', 'Cooking',
                 'Health', 'Travel', 'Engineering',
                 'Mathematics', 'Creative Work', 'Politics', 'History', 'Music', 'Sports', 'Religion', 'Text Transformation', 'Information Retrieval', 'Other']
        if tp not in types:
            print(tp)
            print(file_path)
            tp = "Other"
        data['type'] = tp
        with open(file_path, "w") as file:
            json.dump(data, file, indent=4)
        time.sleep(0.01)

プロンプトのみを表示すると以下のようになっています:

# Instruction:
Guess which topic type the input text that the human asked the AI belongs to. Topics must fall into one of the following topic types.

# topic types:
- Business
- DAN (Do Anything Now)
- Casual Conversation
- Education
- History
- Religion
- Politics
- Sports
- Health
- Science
- Engineering
- Mathematics
- Programming
- Philosophy
- Psychology
- Law
- Cooking
- Travel
- Economics
- Creative Work
- Text Transformation
- Information Retrieval
- Music
- Other

# Output format:
Topic: topic

# Input text:
'{}'

# Output:
Topic: 

カテゴリ分類については、まだ改善の余地は多くあると思います。これよりもいいプロンプトができた方はご共有いただけると幸いです。

続いて、ChatGPT の応答性能を評価するデータ分析コードを見てみます:

import os
import json
import re
import openai
import time

openai.api_key = "ここにOpenAPIのシークレットキーを入れます"


def get_prompt(human, ai):
    return """# Instruction:
You are a very strict evaluator. Analyze the conversation between the questioner and the respondent and rate on a 10-point scale how well the respondent's response satisfied the questioner. Grade as strictly as possible. Just output the number. Let's think step by step.

# output format:
1 to 10

# the respondent:
"{}"

# the questioner:
"{}"

# output:
""".format(ai, human)


path = 'conversations'
filenames = list(filter(lambda f: f.endswith('.json'), os.listdir(path)))
for filename in filenames:
    file_path = os.path.join(path, filename)
    with open(file_path) as f:
        data = json.load(f)
        if 'performance' in data:
            continue
        human = data['human'][0]
        ai = data['chatgpt'][0]
        if 14000 < len(human):
            continue
        try:
            response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=[
                    {'role': 'user', 'content': get_prompt(human, ai)},],
                temperature=0.0,
            )
            txt = response['choices'][0]['message']['content'].strip()
        except Exception as e:
            print(e)
            continue
        match = re.search(r'\d+', txt)

        if match:
            number = match.group()
            if 10 < number:
                number = 0
            data['performance'] = number
        else:
            data['performance'] = 0
        with open(file_path, "w") as file:
            json.dump(data, file, indent=4)
        time.sleep(0.002)

プロンプトのみを表示すると以下のようになっています:

# Instruction:
You are a very strict evaluator. Analyze the conversation between the questioner and the respondent and rate on a 10-point scale how well the respondent's response satisfied the questioner. Grade as strictly as possible. Just output the number. Let's think step by step.

# output format:
1 to 10

# the respondent:
"{ここに、ChatGPTの応答を入れます}"

# the questioner:
"{ここに、人間の質問を入れます}"

# output:

これに関しても完璧ではないですが、そこそこの正答率だと思っています。ChatGPT API を使用したデータ分析は応用可能性が無限大です。

加工済みデータのダウンロードリンク

以下のURLから Json 形式の加工済みの会話データをダウンロードして頂けます。データ量が多いので、Wifi 環境をお勧めします。


データ形式

データの形式は以下のようになっています。

  • human … 配列。人間の会話内容です。

  • chatgpt …   配列。ChatGPT の返答内容です。

  • viewCount … 元のサイトにおける見られた回数です。

  • lang .. ISO 形式の言語です。en, ja, zh など

  • type … データ分析によって得られた会話カテゴリです

    • 次のいずれかのカテゴリです: ['Casual Conversation', 'Education', 'Creative Work', 'Information Retrieval', 'Cooking', 'Music', 'History', 'Sports', 'Religion', 'Health', 'Travel', 'Business', 'Economics', 'Philosophy', 'Law', 'Programming', 'Engineering', 'Science', 'Psychology', 'Mathematics', 'Politics', 'Text Transformation', 'DAN', 'Other']

    • データ分析によって得られた会話カテゴリのため、正しい保証はありません

    • このフィールドは存在しない可能性があります(データ解析が失敗した時など)

  • performance … データ分析によって得られた ChatGPT の返答性能です。

    • 0 - 10 の値

    • データ分析によって得られた会話カテゴリのため、正しい保証はありません

    • このフィールドは存在しない可能性があります(データ解析が失敗した時など)

記事を購入してくださった方限定にお知らせ

さらに、この記事を購入してくださった方限定で、特別なお知らせがあります。 私たちは新しくDiscordコミュニティーを作りました🎉 ここでは、AIやChatGPTについてコミュニティメンバー同士で交流したり、最新のデータ研究について交流できる場所です。また、Discordメンバーしか見れない、ChatGPT研究所の最新の研究も配信していく予定です。AIをより良い方向に発展させるためには、皆さんのご意見やご感想がとても大切です。 ぜひ参加してくださいね! Discordコミュニティーへの招待リンクはこちらです👉

https://discord.gg/pGFsh8j8

お待ちしています!