お疲れ様です<(_ _)>

 

5時。

 

徹夜でございます。

たった1度のBBQ夜更かしで

息子のリズムが崩壊し、夜泣きしています。

 

3時に晩飯食わせ、寝るかと思ったけど

地獄

 

 

9時から療育だし、もう寝られん

 

 

ところでchatGPT-o1

 

解禁になりました!!

今まで4oはめんどくさい奴だけど

天才だと思っていましたが

 

もう彼がバカに見えるw

 

 

高度な推論を~とか書いてます通り

何か送信したらすぐ「はい!それはこうです!」なんて

返す4oと異なり

 

まず考えるんですねw

”考え中(〇〇を)”とか表示も出て

あの可能性を検討中・・

あれを手伝うため・・

とか

 

愛らしい感じw

 

 

そして、しっかり考えて少し待たせるのに

相応しい高度な回答をくれますね!!

 

chatBotの制作のためのデータベース構築を

かなり手伝ってもらって

156083文字・・ね

 

いよいよデータベースの実装開始

そして数パターン可能性を探っていたら

 

 

 

制限にかかる、まぁGPTあるある

 

と思いきや

 

9月25日!?

はあx!???

 

3時間後とかじゃないんか・・

マジで天から血

 

 

4oに戻ると作業は難航の一歩

ミスるし忘れるし

まったくもうwwww

 

だめ!だから言ってんじゃんさっき!

 

とかGPTにキレ入力しだす

すると向こうも

 

そうだな、お前の言ってることはわかった。

 

とかキレ気味で返してくるw

やめれww

 

 

 

そして、データベースを参照してキーワードをランダムに

抽出し、それを質問として出力するA

 

それに対してデータベースを参照して正確な情報を

伝えるB

 

 

という2人でエンドレスでゲームの攻略情報を

吐き続けるBotがふんわり完成しました。。

 

データベースが不完全、プロンプトのレベルも低い

ので、イマイチですが

かなりの精度でデータベースから情報を引っ張り出して

質問も回答もしていますね、かわいい

 

動作確認は↓12パターンのうちの10番目の二人

 

 

コードは↓多分、5時間ぐらいでAPIは0.6ドルぐらい消費する

 

import openai
import requests
import urllib.parse
import os
import time
import re
import sqlite3
import random

# OpenAI APIキーの設定(環境変数から取得)
openai.api_key = os.getenv('OPENAI_API_KEY')

def get_chatgpt_responses(prompt, current_role, db_connection):
    """
    AとBのリアクションを生成し、Aはデータベースから質問を生成し、Bはデータベースから回答します。
    """
    role_instructions = {
        'A': (
            "あなたはギャルです。以下のゲーム情報を元に、"
            "データベース内の情報、文章を全て参照しランダムに抽出、それについてあらゆる角度から質問をしてください。抽出したキーワードは””で囲うこと。"
            "ギャル語を使い、30文字以内で質問してください。"
        ),
        'B': (
            "あなたはMADISLANDというゲームの攻略情報を熟知している専門家です。"
            "ユーザーからの質問に対し、不可解な質問であってもキーワードを理解し、データベースから関連情報を取得し、関連情報を統合し、柔軟に、適切な文言に変換し解説してください。"
            "回答は50文字以内で、補足情報があれば提供してください。データベースにない嘘は絶対につかないこと。"
        )
    }

    if current_role == 'A':
        # Aはデータベースから攻略に関連した質問を生成
        game_info = get_random_game_info(db_connection)
        if game_info is None:
            game_info_text = "データベースから情報が取得できなかったよ。"
        else:
            game_info_text = f"ゲーム情報: {game_info}"

        # ChatGPTへのメッセージを構築
        messages = [
            {"role": "system", "content": role_instructions[current_role]},
            {"role": "assistant", "content": game_info_text}
        ]
    else:
        # BはAの質問に対して回答を返す
        db_info = query_database(prompt, db_connection)
        messages = [
            {"role": "system", "content": role_instructions[current_role]},
            {"role": "user", "content": f"{prompt}"}
        ]
        if db_info:
            db_info_text = format_db_info(db_info)
            messages.append({"role": "assistant", "content": f"関連情報:\n{db_info_text}"})
        else:
            # 柔軟な返答
            messages.append({"role": "assistant", "content": generate_fallback_response()})

    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=messages
    )

    response_text = response.choices[0].message['content'].strip()
    print(f"API応答 ({current_role}): {response_text}")

    return response_text

def get_random_game_info(db_connection):
    """
    データベースから攻略に関連する情報を取得します。
    """
    cursor = db_connection.cursor()

    # データベース内の全テーブル名を取得
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
    tables = cursor.fetchall()

    random.shuffle(tables)

    for table_name_tuple in tables:
        table_name = table_name_tuple[0]
        try:
            cursor.execute(f"PRAGMA table_info('{table_name}');")
            columns_info = cursor.fetchall()
            columns = [info[1] for info in columns_info if info[1].lower() != 'id']

            if not columns:
                continue

            cursor.execute(f"SELECT * FROM '{table_name}' ORDER BY RANDOM() LIMIT 1;")
            row = cursor.fetchone()
            if not row:
                continue

            row_dict = dict(zip([desc[0] for desc in cursor.description], row))

            key_info = ', '.join(f"{k}: {v}" for k, v in row_dict.items() if v)
            return f"テーブル: {table_name}, データ: {key_info}"
        except sqlite3.Error as e:
            print(f"Error accessing table '{table_name}': {e}")
            continue

    return None

def query_database(prompt, db_connection):
    """
    ユーザーの入力に基づいてデータベース全体をクエリし、関連情報を取得します。
    """
    cursor = db_connection.cursor()

    # データベース内の全テーブル名を取得
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
    tables = cursor.fetchall()

    results = []

    keywords = extract_keywords(prompt)

    for table_name_tuple in tables:
        table_name = table_name_tuple[0]
        cursor.execute(f"PRAGMA table_info('{table_name}');")
        columns_info = cursor.fetchall()
        columns = [info[1] for info in columns_info]

        for keyword in keywords:
            for column in columns:
                try:
                    query = f"SELECT * FROM '{table_name}' WHERE \"{column}\" LIKE ? LIMIT 1;"
                    cursor.execute(query, ('%' + keyword + '%',))
                    row = cursor.fetchone()
                    if row:
                        row_dict = dict(zip([desc[0] for desc in cursor.description], row))
                        result_entry = {
                            'table': table_name,
                            'column': column,
                            'data': row_dict
                        }
                        results.append(result_entry)
                        break
                except sqlite3.Error as e:
                    print(f"Error querying table '{table_name}', column '{column}': {e}")
                    continue

    if results:
        return results
    else:
        return None

def extract_keywords(text):
    """
    テキストからキーワードを抽出します。(簡易的な実装)
    """
    words = re.findall(r'\w+', text)
    keywords = [word for word in words if len(word) > 1]
    return keywords

def format_db_info(db_info):
    """
    データベースから取得した情報をフォーマットします。
    """
    formatted = ""
    for entry in db_info:
        data = entry['data']
        key_info = ', '.join(f"{k}: {v}" for k, v in data.items() if v)
        formatted += f"{key_info}\n"
    return formatted.strip()

def generate_fallback_response():
    """
    データベースに関連情報がない場合の曖昧な返答を生成。
    """
    fallback_responses = [
        "それ、ちょっとわからないかも!",
        "新しい情報?詳しく教えてほしいな。",
        "今は情報が手元にないみたい、ごめん!"
    ]
    return random.choice(fallback_responses)

def clean_text(text):
    """
    テキストから不要な文字を削除する
    """
    text = re.sub(r"^[AB]:\s*", "", text).strip()
    text = re.sub(r"(令和ギャル|雑学おじさん):", "", text).strip()
    text = re.sub(r"(【.*?】)", "", text).strip()
    return text

def send_to_bouyomi(text, voice, speed, volume):
    """
    棒読みちゃんにテキストを読み上げさせる
    """
    voice_settings = f"voice={voice}&volume={volume}&speed={speed}"
    encoded_text = urllib.parse.quote(text)
    url = f"http://localhost:50080/talk?text={encoded_text}&{voice_settings}"
    requests.get(url)

def write_to_text_file(filename, text):
    """
    テキストをファイルに出力する (OBS用)
    """
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(text)

if __name__ == "__main__":
    db_connection = sqlite3.connect('game_database.db')  # データベースのパスを指定

    current_role = 'A'  # 開始時の役割

    while True:
        if current_role == 'A':
            # Aはデータベースから攻略に関連した質問をする
            response_text = get_chatgpt_responses('', current_role, db_connection)

            clean_response_text = clean_text(response_text)
            print(f"棒読みちゃん用テキスト (A): {clean_response_text}")
            send_to_bouyomi(clean_response_text, voice="1", speed=130, volume=40)
            write_to_text_file('bouyomi_output.txt', clean_response_text)
            current_role = 'B'  # 次はBのリアクション
            user_input = clean_response_text
        else:
            # Bのリアクションを生成
            response_text = get_chatgpt_responses(user_input, current_role, db_connection)

            clean_response_text = clean_text(response_text)
            print(f"リアクションテキスト (B): {clean_response_text}")
            send_to_bouyomi(clean_response_text, voice="4", speed=140, volume=40)
            write_to_text_file('reaction_output.txt', clean_response_text)
            current_role = 'A'

        time.sleep(10)

    db_connection.close()